diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 50cb129308f7cace7fb98f3fb3dbc5ac8df507f3..803ffb5d5c39c60760e60e2fd30963f9f60779a4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -67,7 +67,7 @@ trigger_build:
        -F "variables[WEBUI]=$CI_COMMIT_REF_NAME"
        -F "variables[TriggerdBy]=WEBUI"
        -F "variables[TriggerdByHash]=$CI_COMMIT_SHORT_SHA"
-       -F ref=master https://gitlab.indiscale.com/api/v4/projects/14/trigger/pipeline
+       -F ref=dev https://gitlab.indiscale.com/api/v4/projects/14/trigger/pipeline
 
 # Build a docker image in which tests for this repository can run
 build-testenv:
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..e5a4b171688b22f0295cff46dd407eaaa85a99be
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,47 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+### Added (for new features, dependecies etc.)
+
+* Map (v0.1)
+    * adds a button to the navbar which toggles a map in the top of the main
+      panel. The map currently shows all entities on the current page and can be used to select an area in the map and generate a query filter for this area which is can be openend in the query panel.
+    * see the caosdb_map module in  [ext_map.js](./src/core/js/ext_map.js)
+    * the default configuration is located in the module itself.
+    * the module needs an additional [ext.json](./conf/ext/json/ext_map.json)
+      defines at least the tiling server. The tiling server is not configured
+      in the default config because this would require the caosdb maintainers
+      to enforce the respective usage policies of the tiling server providers.
+    * test data for your server can be generated with [map_test_data.py](./misc/map_test_data.py).
+* navbar module (v0.1)
+    * A collection of helper functions for adding stuff to the navbar.
+* caosdb_utils module (v0.1)
+    * A collection of helper functions for multiple purposes, especially for
+      checking a functions parameters (to mimic type savety).
+* New Dependency: leaflet-1.5-1
+    * for the map
+* New Dependency: loglevel-1.6.4
+    * our new logging framework. Any new logging should be done with this framework.
+
+### Changed (for changes in existing functionality)
+
+* in [entity.xsl](./src/core/xsl/entity.xsl): an emtpy property value (a `NULL` property) did not produce any `<span>` element with class `caosdb-property-text-value`. This caused the current implementation of `getPropertyFromElement` in [caosdb.js](./src/core/js/caosdb.js) to return the unit of the property as the value. The new implementation produces an empty `<span>` (no child text node) which is more appropriate and also fixes the buggy `getPropertyFromElement` without touching it.
+* in [webcaosdb.js](./src/core/js/webcaosdb.js), `markdown` module: The markdown module is very generell and small now. The logic for converting comments (aka CommentAnnotations) to markdown is implemented in the `annotation` module now (which uses the `markdown` module as back-end, tho).
+
+### Deprecated (for soon-to-be removed features) 
+
+### Removed (for now removed features) 
+
+* Removed non-informative tests for webcaosdb.css
+
+### Fixed (for any bug fixes) 
+
+* Bug in `getPropertyFromElement` (see above) which returned the unit as the property value if the actual value was an empty string.
+
+### Security (in case of vulnerabilities)
+
diff --git a/README.md b/README.md
index 189909c71df33064092308d575e672784903b26e..3f144a30731dab4f425f3f8978248f730a4c392c 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 <!--THIS FILE HAS BEEN GENERATED BY A SCRIPT. PLEASE DON'T CHANGE IT MANUALLY.-->
 
+Project migrated to https://gitlab.com/caosdb
+
 # Welcome
 
 This is the **CaosDB WebUI** repository and a part of the CaosDB project.
diff --git a/doc/QueryShortcuts/choose_edit.png b/doc/QueryShortcuts/choose_edit.png
new file mode 100644
index 0000000000000000000000000000000000000000..3866cea1ffcad5c675357cff335baddccb3e8efd
Binary files /dev/null and b/doc/QueryShortcuts/choose_edit.png differ
diff --git a/doc/QueryShortcuts/create_shortcut.png b/doc/QueryShortcuts/create_shortcut.png
new file mode 100644
index 0000000000000000000000000000000000000000..537a128559ea9eced1e0b24dbaeb0a1a931c8109
Binary files /dev/null and b/doc/QueryShortcuts/create_shortcut.png differ
diff --git a/doc/QueryShortcuts/create_success.png b/doc/QueryShortcuts/create_success.png
new file mode 100644
index 0000000000000000000000000000000000000000..5259849e135b5f63c53e29838134c9e17f34c1cc
Binary files /dev/null and b/doc/QueryShortcuts/create_success.png differ
diff --git a/doc/QueryShortcuts/delete_shortcuts.png b/doc/QueryShortcuts/delete_shortcuts.png
new file mode 100644
index 0000000000000000000000000000000000000000..385ea33c2fdbb89c20355c66458ccea0a770d3ab
Binary files /dev/null and b/doc/QueryShortcuts/delete_shortcuts.png differ
diff --git a/doc/QueryShortcuts/delete_success.png b/doc/QueryShortcuts/delete_success.png
new file mode 100644
index 0000000000000000000000000000000000000000..1e9f727f4420ab478d327175318924a329960810
Binary files /dev/null and b/doc/QueryShortcuts/delete_success.png differ
diff --git a/doc/QueryShortcuts/doc.pdf b/doc/QueryShortcuts/doc.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..0f7e46bb78b4f8c6cf7a30216cb9f507be747ad4
Binary files /dev/null and b/doc/QueryShortcuts/doc.pdf differ
diff --git a/doc/QueryShortcuts/doc.tex b/doc/QueryShortcuts/doc.tex
new file mode 100644
index 0000000000000000000000000000000000000000..4cd78391d1cda808dc9c332328d3a984ae5926d8
--- /dev/null
+++ b/doc/QueryShortcuts/doc.tex
@@ -0,0 +1,192 @@
+\documentclass{article}
+% General document formatting
+\usepackage[margin=0.7in]{geometry}
+\usepackage[parfill]{parskip}
+\usepackage[utf8]{inputenc}
+\usepackage{graphicx}
+
+% Related to math
+\usepackage{amsmath,amssymb,amsfonts,amsthm}
+\title{Documentation Query Shortcuts}
+
+\begin{document}
+\maketitle
+\section{Introduction}\label{introduction}
+
+The WebUI supports the creation of query shortcuts which appear below
+the normal query input field. These shortcuts facilitate looking for
+data as query strings which are used frequently. They can be stored and
+reused.
+
+\begin{figure}[h]
+\centering
+\includegraphics[width=.8\textwidth]{shortcut_toolbox.png}
+\caption{The Shortcuts in the Query Panel; Note the Toolbox for in the top
+right}
+\end{figure}
+
+There are two ways to integrate query templates into the WebUI:
+
+\begin{itemize}
+\item
+  Global shortcuts are integrated by the webmaster only. They are
+  defined and stored in a\\
+  \texttt{./conf/ext/json/globale\_query\_shortcuts.json} in the root
+  directory of the webui.
+\item
+  User-defined templates can be defined by users and are only visible
+  for the user who created them. In this sense, user-defined shortcuts
+  are also private, whereas global shortcuts are always publicly
+  visible.
+\end{itemize}
+
+\section{User-defined Query Shortcuts}\label{user-defined-query-shortcuts}
+
+\subsection{Create a New Shortcut}\label{create-a-new-shortcut}
+
+New Query Shortcuts can be generated by any authenticated user with
+sufficient write permissions.
+
+In the web interface, click \texttt{Query}. In the \texttt{Shortcuts}
+section, click the wrench (on the right side).
+
+In the drop-down menu, click \texttt{Create}.
+
+It now opens a form with two input fields, \texttt{Description} and
+\texttt{Query}.
+\begin{figure}[h]
+\centering
+\includegraphics[width=.6\textwidth]{create_shortcut.png}
+\caption{The view to create a new shortcut}
+\end{figure}
+
+See \ref{basic-shortcut} and
+\ref{advanced-shortcut} for further
+explanation of the components of a Query Shortcut.
+
+Edit the fields and click \texttt{Submit} for the creation of the new
+shortcut or click \texttt{Cancel} to cancel the process.
+
+The new shortcut is shown in the shortcuts section.
+\begin{figure}[h]
+\centering
+\includegraphics[width=.6\textwidth]{create_success.png}
+\caption{The view when creation was successful}
+\end{figure}
+
+\subsection{Change an Existing Shortcut}\label{change-an-existing-shortcut}
+
+Existing Query Shortcuts which are visible in your shortcuts section can
+be edited directly in the shortcuts section.
+
+In the web interface, click \texttt{Query}. In the \texttt{Shortcuts}
+section, click the wrench (on the right side).
+
+In the drop-down menu, click \texttt{Edit}.
+
+\begin{figure}[h]
+\centering
+\includegraphics[width=.6\textwidth]{choose_edit.png}
+\caption{Choosing which shortcut to edit}
+\end{figure}
+Every editable shortcut (note: global shortcuts are not editable in the
+webinterface at all) will receive a new button \texttt{Edit}
+
+Click \texttt{Edit} of the shortcut that is to be changed.
+
+It now opens a form with two input fields, \texttt{Description} and
+\texttt{Query}, pre-filled.
+
+See \ref{basic-shortcut} and
+\ref{advanced-shortcut} for further
+explanation of the components of a Query Shortcut.
+
+Edit the fields and click \texttt{Submit} for the creation of the new
+shortcut or click \texttt{Cancel} to cancel the process.
+
+The updated shortcut is shown in the shortcuts section.
+
+See the
+
+\subsection{Delete an Existing Shortcut}\label{delete-an-existing-shortcut}
+
+Existing Query Shortcut which are visible in your shortcuts section can
+be edited directly in the shortcuts section.
+
+In the web interface, click \texttt{Query}. In the \texttt{Shortcuts}
+section, click the wrench (on the right side).
+
+In the drop-down menu, click \texttt{Delete}.
+\begin{figure}[h]
+\centering
+\includegraphics[width=.6\textwidth]{delete_shortcuts.png}
+\caption{Choosing which shortcuts to delete}
+\end{figure}
+
+Every user-defined shortcut (note: global shortcuts are not deletable in
+the webinterface at all) will receive checkbox and \texttt{Delete} and
+\texttt{Cancel} buttons appear at the bottom of the shortcuts section.
+
+Check all shortcuts which are to be deleted and click \texttt{Delete} or
+click \texttt{Cancel} to cancel the deletion.
+
+All deleted shortcuts are marked as deleted afterwards and will not
+appear again in the shortcuts section after reload.
+
+\subsection{Basic Shortcut}\label{basic-shortcut}
+
+The \texttt{Description} is a verbose definition of the query,
+e.g.~``Search for experiments and return a table.''. It will be the text
+that is visible in the shortcuts section.
+
+The \texttt{Query} is the query that will be executed with the shortcut.
+It adheres to the definition of the CaosDB Query Language (CQL).
+
+The corresponding query of our example is
+\texttt{SELECT\ date,\ name\ FROM\ Experiment}.
+
+\subsection{Advanced Shortcut}\label{advanced-shortcut}
+
+The basic shortcut does not allow for any parameterization. It is just a
+plain string or like a bookmark.
+
+Advanced shortcuts use a special syntax, where text placeholders are
+used to define parameters of the shortcut. The parameters can be set by
+the user at the time of the execution. An example can best illustrate
+what that means:
+
+Suppose you want to search for experiments by their year. The query for
+that would be
+\texttt{SELECT\ date,\ name\ FROM\ Experiment\ WITH\ date\ IN\ 2018}.
+
+Now, the actual year in the query can be made editable by replacing the
+year \texttt{2018} with \texttt{\{year\}}.
+
+The \texttt{Description} now must also contain this placeholder
+\texttt{\{year\}}, e.g.~``Search for experiements conducted in year
+\{year\}''. When the shortcut is displayed in the shortcuts section
+below the query input field, the placeholder is replaced by a text input
+field and the user can insert a year and execute the shortcut with the
+year being inserted into the query.
+
+\subsubsection{Placeholders}\label{placeholders}
+
+The placeholders have simple rules. A placeholder always starts and ends
+with curly brackets, like in the example \texttt{\{year\}}. The text
+inside the brackets (the placeholder's \emph{id}) may contain any
+combination of alphanumeric signs (0-9,a-z,A-Z). The use of special
+characters like colons, commas or the like is discouraged. They are
+reserved for future extensions of the placeholders. Apart from that, you
+are free to choose any placeholder \emph{id} that seems suitable for
+you.
+
+Both components of the query shortcut (description and query) must
+contain the same set of placeholders, otherwise the query shortcuts
+might not work as intended. If there is a \texttt{\{year\}} in the
+query, there must be a \texttt{\{year\}} in the description.
+
+Each placeholder \emph{id} must occur only once in both components -- if
+you need to use two years in your shortcut you have to use
+\texttt{\{year1\}} and \texttt{\{year2\}} or any other combinations of
+placeholder \emph{ids}.
+\end{document}
diff --git a/doc/QueryShortcuts/edit_shortcut.png b/doc/QueryShortcuts/edit_shortcut.png
new file mode 100644
index 0000000000000000000000000000000000000000..55360e538ce4665ca27f6f43639dbafbd3293974
Binary files /dev/null and b/doc/QueryShortcuts/edit_shortcut.png differ
diff --git a/doc/QueryShortcuts/edit_success.png b/doc/QueryShortcuts/edit_success.png
new file mode 100644
index 0000000000000000000000000000000000000000..2223489ddafa6b3a6141eca3d8fcfca722248a89
Binary files /dev/null and b/doc/QueryShortcuts/edit_success.png differ
diff --git a/doc/QueryShortcuts/shortcut_toolbox.png b/doc/QueryShortcuts/shortcut_toolbox.png
new file mode 100644
index 0000000000000000000000000000000000000000..27db06379cfa883727118ce6ca58ca7676360572
Binary files /dev/null and b/doc/QueryShortcuts/shortcut_toolbox.png differ
diff --git a/doc/Templates.md b/doc/Templates.md
deleted file mode 100644
index 9e8b3861ecce15f3af4665c44af1a1c76fdcea11..0000000000000000000000000000000000000000
--- a/doc/Templates.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Documentation of Query Templates for WebUI
-
-The WebUI supports the creation of user templates which appear below the normal query input field. These templates facilitate looking for data as query strings which are used frequently can be stored and reused.
-
-There are two ways to integrate query templates into the WebUI:
-
-- Default templates are integrated by the webmaster only.
-- Custom templates can be integrated using the "New Template" button.
-
-# Template definition
-
-Templates are defined using a special syntax. Every template has a description and a corresponding query.
-
-The description is a verbose definition of the query, e.b. "Search for experiments and return a table.".
-The corresponding query will probably be similar to "SELECT date, name FROM Experiment".
-
-Templates can contain placeholders which will be used to generate an editable field. Suppose we want to search for experiments with a specific year and return them using SELECT. This would look like:
-
-description: Search for experiments which were done in {text} and return a table.
-query: SELECT date, name FROM Experiment with date in "$1"
-
-The placeholder {text} can be used multiple times and will lead to the creation of variables called $1, $2, ... in query. The numbers specifying the variable are created in the order of appearance of {text}.
diff --git a/libs/L.Graticule.js b/libs/L.Graticule.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e761339d5f75a5df3f190251e3e55e02abd0694
--- /dev/null
+++ b/libs/L.Graticule.js
@@ -0,0 +1,104 @@
+/*
+ Graticule plugin for Leaflet powered maps.
+*/
+L.Graticule = L.GeoJSON.extend({
+
+    options: {
+        style: {
+            color: '#333',
+            weight: 1
+        },
+        interval: 20
+    },
+
+    initialize: function (options) {
+        L.Util.setOptions(this, options);
+        this._layers = {};
+
+        if (this.options.sphere) {
+            this.addData(this._getFrame());
+        } else {
+            this.addData(this._getGraticule());
+        }
+    },
+
+    _getFrame: function() {
+        return { "type": "Polygon",
+          "coordinates": [
+              this._getMeridian(-180).concat(this._getMeridian(180).reverse())
+          ]
+        };
+    },
+
+    _getGraticule: function () {
+        var features = [], interval = this.options.interval;
+
+        // Meridians
+        for (var lng = 0; lng <= 180; lng = lng + interval) {
+            features.push(this._getFeature(this._getMeridian(lng), {
+                "name": (lng) ? lng.toString() + "° E" : "Prime meridian"
+            }));
+            if (lng !== 0) {
+                features.push(this._getFeature(this._getMeridian(-lng), {
+                    "name": lng.toString() + "° W"
+                }));
+            }
+        }
+
+        // Parallels
+        for (var lat = 0; lat <= 90; lat = lat + interval) {
+            features.push(this._getFeature(this._getParallel(lat), {
+                "name": (lat) ? lat.toString() + "° N" : "Equator"
+            }));
+            if (lat !== 0) {
+                features.push(this._getFeature(this._getParallel(-lat), {
+                    "name": lat.toString() + "° S"
+                }));
+            }
+        }
+
+        return {
+            "type": "FeatureCollection",
+            "features": features
+        };
+    },
+
+    _getMeridian: function (lng) {
+        lng = this._lngFix(lng);
+        var coords = [];
+        for (var lat = -90; lat <= 90; lat++) {
+            coords.push([lng, lat]);
+        }
+        return coords;
+    },
+
+    _getParallel: function (lat) {
+        var coords = [];
+        for (var lng = -180; lng <= 180; lng++) {
+            coords.push([this._lngFix(lng), lat]);
+        }
+        return coords;
+    },
+
+    _getFeature: function (coords, prop) {
+        return {
+            "type": "Feature",
+            "geometry": {
+                "type": "LineString",
+                "coordinates": coords
+            },
+            "properties": prop
+        };
+    },
+
+    _lngFix: function (lng) {
+        if (lng >= 180) return 179.999999;
+        if (lng <= -180) return -179.999999;
+        return lng;
+    }
+
+});
+
+L.graticule = function (options) {
+    return new L.Graticule(options);
+};
diff --git a/libs/Leaflet.Coordinates-0.1.5.zip b/libs/Leaflet.Coordinates-0.1.5.zip
new file mode 100644
index 0000000000000000000000000000000000000000..72cb7ed98237ae674bb08b7cfadf77ef24956e52
Binary files /dev/null and b/libs/Leaflet.Coordinates-0.1.5.zip differ
diff --git a/libs/Proj4Leaflet-1.0.1.zip b/libs/Proj4Leaflet-1.0.1.zip
new file mode 100644
index 0000000000000000000000000000000000000000..474b0fb2b841e9ff6ce6648d76b97755dfdb4f4e
Binary files /dev/null and b/libs/Proj4Leaflet-1.0.1.zip differ
diff --git a/libs/bootstrap-select-v1.13.9.zip b/libs/bootstrap-select-v1.13.9.zip
new file mode 100644
index 0000000000000000000000000000000000000000..f52eea6450673782ba84504b249d65f3e6f8fa14
Binary files /dev/null and b/libs/bootstrap-select-v1.13.9.zip differ
diff --git a/libs/leaflet-1.5.1.zip b/libs/leaflet-1.5.1.zip
new file mode 100644
index 0000000000000000000000000000000000000000..aa9c1093dc6532db695cec997810602606a0800b
Binary files /dev/null and b/libs/leaflet-1.5.1.zip differ
diff --git a/libs/leaflet.latlng-graticule-20191007.zip b/libs/leaflet.latlng-graticule-20191007.zip
new file mode 100644
index 0000000000000000000000000000000000000000..559c37ab51d49830ac45baedb139384c81684d87
Binary files /dev/null and b/libs/leaflet.latlng-graticule-20191007.zip differ
diff --git a/libs/loglevel-1.6.4.zip b/libs/loglevel-1.6.4.zip
new file mode 100644
index 0000000000000000000000000000000000000000..b50137a5974e5e7bad0fec813ac34e30044338ad
Binary files /dev/null and b/libs/loglevel-1.6.4.zip differ
diff --git a/libs/proj4js-2.5.0.zip b/libs/proj4js-2.5.0.zip
new file mode 100644
index 0000000000000000000000000000000000000000..f0172ef5839233873e32ede6942e8e1415f95772
Binary files /dev/null and b/libs/proj4js-2.5.0.zip differ
diff --git a/makefile b/makefile
index 54d06ea3038f943eaef268ca2444b9dde0603181..3da0e43822f807e866c5953871361364efb5eb3b 100644
--- a/makefile
+++ b/makefile
@@ -23,6 +23,8 @@
 
 # Unzip all the external libraries and set up the links in the public folder
 
+PERCENT=%
+BUILD_NUMBER:=$(shell date +$(PERCENT)s)
 SQ=\'
 ROOT_DIR = $(abspath .)
 MISC_DIR = $(abspath misc)
@@ -34,7 +36,7 @@ SRC_EXT_DIR = $(abspath src/ext)
 LIBS_DIR = $(abspath libs)
 TEST_CORE_DIR = $(abspath test/core/)
 TEST_EXT_DIR = $(abspath test/ext)
-LIBS = fonts css/bootstrap.css js/bootstrap.js js/state-machine.js js/jquery.js js/showdown.js js/dropzone.js css/dropzone.css
+LIBS = fonts css/bootstrap.css js/bootstrap.js js/state-machine.js js/jquery.js js/showdown.js js/dropzone.js css/dropzone.css js/loglevel.js js/leaflet.js css/leaflet.css css/images js/leaflet-latlng-graticule.js js/proj4.js js/proj4leaflet.js js/leaflet-coordinates.js css/leaflet-coordinates.css js/leaflet-graticule.js js/bootstrap-select.js css/bootstrap-select.css
 
 TEST_LIBS = $(LIBS) js/qunit.js css/qunit.css $(subst $(TEST_CORE_DIR)/,,$(shell find $(TEST_CORE_DIR)/))
 
@@ -44,6 +46,9 @@ LIBS_SUBDIRS = $(addprefix $(LIBS_DIR)/, js css fonts)
 ALL: install
 
 install: clean cp-src cp-ext cp-conf $(addprefix $(PUBLIC_DIR)/, $(LIBS))
+	for f in $$(grep "__BUILD_NUMBER__" -r -l public/); do \
+		sed -i "s/__BUILD_NUMBER__/$(BUILD_NUMBER)/g" $$f ; \
+	done
 
 test: clean cp-src cp-ext cp-ext-test cp-conf $(addprefix $(PUBLIC_DIR)/, $(TEST_LIBS))
 	@for f in $(shell find $(TEST_EXT_DIR) -type f -iname *.js) ; do \
@@ -55,6 +60,9 @@ test: clean cp-src cp-ext cp-ext-test cp-conf $(addprefix $(PUBLIC_DIR)/, $(TEST
 		echo include $$f; \
 	done
 	ln -s $(PUBLIC_DIR) $(PUBLIC_DIR)/webinterface
+	for f in $$(grep "__BUILD_NUMBER__" -r -l public/); do \
+		sed -i "s/__BUILD_NUMBER__/$(BUILD_NUMBER)/g" $$f ; \
+	done
 
 PORT = 8000
 TIMEOUT = 500
@@ -94,11 +102,7 @@ run-qunit:
 cp-ext:
 	for f in $(wildcard $(SRC_EXT_DIR)/js/*) ; do \
 		echo "y" | cp -i -r "$$f" $(PUBLIC_DIR)/js/ ; \
-		sed -i "/JS_EXTENSIONS/a \<xsl:element name=\"script\"><xsl:attribute name=\"src\"><xsl:value-of select=\"concat\(\$$basepath, 'webinterface$${f#$(SRC_EXT_DIR)}'\)\" /></xsl:attribute></xsl:element>" $(PUBLIC_DIR)/xsl/main.xsl ; \
-	done
-	for f in $(wildcard $(SRC_EXT_DIR)/css/*) ; do \
-		echo "y" | cp -i -r "$$f" $(PUBLIC_DIR)/css/ ; \
-		sed -i "/CSS_EXTENSIONS/a \<xsl:element name=\"link\"><xsl:attribute name=\"rel\">stylesheet</xsl:attribute><xsl:attribute name=\"href\"><xsl:value-of select=\"concat\(\$$basepath, 'webinterface$${f#$(SRC_EXT_DIR)}'\)\" /></xsl:attribute></xsl:element>" $(PUBLIC_DIR)/xsl/main.xsl ; \
+		sed -i "/EXTENSIONS/a \<xsl:element name=\"script\"><xsl:attribute name=\"src\"><xsl:value-of select=\"concat\(\$$basepath, 'webinterface/__BUILD_NUMBER__$${f#$(SRC_EXT_DIR)}'\)\" /></xsl:attribute></xsl:element>" $(PUBLIC_DIR)/xsl/main.xsl ; \
 	done
 	mkdir -p $(PUBLIC_DIR)/html
 	for f in $(wildcard $(SRC_EXT_DIR)/html/*) ; do \
@@ -114,7 +118,7 @@ cp-ext:
 cp-ext-test:
 	for f in $(wildcard $(TEST_EXT_DIR)/js/*) ; do \
 		echo "y" | cp -i -r "$$f" $(PUBLIC_DIR)/js/ ; \
-		sed -i "/EXTENSIONS/a \<xsl:element name=\"script\"><xsl:attribute name=\"src\"><xsl:value-of select=\"concat\(\$$basepath, 'webinterface$${f#$(SRC_EXT_DIR)}'\)\" /></xsl:attribute></xsl:element>" $(PUBLIC_DIR)/xsl/main.xsl ; \
+		sed -i "/EXTENSIONS/a \<xsl:element name=\"script\"><xsl:attribute name=\"src\"><xsl:value-of select=\"concat\(\$$basepath, 'webinterface/__BUILD_NUMBER__$${f#$(SRC_EXT_DIR)}'\)\" /></xsl:attribute></xsl:element>" $(PUBLIC_DIR)/xsl/main.xsl ; \
 	done
 	mkdir -p $(PUBLIC_DIR)/html
 	for f in $(wildcard $(TEST_EXT_DIR)/html/*) ; do \
@@ -139,15 +143,17 @@ convert-yaml:
 
 cp-src:
 	cp -r $(SRC_CORE_DIR) $(PUBLIC_DIR)
+	echo $(BUILD_NUMBER) > $(PUBLIC_DIR)/.build_number
+	ln -s $(PUBLIC_DIR) $(PUBLIC_DIR)/$(BUILD_NUMBER)
 
 $(PUBLIC_DIR)/%: $(LIBS_DIR)/%
 	ln -s $< $@
 
 $(PUBLIC_DIR)/%: $(TEST_CORE_DIR)/%
-	ln -s $< $@
+	cp -r $< $@
 
 $(PUBLIC_DIR)/%: $(TEST_EXT_DIR)/%
-	ln -s $< $@
+	cp -r $< $@
 
 $(LIBS_DIR)/fonts: unzip
 	ln -s $(LIBS_DIR)/bootstrap-3.3.7-dist/fonts $@
@@ -158,6 +164,12 @@ $(LIBS_DIR)/js/bootstrap.js: unzip $(LIBS_DIR)/js
 $(LIBS_DIR)/css/bootstrap.css: unzip $(LIBS_DIR)/css
 	ln -s $(LIBS_DIR)/bootstrap-3.3.7-dist/css/bootstrap.min.css $@
 
+$(LIBS_DIR)/js/bootstrap-select.js: unzip $(LIBS_DIR)/js
+	ln -s $(LIBS_DIR)/bootstrap-select-1.13.9/dist/js/bootstrap-select.min.js $@
+
+$(LIBS_DIR)/css/bootstrap-select.css: unzip $(LIBS_DIR)/css
+	ln -s $(LIBS_DIR)/bootstrap-select-1.13.9/dist/css/bootstrap-select.min.css $@
+
 $(LIBS_DIR)/js/jquery.js: unzip $(LIBS_DIR)/js
 	ln -s $(LIBS_DIR)/jquery-3.3.1/jquery-3.3.1.min.js $@
 
@@ -179,6 +191,37 @@ $(LIBS_DIR)/js/dropzone.js: unzip $(LIBS_DIR)/js
 $(LIBS_DIR)/css/dropzone.css: unzip $(LIBS_DIR)/css
 	ln -s $(LIBS_DIR)/dropzone-5.5.0/dist/dropzone.css $@
 
+$(LIBS_DIR)/js/loglevel.js: unzip $(LIBS_DIR)/js
+	ln -s $(LIBS_DIR)/loglevel-1.6.4/loglevel.min.js $@
+
+$(LIBS_DIR)/js/leaflet.js: unzip $(LIBS_DIR)/js $(LIBS_DIR)/css/leaflet.css
+	ln -s $(LIBS_DIR)/leaflet-1.5.1/leaflet.js $@
+
+$(LIBS_DIR)/css/leaflet.css: $(LIBS_DIR)/css/images
+	ln -s $(LIBS_DIR)/leaflet-1.5.1/leaflet.css $@
+
+$(LIBS_DIR)/css/images: unzip $(LIBS_DIR)/css
+	ln -s $(LIBS_DIR)/leaflet-1.5.1/images $@
+
+$(LIBS_DIR)/js/leaflet-graticule.js: unzip $(LIBS_DIR)/js
+	ln -s $(LIBS_DIR)/L.Graticule.js $@
+
+$(LIBS_DIR)/js/leaflet-latlng-graticule.js: unzip $(LIBS_DIR)/js
+	ln -s $(LIBS_DIR)/leaflet.latlng-graticule-20191007/leaflet.latlng-graticule.js $@
+
+$(LIBS_DIR)/js/proj4.js: unzip $(LIBS_DIR)/js
+	ln -s $(LIBS_DIR)/proj4js-2.5.0/dist/proj4.js $@
+
+$(LIBS_DIR)/js/proj4leaflet.js: unzip $(LIBS_DIR)/js
+	ln -s $(LIBS_DIR)/Proj4Leaflet-1.0.1/src/proj4leaflet.js $@
+
+$(LIBS_DIR)/js/leaflet-coordinates.js: unzip $(LIBS_DIR)/js
+	ln -s $(LIBS_DIR)/Leaflet.Coordinates-0.1.5/dist/Leaflet.Coordinates-0.1.5.min.js $@
+
+$(LIBS_DIR)/css/leaflet-coordinates.css: unzip $(LIBS_DIR)/css
+	ln -s $(LIBS_DIR)/Leaflet.Coordinates-0.1.5/dist/Leaflet.Coordinates-0.1.5.css $@
+
+
 $(addprefix $(LIBS_DIR)/, js css):
 	mkdir $@ || true
 
diff --git a/misc/map_test_data.py b/misc/map_test_data.py
new file mode 100755
index 0000000000000000000000000000000000000000..addc0e8c7f52cc60d228e079e5b76f5893be74d4
--- /dev/null
+++ b/misc/map_test_data.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+(C) Copyright IndiScale GmbH 2019
+"""
+
+import caosdb
+import random
+
+caosdb.get_connection()._login()
+
+# data model
+datamodel = caosdb.Container()
+datamodel.extend([
+    caosdb.Property("longitude", datatype=caosdb.DOUBLE, unit="°"),
+    caosdb.Property("latitude", datatype=caosdb.DOUBLE, unit="°"),
+    caosdb.RecordType(
+        "MapObject"
+        ).add_property("longitude", importance=caosdb.OBLIGATORY
+        ).add_property("latitude", importance=caosdb.OBLIGATORY),
+])
+
+datamodel.insert()
+
+
+# test data
+
+
+
+
+testdata = caosdb.Container()
+
+for i in range(100):
+    testdata.append(
+        caosdb.Record(
+            "Object-{}".format(i)
+            ).add_parent("MapObject"
+            ).add_property("longitude", random.gauss(-42.0, 5)
+            ).add_property("latitude", random.gauss(77.0, 5))
+    )
+
+testdata.insert();
+
+
+
diff --git a/misc/query_shortcuts_test_data.py b/misc/query_shortcuts_test_data.py
new file mode 100755
index 0000000000000000000000000000000000000000..1fdcf463fc0ae0265f006d866a4302df7a278560
--- /dev/null
+++ b/misc/query_shortcuts_test_data.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+(C) Copyright IndiScale GmbH 2019
+"""
+
+import caosdb
+
+caosdb.get_connection()._login()
+
+# data model
+if caosdb.execute_query("COUNT RecordType UserTemplate") == 0:
+
+    datamodel = caosdb.Container()
+    datamodel.extend([
+        caosdb.Property("Query", datatype=caosdb.TEXT),
+        caosdb.Property("templateDescription", datatype=caosdb.TEXT),
+        caosdb.RecordType(
+            "UserTemplate"
+            ).add_property("Query", importance=caosdb.OBLIGATORY
+            ).add_property("templateDescription", importance=caosdb.OBLIGATORY),
+    ])
+
+    datamodel.insert()
+
+
+# test data
+testdata = caosdb.Container()
+
+if caosdb.execute_query("COUNT Record 'Test Template (Delete with Error)'") == 0:
+    testdata.append(
+        caosdb.Record(
+            "Test Template (Delete with Error)"
+            ).add_parent("UserTemplate"
+            ).add_property("Query", "FIND Error"
+            ).add_property("templateDescription",
+                           "Test Template (Delete with Error)")
+    )
+
+if caosdb.execute_query("COUNT Record 'Test Template (Referencing)'") == 0:
+    testdata.append(
+        caosdb.Record(
+            "Test Template (Referencing)"
+            ).add_parent("UserTemplate"
+            ).add_property("UserTemplate", "Test Template (Delete with Error)")
+    )
+
+for i in range(2):
+    testdata.append(
+        caosdb.Record(
+            "Test Template (User {})".format(i)
+            ).add_parent("UserTemplate"
+            ).add_property("Query", "FIND Thing{}".format(i)
+            ).add_property("templateDescription",
+                           "Test Template (User {})".format(i))
+    )
+
+testdata.insert();
+
+
+
diff --git a/src/core/js/annotation.js b/src/core/js/annotation.js
index d5d3dd17a0c272d274d01900f29a5f2b0a7ea7cd..8a05bd0e03e6b3dc94488bedf27d99c8de32c415 100644
--- a/src/core/js/annotation.js
+++ b/src/core/js/annotation.js
@@ -302,7 +302,22 @@ this.annotation = new function() {
             $(this).html('');
             $(this).text(text);
         });
-        return markdown.toHtml(ret);
+        return annotation.markdownToHtml(ret);
+    }
+
+    this.markdownToHtml = function(textElement) {
+        if ($(textElement).hasClass('markdowned')) {
+            return textElement;
+        }
+        $(textElement).toggleClass('markdowned', true);
+
+        $(textElement).find(".caosdb-comment-annotation-text").each(function() {
+            markdown.toHtml(this);
+        });
+        $(textElement).find(".media-body:not(:has(.media-heading))").each(function() {
+            $('<h4 class="media-heading">You<small><i> just posted</i></small></h4>').prependTo($(this));
+        });
+        return textElement;
     }
 
     /**
@@ -332,7 +347,7 @@ this.annotation = new function() {
      * @return an array of DOMElements.
      */
     this.getAnnotationsForEntity = async function(entityId, requestDatabase, xslPromise) {
-        return markdown.toHtml((await asyncXslt(requestDatabase(entityId), xslPromise)).firstChild.children);
+        return annotation.markdownToHtml((await asyncXslt(requestDatabase(entityId), xslPromise)).firstChild.children);
     }
 
     this.queryAnnotation = function(referencedId) {
@@ -347,7 +362,7 @@ this.annotation = new function() {
         return $.ajax({
             cache: true,
             dataType: 'xml',
-            url: basepath + "webinterface/xsl/annotation.xsl",
+            url: basepath + "webinterface/__BUILD_NUMBER__/xsl/annotation.xsl",
         });
     }
 
diff --git a/src/core/js/caosdb.js b/src/core/js/caosdb.js
index d9dfe23d5c56033432439970689f2662d7d95592..85032d8e973f64f94565fff2e1b3187f735d9021 100644
--- a/src/core/js/caosdb.js
+++ b/src/core/js/caosdb.js
@@ -114,13 +114,22 @@ function getEntities() {
  * @return A String holding the role or undefined if the role could not be found.
  */
 function getEntityRole(element) {
-    if (typeof element.dataset.entityRole !== 'undefined') {
-        return element.dataset.entityRole;
+    if ($(element).is("[data-entity-role]")) {
+        return $(element).attr("data-entity-role");
     }
+    if ($(element).is(".caosdb-f-entity-role")) {
+        return $(element).text();
+    }
+
 
-    let res = element.getElementsByClassName("caosdb-f-entity-role");
+    let res = $(element).find("[data-entity-role]");
     if (res.length == 1) {
-        return res[0].dataset.entityRole;
+        return res.attr("data-entity-role");
+    }
+
+    res = $(element).find(".caosdb-f-entity-role");
+    if (res.length == 1) {
+        return res.text();
     }
     return undefined;
 }
@@ -359,6 +368,37 @@ function findElementByConditions(element, condition, except) {
     return found;
 }
 
+function getEntityXML(ent_element) {
+    var xml = createEntityXML(
+        getEntityRole(ent_element),
+        getEntityName(ent_element),
+        getEntityID(ent_element),
+        getProperties(ent_element),
+        getParents(ent_element),
+        true,
+        getEntityDatatype(ent_element),
+        getEntityDescription(ent_element),
+        getEntityUnit(ent_element),
+    );
+    return xml;
+}
+
+function getPropertyName(element) {
+    var name_element = element.getElementsByClassName("caosdb-property-name");
+    if(name_element.length > 0) {
+        return name_element[0].textContent;
+    } else if ($(element).is("[data-property-name]")) {
+        return $(element).attr("data-property-name");
+    }
+
+    var ret = $(element).find("[data-property-name]").attr("data-property-name");
+    if (ret && ret.length > 0) {
+        return ret;
+    } else {
+        return undefined;
+    }
+}
+
 /**
  *  Return a list of property objects from the dom property element.
  *  @param propertyelement: A HTMLElement identifying the property element.
@@ -369,27 +409,28 @@ function findElementByConditions(element, condition, except) {
 function getPropertyFromElement(propertyelement, names = undefined) {
 
     let property = new Object({});
-    let namel = propertyelement.getElementsByClassName("caosdb-property-name")[0];
     let valel = propertyelement.getElementsByClassName("caosdb-property-value")[0];
     let dtel = propertyelement.getElementsByClassName("caosdb-property-datatype")[0];
     let idel = propertyelement.getElementsByClassName("caosdb-property-id")[0];
     let unitel = valel.getElementsByClassName("caosdb-unit")[0];
 
-    if (typeof unitel == "undefined") {
-        property.unit = undefined;
-    } else {
-        property.unit = unitel.textContent.trim();
-    }
-    if (namel === undefined) {
-        property.name = undefined;
-    } else {
-        property.name = namel.textContent;
-    }
+    // name
+    property.name = getPropertyName(propertyelement);
+
+    // id
     if (idel === undefined) {
         property.id = undefined;
     } else {
         property.id = idel.textContent;
     }
+
+    // unit
+    if (typeof unitel == "undefined") {
+        property.unit = undefined;
+    } else {
+        property.unit = unitel.textContent.trim();
+    }
+
     if (dtel === undefined) {
         property.datatype = undefined;
         property.list = undefined;
@@ -404,6 +445,7 @@ function getPropertyFromElement(propertyelement, names = undefined) {
             property.value = [];
             var list_datatype = property.datatype.substring(5, property.datatype.length - 1);
             property.reference = base_datatypes.filter(el => el == list_datatype).length == 0;
+            property.listDatatype = list_datatype;
         } else {
             property.list = false;
             property.value = "";
@@ -416,6 +458,13 @@ function getPropertyFromElement(propertyelement, names = undefined) {
         valel = valel.getElementsByClassName("caosdb-property-text-value")[0];
     }
 
+    var value_string = undefined;
+    if (valel && valel.textContent.length > 0) {
+        value_string = valel.textContent;
+    } else if (valel && valel.value &&  valel.value.length > 0 ) {
+        value_string = valel.value;
+    }
+
     // Needed for multiple properties with the same name:
     // It is not set when names is undefined.
     if (!(names === undefined)) {
@@ -427,7 +476,7 @@ function getPropertyFromElement(propertyelement, names = undefined) {
         property.duplicateIndex = names.get(property.name);
     }
 
-    if (valel !== undefined && valel.textContent.length > 0) {
+    if (typeof value_string !== "undefined") {
         // This is set to true, when there is a reference or a list of references:
         property.reference = (valel.getElementsByClassName("caosdb-id").length > 0);
         if (property.list) {
@@ -457,7 +506,7 @@ function getPropertyFromElement(propertyelement, names = undefined) {
             property.value = getIDfromHREF(valel.getElementsByTagName("a")[0]);
         } else {
             // all other datatypes
-            property.value = valel.textContent.trim();
+            property.value = value_string;
         }
     }
 
@@ -472,15 +521,16 @@ function getPropertyFromElement(propertyelement, names = undefined) {
  */
 function getPropertyElements(element) {
     return findElementByConditions(element,
-        x => x.classList.contains("list-group-item") &&
-        x.classList.contains("caosdb-property-row"),
+        x => x.classList.contains("caosdb-property-row"),
         x => x.classList.contains("caosdb-preview-container"));
 }
 
 /**
- * Return high level representations of the properties of an entity.
- * @param element The element holding the entity.
- * @return a list of objects for the properties according to the following specification.
+ * Return JavaScript object representations of the properties of an entity.
+ *
+ * @param {HTMLElement} element - The element holding the entity.
+ * @return {object[]} A list of objects for the properties according to the
+ *     following specification.
  *
  *
  * Specification of properties:
@@ -589,13 +639,14 @@ function setProperty(element, property) {
 }
 
 /**
- * Get a property by name.
- * @param element The element holding the entity.
- * @param property_name The name of the property.
- * @param case_sensitive If true search for property names case-sensitively. Otherwise neglect the case ("A" and "a" are equivalent).
- *                         Optional. Default is true.
- * @return The value of the the property with property_name.
- * This function returns undefined when this property is not available for this entity.
+ * Get a property value by name from an Entity in HTML representation.
+ *
+ * @param {HTMLElement} element - The element holding the entity.
+ * @param {string} property_name - The name of the property.
+ * @param {boolean} [case_sensitive=True] - If true search for property names
+ *     case-sensitively. Otherwise neglect the case ("A" and "a" are
+ *     equivalent).
+ * @returns {string} The value of the the property with property_name or `undefined` when this property is not available for this entity.
  */
 function getProperty(element, property_name, case_sensitive=true) {
     var props;
@@ -632,7 +683,7 @@ function setNameID(parentElement, parent) {
  * @param parent An object containing a name and or an id.
  */
 function appendParent(doc, element, parent) {
-    var parentElement = doc.createElement("Parent");
+    var parentElement = document.createElementNS(undefined, "Parent");
     setNameID(parentElement, parent);
     element.appendChild(parentElement);
 }
@@ -645,8 +696,8 @@ function appendParent(doc, element, parent) {
  * @param value
  */
 function appendValueNode(doc, element, name, value) {
-    let el = doc.createElement(name);
-    let valel = doc.createTextNode(value);
+    let el = document.createElementNS(undefined, name);
+    let valel = document.createTextNode(value);
     el.appendChild(valel);
     element.appendChild(el);
 }
@@ -659,9 +710,9 @@ function appendValueNode(doc, element, name, value) {
  * @param property An object specifying a property.
  */
 function appendProperty(doc, element, property, append_datatype = false) {
-    var propertyElement = doc.createElement("Property");
+    var propertyElement = document.createElementNS(undefined, "Property");
     setNameID(propertyElement, property);
-    if (append_datatype == true) {
+    if (append_datatype && typeof property.datatype !== "undefined") {
         propertyElement.setAttribute("datatype", property.datatype);
     }
     if (typeof property.unit !== 'undefined') {
@@ -678,7 +729,7 @@ function appendProperty(doc, element, property, append_datatype = false) {
                 appendValueNode(doc, propertyElement, "Value", property.value);
             }
         } else {
-            let valel = doc.createTextNode(property.value);
+            let valel = document.createTextNode(property.value);
             propertyElement.appendChild(valel);
         }
     }
@@ -687,6 +738,27 @@ function appendProperty(doc, element, property, append_datatype = false) {
 }
 
 
+/**
+ * Return a new Document or DocumentFragment, depending on the availability of the latter.
+ *
+ * Helper function.
+ *
+ * @param {string} root - the new root element.
+ * @returns {(Document|DocumentFragement)} the new document.
+ */ 
+function _createDocument(root) {
+    var doc = undefined;
+    if (window.DocumentFragment) {
+        doc = new DocumentFragment();
+        const rootNode = document.createElementNS(undefined, root);
+        doc.append(rootNode);
+    } else {
+        doc = document.implementation.createDocument(null, root, null);
+    }
+    return doc;
+}
+
+
 /**
  * Create an XML for an entity.
  * This function uses the object notation.
@@ -697,12 +769,14 @@ function appendProperty(doc, element, property, append_datatype = false) {
  * @param id The id of the entity. Can be undefined.
  * @param properties A list of properties.
  * @param parents A list of parents.
- * @return A document holding the newly created entity.
+ * @return {Document|DocumentFragement} - An xml document holding the newly
+ *         created entity.
  *
  */
 function createEntityXML(role, name, id, properties, parents,
     append_datatypes = false, datatype = undefined, description = undefined, unit = undefined) {
-    var doc = document.implementation.createDocument(null, role, null);
+
+    var doc = _createDocument(role);
     var nelnode = doc.children[0];
     setNameID(nelnode, {
         name: name,
@@ -738,47 +812,58 @@ function createEntityXML(role, name, id, properties, parents,
 /**
  * Helper function to wrap xml documents into another node which could e.g. be
  * Update, Response, Delete.
- * @param The name of the newly created top level node.
- * @param The xml document.
- * @return A new xml document.
+ *
+ * @param {string} root - The name of the newly created document root node.
+ * @param {(Document|XMLDocumentFragment)} xmls The xml documents.
+ * @return {Document} A new xml document.
  */
-function wrapXML(elementname, xml) {
-    var doc = document.implementation.createDocument(null, elementname, null);
+function wrapXML(root, xmls) {
+    xmls = caosdb_utils.assert_array(xmls, "param `xmls`", true);
+    caosdb_utils.assert_string(root, "param `root`");
+
+    var doc = _createDocument(root);
+    for (var i=0; i < xmls.length; i++) {
+        doc.firstElementChild.appendChild(xmls[i].firstElementChild);
+    }
 
-    doc.children[0].appendChild(xml.children[0]);
     return doc;
 }
 
 /**
  * Convert this xml document into an update.
- * @param The xml document.
- * @return A new xml document.
+ * @param {(Document[]|DocumentFragment[])} xmls - Array of xml documents.
+ * @return {(Document|DocumentFragment)} A new xml document.
  */
-function createUpdate(xml) {
-    return wrapXML("Request", xml);
+function createUpdate(xmls) {
+    return wrapXML("Request", xmls);
 }
 
 /**
- * Convert this xml document into an insert.
- * @param The xml document.
- * @return A new xml document.
+ * Concat and convert these xml documents into an insert request body for caosdb server.
+ *
+ * @param {(Document[]|DocumentFragment[])} xmls - Array of xml documents.
+ * @return {(Document|DocumentFragment)} A new xml document.
  */
-function createInsert(xml) {
-    return wrapXML("Request", xml);
+function createInsert(xmls) {
+    return wrapXML("Request", xmls);
 }
 
 /**
  * Convert this xml document into a response.
- * @param The xml document.
- * @return A new xml document.
+ *
+ * @param {(Document[]|DocumentFragment[])} xmls - Array of xml documents.
+ * @return {(Document|DocumentFragment)} A new xml document.
  */
-function createResponse(xml) {
-    return wrapXML("Response", xml);
+function createResponse(xmls) {
+    return wrapXML("Response", xmls);
 }
 
 
 /**
  * Retrieve an entity by using an id or a name.
+ *
+ * TODO merge with connection.retrieveEntityById
+ *
  * @param id The id of the entity. Can be undefined when name is used.
  * @param name The name of the entity. Can be undefined when id is used.
  * @return The element holding that entity.
@@ -834,13 +919,18 @@ async function retrieve_data_model() {
  * @param xml The xml of the entity which will be automatically wrapped with an Update.
  */
 async function update(xml) {
-    return transaction.updateEntitiesXml(createUpdate(xml));
+    var wrapped = createUpdate(xml);
+    return await transaction.updateEntitiesXml(wrapped);
 }
 
 /**
- * Insert an entity using its xml representation.
- * @param xml The xml of the entity which will be automatically wrapped with an Insert.
+ * Insert an entity in xml representation.
+ *
+ * @param {(Document[]|DocumentFragment[])} xml - xml of the entities which
+ *        will be automatically wrapped with an Insert.
+ * @returns {Document} server response.
  */
 async function insert(xml) {
-    return transaction.insertEntitiesXml(createInsert(xml));
+    var wrapped = createInsert(xml);
+    return await transaction.insertEntitiesXml(wrapped);
 }
diff --git a/src/core/js/edit_mode.js b/src/core/js/edit_mode.js
index a31dd2cc351960986d1b7fbb20a32231f74a55df..1aa5626744150bdd1ba7eda6f0875f5378b30b7e 100644
--- a/src/core/js/edit_mode.js
+++ b/src/core/js/edit_mode.js
@@ -22,6 +22,8 @@
  * ** end header
  */
 
+"use strict";
+
 /**
  * Edit mode module
  */
@@ -287,19 +289,43 @@ var edit_mode = new function() {
         return this.update_entity(ent_element);
     }
 
-    this.insert_entity = async function(ent_element) {
-        var xml = createEntityXML(
-            getEntityRole(ent_element),
-            getEntityName(ent_element),
-            undefined,
-            edit_mode.getProperties(ent_element),
-            getParents(ent_element),
-            true,
-            getEntityDatatype(ent_element),
-            getEntityDescription(ent_element),
-            getEntityUnit(ent_element),
-        );
-        return await insert(xml);
+    /**
+     * Insert entities.
+     *
+     * @param {(HTMLElement|HTMLElement[])} ent_elements - a single or an array
+     *        of entities in HTML representation.
+     * @returns {XMLDocument} the unprocessed server response.
+     */
+    this.insert_entity = async function(ent_elements) {
+        ent_elements = caosdb_utils.assert_array(ent_elements, "param `ent_elements`", true);
+        var xmls = [];
+        for ( const ent_element of ent_elements ) {
+            xmls.push(createEntityXML(
+                getEntityRole(ent_element),
+                getEntityName(ent_element),
+                undefined,
+                edit_mode.getProperties(ent_element),
+                getParents(ent_element),
+                true,
+                getEntityDatatype(ent_element),
+                getEntityDescription(ent_element),
+                getEntityUnit(ent_element),
+            ));
+        }
+        return await insert(xmls);
+    }
+
+    /**
+      * Check whether datatypestring equals one of the datatypes in
+      * the array datatypelist.
+      */
+    this.checkForDatatypeList = function (datatypestring, datatypelist) {
+        for (var i=0; i<datatypelist.length; i++) {
+            if (datatypestring == datatypelist[i]) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -318,31 +344,45 @@ var edit_mode = new function() {
             var editfield = $(element).find(".caosdb-property-edit-value");
             var property = getPropertyFromElement(element);
 
-            property.unit = editfield.find(".caosdb-unit").val();
-            if (property.datatype == "TEXT" ||
-                property.datatype == "DATE" ||
-                property.datatype == "DOUBLE" ||
-                property.datatype == "INTEGER" ||
-                property.datatype == "BOOLEAN" ||
-                property.datatype == "FILE") {
-                property.value = editfield.find(":input").val()
-            } else if (property.datatype == "DATETIME") {
-                let es = editfield.find(":input");
-                if (es.length == 2) {
-                    property.value = input2caosdbDate(
-                        es[0].value,
-                        es[1].value);
-                } else if (es[0]) {
-                    property.value = es[0].value;
+            // LISTs need to be handled here
+            if (property.list == true) {
+                // TODO: unit missing
+                property.value = [];
+                if (this.checkForDatatypeList(property.listDatatype,
+                                              ["TEXT","DATE","DOUBLE","INTEGER","BOOLEAN","FILE"])) {
+                    // LOOP over elements of editfield.find(":input")
+                    for (var singleelement of $(editfield).find(":not(.caosdb-f-list-item-button):input")) {
+                        property.value.push($(singleelement).val());
+                    }
+                } else if (property.datatype == "DATETIME") {
+                    throw ("Lists of DATETIME currently not supported.");
+                } else if (property.reference) {
+                    // LOOP over elements of editfield.find("select")
+                    for (var singleelement of $(editfield).find(":not(.caosdb-f-list-item-button):input")) {
+                        property.value.push(singleelement.selectedOptions[0].value);
+                    }
+                } else {
+                    throw ("This property's data type is not supported by the webui. Please issue a feature request for support for `" + property.datatype + "`.");
                 }
-            } else if (property.reference) {
-                if (!property.list) {
+            } else {
+                property.unit = editfield.find(".caosdb-unit").val();
+                if (this.checkForDatatypeList(property.datatype,
+                                              ["TEXT","DATE","DOUBLE","INTEGER","BOOLEAN","FILE"])) {
+                    property.value = editfield.find(":input").val()
+                } else if (property.datatype == "DATETIME") {
+                    let es = editfield.find(":input");
+                    if (es.length == 2) {
+                        property.value = input2caosdbDate(
+                            es[0].value,
+                            es[1].value);
+                    } else if (es[0]) {
+                        property.value = es[0].value;
+                    }
+                } else if (property.reference) {
                     property.value = $(editfield).find("select").first()[0].selectedOptions[0].value;
                 } else {
-                    throw ("Reference lists not supported. Please issue a feature request.");
+                    throw ("This property's data type is not supported by the webui. Please issue a feature request for support for `" + property.datatype + "`.");
                 }
-            } else {
-                throw ("This property's data type is not supported by the webui. Please issue a feature request for support for `" + property.datatype + "`.");
             }
             properties.push(property);
         }
@@ -395,7 +435,6 @@ var edit_mode = new function() {
         var editPanel = edit_mode.get_edit_panel();
         removeAllWaitingNotifications(editPanel);
         this.add_wait_datamodel_info();
-        edit_mode.init_actions_panels();
 
         // TODO make enter_edit_mode ayncronous?
         return edit_mode.retrieve_data_model().then(model => {
@@ -434,12 +473,14 @@ var edit_mode = new function() {
 
     /**
      * Add an actions panel which will be used by the edit mode and hide the
-     * original actions panel. The original actionspanel can be restored with
+     * original actions panel. The original actions-panel can be restored with
      * {@link edit_mode.reset_actions_panels}.
+     *
+     * @param {HTMLElement} entity
      */
-    this.init_actions_panels = function() {
-        this.reset_actions_panels();
-        $(".caosdb-entity-actions-panel").each(function(index) {
+    this.init_actions_panels = function(entity) {
+        this.reset_actions_panels([entity]);
+        $(entity).find(".caosdb-entity-actions-panel").each(function(index) {
             var clone = $(this).clone(true)[0];
             $(clone).removeClass("caosdb-entity-actions-panel").addClass("caosdb-f-edit-mode-entity-actions-panel").insertBefore(this);
             $(clone).children().remove();
@@ -449,10 +490,12 @@ var edit_mode = new function() {
 
     /**
      * Remove the edit_mode action panel and restore the original action panel.
+     *
+     * @param {HTMLElements[]} array of entities in HTML representation.
      */
-    this.reset_actions_panels = function() {
-        $(".caosdb-f-edit-mode-entity-actions-panel").remove();
-        $(".caosdb-entity-actions-panel").show();
+    this.reset_actions_panels = function(entities) {
+        $(entities).find(".caosdb-f-edit-mode-entity-actions-panel").remove();
+        $(entities).find(".caosdb-entity-actions-panel").show();
     }
 
     this.make_header_editable = function(entity) {
@@ -475,7 +518,7 @@ var edit_mode = new function() {
             this.make_input("description", getEntityDescription(entity)),
         ];
         if (getEntityRole(roleElem[0]) == "Property") {
-            for (input of this.make_datatype_input(getEntityDatatype(entity), getEntityUnit(entity))) {
+            for (const input of this.make_datatype_input(getEntityDatatype(entity), getEntityUnit(entity))) {
                 inputs.push(input);
             }
             temp.hide();
@@ -553,31 +596,18 @@ var edit_mode = new function() {
     }
 
     /**
-     * @param {HTMLElement} entity property in view mode representation.
-     * @return {undefined}
-     */
-    this.make_property_editable = function(element) {
-        if (typeof element == "undefined") {
-            throw Error("parameter `element` was undefined.");
-        }
-
-        edit_mode.add_property_trash_button($(element).find(".caosdb-property-edit")[0], element);
-        var valfield = $(element).find(".caosdb-property-value");
-        var editfield = $(element).find(".caosdb-property-edit-value");
-        var property = getPropertyFromElement(element);
-
-        valfield.hide();
-        editfield.show();
-        editfield.text("");
+      * Helper function that creates an HTML string for a specific property.
+      */
+    this.createElementstringForProperty = function(property) {
         var editelementstring;
         if (property.datatype == "TEXT") {
             //editelementstring = "<input type='text' value='" + property.value + "'></input>";
             editelementstring = "<textarea>" + property.value + "</textarea>";
-        } else if (property.datatype == "DATE") {
-            let date = caosdbq2InputDate(property.value)[0];
-            editelementstring = "<input type='date' value='" + date + "'></input>";
         } else if (property.datatype == "DATETIME") {
-            let dateandtime = caosdb2InputDate(property.value);
+            var dateandtime = [""];
+            if(property.value) {
+                dateandtime = caosdb2InputDate(property.value);
+            }
             let date = dateandtime[0];
             if (dateandtime.length == 2) {
                 let time = dateandtime[1];
@@ -596,17 +626,110 @@ var edit_mode = new function() {
             editelementstring = $('<select class="form-control caosdb-list-' + property.datatype + '"><option selected value=""></option><option value="FALSE">FALSE</option><option value="TRUE">TRUE</option></select>');
             $(editelementstring).val(property.value);
         } else if (property.reference) {
-            editelementstring = '<select class="form-control caosdb-list-' + property.datatype + '" data-resolved="false"><option selected class="caosdb-f-option-default" value="' + property.value + '">' + property.value + '</option><option></option></select>';
-            edit_mode.retrieve_datatype_list(property.datatype).then(() => {
-                var elist = $(editfield).find(".caosdb-list-" + property.datatype);
-                elist.find("[value='" + property.value + "'].caosdb-f-option-default").remove();
-                elist.find("[value='" + property.value + "']").attr("selected", "selected");
-            }, edit_mode.handle_error);
-            edit_mode.retrieve_datatype_list(property.datatype);
+            editelementstring = '<select style="width:80%;display:inline;" class="form-control caosdb-list-' + property.datatype + '" data-resolved="false"><option selected class="caosdb-f-option-default" value="' + property.value + '">' + property.value + '</option><option></option></select>';
         } else {
             throw ("Unsupported data type: `" + property.datatype + "`. Please issue a feature request.");
         }
+        return editelementstring;
+    }
+
+    this.generate_list_item_control_panel = function(property) {
+        // Add list delete buttons:
+        var deleteButton = $('<button title="Delete this list element." class="btn btn-link caosdb-update-entity-button caosdb-f-list-item-button"><span class="glyphicon glyphicon-trash"></span></button>');
+        $(deleteButton).click(function() {
+            $(this.parentElement.parentElement).remove();
+        });
+        
+        
+        // Add list insert buttons:
+        var insertButton = $('<button title="Insert a new list element before this element." class="btn btn-link caosdb-update-entity-button caosdb-f-list-item-button"><span class="glyphicon glyphicon-plus"></span></button>');
+        $(insertButton).click(function() {
+            var newelementstring = "";
+            var proptemp = {
+                list: false,
+                reference: property.reference,
+                value: "",
+                unit: property.unit,
+                name: undefined,
+                id: undefined,
+                datatype: property.listDatatype
+            };
+            newelementstring += "<li>" + edit_mode.createElementstringForProperty(proptemp) + "</li>";
+            $(newelementstring).append(
+                edit_mode.generate_list_item_control_panel(property)).insertBefore($(this.parentElement.parentElement));
+
+            edit_mode.retrieve_datatype_list(property.listDatatype);
+        });
+
+        return $("<span></span>").append(deleteButton).append(insertButton);
+    }
+
+    /**
+     * @param {HTMLElement} entity property in view mode representation.
+     * @return {undefined}
+     */
+    this.make_property_editable = function(element) {
+        if (typeof element == "undefined") {
+            throw Error("parameter `element` was undefined.");
+        }
+
+        edit_mode.add_property_trash_button($(element).find(".caosdb-property-edit")[0], element);
+        var valfield = $(element).find(".caosdb-property-value");
+        var editfield = $(element).find(".caosdb-property-edit-value");
+        var property = getPropertyFromElement(element);
+
+        valfield.hide();
+        editfield.show();
+        editfield.text("");
+        var editelementstring;
+        if (property.list == false) {
+            editelementstring = edit_mode.createElementstringForProperty(property);
+            if (property.reference == true) {
+                edit_mode.retrieve_datatype_list(property.datatype);
+            }
+        } else {
+            editelementstring = "<ul>";
+            for (var i=0; i<property.value.length; i++) {
+                var proptemp = {
+                    list: false,
+                    reference: property.reference,
+                    value: property.value[i],
+                    unit: property.unit,
+                    name: undefined,
+                    id: undefined,
+                    datatype: property.listDatatype
+                };
+                editelementstring += "<li>" + edit_mode.createElementstringForProperty(proptemp) + "</li>";
+                edit_mode.retrieve_datatype_list(property.listDatatype);
+            }
+            editelementstring += "</ul>";
+        }
         editfield.append($(editelementstring));
+
+        $(editfield).find("li").append(edit_mode.generate_list_item_control_panel(property));
+
+        // Add a single list insert button at the end of each list:
+        var insertButton = $('<button title="Insert a new list element before this element." class="btn btn-link caosdb-update-entity-button caosdb-f-list-item-button"><span class="glyphicon glyphicon-plus"></span></button>');
+        $(insertButton).click(function() {
+            var newelementstring = "";
+            var proptemp = {
+                list: false,
+                reference: property.reference,
+                value: "",
+                unit: property.unit,
+                name: undefined,
+                id: undefined,
+                datatype: property.listDatatype
+            };
+            newelementstring += "<li>" + edit_mode.createElementstringForProperty(proptemp) + "</li>";
+            $($(this.parentElement.parentElement).find("ul")).append($(newelementstring).append(
+                edit_mode.generate_list_item_control_panel(property)));
+
+            edit_mode.retrieve_datatype_list(property.listDatatype);
+        });
+
+        ($("<span>Insert element at the end of the list: </span>").append($(insertButton))).insertAfter($(editfield).find("ul"));
+
     }
 
     this.create_new_record = async function(recordtype_id, name = undefined) {
@@ -653,7 +776,7 @@ var edit_mode = new function() {
         if (edit_mode.has_errors(app.entity)) {
             hintMessages.hintMessages(app.entity);
 
-            edit_mode.init_actions_panels();
+            edit_mode.init_actions_panels(app.entity);
             // only add edit button, because a deletion would fail again
             edit_mode.add_start_edit_button(app.entity, () => {
                 app.startEdit(app.entity)
@@ -841,11 +964,13 @@ var edit_mode = new function() {
                     let entity = this;
                     if (typeof getEntityID(entity) == "undefined" || getEntityID(entity) == '') {
                         // no id -> insert
+                        edit_mode.init_actions_panels(entity);
                         edit_mode.add_start_edit_button(entity, () => {
                             app.newEntity(entity)
                         });
                     } else {
                         // has id -> delete, edit, create RT
+                        edit_mode.init_actions_panels(entity);
                         edit_mode.add_delete_button(entity);
                         edit_mode.add_start_edit_button(entity, () => {
                             app.startEdit(entity)
@@ -935,7 +1060,7 @@ var edit_mode = new function() {
             }
             $(entity).fadeIn();
 
-            edit_mode.init_actions_panels();
+            edit_mode.init_actions_panels(entity);
             edit_mode.add_save_button(entity, () => app.insert(entity));
             edit_mode.add_cancel_button(entity, () => app.cancel(entity));
 
@@ -973,11 +1098,6 @@ var edit_mode = new function() {
             }
             hintMessages.hintMessages(app.entity);
             edit_mode.unfreeze();
-            if (!edit_mode.has_errors(app.entity)) {
-                // TODO why is this:
-                edit_mode.enter_edit_mode(app);
-                edit_mode.init_actions_panels();
-            }
             resolve_references.init();
             preview.init();
         }
@@ -1010,11 +1130,12 @@ var edit_mode = new function() {
         });
     }
 
+
     // TODO: write generic function format property depending on datatype and the property
 
     this.retrieve_datatype_list = async function(datatype) {
-        var entities = await query("FIND Record " + datatype);
-        var files = await query("FIND File " + datatype);
+        var entities = await edit_mode.query("FIND Record " + datatype);
+        var files = await edit_mode.query("FIND File " + datatype);
 
         for (var i = 0; i < entities.length + files.length; i++) {
 
@@ -1025,15 +1146,32 @@ var edit_mode = new function() {
             }
             var prlist = getProperties(eli);
             var prdict = [];
+            // The name is not included in the property list.
+            var entname = getEntityName(eli);
+            if (entname.length > 0) {
+                prdict.push("Name: " + entname);
+            }
             for (var j = 0; j < prlist.length; j++) {
                 prdict.push(prlist[j].name + ": " + prlist[j].value);
             }
-            if (prlist.length == 0) {
+            if (prdict.length == 0) {
                 prdict.push("ID: " + getEntityID(eli));
             }
             $("select.caosdb-list-" + datatype).not('[data-resolved="true"]').append(
                 $("<option value=\"" + getEntityID(eli) + "\">" + prdict.join(", ") + "</option>"));
         }
+        
+        var elist = $("select.caosdb-list-" + datatype).not('[data-resolved="true"]');
+        for (var i=0; i<elist.length; i++) {
+            var defauopt = $(elist[i]).find("option.caosdb-f-option-default")[0];
+            var val = defauopt.value;
+            console.log(defauopt);
+            $(defauopt).remove();
+            console.log(val);
+            console.log(elist[i]);
+            $(elist[i]).find("[value='" + val + "']").attr("selected", "selected");
+        }
+        
         $("select.caosdb-list-" + datatype).not('[data-resolved="true"]').attr("data-resolved", "true");
     }
 
@@ -1066,7 +1204,7 @@ var edit_mode = new function() {
     this.leave_edit_mode_template = function(app) {
         app.finish();
         $(".caosdb-f-btn-toggle-edit-mode").text("Edit Mode");
-        edit_mode.reset_actions_panels();
+        edit_mode.reset_actions_panels($(".caosdb-f-main").toArray());
         window.localStorage.removeItem("edit_mode");
     }
 
@@ -1105,6 +1243,9 @@ var edit_mode = new function() {
         $(entity).css("pointer-events", "").css("filter", "");
     }
 
+    /**
+     * this function is called in entity_palette.xsl
+     */
     this.filter = function(ent_type) {
         var text = $("#caosdb-f-filter-" + ent_type).val();
         if (ent_type == "properties") {
@@ -1112,7 +1253,7 @@ var edit_mode = new function() {
         } else if (ent_type == "recordtypes") {
             var short_type = "rt";
         } else {
-            alert("unkown type");
+            globalError("unknown type");
         }
 
         var keywords = text.toLowerCase().split(" ");
@@ -1179,7 +1320,11 @@ var edit_mode = new function() {
         $(entity).find(".caosdb-f-entity-delete-button").remove();
     }
 
-}
+    this.query = (str) => {
+        return query(str);
+    }
+
+}()
 /**
  * Add the extensions to the webui.
  */
diff --git a/src/core/js/ext_map.js b/src/core/js/ext_map.js
new file mode 100644
index 0000000000000000000000000000000000000000..bef4930e91cfb6889b500c9fdd25a2f5c5847b36
--- /dev/null
+++ b/src/core/js/ext_map.js
@@ -0,0 +1,1121 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2019 IndiScale GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+
+'use strict';
+
+/**
+ * caosdb_map module for displaying a geographical map which shows entities at their associated geo location.
+ *
+ * The configuration for this module has to be stored in `conf/ext/json/ext_map.json` and comply with the {@link MapConfig} type which is described below.
+ */
+var caosdb_map = new function() {
+
+    var logger = log.getLogger("caosdb_map");
+    this.version = "0.2";
+    this.dependencies = ["log", {"L": ["latlngGraticule", "Proj"]}, "navbar", "caosdb_utils"];
+    this.logger = logger;
+
+    /**
+     * The MapConfig object is used to define all relevant parameters for the
+     * map including the tiling servers, different views and CRSs of the map,
+     * the configuration of the graticule(s) and the data model for the
+     * integrated query generator.
+     *
+     * @typedef {Object} MapConfig
+     * @property {string} version - the version of the map
+     * @property {string} default_view - the view which is shown when the user
+     *     opens the map and has no stored view from prior visits to the map.
+     *     The view are defined in the `views` property.
+     * @property {ViewConfig[]} views - array of the configurations for the
+     *     available views of the map. This includes the tiling servers, the
+     *     graticule, the CRS and more.
+     * @property {DataModelConfig} datamodel - the data model for the
+     *     display of entities in the map (also used by the query generator).
+     * @property {SelectConfig} select - config for the query generator.
+     */
+
+    /**
+     * The DataModelConfig object is used to define the CaosDB Properties which
+     * are interpreted as latitude and longitude in the map.
+     *
+     * Note: Both latitude and longitude are expected to be represented in
+     * decimal format. The latitude should not exceed [-90°,90°] ranges and the
+     * longitude should not exceed [-180°, 180°] ranges.
+     *
+     * @typedef {Object} DataModelConfig
+     * @property {string} [lat=latitude] - the name of the latitude property.
+     * @property {string} [lng=longitude] - the name of the longitude property.
+     */
+
+    /**
+     * The SelectConfig object configures the custom {@link select_handler}
+     * plugin for the Leaflet.js module, especially the query generation (for
+     * searching for Entities in the selected area).
+     *
+     * The generated query has the pattern <code>FIND {@link query.role} {@link
+     * query.entity} WITH ...<code>. The dots stand for the area filter here.
+     *
+     * The default values of the {@link query} result in queries for any Record
+     * in the selected map area.
+     *
+     * @typedef {object} SelectConfig
+     * @property {object} [query] - The configuration of the query.
+     * @property {string} [query.role=Record] - The role of the entities which
+     *     are to be searched in the selected ares.
+     * @property {string} [query.entity] The (parent) entity to be searched
+     *     for in the area. Defaults to empty string.
+     */
+
+    /**
+     * The ViewConfig contains the most important parts of the configuration as
+     * there are no default values set for legal reasons - each person who is
+     * responsible for a CaosDB Server and WebUI has to answer for the
+     * configuration of the tiling servers and possibly has to negotiate the
+     * terms of use with the tiling service providers or provide an own tiling
+     * server.
+     *
+     * It governs most of the actual map functionality including the graticule,
+     * zoom levels, intial zoom and center of the map, and more.
+     *
+     * Furthermore it affects how this view is displayed by the menu of the
+     * {@link view_change_handler} plugin.
+     *
+     * Note: Leaflet comes with a few pre-defined coordinate reference systems
+     * (cf. {@link https://leafletjs.com/reference-1.5.0.html#crs Defined CRSs}). By
+     * default, the default CRS of leaflet will be used for the map (which is
+     * currently EPSG:3857, the Sperical Mercator). If {@link crs} is a string,
+     * e.g. "EPSG:3395" or "Simple" that matches the pre-defined CRS, the
+     * pre-defined CRS is used.
+     *
+     * @typedef {object} ViewConfig
+     * @property {string} id - the unique view id, used by the 
+     *     {@link default_view} property to identify the default view for
+     *     preserving the active view and view configuration across reloads of
+     *     the page.
+     * @property {string} name - the name is shown in the views menu.
+     * @property {string} descriptoin - a short discription of the views
+     *     purpose and properties. Also shown in the views menu when mouse
+     *     hovers over the name.
+     * @property {number} zoom - Initial zoom level. Must be an integer and
+     *     >=0.
+     * @property {object} center - the coordinates of the initial map center.
+     * @property {number} center.lat - latitude of the initial map center.
+     * @property {number} center.lng - longitude of the initial map center.
+     * @property {TileLayerConfig} tileLayer - configuration of the tiling
+     *     server for the base layer of the map.
+     * @property {GraticuleConfig} [graticule] - configuration of the graticule
+     *     of the map.
+     * @property {string|CRSConfig} [crs] - coordinate
+     *     reference system of the map.
+     */
+
+    /**
+     * The TileLayerConfig is a thin extension wrapper around the {@link
+     * https://leafletjs.com/reference-1.5.0.html#tilelayer-wms-option
+     * TileLayer.WMS options} and the {@link
+     * https://leafletjs.com/reference-1.5.0.html#tilelayer-option TileLayer
+     * options}.
+     *
+     * Only three properties are defined by the wrapper {@link type}, {@link
+     * url} and {@link options}.
+     *
+     * If {@link type} is "osm", the tiling layer is configured with an
+     * OpenStreetMap tile server and the rest of the properties are the ones
+     * defined by the TileLayer options.
+     *
+     * If the {@link type} is "wms", the tiling layer is configured with an
+     * WebMapService server and the rest of the properties are the ones defined
+     * by the TileLayer.WMS options.
+     *
+     * Other types of tiling layers are not supported as for now.
+     *
+     * The {@link url} is of course the url of either the WMS server or the OSM
+     * tiling server.
+     *
+     * The {@link options} is an object which has all properties of the
+     * respective tileLayer as defined by {@link
+     * https://leafletjs.com/reference-1.5.0.html#tilelayer-option
+     * TileLayer options} when {@link type} = "osm" or {@link
+     * https://leafletjs.com/reference-1.5.0.html#tilelayer-wms-option
+     * TileLayer.WMS options} when {@link type} = "wms".
+     *
+     * @example <caption>Example for a TileLayerConfig with OSM</caption>
+     *     { type: "osm",
+     *       url: "https://example.com/tile/{z}/{y}/{x}",
+     *       options: {
+     *         attribution: "Tiles &copy; Example.com",
+     *         maxZoom: 13
+     *       }
+     *     }
+     *
+     * @example <caption>Example for a TileLayerConfig with WMS</caption>
+     *     { type: "wms",
+     *       url: "https://example.com/wms",
+     *       options: {
+     *         layers: "0",
+     *         format: "image/png",
+     *         attribution: "WMS Server by Example.com",
+     *         version: "1.3.0",
+     *         transparent: true,
+     *       }
+     *     }
+     *
+     * @typedef {object} TileLayerConfig
+     * @property {string} [type="osm"] - the type of the tile layer, "osm" or
+     *     "wms"
+     * @property {string} url - the url of the OSM or WMS server.
+     * @property {object} options - the {@link
+     *     https://leafletjs.com/reference-1.5.0.html#tilelayer-option
+     *     TileLayer options} or {@link
+     *     https://leafletjs.com/reference-1.5.0.html#tilelayer-wms-option
+     *     TileLayer.WMS options}.
+     */
+
+    /**
+     * GraticuleConfig for configuring a graticule to be shown on the map.
+     *
+     * Experimental Feature!
+     *
+     * Currently, two graticule plug-ins are used. {@link
+     * https://github.com/turban/Leaflet.Graticule L.Graticule.js} handles
+     * polar maps better but lacks configurability and has no lat/lng labels
+     * while {@link
+     * https://github.com/Leaflet/Leaflet.Graticule leaflet.latlng-graticule}
+     * can show lat/lng labels, comes with a more flexible configurability, but
+     * cannot handle polar maps sufficiently.
+     *
+     * Unfortunately, both plug-ins seem to be unmaintained or at least without
+     * any progress in the last years.
+     *
+     * It is unclear wheather we have to write our own or refactor one of these
+     * plug-ins It is unclear which plug-in will make it, wheather we have to
+     * write our own or refactor one of these plug-ins.
+     *
+     * For the time being, both can be used and the implementation is set by
+     * the {@link type} property. If unset or "simple", the L.Graticule.js implementation is used.
+     *
+     * If {@link type} is "latlngGraticule" the leaflet.latlng-graticule implementation is used.
+     *
+     * The {@link options} must comply with the configuration options of the respective implementation.
+     *
+     * @example <caption>Example for the `simple` graticule</caption>
+     *     // this works for polar maps
+     *     { "type": "simple",
+     *       "options": {
+     *         "interval": 45, // draw line every 45th degree
+     *         "style": {
+     *           "color": "#333",
+     *           "weight": 1
+     *         }
+     *       }
+     *     }
+     *
+     *
+     * @example <caption>Example for the `latlng-graticule`</caption>
+     *     // this does not work for polar maps
+     *     { "type": "latlngGraticule",
+     *       "options": {
+     *         "showLabel": true,
+     *         "dashArray": [5, 5],
+     *         "zoomInterval": {
+     *           // interval configuration for different zoom levels
+     *           // and for lat/lng separately.
+     *           "latitude": [ 
+     *             {"start": 2, "end": 2, "interval": 20},
+     *             {"start": 3, "end": 3, "interval": 10},
+     *             {"start": 4, "end": 6, "interval": 5},
+     *             {"start": 7, "end": 10, "interval": 1},
+     *             {"start": 11, "end": 20, "interval": 1}
+     *           ],
+     *           "longitude": [
+     *             {"start": 2, "end": 2, "interval": 20},
+     *             {"start": 3, "end": 3, "interval": 10},
+     *             {"start": 4, "end": 6, "interval": 5},
+     *             {"start": 7, "end": 10, "interval": 1},
+     *             {"start": 11, "end": 20, "interval": 1}
+     *           ]
+     *         }
+     *       }
+     *     }
+     *
+     * @property {string} type - either "simple" or "latlngGraticule".
+     * @property {object} options - the options for the graticule implementation.
+     */
+
+    /**
+     * CRSConfig for the configuration of the coordinate reference system.
+     *
+     * The CRS is managed by the {@link http://kartena.github.io/Proj4Leaflet/
+     * Proj4Leaflet} plugin of the Leaflet.js module.
+     *
+     * The {@link code} defines the standardized CRS Code, e.g. "EPSG:3857" for
+     * the widely used Sperical Mercator CRS.
+     *
+     * The {@link proj4def} contains the proj4 definition of the CRS. A good
+     * soure for these definitions is {@link https://epsg.io}, e.g. {@link
+     * https://epsg.io/3857} for the Sperical Mercartor CRS.
+     *
+     * The {@link options} defines the options for the Proj4Leaflet plug-in,
+     * see {@link http://kartena.github.io/Proj4Leaflet/api/#l-proj-crs-options
+     * Proj.CRS options}.
+     *
+     * @example <caption>Example for CRSConfig</caption>
+     *     { "code": "EPSG:3995",
+     *       "proj4def": `+proj=stere +lat_0=90 +lat_ts=71 +lon_0=0 +k=1
+     *          +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs`,
+     *       "options": {
+     *         "resolutions": [ "16384", "8192", "4096", "2048",
+     *            "1024", "512", "256", "128", "64", "32", "16",
+     *            "8", "4", "2", "1", "0.5" ]
+     *       }
+     *     }
+     *
+     * @property {string} code - the standardized CRS Code.
+     * @property {string} proj4def - the proj4 definition of the CRS.
+     * @property {object} options - options according to the 
+     *     {@link http://kartena.github.io/Proj4Leaflet/api/#l-proj-crs-options
+     *     Proj.CRS options}.
+     */
+
+    /**
+     * default configuration for the map.
+     * @type {MapConfig}
+     */
+    this._default_config = {
+        "version": "0.2",
+        "datamodel": {
+            "lat": "latitude",
+            "lng": "longitude",
+        },
+        "select": {
+            "query": {
+                "role": "RECORD",
+                "entity": "",
+            },
+        },
+        // TODO move to css
+        "panel": {
+            "css": {
+                "height": "500px",
+            },
+        },
+    }
+
+    /**
+     * (Re-)set this module's functions to standard implementation.
+     */
+    this._init_functions = function() {
+        logger.trace("enter _init_functions");
+
+        /**
+         * Create button with the caosdb-f-toggle-map-button class.
+         *
+         * @param {string} content - the button content. Optional, defaults to "Map"
+         */
+        this.create_toggle_map_button = function(content = "Map") {
+            logger.trace("enter create_toggle_map_button");
+            let button = $(`<button class="navbar-btn btn btn-link"/>`);
+            button.toggleClass("caosdb-f-toggle-map-button", true);
+            button.text(content);
+            logger.trace("leave create_toggle_map_button");
+            return button[0];
+        }
+
+        /**
+         * Create map panel (div.caosdb-f-map-panel).
+         */
+        this.create_map_panel = function() {
+            let panel = $("<div>");
+            panel.toggleClass("caosdb-f-map-panel", true);
+
+            // for centered and responsive display
+            panel.toggleClass("container", true);
+            return panel[0];
+        }
+
+
+        /**
+         * Create a Leaflet map in the container and return the map object.
+         *
+         * @param {HTMLElement} container - the map container.
+         * @param {ViewConfig} config - configuration for the map.
+         *
+         * @returns {L.Map} the map
+         */
+        this.create_map_view = function(container, config) {
+            logger.trace("enter create_map_view", container, config);
+
+            // crs
+            if (typeof config.crs === "string" || config.crs instanceof String) {
+                config.crs = L.CRS[crs.replace(":","")];
+                logger.debug("use pre-defined CRS ", config.crs);
+            } else if (typeof config.crs === "object") {
+                config.crs = new L.Proj.CRS(config.crs.code,
+                    config.crs.proj4def, config.crs.options);
+                logger.debug("use custom proj4 CRS ", config.crs);
+            }
+
+            // set tiling server
+            var tileLayer;
+            if (config.tileLayer.type && config.tileLayer.type === "wms") {
+                tileLayer = L.tileLayer
+                    .wms(config.tileLayer.url, config.tileLayer.options);
+            } else if (config.tileLayer.type === "osm") {
+                tileLayer = L
+                    .tileLayer(config.tileLayer.url, config.tileLayer.options);
+            } else {
+                throw new Error("unknown tileLayer type: "
+                    + config.tileLayer.type);
+            }
+
+
+            var map = L.map(container, config);
+            tileLayer.addTo(map);
+
+            // add mouse coords
+            // TODO move to config
+            L.control.coordinates({
+                "position": "bottomleft",
+                "decimals": 2,
+                "enableUserInput": false,
+                "useDMS": true,
+            }).addTo(map);
+
+            this._toggle_cb = () => {
+                // TODO this is shit
+                // resizing of the jquery toggle() function is the problem
+                map.invalidateSize(true);
+            };
+
+            if(config.graticule) {
+                this.add_graticule(map, config.graticule);
+            }
+
+            return map;
+        }
+
+
+        this.init_map_panel = function(config) {
+            logger.trace("enter init_map_panel");
+
+            // remove old
+            $('.caosdb-f-map-panel').remove();
+
+            let panel = this.create_map_panel();
+
+            $(panel).css(config.css);
+
+
+            $(panel).hide();
+            $('#subnav').first().after(panel);
+
+            logger.trace("leave init_map_panel");
+            return panel;
+        }
+
+
+        /**
+         * Toggle the map (show/hide).
+         */
+        this.toggle_map = function() {
+            logger.trace("enter toggle_map");
+            $(".caosdb-f-map-panel").toggle(900, ()=>this._toggle_cb());
+        }
+
+
+        /**
+         * To be called after the map panel has been toggled.
+         */
+        this._toggle_cb = undefined;
+
+        /**
+         * Bind the toggle_cb function to the click event of the button.
+         *
+         * @param {HTMLElement} button
+         * @param {function} toggle_cb - to be called on click.
+         * @throws TypeError if the parameters have wrong types.
+         * @returns {HTMLElement} the button
+         */
+        this.bind_toggle_map = function(button, toggle_cb) {
+            logger.trace("enter bind_toggle_map");
+            caosdb_utils.assert_html_element(button, "parameter 'button'");
+            caosdb_utils.assert_type(toggle_cb, "function", "parameter 'toggle_cb'");
+            $(button).on("click", toggle_cb);
+            logger.trace("leave bind_toggle_map");
+            return button;
+        }
+
+        /**
+         * Test if the dependencies are defined in window.
+         *
+         * @throws Error - if a dependency is unmet.
+         * @returns {boolean} true if all dependencies are defined.
+         */
+        this.check_dependencies = function() {
+            logger.trace("enter check_dependencies");
+            for (let dep of this.dependencies) {
+                if (typeof dep == "string") {
+                    if (typeof window[dep] == "undefined") {
+                        throw new Error("Unmet dependency: " + dep);
+                    }
+                } else {
+                    // TODO
+                    logger.warn("could not check dep", dep);
+                }
+            }
+            logger.trace("leave check_dependencies");
+            return true;
+        }
+
+
+        /**
+         * Initialize the caosdb_map module.
+         *
+         * 1) load config
+         * 2) initialize leaflet plug-ins (select_handler, change-view-handler)
+         * 3) initialize the container panel
+         * 4) inttialize the map itself
+         * 5) add the map toggle button to the navbar
+         */
+        this.init = async function() {
+            logger.trace("enter init");
+            var panel = undefined;
+            var toggle_button = undefined;
+            try {
+                const config = await this.load_config();
+                this.config = config;
+                this.init_select_handler();
+                this.init_view_change_handler();
+                panel = this.init_map_panel(config.panel);
+
+                this.change_map_view = (view) => {
+                    var local_conf = {};
+                    if(this._map) {
+                        // TODO it would be nice if a change of the view would not reset the center and zoom.
+                        // However, if the old center is not on the current
+                        // map, leaflet throws exceptions. Furthermore, the
+                        // zoom level is view-specific - level 2 in one view
+                        // does not necessarily have the same resolution as the
+                        // level 2 in another view. No idea, how to find a good
+                        // zoom approximation...
+                        // At least we know this - the following does not work:
+                        //local_conf["zoom"] = this._map.getZoom();
+                        //local_conf["center"] = this._map.getCenter();
+                        this._map.remove();
+                    }
+
+                    var nextview = view || sessionStorage["caosdb_map.view"] || config.leaflet.default_view;
+                    sessionStorage["caosdb_map.view"] = nextview;
+                    var view_config = $.extend(true, {}, {
+                        // TODO move to defaults object
+                        "select": true,
+                        "boxZoom": false,
+                        "view_change": true,
+                        "zoom": 1,
+                        "center": { "lat": 0, "lng": 0 },
+                        }, config.leaflet.views[nextview], local_conf);
+                    this._map = this.create_map_view(panel, view_config);
+                    this.init_layer_groups(this._map);
+
+                    this.create_layer_current_page_entities();
+                    this.add_select_handler(this._map);
+                    this.add_view_change_handler(
+                        this._map,
+                        config.leaflet.views,
+                        nextview,
+                        this.change_map_view
+                    );
+                }
+                this.change_map_view();
+
+                toggle_button = this.init_toggle_map_button();
+            } catch (err) {
+                logger.error("Could not initialize the map.", err);
+                if (typeof toggle_button !== "undefined") {
+                    $(toggle_button).remove();
+                }
+                if (typeof panel !== "undefined") {
+                    $(panel).remove();
+                }
+            }
+            logger.trace("leave init");
+        }
+
+        /**
+         * Add the graticule to the current map view.
+         *
+         * @parameter {L.Map} map - the leaflet map.
+         * @parameter {GraticuleConfig} config - the graticule config.
+         */
+        this.add_graticule = function(map, config) {
+            if(config.type === "latlngGraticule") {
+                L.latlngGraticule(config.options).addTo(map);
+            } else if( typeof config.type === "undefined"
+                || config.type === "simple") {
+                L.graticule(config.options).addTo(map);
+            } else {
+                this.logger.warn("unknown graticule type: ", type);
+            }
+        }
+
+        /**
+         * Add the select_handler to the map
+         *
+         * @param {L.Map} map
+         */
+        this.add_select_handler = function(map){
+            map.addHandler("select", L.SelectHandler);
+        }
+
+        /**
+         * @callback ViewChangeCB
+         * @param {string} view - the id of the view to be changed to.
+         */
+
+        /**
+         * Add the view_change_handler to the map.
+         *
+         *
+         * @parameter {L.Map} map
+         * @parameter {ViewConfig[]} views - the available views.
+         * @parameter {string} active - the id of the currently active view.
+         * @parameter {ViewChangeCB} view_changer_cb - callback which changes the view.
+         */
+        this.add_view_change_handler = function(map, views, active, view_changer_cb) {
+            map.addHandler("view_change", L.ViewChangeHandler);
+            map.view_change.init(views, active, view_changer_cb);
+        }
+
+
+        this.init_view_change_handler = function(views) {
+            L.ViewChangeHandler = L.Handler.extend(this.view_change_handler);
+        }
+
+        this.init_select_handler = function() {
+            L.SelectHandler = L.Handler.extend(this.select_handler);
+        }
+
+
+        this.open_query_panel = function () {
+            var query_panel = $("#caosdb-query-panel");
+
+            // hide query shortcuts in available
+            query_panel.find(".caosdb-f-shortcuts-panel-toggle-button:not('.caosdb-f-shortcuts-panel-hidden')").click();
+
+            query_panel
+                .collapse("show");
+        }
+
+
+        this.fill_query_filter = function (query_filter) {
+            let role = this.config.select.query.role;
+            let entity = this.config.select.query.entity;
+            var query = "FIND " + role + " " + entity + " WITH " + query_filter;
+            $("#caosdb-query-textarea").val(query);
+            // remove paging for queries generated by the map
+            $("#caosdb-query-paging-input").remove();
+        }
+
+
+        /**
+         * Return a config.
+         *
+         * @returns {Object} config
+         */
+        this.load_config = async function() {
+            logger.trace("enter load_config");
+
+            var conf = {};
+            try {
+                conf = await load_config("ext_map.json");
+            } catch (err) {
+                logger.error(err);
+            }
+
+
+            logger.debug("Could not find any config. returning default config.");
+            logger.trace("leave load_config");
+            var result = $.extend(true, {}, this._default_config, conf);
+            return result; 
+        }
+
+
+        /**
+         * Check config (version and all important keys).
+         *
+         * @param {MapConfig} config - the config which is to be checked.
+         * @throws TypeError, if version does not match this modules version.
+         * @throws Error, if any assertion about the config fails.
+         * @returns {boolean} true, iff everything is fine.
+         */
+        this.check_config = function(config) {
+            logger.trace("enter check_config");
+            caosdb_utils.assert_type(config, "object", "config");
+            if (config.version !== caosdb_map.version) {
+                throw new TypeError("The version of the configuration does not match the version of this implementation of the caosdb_map module. Should be '"+caosdb_map.version+"', was '"+config.version+"'.");
+            }
+
+            logger.trace("enter check_config");
+            return true;
+        }
+
+
+        /**
+         * Create a button, bind the toggle_map function to the on-click event and append it to the navbar.
+         */
+        this.init_toggle_map_button = function() {
+            logger.trace("enter init_toggle_map_button");
+
+            // remove old
+            $('.caosdb-f-toggle-map-button').remove();
+
+            let button = this.create_toggle_map_button();
+            this.bind_toggle_map(button, () => this.toggle_map());
+
+            var ret = navbar.add_button(button);
+            logger.trace("leave init_toggle_map_button", ret);
+            return ret;
+        }
+
+
+        this.get_map_objects = function() {
+            var datamodel = this.config.datamodel;
+            var map_objects = $(".caosdb-entity-panel").has(".caosdb-property-name:contains('"+ datamodel.lng + "')").has(".caosdb-property-name:contains('" + datamodel.lat + "')");
+            return map_objects.toArray();
+        }
+
+
+        this.make_parent_labels = function(entity) {
+            var parents = getParents(entity);
+            var ret = [];
+            for(const par of parents) {
+                // TODO handle case where the parent is shown
+                var label = $('<span class="label">' + par.name + '</span>')
+                    .css({"color": "#333", "border": "1px solid #333"});
+                ret.push(label[0]);
+            }
+            return ret;
+        }
+
+
+        this.make_entity_name_label = function(entity) {
+            var name = getEntityName(entity);
+            var id = getEntityId(entity);
+            var name_label = $('<div/>')
+                .css({"margin-top": "4px", "margin-bottom":"4px"})
+                .text(name)
+                .append('<a title="Jump to this entity" class="pull-right" href="#' + id + '"><span class="glyphicon glyphicon-share-alt"/></a>');
+            return name_label[0];
+        }
+
+
+        this.make_map_popup_representation = function(entity) {
+            var role_label = $(entity).find(".label.caosdb-f-entity-role").first().clone();
+            var parent_list = this.make_parent_labels(entity);
+            var name = this.make_entity_name_label(entity);
+            var ret = $('<div/>')
+                .append(role_label)
+                .append(parent_list)
+                .append(name);
+            return ret[0];
+        }
+
+        this.create_layer_current_page_entities = function() {
+            logger.trace("enter create_layer_current_page_entities");
+            var datamodel = this.config.datamodel;
+            var map_objects = this.get_map_objects();
+
+            for (const map_object of map_objects) {
+                var lat = getProperty(map_object, datamodel.lat);
+                var lng = getProperty(map_object, datamodel.lng);
+
+                if (lat && lng) {
+                    logger.debug("found map-object", map_object, lat, lng);
+                    var marker = L.marker([lat, lng]);
+                    marker.bindPopup(this.make_map_popup_representation(map_object));
+                    this.add_to_layer_group("current_page_entities", marker);
+                } else {
+                    logger.debug("no valid latitude or longitude", map_object, lat, lng);
+                }
+            }
+            logger.debug("current_page_layer", this.get_layer_group("current_page_layer"));
+            logger.trace("leave create_layer_current_page_entities");
+        }
+
+        this.get_standard_layer_groups = function() {
+            logger.trace("enter get_standard_layer_groups");
+            var new_groups = {};
+
+            // current page entities
+            var cpe_group = L.layerGroup();
+            new_groups["current_page_entities"] = cpe_group;
+
+            logger.trace("leave get_standard_layer_groups");
+            return new_groups;
+        }
+
+        this.init_layer_groups = function(map) {
+            logger.trace("enter init_layer_groups");
+            if (typeof this._layer_groups == "undefined") {
+                this._layer_groups = this.get_standard_layer_groups();
+            }
+
+            for (var name in this._layer_groups) {
+                let lg = this.get_layer_group(name);
+                logger.debug("add layer group to map:", name, lg);
+                lg.addTo(map);
+            }
+            logger.trace("leave init_layer_groups");
+        }
+
+        this.add_to_layer_group = function(group_name, layer) {
+            logger.trace("enter add_to_layer_group");
+            this.get_layer_group(group_name).addLayer(layer);
+            logger.trace("leave add_to_layer_group");
+        }
+
+        this.get_layer_group = function(name) {
+            return this._layer_groups[name];
+        }
+
+        this.view_change_handler = {
+            init: function(views, active, view_changer) {
+                this._add_view_options(this._view_menu, views, active, view_changer);
+            },
+
+            _add_view_options: function(menu, views, active, view_changer) {
+                const click = function(e) {
+                    logger.trace("click on view_menu option", e);
+                    var next = e.target.value;
+                    if(next !== active) {
+                        view_changer(e.target.value);
+                    }
+                }
+                for( const key of Object.keys(views)) {
+                    const name = views[key].name || key;
+                    const description = views[key].description || key;
+                    const checked = key === active;
+                    const option = $('<div title="'
+                        + description
+                        + '"><input name="view" type="radio" value="' 
+                        + key + '"/><label style="margin-left: 8px">' 
+                        + name + '</label></div>')
+                        .css({"width": "max-content"});
+                    option
+                        .find(":input")
+                        .on("click", click) // TODO
+                        .prop("checked", checked)
+                        .prop("name", "nextview");
+                    $(menu).append(option);
+                }
+            },
+
+            addHooks: function() {
+                this._view_menu = this._make_view_menu();
+                const toggle_view_menu_button = this.
+                    _make_toggle_view_menu_button(this._view_menu);
+
+                const ChangeViewControl = L.Control.extend({
+                    options: {position: "bottomleft"},
+                    onAdd: function() {
+                        return toggle_view_menu_button;
+                    }
+                })
+
+                this._map.addControl(new ChangeViewControl()); 
+            },
+
+            _make_view_menu: function() {
+                var form = $('<form/>')
+                    .hide()
+                    .css({ // TODO move to css
+                        "padding": "4px 10px",
+                        "text-align": "left",
+                        "background-color": "white",
+                        "position": "absolute",
+                        "bottom": "0px",
+                        "left": "34px", 
+                        "border": "1px solid black",
+                        "border-radius": "4px",
+                        "min-width": "100px"
+                    });
+
+                form[0].addEventListener("click", function(e) {
+                    logger.trace("click on view menu", e);
+                    e.stopPropagation();
+                    // TODO
+                    //caosdb_map.set_map_view(views[this.nextview]);
+                    //caosdb_map._active_view = this.nextview;
+                });
+
+                return form[0];
+            },
+
+            _make_toggle_view_menu_button: function(view_menu) {
+                var click = (e) => {
+                    e.stopPropagation();
+                    logger.trace("click on toggle_view_menu_button", e, view_menu);
+                    $(view_menu).toggle();
+                };
+
+                // TODO refactor and extract function for map controls
+                var button = L.DomUtil.create("div", "leaflet-bar leaflet-control leaflet-control-custom");
+                button.title = "Change the view";
+                // TODO move to css
+                button.style.backgroundColor = "white";
+                button.style.width = "34px";
+                button.style.height = "34px";
+                button.style.textAlign  = "center";
+                button.style.marginTop = "2px";
+                button.innerHTML = '<span style="margin-top: 5px; font-size: 15px" class="glyphicon glyphicon-option-vertical"></span>';
+
+                button.addEventListener("click", click);
+                $(button).prepend(view_menu);
+
+                return button;
+            },
+
+            removeHooks: function() {
+                $(this._toggle_view_menu_button).remove();
+            },
+        }
+
+
+        /**
+         * Plug-in for leaflet which lets the user select an area in the map
+         * and execute a query using a latitude/longitude filter for entities.
+         */
+        this.select_handler = {
+            addHooks: function() {
+                const select_button = this._get_select_button((event)=>{
+                    logger.trace("select button clicked", this);
+                    event.preventDefault();
+                    event.stopPropagation();
+                    this._toggle_select();
+                });
+                this._select_button = select_button;
+                this._map.addControl(select_button); 
+                this._map.on('mousedown', this._startSelect);
+            },
+
+            removeHooks: function() {
+                // TODO remove button
+                this._map.off('mousedown', this._startSelect);
+            },
+
+            _highlight_select_button: function() {
+                $(this._select_button.button).css({backgroundColor: "#90EE90"});
+            },
+
+            _unhighlight_select_button: function() {
+                $(this._select_button.button).css({backgroundColor: "white"});
+            },
+
+            _toggle_select: function() {
+                logger.trace("toggle select", this);
+                if(this._select_active) {
+                    this._unhighlight_select_button();
+                    this._map.dragging.enable();
+                    this._select_active = false;
+                } else {
+                    this._highlight_select_button();
+                    this._map.dragging.disable();
+                    this._select_active = true;
+                }
+            },
+
+            _get_select_button: function(callback) {
+                var select_button = L.Control.extend({
+                    options: {position: "topleft"},
+
+                    onAdd: function(m) {
+                        return this.button;
+                    },
+
+                    button: function() {
+                        // TODO refactor to make_map_control function
+                        var button = L.DomUtil.create("div", "leaflet-bar leaflet-control leaflet-control-custom");
+                        button.title = "Select an area";
+                        button.style.backgroundColor = "white";
+                        button.style.width = "34px";
+                        button.style.height = "34px";
+                        button.style.textAlign  = "center";
+                        // Distance to zoom buttons:
+                        button.style.marginTop = "10px";
+                        // TODO implement helper for pictures
+                        button.innerHTML = '<img width="20px" height="20px" style="margin-top: 5px;" src="/webinterface/__BUILD_NUMBER__/pics/select.svg.png">';
+                        button.onclick = callback;
+
+                        $(button).on("mousedown", (event) => { event.stopPropagation(); });
+                        $(button).on("mouseup", (event) => { event.stopPropagation(); });
+                        return button;
+                    }(),
+                });
+                return new select_button();
+            },
+
+            _get_query_button: function(callback){
+                var query_button = L.Control.extend({
+                    options: {position: "topleft"},
+
+                    onAdd: function(m) {
+                        return this.button;
+                    },
+
+                    button: function() {
+                        var button = L.DomUtil.create("div", "leaflet-bar leaflet-control leaflet-control-custom");
+                        button.title = "Search within this area";
+                        button.style.backgroundColor = "#ff8700";
+                        button.style.width = "34px";
+                        button.style.height = "34px";
+                        button.style.textAlign  = "center";
+                        button.style.marginTop = "2px";
+                        button.innerHTML = '<span style="margin-top: 5px; font-size: 15px" class="glyphicon glyphicon-search"></span>';
+                        button.onclick = callback;
+
+                        $(button).on("mousedown", (event) => { event.stopPropagation(); });
+                        $(button).on("mouseup", (event) => { event.stopPropagation(); });
+                        return button;
+                    }(),
+                });
+                return new query_button();
+            },
+
+            _startSelect: function(event) {
+                logger.trace("mousedown", event, "on", this);
+                if(!event.originalEvent.shiftKey && !this.select._select_active) {
+                    return;
+                }
+                event.originalEvent.preventDefault();
+                event.originalEvent.stopPropagation();
+                this.select._reset_selection();
+                this.select._point1 = event.latlng;
+                this.select._point2 = undefined;
+                logger.trace("point1", this.select._point1);
+
+                this.on("mousemove", this.select._drawRect);
+                this.on("mouseup", this.select._endSelect);
+            },
+
+            _reset_selection: function() {
+                if (this._rectangle) {
+                    this._rectangle.remove();
+                }
+                this._remove_query_button();
+            },
+
+            _drawRect: function(event) {
+                logger.trace("mousemove", event, "on", this);
+                event.originalEvent.preventDefault();
+                event.originalEvent.stopPropagation();
+                if (this.select._rectangle) {
+                    this.select._rectangle.remove();
+                }
+                this.select._point2 = event.latlng;
+                const area = this.select._get_area(this.select._point1, this.select._point2)
+                this.select._rectangle = this.select._get_select_rectangle(area);
+                this.select._rectangle.addTo(this);
+            },
+
+            _get_select_rectangle: function(area) {
+                return L.rectangle(area, {color: "#ff7800", weight: 1});
+
+            },
+
+            _endSelect: function(event) {
+                logger.trace("mouseup", event, "on", this);
+                event.originalEvent.preventDefault();
+                event.originalEvent.stopPropagation();
+                if(this.select._point2) {
+                    // was moved, update last time
+                    this.select._point2 = event.latlng;
+                    logger.trace("point1", this.select._point1);
+                    logger.trace("point2", this.select._point2);
+
+                    const area = this.select._get_area(this.select._point1, this.select._point2)
+
+                    var query_filter = this.select._generate_query_filter(area);
+                    logger.debug("generated query filter", query_filter);
+                    this.select._add_query_button(query_filter);
+                } else {
+                    // mouse has not been moved, was a click
+                }
+                this.select._point1 = undefined;
+                this.select._point2 = undefined;
+                this.off("mouseup", this.select._endSelect);
+                this.off("mousemove", this.select._drawRect);
+
+            },
+
+            _add_query_button: function(query_filter) {
+                logger.trace("_add_query_button", query_filter, this);
+                this._remove_query_button();
+                var callback = (event) => {
+                    logger.trace("click query_button", this);
+                    event.stopPropagation();
+                    caosdb_map.open_query_panel();
+                    caosdb_map.fill_query_filter(query_filter);
+                }
+                this._query_button = this._get_query_button(callback);
+                this._map.addControl(this._query_button);
+            },
+
+            _remove_query_button: function() {
+                if(this._query_button) {
+                    this._query_button.remove();
+                    this._query_button = undefined;
+                }
+            },
+
+            _get_area: function(point1, point2) {
+                return L.latLngBounds(point1, point2);
+            },
+
+            /**
+             * @param {LatLngBounds} a - the area.
+             */
+            _generate_query_filter: function (a) {
+                let lat = caosdb_map.config.datamodel.lat;
+                let lng = caosdb_map.config.datamodel.lng;
+                let no = this._round(a.getNorth());
+                let so = this._round(a.getSouth());
+                let ea = this._round(a.getEast());
+                let we = this._round(a.getWest());
+                return " ( " + lat + " < '" + no + "' AND " + lat + " > '" + so + "' AND " + lng + " > '" + we + "' AND " + lng + " < '" + ea + "' ) ";
+            },
+
+            _round: function(d) {
+                return Math.round(d*1000)/1000;
+            },
+
+            _point1: undefined,
+            _point2: undefined,
+        };
+
+        logger.trace("leave _init_functions");
+    }
+    this._init_functions();
+}
+
+$(document).ready(function() {
+    caosdb_modules.register(caosdb_map);
+});
diff --git a/src/core/js/ext_references.js b/src/core/js/ext_references.js
index ef1c8b8504e4261e28e6d711d85423c11ba9ffaf..943eadad4dd1bc50cd1df96deb93caa153678887 100644
--- a/src/core/js/ext_references.js
+++ b/src/core/js/ext_references.js
@@ -29,7 +29,7 @@ var isOutOfViewport = function(elem) {
 };
 
 /**
- * Check if an element is inside of the viewport on the horizontal axis.
+ * Check if an element is inside of the viewport on the vertical axis.
  *
  * Returns true if any of the element's bounding box's top or bottom edges are in the
  * viewport.
@@ -38,11 +38,36 @@ var isOutOfViewport = function(elem) {
  * @return {boolean}
  *
  */
-var is_in_viewport_horizontally = function(elem) {
+var is_in_viewport_vertically = function(elem) {
     var out = isOutOfViewport(elem);
     return !(out.top || out.bottom);
 }
 
+/**
+ * Check if an element is inside of the viewport on the horizontal axis.
+ *
+ * This criterion is very much different from the vertical correspondent:
+ * It looks for the parent which contains the list scroll bar for caosdb values.
+ * Then it is checked whether the element's bounding box is visible inside the scroll box.
+ *
+ * @param {HTMLElement} elem - the element to check
+ * @return {boolean}
+ *
+ */
+var is_in_viewport_horizontally = function(elem) {
+    var scrollbox = elem.parentElement.parentElement;
+    // Check this condition only if the grand parent is a list and return true otherwise.
+    if (scrollbox.classList.contains("caosdb-value-list") == true) {
+        var boundel = elem.getBoundingClientRect();
+        var boundscroll = scrollbox.getBoundingClientRect();
+        var leftcrit = boundel.right > boundscroll.left;
+        var rightcrit = boundel.left < boundscroll.right;
+        return leftcrit && rightcrit;
+    } else {
+        return true;
+    }
+}
+
 
 /**
  * The resolve_references module.
@@ -88,6 +113,8 @@ var resolve_references = new function() {
             rseditable.textContent = "Borrowed by " + this.get_person_str(persel[0]) + " (" + loan_state.replace("_", " ") + ")";
         } else if (pr[0].name == "Box") {
             rseditable.textContent = getProperty(el[0], "Number");
+        } else if (pr[0].name == "Bag") {
+            rseditable.textContent = getProperty(el[0], "Number");
         } else if (pr[0].name == "Palette") {
             rseditable.textContent = getProperty(el[0], "Number");
         } else if (pr[0].name.includes("Model")) {
@@ -105,7 +132,8 @@ var resolve_references = new function() {
         var rs = document.getElementsByClassName("caosdb-resolvable-reference");
 
         for (var i = 0; i < rs.length; i++) {
-            if (is_in_viewport_horizontally(rs[i])) {
+            if (is_in_viewport_vertically(rs[i]) &&
+                is_in_viewport_horizontally(rs[i])) {
                 this.update_single_resolvable_reference(rs[i]);
             }
         }
@@ -124,12 +152,14 @@ var resolve_references = new function() {
 $(document).ready(function() {
     resolve_references.init();
     var scrollTimeout = undefined;
-    $(window).scroll(() => {
+    var updatefunc = () => {
         if (scrollTimeout) {
             clearTimeout(scrollTimeout);
         }
         scrollTimeout = setTimeout(function() {
             resolve_references.update_visible_references();
         }, 500);
-    });
+    };
+    $(window).scroll(updatefunc);
+    $(".caosdb-value-list").scroll(updatefunc);
 });
diff --git a/src/core/js/ext_xsl_download.js b/src/core/js/ext_xls_download.js
similarity index 84%
rename from src/core/js/ext_xsl_download.js
rename to src/core/js/ext_xls_download.js
index 43d223c430bb4f09b3f03f578b04ad000807a5e2..37349b35a609c57b3cddd371b3b37ebc9a93fdb2 100644
--- a/src/core/js/ext_xsl_download.js
+++ b/src/core/js/ext_xls_download.js
@@ -35,9 +35,7 @@ function _get_csv_string(){
         return undefined;
     }
 
-    // string newlines (\n) must be replaced. the tsv newlines are encoded as
-    // %0A and will not be touched.
-    return csv_string.replace(/\n/gm, "");
+    return decodeURIComponent(csv_string.replace(/^data.*utf-8,/, ""));
 }
 
 /**
@@ -53,7 +51,7 @@ async function downloadXLS(xls_link) {
 
     try {
         const xls_result = await connection.runScript("xls_from_csv.py",
-                                                {"urlencoded": csv_string});
+            {"-p0": {"filename": "selected.tsv", "blob": new Blob([csv_string], {type: "text/tab-separated-values;charset=utf-8"})}});
         const code = xls_result.getElementsByTagName("script")[0].getAttribute("code");
         if (parseInt(code) > 0) {
             throw ("An error occurred during execution of the server-side script:\n"
@@ -66,10 +64,7 @@ async function downloadXLS(xls_link) {
         }
 
         // set the href in order to download the file and simulate a click.
-        xls_link.setAttribute(
-            "href",
-            location.protocol + "//" +location.host + "/Shared/" + filename);
-        xls_link.click();
+        _go_to_script_results(xls_link, filename);
     } catch (e) {
         globalError(e);
         // restore the old click handler
@@ -78,3 +73,9 @@ async function downloadXLS(xls_link) {
     return true;
 }
 
+function _go_to_script_results(xls_link, filename) {
+    xls_link.setAttribute(
+        "href",
+        location.protocol + "//" +location.host + "/Shared/" + filename);
+    xls_link.click();
+}
diff --git a/src/core/js/form_elements.js b/src/core/js/form_elements.js
new file mode 100644
index 0000000000000000000000000000000000000000..fa63145b32132fa7abfcd5af8c410db1976b71fb
--- /dev/null
+++ b/src/core/js/form_elements.js
@@ -0,0 +1,1112 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2019 IndiScale GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+
+'use strict';
+
+/**
+ * caosdb_map module for reusable form elemenst which already have a basic css styling.
+ *
+ * IMPORTANCE CONCEPTS
+ *
+ * FIELD - an HTMLElement which wraps a LABEL element (the fields name) and the
+ * INPUT element together. By default, FIELDS are a flat and stringy list of
+ * key-value pairs.  Use SUBFORMS for nesting FIELDS. FIELDS come in the
+ * following flavours:
+ * INTEGER
+ * DOUBLE
+ * DATE
+ * RANGE
+ * REFERENCE_DROP_DOWN
+ *
+ * GROUP - a set of FIELDS and SUBFORMS. FIELDS and SUBFORMS can belong to
+ * multiple groups. The group can be used to disable or enable a set of FIELDS
+ * or SUBFORMS at once. Therefore, GROUPS are mainly used for the look and feel
+ * of the form. However, disabled fields are also ignored in the
+ * json-conversion of a form.
+ *
+ * SUBFORM - an HTMLElement which contains FIELDS and other SUBFORMS. SUBFORMS
+ * can be used to nest FIELDS, which is not supported by HTML5 but allows only
+ * for flat key-value pairs.
+ */
+
+/**
+ * The configuration for double, integer, date input elements.
+ *
+ * @typedef {object} input_config
+ * @property {string} name
+ * @property {string} type
+ * @property {string} label
+ */
+
+/**
+ * The configuration for reference_select input fields
+ *
+ * TODO
+ *
+ */
+var form_elements = new function() {
+
+    this.version = "0.1";
+    this.dependencies = ["log", "caosdb_utils", "markdown"];
+    this.logger = log.getLogger("form_elements");
+    this.cancel_form_event = new Event("caosdb.form.cancel");
+    this.submit_form_event = new Event("caosdb.form.submit");
+    this.form_ready_event = new Event("caosdb.form.ready");
+    this.field_changed_event = new Event("caosdb.field.changed");
+    this.field_enabled_event = new Event("caosdb.field.enabled");
+    this.field_disabled_event = new Event("caosdb.field.disabled");
+    this.field_ready_event = new Event("caosdb.field.ready");
+    this.field_error_event = new Event("caosdb.field.error");
+    this.form_success_event = new Event("caosdb.form.success");
+    this.form_error_event = new Event("caosdb.form.error");
+
+
+    this.get_cache_key = function(form, field) {
+        var form_key = $(form).prop("name");
+        var field_key = $(field).attr("data-field-name");
+        return "form_elements." + form_key + "." + field_key;
+    }
+
+    this.get_cache_value = function(field) {
+        var ret = $(field)
+            .find(":input")
+            .val();
+        if (!ret) {
+            return null;
+        } else {
+            return ret;
+        }
+    }
+
+    this.cache_form = function(cache, form) {
+        this.logger.trace("enter cache_form", cache, form);
+        $(form)
+            .find(".caosdb-f-field.caosdb-f-form-field-cached")
+            .each(function(index, field) {
+                var value = form_elements.get_cache_value(field);
+                const key = form_elements.get_cache_key(form, field);
+                if (value !== null) {
+                    form_elements.logger.trace("cache form field", key, value);
+                    cache[key] = value;
+                } else {
+                    delete cache[key];
+                }
+            });
+    }
+
+
+    this.set_cached = function(field) {
+        $(field).toggleClass("caosdb-f-form-field-cached", true);
+    }
+
+
+    this.set_cached_value = async function (field, value) {
+        this.logger.trace("enter set_cached_value", field, value);
+        caosdb_utils.assert_html_element(field, "parameter `field`");
+        caosdb_utils.assert_string(value, "parameter `value`");
+        await form_elements.field_ready(field);
+        const old_value = form_elements.get_cache_value(field);
+
+        if(old_value !== value) {
+            form_elements.logger.trace("loaded from cache", field, value);
+            if(typeof $().selectpicker === "function" &&
+                $(field).find(".selectpicker").length > 0) {
+                $(field).find(".selectpicker").selectpicker("val", value);
+            } else {
+                $(field).find(":input").val(value);
+                field.dispatchEvent(form_elements.field_changed_event);
+            }
+        }
+    }
+
+    this.is_set = function(field) {
+        var value = $(field).find(":input").val();
+        return value && value.length > 0;
+    }
+
+    this.load_cached = function(cache, form) {
+        this.logger.trace("enter load_cached", cache, form);
+        $(form)
+            .find(".caosdb-f-field.caosdb-f-form-field-cached")
+            .each(function(index, field) {
+                var key = form_elements.get_cache_key(form, field);
+                var value = cache[key] || null;
+                if (value !== null) {
+                    try {
+                        form_elements.set_cached_value(field, value);
+                    } catch (err) {
+                        form_elements.logger.error(err);
+                    }
+                }
+            });
+    }
+
+
+    /**
+     * (Re-)set this module's functions to standard implementation.
+     */
+    this._init_functions = function() {
+
+        this.init = function() {
+            this.logger.trace("enter init");
+        }
+
+        /**
+         * Return an OPTION element with entity reference.
+         *
+         * The OPTION element for a SELECT form input shows a short
+         * summary/description of an entity and has the entity's id as value.
+         *
+         * If the `desc` parameter is undefined, the entity_id is shown
+         * instead.
+         *
+         * @param {string} entity_id - the entity's id.
+         * @param {string} [desc] - the description for the entity.
+         * @returns {HTMLElement} OPTION element.
+         */
+        this.make_reference_option = function(entity_id, desc) {
+            caosdb_utils.assert_string(entity_id, "param `entity_id`");
+            if(typeof desc == "undefined") {
+                desc = entity_id;
+            }
+            var opt_str = '<option value="' + entity_id + '">' + desc
+                + "</option>";
+            return $(opt_str)[0];
+        }
+
+        /**
+         * Return SELECT form element with entity references.
+         *
+         * The OPTIONS have the entities' ids as values and a description which
+         * is generated by a `make_desc` call-back function. If `make_desc` is
+         * undefined, the ids are shown instead.
+         *
+         * @param {HTMLElement[]} entities - an array with entity elements.
+         * @param {function} [make_desc] - a call-back function with one
+         *      parameter.
+         * @returns {HTMLElement} SELECT element with entity options.
+         */
+        this.make_reference_select = async function(entities, make_desc, multiple=false) {
+            caosdb_utils.assert_array(entities, "param `entities`", false);
+            if ( typeof make_desc !== "undefined" ) {
+                caosdb_utils.assert_type(make_desc, "function",
+                    "param `make_desc`");
+            }
+            const ret = $('<select class="selectpicker form-control" title="Nothing selected"/>');
+            if (multiple) {
+                ret.attr("multiple", "");
+            } else {
+                ret.append('<option style="display: none" selected="selected" value="" disabled="disabled"></option>');
+            }
+            for ( let entity of entities ) {
+                this.logger.trace("add option", entity);
+                let entity_id = getEntityID(entity);
+                let desc = typeof make_desc == "function" ? await make_desc(entity) :
+                    entity_id;
+                let option = this.make_reference_option(entity_id, desc);
+                ret.append(option);
+            }
+            return ret[0];
+        }
+
+
+        /**
+         * Search and retrieve entities and create a SELECT from element.
+         *
+         * The OPTIONS have the entities' ids as values and a description which
+         * is generated by a `make_desc` call-back function. If `make_desc` is
+         * undefined, the ids are shown instead.
+         *
+         * @param {object} config
+         * @returns {HTMLElement} SELECT element.
+         */
+        this.make_reference_drop_down = async function(config) {
+            let ret = $(this._make_field_wrapper(config.name));
+            let label = this._make_input_label_str(config);
+            let loading = $('<div class="caosdb-f-field-not-ready">loading...</div>');
+            let input_col = $('<div class="col-sm-9"/>');
+
+            input_col.append(loading);
+            this._query(config.query).then(async function(entities){
+                let select = $(await form_elements.make_reference_select(
+                    entities, config.make_desc, config.multiple));
+                select.attr("name", config.name);
+                loading.remove();
+                input_col.append(select);
+                form_elements.init_select_picker(ret[0]);
+                ret[0].dispatchEvent(form_elements.field_ready_event);
+                select.change(function() {
+                    ret[0].dispatchEvent(form_elements.field_changed_event);
+                });
+            }).catch(err => {
+                form_elements.logger.error(err);
+                loading.remove();
+                input_col.append(err);
+                ret[0].dispatchEvent(form_elements.field_error_event);
+            });
+
+            return ret.append(label, input_col)[0];
+        }
+
+
+        this.init_select_picker = function(field) {
+            caosdb_utils.assert_html_element(field, "parameter `field`");
+            const select = $(field).find("select")[0];
+            const select_picker_options = {};
+            if ($(select).prop("multiple")) {
+                select_picker_options["actionsBox"] = true;
+            }
+            if ($(select).find("option").length > 8) {
+                select_picker_options["liveSearch"] = true;
+                select_picker_options["liveSearchNormalize"] = true;
+                select_picker_options["liveSearchPlaceholder"] = "search...";
+            }
+            $(select).selectpicker(select_picker_options);
+            this.init_actions_box(field);
+        }
+
+
+        this.init_actions_box = function(field) {
+            this.logger.trace("enter init_actions_box", field);
+            caosdb_utils.assert_html_element(field, "parameter `field`");
+            const select = $(field).find("select");
+            var actions_box = select.siblings().find(".bs-actionsbox");
+            if(actions_box.length === 0) {
+                actions_box = $(`<div class="bs-actionsbox">
+                            <div class="btn-group btn-group-sm btn-block">
+                                <button type="button" class="actions-btn btn-default bs-deselect-all btn btn-light">None</button>
+                            </div>
+                        </div>`)
+                    .hide();
+
+                select
+                    .siblings(".dropdown-menu")
+                    .prepend(actions_box);
+
+                field.addEventListener(
+                    form_elements.field_changed_event.type,
+                    (e) => {
+                        if(form_elements.is_set(field)) {
+                            actions_box.show();
+                        } else {
+                            actions_box.hide();
+                        }
+                    }, true);
+
+                actions_box
+                    .find(".bs-deselect-all")
+                    .click((e)=>{
+                        select.val(null)
+                            .selectpicker("render")
+                            .parent().toggleClass("open", false);
+                        select[0].dispatchEvent(form_elements.field_changed_event);
+                    });
+            }
+        }
+
+        /**
+         * Return a promise which resolves with the field when the field is ready.
+         *
+         * This function is especially useful if the caller can not be sure if
+         * the field_ready_event has been dispatched already and the field is
+         * ready or if the fields creation is still pending.
+         *
+         * @param {HTMLElement} field
+         * @return {Promise} the field-ready promise
+         */
+        this.field_ready = function(field) {
+            // TODO add support for field name (string) as field parameter
+            // TODO check type of param field (not an array!)
+            caosdb_utils.assert_html_element(field, "parameter `field`");
+            return new Promise(function(resolve, reject) {
+                try {
+                    if(!$(field).hasClass("caosdb-f-field-not-ready") && $(field).find(".caosdb-f-field-not-ready").length === 0) {
+                        resolve(field);
+                    } else {
+                        field.addEventListener(form_elements.field_ready_event.type,
+                            (e) => resolve(e.target), true);
+                    }
+                } catch (err) {
+                    reject(err);
+                }
+            });
+        }
+
+        this._query = async function (q) {
+            const result = await query(q);
+            this.logger.debug("query returned", result);
+            return result;
+        }
+
+        this._run_script = async function (script, form) {
+            const json_str = JSON.stringify(form_elements.form_to_object(form[0]));
+            const params = {"-p0": {"filename": "form.json", "blob": new Blob([json_str], {type: "application/json"})}};
+            const result = await connection.runScript(script, params);
+            this.logger.debug("server-side script returned", result);
+            return this.parse_script_result(result);
+        }
+
+        this.parse_script_result = function(result) {
+            console.log(result);
+            const scriptNode = result.evaluate("/Response/script", result, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
+            const code = result.evaluate("@code", scriptNode, null, XPathResult.STRING_TYPE, null).stringValue;
+
+            const call = result.evaluate("call", scriptNode, null, XPathResult.STRING_TYPE, null).stringValue;
+            const stderr = result.evaluate("stderr", scriptNode, null, XPathResult.STRING_TYPE, null).stringValue;
+            const stdout = result.evaluate("stdout", scriptNode, null, XPathResult.STRING_TYPE, null).stringValue;
+
+            return { "code": code, "call": call, "stdout": stdout, "stderr": stderr };
+        }
+
+        /**
+         * generate a java script object representation of a form
+         */
+        this.form_to_object = function(form) {
+            this.logger.trace("entity form_to_json", form);
+            caosdb_utils.assert_html_element(form, "parameter `form`");
+
+            const _to_json = (element, data) => {
+                this.logger.trace("enter element_to_json", element, data);
+
+                for (const child of element.children) {
+                    // ignore disabled fields and subforms
+                    if ($(child).hasClass("caosdb-f-field-disabled")){
+                        continue;
+                    }
+                    const name = $(child).attr("name");
+                    const is_subform = $(child).hasClass("caosdb-f-form-elements-subform");
+                    if (is_subform) {
+                        const subform = $(child).data("subform-name");
+                        // recursive
+                        var subform_obj = _to_json(child, {});
+                        if (typeof data[subform] === "undefined") {
+                            data[subform] = subform_obj;
+                        } else if (Array.isArray(data[subform])){
+                            data[subform].push(subform_obj);
+                        } else {
+                            data[subform] = [data[subform], subform_obj]
+                        }
+                    } else if (name && name !== "") {
+                        // input elements
+                        const not_checkbox = !$(child).is(":checkbox");
+                        if ( not_checkbox || $(child).is(":checked")) {
+                            // checked or not a checkbox
+                            var value = $(child).val();
+                            if (typeof data[name] === "undefined") {
+                                data[name] = value;
+                            } else if (Array.isArray(data[name])){
+                                data[name].push(value);
+                            } else {
+                                data[name] = [data[name], value]
+                            }
+                        } else {
+                            // TODO checkbox
+                        }
+                    } else if (child.children.length > 0) {
+                        // recursive
+                        _to_json(child, data);
+                    }
+                }
+
+                this.logger.trace("leave element_to_json", element, data);
+                return data;
+            };
+
+            const ret = _to_json(form, {});
+            this.logger.trace("leave form_to_json", ret);
+            return ret;
+        }
+
+        this.make_submit_button = function() {
+            var ret = $('<button class="caosdb-f-form-elements-submit-button btn btn-primary" type="submit">Submit</button>');
+            return ret[0];
+        }
+
+        this.make_cancel_button = function(form) {
+            var ret = $('<button class="caosdb-f-form-elements-cancel-button btn btn-primary" type="button">Cancel</button>');
+            ret.on("click", e => {
+                this.logger.debug("cancel form", e, form);
+                form.dispatchEvent(this.cancel_form_event);
+            });
+            return ret[0];
+        }
+
+        this.make_form_field = async function(config) {
+            caosdb_utils.assert_type(config, "object", "param `config`");
+            caosdb_utils.assert_string(config.type, "`config.type` of param `config`");
+
+            var field = undefined;
+            const type = config.type;
+            if (type === "date") {
+                field = await this.make_date_input(config);
+            } else if (type === "checkbox") {
+                field = await this.make_checkbox_input(config);
+            } else if (type === "text") {
+                field = await this.make_text_input(config);
+            } else if (type === "double") {
+                field = await this.make_double_input(config);
+            } else if (type === "integer") {
+                field = await this.make_integer_input(config);
+            } else if (type === "range") {
+                field = await this.make_range_input(config);
+            } else if (type === "reference_drop_down") {
+                field = await this.make_reference_drop_down(config);
+            } else if (type === "subform") {
+                // TODO handle cache and required for subforms
+                return await this.make_subform(config);
+            } else {
+                throw new TypeError("undefined field type `" + type + "`");
+            }
+
+            if (config.required) {
+                this.set_required(field);
+            }
+            if (config.cached) {
+                this.set_cached(field);
+            }
+            if (config.help) {
+                this.add_help(field, config.help);
+            }
+
+            return field;
+        }
+
+
+        this.add_help = function(field, config) {
+            var help_button = $('<span data-trigger="click focus" data-toggle="popover" class="caosdb-f-form-help pull-right glyphicon glyphicon-info-sign"/>')
+                .css({"cursor": "pointer"});
+
+            if (typeof config === "string" || config instanceof String) {
+                help_button.attr("data-content", config);
+                help_button.popover();
+            } else {
+                help_button.popover(config);
+            }
+
+
+            var label = $(field).children("label");
+            if(label.length > 0) {
+                help_button.css({"margin-left": "4px"});
+                label.first().append(help_button);
+            } else {
+                $(field).append(help_button);
+            }
+        }
+
+        this.make_heading = function(config) {
+            if(typeof config.header === "undefined") {
+                return;
+            } else if (typeof config.header === "string" || config.header instanceof String) {
+                return $('<div class="caosdb-f-form-header h3">' + config.header + '</div>')[0];
+            }
+            caosdb_utils.assert_html_element(config.header, "member `header` of parameter `config`");
+            return config.header;
+        }
+
+        this.make_form_wrapper = function(form, config) {
+            var wrapper = $('<div class="caosdb-f-form-wrapper"/>');
+
+            var header = this.make_heading(config);
+            wrapper.append(header);
+
+            var loading = $('<div>loading...</div>');
+            var logger = this.logger;
+            var cancel = (e) => {
+                logger.trace("cancel form", e);
+                wrapper.remove();
+            };
+
+            wrapper.append(loading);
+
+            Promise.resolve(form).then(form => {
+                // form ready
+                loading.remove();
+                wrapper.append(form);
+                wrapper[0].dispatchEvent(this.form_ready_event);
+
+            }).catch(err => {
+                logger.error("form loading error", err);
+                loading.remove();
+                wrapper.append(err);
+            });
+
+            wrapper[0].addEventListener(this.cancel_form_event.type, cancel, true);
+
+            return wrapper[0];
+        }
+
+        this.make_form = function(config) {
+            var form = undefined;
+
+            if(config.script) {
+                form = this.make_script_form(config, config.script);
+            } else {
+                form = this.make_generic_form(config);
+            }
+            var wrapper = this.make_form_wrapper(form, config);
+            return wrapper;
+        }
+
+        this.make_subform = async function(config) {
+            this.logger.trace("enter make_subform");
+            caosdb_utils.assert_type(config, "object", "param `config`");
+            caosdb_utils.assert_string(config.name, "`config.name` of param `config`");
+            caosdb_utils.assert_array(config.fields, "`config.fields` of param `config`");
+
+            const name = config.name;
+            var form = $('<div data-subform-name="' + name + '" class="caosdb-f-form-elements-subform"/>');
+
+            for ( let field of config.fields ) {
+                this.logger.trace("add subform field", field);
+                let elem = await this.make_form_field(field);
+                form.append(elem);
+            }
+
+            this.logger.trace("leave make_subform", form[0]);
+            return form[0];
+        }
+
+        this.dismiss_form = function(form) {
+            if(form.tagName === "FORM") {
+                form.dispatchEvent(this.cancel_form_event);
+            }
+            var _form = $(form).find("form");
+            if (_form.length > 0){
+                _form[0].dispatchEvent(this.cancel_form_event);
+            }
+        }
+
+        this.enable_group = function(form, group) {
+            this.enable_fields(this.get_group_fields(form, group));
+        }
+
+        this.disable_group = function(form, group) {
+            this.disable_fields(this.get_group_fields(form, group));
+        }
+
+        this.get_group_fields = function(form, group) {
+            return $(form).find(".caosdb-f-field[data-groups*='("+group+")']").toArray();
+        }
+
+        /**
+         * Return an array of field with name
+         *
+         * @param {string} name - the field name
+         * @return {HTMLElement[]} array of fields
+         */
+        this.get_fields = function(form, name) {
+            caosdb_utils.assert_html_element(form, "parameter `form`");
+            caosdb_utils.assert_string(name, "parameter `name`");
+            return $(form).find(".caosdb-f-field[data-field-name='" + name + "']").toArray();
+        }
+
+        this.add_field_to_group = function(field, group) {
+            this.logger.trace("enter add_field_to_group", field, group);
+            var groups = ($(field).attr("data-groups")?$(field).attr("data-groups"):"") + "(" + group + ")";
+            $(field).attr("data-groups", groups);
+        }
+
+        this.disable_fields = function(fields) {
+            $(fields).toggleClass("caosdb-f-field-disabled", true).hide();
+            for (const field of $(fields)) {
+                field.dispatchEvent(this.field_disabled_event);
+            }
+        }
+
+        this.enable_fields = function(fields) {
+            $(fields).toggleClass("caosdb-f-field-disabled", false).show();
+            for (const field of $(fields)) {
+                field.dispatchEvent(this.field_enabled_event);
+            }
+        }
+
+        this.enable_name = function(form, name) {
+            this.enable_fields(form.find(".caosdb-f-field[data-field-name='" + name + "']").toArray());
+        }
+
+        this.disable_name = function(form, name) {
+            this.disable_fields(form.find(".caosdb-f-field[data-field-name='" + name + "']").toArray());
+        }
+
+        this.make_script_form = async function(config, script) {
+            this.logger.trace("enter make_script_form");
+
+            const submit_callback = async function(form) {
+                form = $(form);
+
+
+                // actually submit the form
+                var response = await form_elements._run_script(script, form);
+                var result = [];
+
+                if (response.code === "0") {
+                    // handle success
+                    result.push(form_elements.make_success_message(response.stdout));
+                    return result;
+
+                } else {
+                    // handle scripting error
+                    result.push(form_elements.make_error_message(response.call));
+                    result.push(form_elements.make_error_message(response.stderr));
+                    throw result;
+                }
+            };
+
+            this.logger.trace("leave make_script_form");
+            const new_config = $.extend({}, {name: script, submit:submit_callback}, config);
+            return await this.make_generic_form(new_config);
+        }
+
+        /**
+         * Return a generic form, bind the config.submit to the submit event
+         * of the form.
+         *
+         * The `config.fields` array may contain `form_elements.field_config`
+         * objects or HTMLElements.
+         *
+         * TODO
+         */
+        this.make_generic_form = async function(config) {
+            this.logger.trace("enter make_generic_form");
+
+            caosdb_utils.assert_type(config, "object", "param `config`");
+            caosdb_utils.assert_string(config.name, "`config.name` of param `config`", true);
+            caosdb_utils.assert_array(config.fields, "`config.fields` of param `config`");
+
+            const form = $('<form class="form-horizontal" action="#" method="post" />');
+
+            // set name
+            if(config.name) {
+                form.attr("name", config.name);
+            }
+
+            // add fields
+            for ( let field of config.fields ) {
+                this.logger.trace("add field", field);
+                if ( field instanceof HTMLElement ) {
+                    form.append(field);
+                } else {
+                    let elem = await this.make_form_field(field);
+                    form.append(elem);
+                }
+            }
+
+            // set groups
+            if (config.groups) {
+                for ( let group of config.groups ) {
+                    this.logger.trace("add group", group);
+                    for ( let fieldname of group.fields ) {
+                        let field = form.find(".caosdb-f-field[data-field-name='" + fieldname + "']");
+                        this.logger.trace("set group", field, group);
+                        this.add_field_to_group(field, group.name)
+
+                    }
+                    // disable if necessary
+                    if (typeof group.enabled === "undefined" || group.enabled ) {
+                        this.enable_group(form, group.name);
+                    } else {
+                        this.disable_group(form, group.name);
+                    }
+                }
+            }
+
+            const footer = this.make_footer();
+            form.append(footer);
+
+            if(!(typeof config.submit === 'boolean' && config.submit === false)) {
+                // add submit button unless config.submit is false
+                footer.append(this.make_submit_button());
+            }
+            form[0].addEventListener("submit", (e) => {
+                e.preventDefault();
+                e.stopPropagation();
+                if(form.find(".caosdb-f-form-submitting").length > 0) {
+                    // do not submit twice
+                    return;
+                }
+
+                this.logger.debug("submit form", e);
+
+                form[0].dispatchEvent(this.submit_form_event);
+
+                form.find(":input").prop("disabled", true);
+                var submitting = form_elements.make_submitting_info();
+                form.find(".caosdb-f-form-elements-footer").before(submitting);
+
+
+                form[0].addEventListener(this.form_success_event.type, (e) => {
+                    submitting.remove();
+                }, true);
+                form[0].addEventListener(this.form_error_event.type, (e) => {
+                    submitting.remove();
+                }, true);
+
+
+                // remove old messages
+                const error_handler = config.error;
+                const success_handler = config.success;
+                const submit_callback = config.submit;
+                form.find(".caosdb-f-form-elements-message").remove();
+                if(typeof config.submit === "function") {
+                    // wrap callback in async function
+                    const _wrap_callback = async function() {
+                        try {
+                            var results = await submit_callback(form[0]);
+
+                            // success_handler
+                            if (typeof success_handler === "function") {
+                                var processed = await success_handler(form[0], results);
+                                if (typeof processed !== "undefined") {
+                                    form_elements.show_results(form[0], processed);
+                                }
+                            } else {
+                                form_elements.show_results(form[0], results);
+                            }
+
+                            form[0].dispatchEvent(form_elements.form_success_event);
+                        } catch (err) {
+
+                            // error_handler
+                            if (typeof error_handler === "function") {
+                                var processed = await error_handler(form[0], err);
+                                if (typeof processed !== "undefined") {
+                                    form_elements.show_results(form[0], processed);
+                                }
+                            } else {
+                                form_elements.show_errors(form[0], err);
+                            }
+
+                            form[0].dispatchEvent(form_elements.form_error_event);
+                        }
+
+                    }();
+                }
+                return false;
+
+
+            }, true);
+
+            form[0].addEventListener(this.form_success_event.type, function(e) {
+                // remove submit button, show ok button
+                form.find("button[type='submit']").remove();
+                form.find("button:contains('Cancel')").text("Ok").prop("disabled", false);
+            }, true);
+            form[0].addEventListener(this.form_error_event.type, function(e) {
+                // reenable inputs
+                form.find(":input").prop("disabled", false);
+            }, true);
+
+            // add cancel button
+            $(footer).append(this.make_cancel_button(form[0]));
+
+            // init caching for this form
+            form_elements.init_form_caching(config, form[0]);
+
+            // init validation
+            form_elements.init_validator(form[0]);
+
+            this.logger.trace("leave make_generic_form");
+            return form[0];
+        }
+
+        this.init_form_caching = function(config, form) {
+            var default_config = {
+                "cache_event": form_elements.submit_form_event.type,
+                "cache_storage": localStorage
+            };
+            var lconfig = $.extend({}, default_config, config);
+
+            this.logger.trace("init_form_caching", lconfig, form);
+
+            form.addEventListener(lconfig.cache_event, (e) => {
+                form_elements.cache_form(lconfig.cache_storage, form);
+            }, true);
+            form_elements.load_cached(lconfig.cache_storage, form);
+        }
+
+        this.show_results = function(form, results) {
+            $(form).append(results);
+        }
+
+        this.show_errors = function(form, errors) {
+            $(form).append(errors);
+        }
+
+        this.make_footer = function() {
+            return $('<div class="text-right caosdb-f-form-elements-footer"/>')[0];
+        }
+
+        this.make_error_message = function(message) {
+            return this.make_message(message, "error");
+        }
+
+        this.make_success_message = function(message) {
+            return this.make_message(message, "success");
+        }
+
+        this.make_submitting_info = function() {
+            // TODO styling
+            return $(this.make_message("Submitting... please wait. This might take some time.", "info"))
+                .toggleClass("h3",true)
+                .toggleClass("caosdb-f-form-submitting",true)
+                .toggleClass("text-right",true)[0];
+        }
+
+        this.make_message = function(message, type) {
+            var ret = $('<div class="caosdb-f-form-elements-message"/>');
+            if(type) {
+                ret.addClass("caosdb-f-form-elements-message-" + type);
+            }
+            return ret.append(markdown.textToHtml(message))[0];
+        }
+
+        this.make_range_input = async function(config) {
+
+            // TODO 
+            // 1. wrapp both inputs to separate it from the label into a container
+            // 2. make two rows for each input
+            // 3. make inline-block for all included elements
+            const from_config = $.extend({}, {cached: config.cached, required: config.required, type: "double"}, config.from);
+            const to_config = $.extend({}, {cached: config.cached, required: config.required, type: "double"}, config.to);
+
+            const from_input = await this.make_form_field(from_config);
+            const to_input = await this.make_form_field(to_config);
+
+            const ret = $(this._make_field_wrapper(config.name));
+            if (config.label) {
+                ret.append(this._make_input_label_str(config));
+            }
+
+            ret.append(from_input);
+            ret.append(to_input);
+
+            // styling
+            $(from_input).toggleClass("form-group", false);
+            $(from_input).find(".col-sm-3").toggleClass("col-sm-3", false).toggleClass("col-sm-1");
+            $(from_input).find(".col-sm-9").toggleClass("col-sm-9", false).toggleClass("col-sm-3");
+            $(to_input).toggleClass("form-group", false);
+            $(to_input).find(".col-sm-3").toggleClass("col-sm-3", false).toggleClass("col-sm-1").toggleClass("col-sm-offset-1");
+            $(to_input).find(".col-sm-9").toggleClass("col-sm-9", false).toggleClass("col-sm-3");
+
+            return ret[0];
+        }
+
+        /**
+         * Return a DIV with class `caosdb-f-field` and a data attribute
+         * `data-field-name` which contains the name.
+         *
+         * The DIV is used to wrap LABEL and INPUT elements of a form together.
+         *
+         * @param {string} name - the name of the field.
+         * @returns {HTMLElement} a DIV.
+         */
+        this._make_field_wrapper = function(name) {
+            caosdb_utils.assert_string(name, "param `name`");
+            return $('<div class="form-group caosdb-f-field caosdb-property-row" data-field-name="'+name+'" />')[0];
+        }
+
+        this.make_date_input = function(config) {
+            return this._make_input(config);
+        }
+
+        this.make_text_input = function(config) {
+            return this._make_input(config);
+        }
+
+
+        /**
+         * Return an input field which accepts double values.
+         *
+         * `config.type` is set to "number" and overrides any other type.
+         *
+         * @param {form_elements.input_config} config.
+         * @returns {HTMLElement} a double form field.
+         */
+        this.make_double_input = function(config) {
+            var clone = $.extend({}, config, {type: "number"});
+            var ret = $(this._make_input(clone))
+            ret.find("input").attr("step", "any");
+            return ret[0];
+        }
+
+
+        /**
+         * Return an input field which accepts integers.
+         *
+         * `config.type` is set to "number" and overrides any other type.
+         *
+         * @param {form_elements.input_config} config.
+         * @returns {HTMLElement} an integer form field.
+         */
+        this.make_integer_input = function(config) {
+            var ret = $(this.make_double_input(config));
+            ret.find("input").attr("step", "1");
+            return ret[0];
+        }
+
+
+        /**
+         * Return a checkbox input field.
+         *
+         * @param {form_elements.checkbox_config} config.
+         * @returns {HTMLElement} a checkbox form field.
+         */
+        this.make_checkbox_input = function(config) {
+            var clone = $.extend({}, config, {type: "checkbox"});
+            var ret = $(this._make_input(clone));
+            ret.find("input:checkbox").prop("checked", false);
+            ret.find("input:checkbox").toggleClass("form-control", false);
+            if(config.checked ) {
+                ret.find("input:checkbox").prop("checked", true);
+                ret.find("input:checkbox").attr("checked", "checked");
+            }
+            if(config.value) {
+                ret.find("input:checkbox").attr("value", config.value);
+            }
+            return ret[0];
+        }
+
+
+        /**
+         * Add `caosdb-f-form-field-required` class to form field.
+         *
+         * @param {HTMLElement} field - the required form field.
+         */
+        this.set_required = function(field) {
+            $(field).toggleClass("caosdb-f-form-field-required", true);
+        }
+
+
+        this.get_enabled_required_fields = function(form) {
+            return $(this.get_enabled_fields(form))
+                .filter(".caosdb-f-form-field-required")
+                .toArray();
+        }
+
+
+        this.get_enabled_fields = function(form) {
+            return $(form)
+                .find(".caosdb-f-field")
+                .filter(function(idx){
+                    // remove disabled fields from results
+                    return !$(this).hasClass("caosdb-f-field-disabled");
+                })
+                .toArray();
+        }
+
+
+        this.all_required_fields_set = function(form) {
+            const req = form_elements.get_enabled_required_fields(form);
+            for ( const field of req ) {
+                if (!form_elements.is_set(field)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * @param {HTMLElement} form - the form be validated.
+         */
+        this.is_valid = function(form) {
+            return form_elements.all_required_fields_set(form);
+        }
+
+
+        this.toggle_submit_button_form_valid = function(form, submit) {
+            // TODO do not change the submit button directly. change the
+            // `submittable` state of the form and handle the case where a form
+            // is submitting when this function is called.
+            if(form_elements.is_valid(form)){
+                $(submit).prop("disabled", false);
+            } else {
+                $(submit).prop("disabled", true);
+            }
+        }
+
+
+        this.init_validator = function(form) {
+            const submit = $(form).find(":input[type='submit']")[0];
+            if(submit) {
+                form.addEventListener("caosdb.field.changed", (e) => form_elements.toggle_submit_button_form_valid(form, submit), true);
+                form.addEventListener("caosdb.field.enabled", (e) => form_elements.toggle_submit_button_form_valid(form, submit), true);
+                form.addEventListener("input", (e) => form_elements.toggle_submit_button_form_valid(form, submit), true);
+            }
+        }
+
+
+        /**
+         * Return an input and a label, wrapped in a div with class
+         * `caosdb-f-field`.
+         *
+         * @param {object} config - config object with `name`, `type` and
+         *      optional `label`
+         * @returns {HTMLElement} a form field.
+         */
+        this._make_input = function(config) {
+            caosdb_utils.assert_string(config.name, "the name of a form field");
+            let ret = $(this._make_field_wrapper(config.name));
+            let name = config.name;
+            let label = this._make_input_label_str(config);
+            let type = config.type;
+            let value = config.value;
+            let input = $('<input class="form-control caosdb-property-text-value" type="' + type
+                + '" name="' + name
+                + '" />');
+            input.change(function() {
+                ret[0].dispatchEvent(form_elements.field_changed_event);
+            });
+            let input_col = $('<div class="caosdb-property-value col-sm-9"/>');
+            input_col.append(input);
+            if (value) {
+                input.val(value);
+            }
+            return ret.append(label, input_col)[0];
+        }
+
+        /**
+         * Return a string representation of a LABEL element, ready for parsing.
+         *
+         * This function is used by other functions to generate a LABEL element.
+         *
+         * The config's `name` goes to the `for` attribute, the `label` is the
+         * text node of the resulting LABEL element.
+         *
+         * @param {object} config - a config object with `name` and `label`.
+         * @returns {string} a html string for a LABEL element.
+         */
+        this._make_input_label_str = function(config) {
+            let name = config.name;
+            let label = config.label;
+            return label ? '<label for="' + name
+                + '" data-property-name="' + name
+                + '" class="control-label col-sm-3">' + label
+                + '</label>' : "";
+        }
+
+    }
+    this._init_functions();
+}
+
+$(document).ready(function() {
+    caosdb_modules.register(form_elements);
+});
diff --git a/src/core/js/query_shortcuts.js b/src/core/js/query_shortcuts.js
new file mode 100644
index 0000000000000000000000000000000000000000..7eb92d5e6a22b54e3920d8804aba2c5199c22bd0
--- /dev/null
+++ b/src/core/js/query_shortcuts.js
@@ -0,0 +1,1142 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2018 Alexander Schlemmer
+ * Copyright (C) 2018 Research Group Biomedical Physics,
+ * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com)
+ * Copyright (C) 2019 Daniel Hornung <d.hornung@indiscale.com>
+ * Copyright (C) 2019 IndiScale GmbH, Göttingen
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+
+"use strict";
+
+/**
+ * Query Shortcuts Extension for CaosDB WebUI.
+ *
+ * Loads, generates and expands shortcuts.
+ *
+ * Global shortcuts are loaded from webinterface/__BUILD_NUMBER__/conf/json/global_query_shortcuts.json, the
+ * format is as follows:
+ *
+ * [
+ *   {
+ *     "description": "Find all geological data sets with temperature above {temp} K.",
+ *     "query": "FIND Record Geodata with temperature > \"$1\""
+ *   }, {
+ *     ...
+ *   }
+ * ]
+ */
+var query_shortcuts = new function() {
+
+
+    this.dependencies = ["form_elements", "log", "transaction"];
+    this.logger = log.getLogger("query_shortcuts");
+
+    this._shortcuts_property_description_name = "templateDescription";
+    this._shortcuts_property_query_name = "Query";
+    this._shortcuts_record_type_name = "UserTemplate";
+
+    this._shortcuts_property_query_id = undefined;
+    this._shortcuts_property_description_id = undefined;
+    this._shortcuts_record_type_id = undefined;
+
+    this._global_shortcuts_file = "json/global_query_shortcuts.json";
+
+    /**
+     * Return a button element which opens a drop-down menu. The menu contains
+     * the toolbox with Create, Edit and Delete functionality.
+     *
+     * Fun fact: The button shows a little wrench.
+     *
+     * @return {HTMLElement} The toolbox drop-down.
+     */
+    this.make_toolbox_button = function() {
+        var ret = $(
+            `<div class="col-md-2 dropdown text-right caosdb-f-shortcuts-toolbox-button">
+              <button title="Shortcuts Toolbox" class="btn dropdown-toggle" type="button"
+                  data-toggle="dropdown"><span class="glyphicon glyphicon-wrench"></span></button>
+              <ul class="dropdown-menu">
+                <li class="dropdown-header">Shortcuts Tools</li>
+                <li><button class="btn" type="button" data-tool="create">Create</button></li>
+                <li><button class="btn" type="button" data-tool="edit">Edit</button></li>
+                <li><button class="btn" type="button" data-tool="delete">Delete</button></li>
+              </ul>
+            </div>`);
+
+        // TODO move to separate functions and refactor to `add_tool(toolbox,
+        // name, callback)`...
+
+        // bind callback functions
+        ret.find("button[data-tool='delete']")
+            .click(function() {
+                var shortcuts_panel = $(".caosdb-shortcuts-container");
+                query_shortcuts.init_delete_shortcut_form(shortcuts_panel[0]);
+            });
+        ret.find("button[data-tool='create']")
+            .click(function() {
+                var shortcuts_panel = $(".caosdb-shortcuts-container");
+                query_shortcuts.init_create_shortcut_form(shortcuts_panel[0]);
+            });
+        ret.find("button[data-tool='edit']")
+            .click(function() {
+                var shortcuts_panel = $(".caosdb-shortcuts-container");
+                query_shortcuts.init_update_shortcut_form(shortcuts_panel[0]);
+            });
+
+        return ret[0];
+    }
+
+    this.init_datamodel = function() {
+        // TODO handle the datamodel dependencies in a save way (lazy-loading is
+        // bad, if the data-model is not there).
+        if(typeof this._shortcuts_property_query_id == "undefined") {
+            query("FIND Property " + query_shortcuts._shortcuts_property_query_name)
+                .then(result => {
+                    if(result.length > 0) {
+                        query_shortcuts._shortcuts_property_query_id = getEntityID(result[0]);
+                    } else {
+                        query_shortcuts._shortcuts_property_query_id = null;
+                    }
+                })
+                .catch(query_shortcuts.logger.error);
+        }
+        if(typeof this._shortcuts_property_description_id == "undefined") {
+            query("FIND Property " + this._shortcuts_property_description_name)
+                .then(result => {
+                    if(result.length > 0) {
+                        query_shortcuts._shortcuts_property_description_id = getEntityID(result[0]);
+                    } else {
+                        query_shortcuts._shortcuts_property_description_id = null;
+                    }
+                })
+                .catch(query_shortcuts.logger.error);
+        }
+        if(typeof this._shortcuts_record_type_id == "undefined") {
+            query("FIND RecordType " + query_shortcuts._shortcuts_record_type_name)
+                .then(result => {
+                    if(result.length > 0) {
+                        query_shortcuts._shortcuts_record_type_id = getEntityID(result[0]);
+                    } else {
+                        query_shortcuts._shortcuts_record_type_id = null;
+                    }
+                })
+                .catch(query_shortcuts.logger.error);
+        }
+    }
+
+    this.init = async function() {
+        this.init_datamodel();
+        var header = $('<div class="caosdb-f-shortcuts-panel-header row h3"><span class="caosdb-f-shortcuts-panel-header-title col-md-10">Shortcuts</span></div>')
+            .append(this.make_toolbox_button());
+        var body = $('<div class="caosdb-f-shortcuts-panel-body"/>');
+        var shortcuts_panel = $('<div class="container caosdb-shortcuts-container"></div>')
+            .append(header)
+            .append(body);
+
+        body.append(await this.retrieve_global_shortcuts());
+
+        if(isAuthenticated()) {
+            body.append(await this.retrieve_user_shortcuts());
+        }
+
+        if (body.children(".caosdb-f-query-shortcut").length > 0) {
+            // append if not empty
+            $("#caosdb-query-panel").append(shortcuts_panel);
+        }
+
+        // make toggle button
+        var toggle_button = this
+            .make_shortcuts_panel_toggle_button(shortcuts_panel);
+
+        header.find("span.caosdb-f-shortcuts-panel-header-title")
+            .prepend(toggle_button);
+
+        // initially hide panel or restore old visibility
+        if(sessionStorage[this._cache_visibility_key] !== "true") {
+            toggle_button.click();
+        }
+
+        return shortcuts_panel[0];
+
+    }
+
+
+    this.make_shortcuts_panel_toggle_button = function(panel) {
+        var button = $('<span title="Toggle Shortcuts Panel" class="caosdb-f-shortcuts-panel-toggle-button glyphicon glyphicon-menu-down"/>');
+        button.click((e) => this.toggle_shortcuts_panel(panel));
+        return button[0];
+    }
+
+
+    /**
+     * Find all placeholders in a string.
+     *
+     * E.g. find_placeholders("asdf {test1} safd {test2} asdf") returns
+     * ["test1", "test2"].
+     *
+     * @param {string} str
+     * @returns {string[]} array with all ids of placeholders
+     */
+    this.find_placeholders = function(str) {
+        const re = /\{(\w*?)\}/g;
+        var match =  [...str.matchAll(re)];
+
+        var ret = []
+        for (const ph of match) {
+            ret.push(ph[1]);
+        }
+
+        return ret;
+    }
+
+
+    /**
+     * Replace the placeholders with input form elements.
+     *
+     * E.g. `asdf {test1} safd {test2} asdf` is converted to `asdf <input
+     * name="test1" type="text" title="test1"/> safd <input name="test2"
+     * type="text" title="test2"/> asdf`
+     *
+     * @param {string} description - the description of a shortcut.
+     * @return {string} the description with all placeholders replaced with
+     * input form elements.
+     */
+    this.replace_placeholders_with_inputs = function(description) {
+        var placeholders = this.find_placeholders(description);
+
+        var ret = description;
+        for (const ph of placeholders) {
+            const re = RegExp("\{" + ph + "\}", "g");
+            const type = "text";
+            const name = ph;
+            const title = ph;
+            ret = ret.replace(re, ' <input type="' + type + '" name="' + name + '" title="' + title + '"/> ');
+        }
+        return ret;
+    }
+
+
+
+    /**
+     * Replace all placeholder in a query string with values from a dictionary.
+     *
+     * E.g. "FIND RECORD WITH date IN {year}" is converted to "FIND RECORD WITH
+     * date IN 2018" when `values` is {"year": "2018"}.
+     *
+     * @param {string} query - the query with placeholders
+     * @param {object} values - a dictionary for the values
+     * @return {string} the query string with all placeholders replaced by the
+     * values in the dictionary.
+     */
+    this.replace_placeholders_with_values = function(query, values) {
+        var placeholders = this.find_placeholders(query);
+
+        var ret = query;
+        for (const ph of placeholders) {
+            const re = RegExp("\{" + ph + "\}", "g");
+            ret = ret.replace(re, values[ph]);
+        }
+        return ret;
+    }
+
+
+    /**
+     * Extract a dictionary of the values that the user entered into the
+     * shortcut forms input elements.
+     *
+     * This function assumes that the input elements have unique `name`
+     * attributes. The resulting dictionary uses these names as keys.
+     *
+     * @param {HTMLElement} shortcut_form - a single shortcut form.
+     * @returns {object} a dictionary with the inputs' names as keys.
+     */
+    this.extract_placeholder_values = function(shortcut_form) {
+        var ret = {}
+        for (const input of $(shortcut_form).find("input")) {
+            ret[input.name] = input.value;
+        }
+        return ret;
+    }
+
+
+    /**
+     * Generate a single query shortcut form.
+     *
+     * The form contains the description with all placeholders replaced by
+     * input elements and button which insert the generated query into the
+     * query panel. The generated query has all placeholders replaced by the
+     * values of the input elements.
+     *
+     * @param {string} description
+     * @param {string} query_string
+     * @param {HTMLElement} A `DIV.caosdb-f-query-shortcut.row`.
+     */
+    this.generate_shortcut_form = function(description, query_string) {
+        var preparedstr = query_shortcuts.replace_placeholders_with_inputs(description);
+        var shortcut_form = $(
+            `<div class="row caosdb-f-query-shortcut">
+              <div class="col-md-10">
+                <span class="caosdb-f-query-shortcut-form">` + preparedstr + `</span>
+              </div>
+              <div class="caosdb-f-query-shortcut-right-col col-md-2 text-right">
+              </div>
+            </div>`
+        );
+
+        // function for inserting the generated query string into the query panel
+        var insert_to_query_panel = (_) => {
+            var values = query_shortcuts.extract_placeholder_values(shortcut_form[0]);
+            var replaced_query_string = query_shortcuts.replace_placeholders_with_values(query_string, values);
+            $("#caosdb-query-textarea")
+                .focus()
+                .val(replaced_query_string);
+        };
+
+        // callback for the submission
+        var execute = (_) => {
+            insert_to_query_panel();
+            $("#caosdb-query-form").submit();
+        };
+
+        shortcut_form.find(".caosdb-f-query-shortcut-right-col")
+            .append(this.make_shortcut_buttons(execute, insert_to_query_panel));
+        return shortcut_form[0];
+    }
+
+    this.generate_user_shortcut = function(description, query_string, id) {
+        const ret = query_shortcuts.generate_shortcut_form(description, query_string);
+        $(ret).toggleClass("caosdb-f-user-query-shortcut", true)
+            .attr("data-entity-id", id)
+            .attr("data-query-string", query_string)
+            .attr("data-shortcut-description", description);
+        return ret;
+    }
+
+    /**
+     * Retrieve global query shortcuts and generate forms for each of them.
+     *
+     * The return value is never null. The array is empty if no global
+     * shortcuts are retrieved.
+     *
+     * @returns {HTMLElement[]} array of query shortcut forms.
+     */
+    this.retrieve_global_shortcuts = async function() {
+
+        try {
+            var temparray = await query_shortcuts._query_global_shortcuts();
+
+            var ret = [];
+            for (var i = 0; i < temparray.length; i++) {
+                var tempel = temparray[i];
+                ret.push(this.generate_shortcut_form(tempel.description, tempel.query));
+            }
+            return ret;
+        } catch (err){
+            query_shortcuts.logger.error(err);
+        }
+
+        // always return something when a function is async
+        return [];
+
+    }
+
+    /**
+     * Retrieve the user-defined query shortcuts and generate forms for each of
+     * them.
+     *
+     * The return value is never null. The array is empty if no user-defined
+     * shortcuts are retrieved.
+     *
+     * @returns {HTMLElement[]} array of query shortcut forms.
+     */
+    this.retrieve_user_shortcuts = async function() {
+        try {
+            var temparray = await query_shortcuts._query_user_shortcuts();
+
+            var ret = [];
+            for (var i = 0; i < temparray.length; i++) {
+                var entity_id = getEntityID(temparray[i]);
+                var description = getProperty(temparray[i], query_shortcuts._shortcuts_property_description_name, false);
+                var query_string = getProperty(temparray[i], query_shortcuts._shortcuts_property_query_name, false);
+                if(query_string && description) {
+                    ret.push(this.generate_user_shortcut(description, query_string, entity_id));
+                } else {
+                    this.logger.warn("User-defined query shortcut without description or query", temparray[i]);
+                }
+            }
+            return ret;
+        } catch (err) {
+            if (typeof err.message === "string"
+                || err.message instanceof String) {
+                if (err.message.indexOf("404") > -1) {
+                    query_shortcuts.logger.warn(err);
+                    return;
+                } else if (err.message.indexOf("401") > -1) {
+                    query_shortcuts.logger.warn(err);
+                    return;
+                }
+            }
+            query_shortcuts.logger.error(err);
+        }
+
+        // always return something when a function is async
+        return [];
+    }
+
+    /**
+     * Retrieve the global query shortcuts from the server.
+     *
+     * The returned objects should have "description" and "query" members.
+     *
+     * @return {object[]} array of objects.
+     */
+    this._query_global_shortcuts = () => load_config(query_shortcuts._global_shortcuts_file);
+
+    /**
+     * Retrieve the user-defined query shortcuts from the server.
+     *
+     * @return {HTMLElement[]} array of entities in HTML representation.
+     */
+    this._query_user_shortcuts = () => query("FIND Record " + query_shortcuts._shortcuts_record_type_name + " WHICH HAS BEEN INSERTED BY ME");
+
+    /**
+     * Initialize the delete shortcuts form.
+     *
+     * The original shortcuts panel hides, a similar form appears. If the form
+     * is submitted successfully the shortcuts panel is re-initialized. If the
+     * form is submitted and the server returned an error, the form can be
+     * canceled or the deletion can be tried again. If the form is canceled,
+     * the original shortcuts panel is restored.
+     *
+     * @param {HTMLElement} panel - the shortcuts panel with global and
+     * user-defined shortcuts.
+     */
+    this.init_delete_shortcut_form = function(panel) {
+        $(panel).find(".alert").remove();
+        var form = this.make_delete_form(panel, this.delete_callback, this.handle_delete_success, this.handle_delete_error);
+        this.init_cud_shortcut_form(panel, form);
+        return panel;
+    }
+
+    this.init_create_shortcut_form = function(panel) {
+        $(panel).find(".alert").remove();
+        var form = this.make_create_form(panel, this.create_callback, this.handle_create_success, this.handle_create_error);
+        this.init_cud_shortcut_form(panel, form);
+        return panel;
+    }
+
+    this.init_update_shortcut_form = function(panel) {
+        $(panel).find(".alert").remove();
+        var selector = this.make_update_selector(panel, this.init_update_single_shortcut_form);
+        this.init_cud_shortcut_form(panel, selector);
+    }
+
+
+    this.init_update_single_shortcut_form = function(panel, entity_id) {
+        $(panel).find(".alert").remove();
+        var form = query_shortcuts.make_update_form(panel, entity_id, query_shortcuts.update_callback, query_shortcuts.handle_update_success, query_shortcuts.handle_update_error);
+        query_shortcuts.init_cud_shortcut_form(panel, form);
+        return panel;
+    }
+
+
+    this.handle_update_error = function(panel, results) {
+        query_shortcuts.logger.trace("enter handle_update_error", panel, results);
+
+        var errors = $(results).find(".alert-danger");
+        $(panel).append(errors);
+        query_shortcuts.logger.trace("leave handle_update_error");
+        return query_shortcuts.make_dismissible_alert("danger", "<strong>Failure</strong> Shortcuts have not been updated.");
+    }
+
+
+    this.handle_create_error = function(panel, results) {
+        query_shortcuts.logger.trace("enter handle_create_error", panel, results);
+
+        var errors = $(results).find(".alert-danger");
+        $(panel).append(errors);
+        query_shortcuts.logger.trace("leave handle_create_error");
+        return query_shortcuts.make_dismissible_alert("danger", "<strong>Failure</strong> Shortcuts have not been created.");
+    }
+
+
+    /**
+     * Add an "Edit" button to each query shortcut which opens the actual
+     * update form.
+     */
+    this.make_update_selector = function(panel, init_update_form) {
+        caosdb_utils.assert_html_element(panel, "param `panel`");
+
+        // clone panel
+        var cloned = $(panel.outerHTML);
+
+        // remove old header and toolbox button
+        cloned.find(".caosdb-f-shortcuts-panel-header .h3").text("Edit Shortcut.");
+        cloned.find(".caosdb-f-shortcuts-toolbox-button").remove();
+        // show
+        cloned.children().show();
+
+        cloned.find(".caosdb-f-query-shortcut").each((idx, item) => {
+            var wrapper = $(item).find(".col-md-2.text-right");
+
+            // disable the inputs of the query shortcut
+            $(item).find(":input").prop("disabled", true);
+
+            // remove old buttons
+            wrapper.children().remove();
+            if($(item).hasClass("caosdb-f-user-query-shortcut")) {
+                // user shortcut
+                // insert "UPDATE" button
+                var entity_id = $(item).attr("data-entity-id");
+                var input = $('<button type="button" class="btn btn-default" name="update-' + entity_id + '">Edit</button>')
+                    .attr("title", "Edit this shortcut.")
+                    .click(() => init_update_form(panel, entity_id));
+                wrapper.append(input);
+            } else {
+                // global shortcut
+                // gray out and add hint that this is a global shortcut which cannot be deleted.
+                $(item)
+                    .css({"color": "#CCCCCC"})
+                    .attr("title", "This is a global shortcut which cannot be updated via the browser.");
+            }
+        });
+
+
+        var form = form_elements.make_form({fields: cloned.children().toArray(), submit: false});
+        return form;
+
+    }
+
+    this.init_cud_shortcut_form = function(panel, form) {
+        // hide content
+        $(panel).children().hide();
+        var query_panel = $(".caosdb-query-panel").hide();
+
+        // show original again on cancel
+        form.addEventListener("caosdb.form.cancel", function(e) {
+            query_panel.show();
+            $(panel).children().show();
+        }, true);
+
+        // show results in query panel
+        form.addEventListener("caosdb.form.success", function(e) {
+            form.addEventListener("caosdb.form.cancel", function(e) {
+                // reset shortcuts
+                query_panel.show();
+                query_shortcuts.reset();
+            }, true);
+
+        }, true);
+
+        form.addEventListener("caosdb.form.submit", function(e) {
+            $(panel).find(".alert").remove();
+        }, true);
+
+        $(panel).append(form);
+    }
+
+    this.highlight_resulting_entities = function(panel, results) {
+        for (const elem of $(results).find("[data-entity-id]")) {
+            var result_id = $(elem).attr("data-entity-id");
+            var highlight = $(panel)
+                .find(".caosdb-f-user-query-shortcut[data-entity-id='"
+                    + result_id + "']")
+                .toggleClass("caosdb-v-success-query-shortcut",true);
+            highlight
+                .css({"background": "#90EE90"});
+        }
+        setTimeout(() => {
+            $(".caosdb-v-success-query-shortcut")
+                .css({"background": "unset"});
+                setTimeout(() => {
+                    $(".caosdb-v-success-query-shortcut")
+                        .toggleClass("caosdb-v-success-query-shortcut",false);
+                }, 2000);
+        }, 5000);
+    }
+
+    this.append_messages_handler = function(panel, results) {
+        for (const entity of results) {
+            var result_id = undefined;
+            if($(entity).is("[data-entity-id]")){
+                result_id = $(entity).attr("data-entity-id");
+            } else {
+                result_id = $(elem).attr("data-entity-id");
+            }
+            if(typeof result_id !== "undefined") {
+                var alerts = $(entity)
+                    .find("div.alert")
+                    .toggleClass("col-md-12");
+                $(panel)
+                    .find(".caosdb-f-user-query-shortcut[data-entity-id='"
+                        + result_id + "']")
+                    .append(alerts);
+            }
+        }
+    }
+
+    /**
+     * Reset the query shortcuts, i.e. remove the old container and call init
+     * again.
+     */
+    this.reset = async function() {
+        $(".caosdb-shortcuts-container").remove();
+        return await query_shortcuts.init();
+    }
+
+    /**
+     * Reset the shortcut container, highlight the new shortcuts.
+     */
+    this.handle_create_success = async function(panel, results) {
+        query_shortcuts.logger.trace("enter handle_create_success", panel, results);
+        var new_panel = await query_shortcuts.reset();
+        query_shortcuts.highlight_resulting_entities(new_panel, results);
+
+        $(new_panel).append(query_shortcuts.make_dismissible_alert("info", "<strong>Success</strong> New shortcuts have been created."));
+        query_shortcuts.logger.trace("leave handle_create_success");
+    }
+
+
+    /**
+     * Reset the shortcut container, highlight the updated shortcuts.
+     */
+    this.handle_update_success = async function(panel, results) {
+        query_shortcuts.logger.trace("enter handle_update_success", panel, results);
+        var new_panel = await query_shortcuts.reset();
+        query_shortcuts.highlight_resulting_entities(new_panel, results);
+
+        $(new_panel).append(query_shortcuts.make_dismissible_alert("info", "<strong>Success</strong> Shortcuts have been updated."));
+        query_shortcuts.logger.trace("leave handle_update_success");
+    }
+
+    this.make_dismissible_alert = function(type, content) {
+        var ret = $(
+            `<div class="alert alert-` + type + ` alert-dismissible" role="alert">
+              <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+              </button>
+            </div>`);
+        ret.append(content);
+        return ret[0];
+    }
+
+    /**
+     * Add the successfully-deleted message to the deleted shortcuts.
+     *
+     * This method does not reset the shortcuts container, so the form's [OK]
+     * button is still visible.
+     */
+    this.handle_delete_success = function(panel, results) {
+        query_shortcuts.logger.trace("enter handle_delete_success", panel, results);
+
+        query_shortcuts.append_messages_handler(panel, results);
+        query_shortcuts.logger.trace("leave handle_delete_success");
+        return query_shortcuts.make_dismissible_alert("info", "<strong>Success</strong> Shortcuts have been deleted.");
+    }
+
+    /**
+     * Add the error messages to the shortcuts panel and inform the user that
+     * no shortcut has been deleted.
+     *
+     * This method does not reset the shortcuts container, so the form's
+     * [Submit] and [Cancel] buttons are still visible.
+     */
+    this.handle_delete_error = function(panel, results) {
+        query_shortcuts.logger.trace("enter handle_delete_error", panel, results);
+
+        query_shortcuts.append_messages_handler(panel, results);
+        query_shortcuts.logger.trace("leave handle_delete_error");
+        return query_shortcuts.make_dismissible_alert("danger", "<strong>Failure</strong> Shortcuts have not been deleted.");
+    }
+
+
+    this.make_shortcut_buttons = function(execute, customize) {
+        const execute_button = $('<button class="btn btn-primary" type="button" title="Execute query."><span class="glyphicon glyphicon-search"></span></button>')
+            .css({"font-size": "12px"})
+            .click(execute);
+        const customize_button = $('<button class="btn btn-primary" type="button" title="Write to the Query Panel for customization."><span class="glyphicon glyphicon-pencil"></span></button>')
+            .css({"font-size": "12px"})
+            .click(customize)
+            .mouseenter(function(e) {
+                $("#caosdb-query-textarea")
+                    .css({"border-color": "#66afe9",
+                        "outline": 0,
+                        "-webkit-box-shadow":
+                            "inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)",
+                        "box-shadow":
+                            "inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)"});
+            })
+            .mouseleave(function(e) {
+                $('#caosdb-query-textarea').attr("style", "");
+            });
+        const button_group = $('<div class="btn-group"/>')
+            .css({"font-size": "12px", position: "absolute", top: 0, right: "15px"})
+            .append(customize_button, execute_button)
+            .hide()
+            .mouseleave(function(e) {
+                $(this).hide();
+            });
+
+        const hover = $('<button class="btn btn-default caosdb-button-search"><span class="glyphicon glyphicon-search" aria-hidden="true"></span></button>')
+            .css({"font-size": "12px"})
+            .click(execute)
+            .mouseenter(() => {
+                button_group.fadeIn(150);
+            });
+
+        const ret = $('<span/>')
+            .css({"text-align": "right"})
+            .append(hover, button_group);
+
+        //return [hover[0], button_group[0]];
+        return ret[0];
+    }
+
+    /**
+     * Return a FORM element which lets the user delete one or more
+     * user-defined query shortcuts.
+     *
+     * The form is generated from the content of the shortcuts-panel.
+     *
+     * @param {HTMLElement} panel - the original shortcuts-panel.
+     * @param {function} delete_callback - the submit function for the form.
+     * @returns {HTMLElement} a form.
+     */
+    this.make_delete_form = function(panel, delete_callback, success_handler, error_handler) {
+        caosdb_utils.assert_html_element(panel, "param `panel`");
+        caosdb_utils.assert_type(delete_callback, "function", "param `delete_callback`");
+        // clone panel
+        var cloned = $(panel.outerHTML);
+
+        // remove old header and toolbox button
+        cloned.find(".caosdb-f-shortcuts-panel-header .h3").text("Delete Shortcuts");
+        cloned.find(".caosdb-f-shortcuts-toolbox-button").remove();
+        // show
+        cloned.children().show();
+
+        // make form fields manually, only use the form_elements to wrap it.
+        cloned.find(".caosdb-f-query-shortcut").each((idx, item) => {
+            var wrapper = $(item).find(".col-md-2.text-right");
+
+            // disable the inputs of the query shortcut
+            $(item).find(":input").prop("disabled", true);
+
+            // remove old buttons
+            wrapper.children().remove();
+            if($(item).hasClass("caosdb-f-user-query-shortcut")) {
+                // user shortcut
+                // insert checkbox
+                var entity_id = $(item).attr("data-entity-id");
+
+                // TODO use form_elements.make_checkbox_input
+                var input = $('<input type="checkbox" name="' + entity_id + '"/>')
+                    .attr("title", "Delete this shortcut.");
+                wrapper.append(input);
+            } else {
+                // global shortcut
+                // gray out and add hint that this is a global shortcut which cannot be deleted.
+                $(item)
+                    .css({"color": "#CCCCCC"})
+                    .attr("title", "This is a global shortcut which cannot be deleted.");
+            }
+        });
+
+
+
+        var config = {
+            submit: delete_callback,
+            success: success_handler,
+            error: error_handler,
+            fields: cloned.children().toArray(),
+        };
+
+        var form = form_elements.make_form(config);
+        return form;
+    }
+
+    this.make_form_entity = function(entity_id) {
+        var entity = $(`
+            <div class="hidden" data-entity-role="Record">
+            </div>`);
+        if(typeof entity_id === "string" || entity instanceof String) {
+            entity.attr("data-entity-id", entity_id);
+            entity.append(`<div class="caosdb-id">`
+                + entity_id + `</div>`);
+        }
+        return entity[0];
+    }
+
+
+    this.make_query_shortcut_parent = function() {
+        return $(`<div class="caosdb-parent-name">` 
+            + query_shortcuts._shortcuts_record_type_name + `</div>`)[0];
+    }
+
+
+    /**
+     * Return a FORM element which lets the user create a new user-defined
+     * query shortcuts.
+     *
+     * @param {HTMLElement} panel - the original shortcuts-panel.
+     * @param {function} create_callback - the submit function for the form.
+     * @returns {HTMLElement} a form.
+     */
+    this.make_create_form = function(panel, create_callback, success_handler, error_handler) {
+        caosdb_utils.assert_html_element(panel, "param `panel`");
+        caosdb_utils.assert_type(create_callback, "function", "param `create_callback`");
+        // clone panel
+        var cloned = $(panel.outerHTML);
+
+        // remove old header and toolbox button
+        cloned.find(".caosdb-f-shortcuts-panel-header .h3").text("Create Shortcut");
+        cloned.find(".caosdb-f-shortcuts-toolbox-button").remove();
+        // show
+        cloned.children().show();
+
+        var entity = $(this.make_form_entity());
+        entity.append(this.make_query_shortcut_parent());
+
+        var form_config = {
+            name: "create_shortcut",
+            header: "Create Shortcut",
+            submit: create_callback,
+            success: success_handler,
+            error: error_handler,
+            cache_event: "caosdb.field.changed",
+            fields: this.make_create_fields(entity[0]),
+        };
+        var form = form_elements.make_form(form_config);
+
+        this.logger.trace("leave make_create_form", form);
+        return form;
+    }
+
+    this.make_create_fields = function(include) {
+        return [
+            include,
+            {
+                type: "text", name: query_shortcuts._shortcuts_property_description_name, required: true,
+                label: "Description", required: true, cached: true,
+                //help: query_shortcuts._description_help, TODO
+            }, {
+                type: "text", name: query_shortcuts._shortcuts_property_query_name, required: true,
+                label: "Query", required: true, cached: true,
+                //help: query_shortcuts._query_help, TODO
+            }
+        ];
+    }
+
+
+    this.make_update_fields = function(include, old_description, old_query) {
+        var fields = this.make_create_fields(include);
+        fields[1]["cached"] = false;
+        fields[2]["cached"] = false;
+        fields[1]["value"] = old_description;
+        fields[2]["value"] = old_query;
+        return fields;
+    }
+
+
+    this.get_description_id = function() {
+        while(typeof query_shortcuts._shortcuts_property_description_id == "undefined") {
+            // wait
+        }
+        return query_shortcuts._shortcuts_property_description_id;
+    }
+
+
+    this.get_query_id = function() {
+        while(typeof query_shortcuts._shortcuts_property_query_id == "undefined") {
+            // wait
+        }
+        return query_shortcuts._shortcuts_property_query_id;
+    }
+
+    this.get_record_type_id = function() {
+        while(typeof query_shortcuts._shortcuts_record_type_id == "undefined") {
+            // wait
+        }
+        return query_shortcuts._shortcuts_record_type_id;
+    }
+
+
+    this._description_help = {
+        "title": "Description of a Query Shortcut",
+        "content": " <i>Example:</i> <code>Search for experiments in {year}</code>.  <p> The description of a query shortcut is the text that is displayed to the users in the shortcuts section below the main query input field.  </p> <p> When you insert placeholders into the description, they are replaced by input fields. The placeholders are surrounded by curly brackets and must occur in the query too.  </p> <p> You can use any number of placeholders. They just have to have unique names.  </p>",
+        "html": true
+    };
+
+
+    this._query_help = {
+        "title": "Query of a Query Shortcut",
+        "content": " <i>Example:</i> <code>FIND experiment WITH date in {year}</code>.  <p> The query of a query shortcut must conform to the Query Language syntax with the exception that it may contain placeholder which are surrounded by curly brackets.  </p> <p> In the example, 'year' is a placeholder and it will be set to value of the corresponding input field, that is shown in the description in the shortcuts section below the main query input field.  </p>",
+        "html": true
+    };
+
+
+    /**
+     * Return a FORM element which lets the user update a existing user-defined
+     * query shortcuts.
+     *
+     * @param {HTMLElement} panel - the original shortcuts-panel.
+     * @param {function} update_callback - the submit function for the form.
+     * @returns {HTMLElement} a form.
+     */
+    this.make_update_form = function(panel, entity_id, update_callback, success_handler, error_handler) {
+        caosdb_utils.assert_html_element(panel, "param `panel`");
+        caosdb_utils.assert_type(update_callback, "function", "param `update_callback`");
+        caosdb_utils.assert_type(success_handler, "function", "param `success_handler`");
+        caosdb_utils.assert_type(error_handler, "function", "param `error_handler`");
+
+
+        // remove old form
+        form_elements.dismiss_form(panel);
+
+        // clone panel
+        var cloned = $(panel.outerHTML);
+
+        // remove old header and toolbox button
+        cloned.find(".caosdb-f-shortcuts-panel-header .h3").text("Edit Shortcut");
+        cloned.find(".caosdb-f-shortcuts-toolbox-button").remove();
+        // show
+        cloned.children().show();
+
+        var entity = $(this.make_form_entity(entity_id));
+        entity.append(this.make_query_shortcut_parent());
+
+        var olddef = $(panel).find(".caosdb-f-query-shortcut[data-entity-id='" + entity_id + "']");
+
+        var form_config = {
+            name: "edit_shortcut",
+            header: "Edit Shortcut",
+            submit: update_callback,
+            success: success_handler,
+            error: error_handler,
+            fields: this.make_update_fields(entity[0], olddef.attr("data-shortcut-description"), olddef.attr("data-query-string")),
+        };
+        var form = form_elements.make_form(form_config);
+
+        this.logger.trace("leave make_update_form", form);
+        return form;
+    }
+
+    this._cache_visibility_key = "caosdb.query-shortcuts-panel.visible";
+
+    this.toggle_shortcuts_panel = function(panel) {
+        var toggle_button = $(panel).find(".caosdb-f-shortcuts-panel-toggle-button")
+            .toggleClass("caosdb-f-shortcuts-panel-hidden")
+            .toggleClass("glyphicon-menu-right")
+            .toggleClass("glyphicon-menu-down");
+
+
+        // remember visibility for page reloads
+        sessionStorage[this._cache_visibility_key] = !toggle_button
+            .hasClass("caosdb-f-shortcuts-panel-hidden");
+
+        $(panel).find(".caosdb-f-shortcuts-toolbox-button").toggle();
+        $(panel).find(".caosdb-f-shortcuts-panel-body").toggle()
+        navbar.update_subnav_height();
+    }
+
+
+    // deps
+    this._updateEntities = update;
+    this._insertEntities = insert;
+    this._deleteEntities = transaction.deleteEntities;
+    this._transformEntities = transformation.transformEntities;
+
+    /**
+     * Return the check entities of the form as an array of ids.
+     */
+    this.get_checked_ids = function(form) {
+        var checked = [];
+        $(form).find(":checked").each((idx, item) => {
+            checked.push(item.name);
+        });
+        return checked; 
+    }
+
+    /**
+     * Return the entities of the form in XML representation.
+     */
+    this.get_shortcut_entities = function(form) {
+        var entities = [];
+        entities.push(getEntityXML(form));
+        return entities;
+    }
+
+    /**
+     * @throws {HTMLElement[]} if the results contains `DIV.alert-errors`.
+     * @returns {HTMLElement[]} if the transaction was successful.
+     */
+    this.delete_callback = async function(form) {
+        query_shortcuts.logger.trace("enter delete_callback", form);
+
+        var dels_array = query_shortcuts.get_checked_ids(form);
+        query_shortcuts.logger.debug("delete", dels_array);
+
+        var response = await query_shortcuts._deleteEntities(dels_array);
+
+        var ret = await query_shortcuts.transform_entities(response);
+
+        query_shortcuts.logger.trace("leave delete_callback", ret);
+        return ret;
+    }
+
+    /**
+     * @throws {HTMLElement[]} if the results contains `DIV.alert-errors`.
+     * @returns {HTMLElement[]} if the transaction was successful.
+     */
+    this.create_callback = async function(form) {
+        query_shortcuts.logger.trace("enter create_callback", form);
+
+        var insert_xml = query_shortcuts.get_shortcut_entities(form);
+        query_shortcuts.logger.debug("create new shortcuts", insert_xml);
+
+        var response = await query_shortcuts._insertEntities(insert_xml);
+
+        var ret = await query_shortcuts.transform_entities(response);
+
+        query_shortcuts.logger.trace("leave create_callback", ret);
+        return ret;
+    }
+
+    /**
+     * @throws {HTMLElement[]} if the results contains `DIV.alert-errors`.
+     * @returns {HTMLElement[]} if the transaction was successful.
+     */
+    this.update_callback = async function(form) {
+        query_shortcuts.logger.trace("enter update_callback", form);
+
+        var update_xml = query_shortcuts.get_shortcut_entities(form);
+
+        // the two properties
+        var desc_id = query_shortcuts.get_description_id();
+        var query_id = query_shortcuts.get_query_id();
+
+        // the recordtype for user-defined query shortcuts
+        var qs_id = query_shortcuts.get_record_type_id();
+
+        $(update_xml).find("Property[name='"+ query_shortcuts._shortcuts_property_description_name+"']").attr("id", desc_id);
+        $(update_xml).find("Property[name='" + query_shortcuts._shortcuts_property_query_name +  "']").attr("id", query_id);
+        $(update_xml).find("Parent[name='" + query_shortcuts._shortcuts_record_type_name + "']").attr("id", qs_id);
+        query_shortcuts.logger.debug("update shortcuts", update_xml);
+
+        var response = await query_shortcuts._updateEntities(update_xml);
+
+        var ret = await query_shortcuts.transform_entities(response);
+
+        query_shortcuts.logger.trace("leave update_callback", ret);
+        return ret;
+    }
+
+    /**
+     * Transform the reponse XML into an array of entities in HTML
+     * representation.
+     */
+    this.transform_entities = async function(response) {
+        var ret = await query_shortcuts._transformEntities(response);
+
+        // throw errors:
+        var errors = $(ret).find(".alert.alert-danger").toArray();
+        if (errors.length > 0) {
+            query_shortcuts.logger.debug("errors in shortcuts creation", errors);
+            throw ret;
+        }
+        return ret;
+    }
+
+
+    // TODO move to css file
+    var styles = `
+    .caosdb-f-shortcuts-toolbox-button {
+            font-size: 14px;
+        }
+        .caosdb-f-shortcuts-toolbox-button .dropdown-toggle {
+            background-color: transparent;
+            color: #777;
+        }
+        .caosdb-f-shortcuts-toolbox-button .dropdown-toggle:hover {
+            color: #333;
+        }
+        .caosdb-f-shortcuts-toolbox-button li button {
+            display: block;
+            padding: 3px 20px;
+            border: none;
+            width: 100%;
+            text-align: left;
+    }
+
+    .caosdb-f-query-shortcut div {
+            min-height: 32px;
+            vertical-align: middle;
+    }
+
+    div.text-right ul.dropdown-menu {
+        left: unset;
+        right: 0;
+    }
+
+    .caosdb-f-query-shortcut:hover {
+        background-color: #eaeaea;
+    }
+
+    .caosdb-f-user-query-shortcut.caosdb-v-success-query-shortcut {
+          -moz-transition-property: background-color;  /* FF4+ */
+          -moz-transition-duration: 2s;
+          -webkit-transition-property: background-color;  /* Saf3.2+, Chrome */
+          -webkit-transition-duration: 2s;
+          -o-transition-property: background-color;  /* Opera 10.5+ */
+          -o-transition-duration: 2s;
+          -ms-transition-property: background-color;  /* IE10? */
+          -ms-transition-duration: 2s;
+          transition-property: background-color;  /* Standard */
+          transition-duration: 2s;
+    }
+
+    .caosdb-f-shortcuts-panel-body {
+        border-top: 1px solid #C0C0C0;
+    }
+
+    .caosdb-f-shortcuts-panel-toggle-button {
+        margin-right: 4px;
+        cursor: pointer;
+        font-size: 18px;
+        color: #777;
+        }
+        .caosdb-f-shortcuts-panel-toggle-button:hover {
+            color: #333;
+    }
+
+    `;
+
+    var styleSheet = document.createElement("style");
+    styleSheet.type = "text/css";
+    styleSheet.innerText = styles;
+    document.head.appendChild(styleSheet);
+
+}
+
+
+
+$(document).ready(function() {
+    caosdb_modules.register(query_shortcuts);
+});
diff --git a/src/core/js/templates_ext.js b/src/core/js/templates_ext.js
deleted file mode 100644
index 9fbcc0b6d5ec99b8a46c29dd0c076d0a9f927c39..0000000000000000000000000000000000000000
--- a/src/core/js/templates_ext.js
+++ /dev/null
@@ -1,148 +0,0 @@
-// ** header v3.0
-// This file is a part of the CaosDB Project.
-
-// Copyright (C) 2019 IndiScale GmbH
-// Max-Planck-Institute for Dynamics and Self-Organization Göttingen
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU Affero General Public License for more details.
-
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-// ** end header
-
-// Templates Extension for CaosDB WebUI
-// A. Schlemmer, 11/2018
-// (c) 2019 D. Hornung <d.hornung@indiscale.com>
-
-/**
- * Loads, generates and expands templates.
- *
- * Templates are stored in conf/ext/templates.json, the format is as follows:
- *
- * [
- *   {
- *     "help": "Find all geological data sets with temperature above {temp} K.",
- *     "query": "FIND Record Geodata with temperature > \"$1\""
- *   }, {
- *     ...
- *   }
- * ]
- */
-var templates_ext = new function() {
-
-    this.init = async function() {
-        var shortcuts_container = $('<div class="container caosdb-shortcuts-container"><span class="h3">Shortcuts</span></div>');
-        var ar1 = await this.add_templates();
-        var ar2 = await this.add_user_templates();
-
-        if ($.isArray(ar1) && ar1.length > 0) {
-            shortcuts_container.append(ar1);
-            $("#caosdb-query-panel").append(shortcuts_container);
-        }
-        if ($.isArray(ar2) && ar2.length > 0) {
-            shortcuts_container.append(ar2);
-            $("#caosdb-query-panel").append(shortcuts_container);
-        }
-        console.log(shortcuts_container.length);
-    }
-
-    this.generate_template = function(tempstring, tempquery) {
-        // Syntax:
-        // tempstring: Suche alle Kisten mit Name {text}
-        // tempquery: FIND Record Kiste with KistenName = "$1"
-        var re = /\{(.*?)\}/g;
-        var preparedstr = tempstring.replace(re, ' <input type="text"> </input>');
-        var template1 = $('<div class="row"><div class="col-md-10"><div class="btn invisible" style="padding-left: 0px;">.</div><span class="caosdb-f-query-template-form">' + preparedstr + '</span></div><div class="col-md-2 text-right"><button class="btn btn-default caosdb-button-ok"> <span class="glyphicon glyphicon-wrench" aria-hidden="true"></span></button><button class="btn btn-default caosdb-button-search"> <span class="glyphicon glyphicon-search" aria-hidden="true"></span> </button></div></div>');
-        var clickfun = (_) => {
-            var res = template1.find("input");
-            var req = /\$([0-9]+)/g;
-            $("#caosdb-query-textarea").val(tempquery.replace(req, (match, p1) => res[p1 - 1].value));
-        };
-        var clickfun2 = (_) => {
-            clickfun();
-            $("#caosdb-query-form").submit();
-        };
-        template1.find(".caosdb-button-ok").click(clickfun);
-        template1.find(".caosdb-button-search").click(clickfun2);
-        return template1;
-    }
-
-    this.add_templates = async function() {
-
-        try {
-            var temparray = await templates_ext.getTemplatesConfig();
-
-            var ret = [];
-            for (var i = 0; i < temparray.length; i++) {
-                var tempel = temparray[i];
-                ret.push(this.generate_template(tempel.help, tempel.query));
-            }
-            return ret;
-        } catch (err){
-            templates_ext.handleError(err);
-        }
-
-        // always return something when a function is async
-        return [];
-
-    }
-
-    this.add_user_templates = async function() {
-        try {
-            var temparray = await templates_ext.queryUserTemplates();
-
-            var ret = [];
-            for (var i = 0; i < temparray.length; i++) {
-                var help = getProperty(temparray[i], "templateDescription",
-                    case_sensitive=false);
-                var query = getProperty(temparray[i], "Query",
-                    case_sensitive=false);
-                ret.push(this.generate_template(help, query));
-            }
-            return ret;
-        } catch (err) {
-            if (typeof err.message === "string"
-                || err.message instanceof String) {
-                if (err.message.indexOf("404") > -1) {
-                    templates_ext.warning(err);
-                    return;
-                } else if (err.message.indexOf("401") > -1) {
-                    templates_ext.warning(err);
-                    return;
-                }
-            }
-            templates_ext.handleError(err);
-        }
-
-        // always return something when a function is async
-        return [];
-    }
-
-    // this makes these things testable because we can override it.
-    this.getTemplatesConfig = () => load_config("json/templates.json");
-
-    this.queryUserTemplates = () => query("FIND Record UserTemplate");
-
-    this.handleError = globalError;
-
-    this.warning = function(msg) {
-        console.log("warning");
-        console.log(msg);
-    }
-
-}
-
-
-
-$(document).ready(function() {
-    caosdb_modules.register(templates_ext);
-});
diff --git a/src/core/js/webcaosdb.js b/src/core/js/webcaosdb.js
index 63959e6a9eea65412d42aa30a650b8e0b447bb32..0412b1a14137ff7e26abf954ae1dd4c94509ef3d 100644
--- a/src/core/js/webcaosdb.js
+++ b/src/core/js/webcaosdb.js
@@ -25,7 +25,6 @@
 window.addEventListener('error', (e) => globalError(e.error));
 
 var globalError = function(error) {
-    console.log(error);
     var stack = error.stack;
     var message = "Error! Please help to make CaosDB better! Copy this message and send it via email to info@indiscale.com.\n\n";
     message += error.toString();
@@ -35,6 +34,8 @@ var globalError = function(error) {
     }
 
     window.alert(message);
+    console.log(error);
+    throw error;
 }
 
 var globalClassNames = new function() {
@@ -43,6 +44,107 @@ var globalClassNames = new function() {
     this.ErrorNotification = "caosdb-preview-error-notification";
 }
 
+/**
+ * navbar module contains convenience functions for the navbar.
+ */
+this.navbar = new function() {
+
+    var logger = log.getLogger("navbar");
+    this.logger = logger;
+    /**
+     * Add a button to the navbar (left navbar, append right), wrapped in a LI
+     * element.
+     *
+     * If the param `button` is a string then a suitable BUTTON element will be
+     * created. If the button is otherwise an HTMLElement it will just be
+     * wrapped and appended to the navbar.
+     *
+     * The optional `click_callback` function is bound to the click event.
+     *
+     * @param {String|HTMLElement} button - add this button to navbar
+     * @param {function} [click_callback] - callback function for click
+     * @return {HTMLElement} wrapper of the new button
+     */
+    this.add_button = function(button, click_callback) {
+
+        var button_elem = button;
+        if (typeof button === "string" || button instanceof String) {
+            // create button element from string
+            button_elem = $('<button>' + button + '</button>');
+        }
+        $(button_elem).toggleClass("navbar-btn", true);
+        $(button_elem).toggleClass("btn", true);
+
+        // bind click
+        if(typeof click_callback === "function") {
+            $(button_elem).click(click_callback);
+        }
+
+        // wrapp button
+        let wrapper = $("<li></li>").append(button_elem);
+        $('#top-navbar').find("ul.caosdb-navbar").first().append(wrapper);
+
+        return wrapper[0];
+    }
+
+    this.init = function() {
+        $("nav.navbar-fixed-top")
+            .on("shown.bs.collapse", function(e) {
+                logger.trace("navbar expands", e);
+                navbar.update_subnav_height();
+            })
+            .on("hidden.bs.collapse", function(e) {
+                logger.trace("navbar shrinks", e);
+                navbar.update_subnav_height();
+            });
+    }
+
+    this.update_subnav_height = function() {
+        var height = $("nav.navbar-fixed-top").height();
+        $("#subnav").animate({"height": height + 10 + "px"}, 200);
+    }
+
+}
+
+
+this.caosdb_utils = new function() {
+    this.assert_string = function(obj, name, optional=false) {
+        if (typeof obj === "undefined" && optional) {
+            return obj;
+        }
+        if (typeof obj == "string" || obj instanceof String) {
+            return obj;
+        }
+        throw new TypeError(name + " is expected to be a string, was " + typeof obj);
+    }
+
+    this.assert_type = function(obj, type, name, optional=false) {
+        if (typeof obj === "undefined" && optional) {
+            return obj;
+        }
+        if (typeof obj !== type) {
+            throw new TypeError(name + " is expected to be a " + type + ", was " + typeof obj);
+        }
+        return obj;
+    }
+
+    this.assert_html_element = function(obj, name) {
+        if (typeof obj === "undefined" || !(obj instanceof HTMLElement)) {
+            throw new TypeError(name + " is expected to be an HTMLElement, was " + typeof obj);
+        }
+        return obj;
+    }
+
+    this.assert_array = function(obj, name, wrap_if_not_array) {
+        if (Array.isArray(obj)) {
+            return obj;
+        } else if (wrap_if_not_array) {
+            return [obj];
+        }
+        throw new TypeError(name + " is expected to be an array, was " + typeof obj);
+    }
+}
+
 /**
  * connection module contains all ajax calls.
  */
@@ -60,6 +162,8 @@ this.connection = new function() {
             } catch (error) {
                 if (error.status == 414) {
                     throw new Error("UriTooLongException for GET " + uri);
+                } else if (error.status == 0) {
+                    console.log(error);
                 } else if (error.status != null) {
                     throw new Error("GET " + uri + " returned with HTTP status " + error.status + " - " + error.statusText);
                 } else {
@@ -78,11 +182,13 @@ this.connection = new function() {
                     method: 'PUT',
                     dataType: "xml",
                     processData: false,
-                    data: data,
+                    data: xml2str(data),
                     contentType: 'text/xml',
                 });
             } catch (error) {
-                if (error.status != null) {
+                if (error.status == 0) {
+                    console.log(error);
+                } else if (error.status != null) {
                     throw new Error("PUT " + uri + " returned with HTTP status " + error.status + " - " + error.statusText);
                 } else {
                     throw error;
@@ -96,25 +202,31 @@ this.connection = new function() {
          * @params is an associative array with keys being the options and values being the values.
          */
         this.runScript = async function _runScript(scriptname, params) {
-            var pstring = "call=" + scriptname;
+            var formData = new FormData();
+            formData.append("call", scriptname);
             for (var key in params) {
-                pstring += "&-O" + key + "=" + params[key];
+                if (params[key]["filename"]) {
+                    formData.append(key, params[key]["blob"], params[key]["filename"]);
+                } else {
+                    formData.append(key, params[key]);
+                }
             }
             try {
                 return await $.ajax({
                     url: window.sessionStorage.caosdbBasePath + "scripting",
                     method: 'POST',
                     dataType: "xml",
+                    contentType: false,
                     processData: false,
-                    data: pstring,
-                    contentType: 'application/x-www-form-urlencoded',
+                    data: formData,
                 });
             } catch (error) {
-                if (error.status != null) {
+                if (error.status == 0) {
+                    console.log(error);
+                } else if (error.status != null) {
                     throw new Error(
                         "POST scripting returned with HTTP status " + error.status
-                            + " - " + error.statusText + "\n"
-                            + pstring);
+                            + " - " + error.statusText);
                 } else {
                     throw error;
                 }
@@ -131,11 +243,13 @@ this.connection = new function() {
                     method: 'POST',
                     dataType: "xml",
                     processData: false,
-                    data: data,
+                    data: xml2str(data),
                     contentType: 'text/xml',
                 });
             } catch (error) {
-                if (error.status != null) {
+                if (error.status == 0) {
+                    console.log(error);
+                } else if (error.status != null) {
                     throw new Error("POST " + uri + " returned with HTTP status " + error.status + " - " + error.statusText);
                 } else {
                     throw error;
@@ -158,7 +272,9 @@ this.connection = new function() {
                     contentType: 'text/xml',
                 });
             } catch (error) {
-                if (error.status != null) {
+                if (error.status == 0) {
+                    console.log(error);
+                } else if (error.status != null) {
                     throw new Error("DELETE " + "Entity/" + idline + " returned with HTTP status " + error.status + " - " + error.statusText);
                 } else {
                     throw error;
@@ -211,7 +327,7 @@ this.transformation = new function() {
      * @return {XMLDocument} xslt document.
      */
     this.retrieveXsltScript = async function _rXS(name) {
-        return await connection.get("webinterface/xsl/" + name);
+        return await connection.get("webinterface/__BUILD_NUMBER__/xsl/" + name);
     }
 
     /**
@@ -222,7 +338,7 @@ this.transformation = new function() {
      * @return {HTMLElement[]} an array of HTMLElements.
      */
     this.transformEntities = async function _tME(xml) {
-        let xsl = await this.retrieveEntityXsl();
+        let xsl = await transformation.retrieveEntityXsl();
         let html = await asyncXslt(xml, xsl);
         return $(html).find('div.root > div.caosdb-entity-panel').toArray();
     }
@@ -314,6 +430,8 @@ this.transaction = new function() {
 
     /**
      * Retrieve a single entity and return its XML representation.
+     * 
+     * TODO merge with retrieve() in caosdb.js
      *
      * @param {String} entityId
      * @return {Element} an xml element.
@@ -834,12 +952,16 @@ var queryForm = new function() {
         }
     };
 
-    this.redirect = function(value, pagingOn=true) {
-        var pagingparam = "";
-        if (pagingOn === true) {
-            pagingparam = "P=0L" + paging.defaultPageLen + "&";
+    /**
+     * @value {string} query - the query string.
+     * @param {string} paging - the paging string, e.g. 0L10.
+     */
+    this.redirect = function(query, paging) {
+        var pagingparam = ""
+        if(paging && paging.length > 0) {
+            pagingparam = "P=" + paging + "&";
         }
-        location.href = window.sessionStorage.caosdbBasePath + "Entity/?" + pagingparam + "query=" + value;
+        location.href = window.sessionStorage.caosdbBasePath + "Entity/?" + pagingparam + "query=" + query;
     }
 
     this.bindOnClick = function(form, setter) {
@@ -852,9 +974,9 @@ var queryForm = new function() {
           and the click handler of the button.
           See https://developer.mozilla.org/en-US/docs/Web/Events/submit why this is necessary.
           */
-	    var submithandler = function() {
+        var submithandler = function() {
 
-	        // store current query
+            // store current query
             var queryField = form.query;
             var value = queryField.value.toUpperCase();
             if (typeof value == "undefined" || value.length == 0) {
@@ -865,8 +987,13 @@ var queryForm = new function() {
             }
             setter(queryField.value);
 
-	        queryForm.redirect(queryField.value, !queryForm.isSelectQuery(queryField.value));
-	    };
+            var paging = "";
+            if(form.P && !queryForm.isSelectQuery(queryField.value)) {
+                paging = form.P.value
+            }
+
+            queryForm.redirect(queryField.value, paging);
+        };
 
 
         // handler for the form
@@ -906,26 +1033,39 @@ var queryForm = new function() {
 };
 
 
-// TODO: move to annotation class - too specialized - or refactor
+/**
+ * Small module containing only a converter from markdown to html.
+ */
 this.markdown = new function() {
+    this.dependencies = ["showdown", "caosdb_utils"];
+    this.init = function() {
+        this.converter = new showdown.Converter();
+    };
+
+    /**
+     * Convert the content (the so-called innerHtml) of an element to HTML,
+     * interpreting it as markdown.
+     *
+     * @param {HTMLElement} textElement - an element with text which is to be
+     * converted to html.
+     */
     this.toHtml = function(textElement) {
-        if ($(textElement).hasClass('markdowned')) {
-            return textElement;
-        }
-        $(textElement).toggleClass('markdowned', true);
+        let text = $(textElement).html();
+        let html = this.textToHtml(text);
+        $(textElement).html(html);
+    };
 
-        $(textElement).find(".caosdb-comment-annotation-text").each(function() {
-            let converter = new showdown.Converter();
-            let text = $(this).html();
-            let html = converter.makeHtml(text.trim());
-            $(this).html(html);
-        });
-        $(textElement).find(".media-body:not(:has(.media-heading))").each(function() {
-            $('<h4 class="media-heading">You<small><i> just posted</i></small></h4>').prependTo($(this));
-        });
-        return textElement;
+    /**
+     * Convert a markdown text to HTML
+     */
+    this.textToHtml = function(text) {
+        caosdb_utils.assert_string(text, "param `text`");
+        return this.converter.makeHtml(text.trim());
+    };
 
-    }
+    $(document).ready(function() {
+        caosdb_modules.register(markdown);
+    });
 }
 
 var hintMessages = new function() {
@@ -1017,6 +1157,7 @@ function getEntityId(entity) {
     return id;
 }
 
+// TODO remove and use connection.post
 /**
  * Post an xml document to basepath/Entity
  * 
@@ -1069,11 +1210,13 @@ async function load_config(filename) {
     var uri = connection.getBasePath() + "webinterface/conf/" + filename;
     try {
         var data = await $.ajax({
-            url: uri,
+            url: connection.getBasePath() + "webinterface/__BUILD_NUMBER__/conf/" + filename,
             dataType: "json",
         });
     } catch (error) {
-        if (error.status == 404) {
+        if (error.status == 0) {
+            console.log(error);
+        } else if (error.status == 404) {
             return [];
         } else {
             throw new Error("loading '"+ uri + "' failed.", error);
@@ -1206,6 +1349,7 @@ function initOnDocumentReady() {
         caosdb_modules.auto_init = true;
     }
     caosdb_modules.init();
+    navbar.init();
 
 }
 
@@ -1256,7 +1400,7 @@ class _CaosDBModules {
      */
     init() {
         if (this.auto_init) {
-            for (module of this.modules) {
+            for (const module of this.modules) {
                 this._init_module(module);
             }
         }
diff --git a/src/core/owner.xsl b/src/core/owner.xsl
index 2eb2136ba8604de21eef98cd02cb20e2fbe5343b..85f657ac871ca17b89cb0bce948397766db7bc15 100644
--- a/src/core/owner.xsl
+++ b/src/core/owner.xsl
@@ -37,7 +37,7 @@
                 <link rel="stylesheet" type="text/css">
                     <xsl:attribute name="href">
                 <xsl:value-of
-                        select="concat($base_uri, 'webinterface/owner.css')" />
+                    select="concat($base_uri, 'webinterface/__BUILD_NUMBER__/owner.css')" />
                 </xsl:attribute>
                 </link>
 
diff --git a/src/core/permissions.xsl b/src/core/permissions.xsl
index 25668e5df6795cf9ea057ffffe3ab79e458d6472..61d17e929a9fc90128a592264c8e475f04892ee4 100644
--- a/src/core/permissions.xsl
+++ b/src/core/permissions.xsl
@@ -37,7 +37,7 @@
                 <link rel="stylesheet" type="text/css">
                     <xsl:attribute name="href">
                 <xsl:value-of
-                        select="concat($base_uri, 'webinterface/permissions.css')" />
+                    select="concat($base_uri, 'webinterface/__BUILD_NUMBER__/permissions.css')" />
                 </xsl:attribute>
                 </link>
 
diff --git a/src/core/pics/select.svg b/src/core/pics/select.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ffe746162cd9181b0bbf37c47434771f36f94d95
--- /dev/null
+++ b/src/core/pics/select.svg
@@ -0,0 +1,1220 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="svg567"
+   sodipodi:docname="select.svg"
+   inkscape:version="0.92.4 5da689c313, 2019-01-14">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1027"
+     id="namedview569"
+     showgrid="true"
+     inkscape:zoom="2.36"
+     inkscape:cx="50.847458"
+     inkscape:cy="50"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg567">
+    <inkscape:grid
+       type="xygrid"
+       id="grid1378" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs565">
+    <marker
+       inkscape:stockid="Arrow1Sstart"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Sstart"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path1392"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+         transform="scale(0.2) translate(6,0)" />
+    </marker>
+    <marker
+       style="overflow:visible"
+       id="DistanceStart"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="DistanceStart"
+       inkscape:isstock="true">
+      <g
+         id="g2300">
+        <path
+           style="fill:none;stroke:#ffffff;stroke-width:1.15;stroke-linecap:square"
+           d="M 0,0 L 2,0"
+           id="path2306" />
+        <path
+           style="fill:#000000;fill-rule:evenodd;stroke:none"
+           d="M 0,0 L 13,4 L 9,0 13,-4 L 0,0 z "
+           id="path2302" />
+        <path
+           style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:square"
+           d="M 0,-4 L 0,40"
+           id="path2304" />
+      </g>
+    </marker>
+    <font
+       id="glyphicons_halflingsregular"
+       horiz-adv-x="1200">
+      <font-face
+         units-per-em="1200"
+         ascent="960"
+         descent="-240"
+         id="font-face4" />
+      <missing-glyph
+         horiz-adv-x="500"
+         id="missing-glyph6" />
+      <glyph
+         horiz-adv-x="0"
+         id="glyph8" />
+      <glyph
+         horiz-adv-x="400"
+         id="glyph10" />
+      <glyph
+         unicode=" "
+         id="glyph12" />
+      <glyph
+         unicode="*"
+         d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z"
+         id="glyph14" />
+      <glyph
+         unicode="+"
+         d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph16" />
+      <glyph
+         unicode=" "
+         id="glyph18" />
+      <glyph
+         unicode="¥"
+         d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z"
+         id="glyph20" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="650"
+         id="glyph22" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="1300"
+         id="glyph24" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="650"
+         id="glyph26" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="1300"
+         id="glyph28" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="433"
+         id="glyph30" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="325"
+         id="glyph32" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="216"
+         id="glyph34" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="216"
+         id="glyph36" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="162"
+         id="glyph38" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="260"
+         id="glyph40" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="72"
+         id="glyph42" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="260"
+         id="glyph44" />
+      <glyph
+         unicode=" "
+         horiz-adv-x="325"
+         id="glyph46" />
+      <glyph
+         unicode="€"
+         d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z"
+         id="glyph48" />
+      <glyph
+         unicode="₽"
+         d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z"
+         id="glyph50" />
+      <glyph
+         unicode="−"
+         d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph52" />
+      <glyph
+         unicode="⌛"
+         d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z"
+         id="glyph54" />
+      <glyph
+         unicode="◼"
+         horiz-adv-x="500"
+         d="M0 0z"
+         id="glyph56" />
+      <glyph
+         unicode="☁"
+         d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z"
+         id="glyph58" />
+      <glyph
+         unicode="⛺"
+         d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z "
+         id="glyph60" />
+      <glyph
+         unicode="✉"
+         d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z"
+         id="glyph62" />
+      <glyph
+         unicode="✏"
+         d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z"
+         id="glyph64" />
+      <glyph
+         unicode=""
+         d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z"
+         id="glyph66" />
+      <glyph
+         unicode=""
+         d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z"
+         id="glyph68" />
+      <glyph
+         unicode=""
+         d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z"
+         id="glyph70" />
+      <glyph
+         unicode=""
+         d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z"
+         id="glyph72" />
+      <glyph
+         unicode=""
+         d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z"
+         id="glyph74" />
+      <glyph
+         unicode=""
+         d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z"
+         id="glyph76" />
+      <glyph
+         unicode=""
+         d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z"
+         id="glyph78" />
+      <glyph
+         unicode=""
+         d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z"
+         id="glyph80" />
+      <glyph
+         unicode=""
+         d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph82" />
+      <glyph
+         unicode=""
+         d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z"
+         id="glyph84" />
+      <glyph
+         unicode=""
+         d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph86" />
+      <glyph
+         unicode=""
+         d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z"
+         id="glyph88" />
+      <glyph
+         unicode=""
+         d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z"
+         id="glyph90" />
+      <glyph
+         unicode=""
+         d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph92" />
+      <glyph
+         unicode=""
+         d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph94" />
+      <glyph
+         unicode=""
+         d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z"
+         id="glyph96" />
+      <glyph
+         unicode=""
+         d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph98" />
+      <glyph
+         unicode=""
+         d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z"
+         id="glyph100" />
+      <glyph
+         unicode=""
+         d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z"
+         id="glyph102" />
+      <glyph
+         unicode=""
+         d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z"
+         id="glyph104" />
+      <glyph
+         unicode=""
+         d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z"
+         id="glyph106" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph108" />
+      <glyph
+         unicode=""
+         d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z"
+         id="glyph110" />
+      <glyph
+         unicode=""
+         d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph112" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z "
+         id="glyph114" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z"
+         id="glyph116" />
+      <glyph
+         unicode=""
+         d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z"
+         id="glyph118" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z"
+         id="glyph120" />
+      <glyph
+         unicode=""
+         d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z"
+         id="glyph122" />
+      <glyph
+         unicode=""
+         d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z"
+         id="glyph124" />
+      <glyph
+         unicode=""
+         d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph126" />
+      <glyph
+         unicode=""
+         d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z"
+         id="glyph128" />
+      <glyph
+         unicode=""
+         d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z"
+         id="glyph130" />
+      <glyph
+         unicode=""
+         d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z"
+         id="glyph132" />
+      <glyph
+         unicode=""
+         d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z"
+         id="glyph134" />
+      <glyph
+         unicode=""
+         d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z"
+         id="glyph136" />
+      <glyph
+         unicode=""
+         d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z"
+         id="glyph138" />
+      <glyph
+         unicode=""
+         d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z"
+         id="glyph140" />
+      <glyph
+         unicode=""
+         d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z"
+         id="glyph142" />
+      <glyph
+         unicode=""
+         d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z"
+         id="glyph144" />
+      <glyph
+         unicode=""
+         d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z"
+         id="glyph146" />
+      <glyph
+         unicode=""
+         d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z"
+         id="glyph148" />
+      <glyph
+         unicode=""
+         d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph150" />
+      <glyph
+         unicode=""
+         d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z"
+         id="glyph152" />
+      <glyph
+         unicode=""
+         d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z"
+         id="glyph154" />
+      <glyph
+         unicode=""
+         d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z"
+         id="glyph156" />
+      <glyph
+         unicode=""
+         d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z"
+         id="glyph158" />
+      <glyph
+         unicode=""
+         d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z"
+         id="glyph160" />
+      <glyph
+         unicode=""
+         d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z"
+         id="glyph162" />
+      <glyph
+         unicode=""
+         d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z"
+         id="glyph164" />
+      <glyph
+         unicode=""
+         d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph166" />
+      <glyph
+         unicode=""
+         d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph168" />
+      <glyph
+         unicode=""
+         d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z"
+         id="glyph170" />
+      <glyph
+         unicode=""
+         d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph172" />
+      <glyph
+         unicode=""
+         d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph174" />
+      <glyph
+         unicode=""
+         d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph176" />
+      <glyph
+         unicode=""
+         d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph178" />
+      <glyph
+         unicode=""
+         d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z"
+         id="glyph180" />
+      <glyph
+         unicode=""
+         d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z"
+         id="glyph182" />
+      <glyph
+         unicode=""
+         d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z"
+         id="glyph184" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z"
+         id="glyph186" />
+      <glyph
+         unicode=""
+         d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z"
+         id="glyph188" />
+      <glyph
+         unicode=""
+         d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z"
+         id="glyph190" />
+      <glyph
+         unicode=""
+         d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z"
+         id="glyph192" />
+      <glyph
+         unicode=""
+         d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z"
+         id="glyph194" />
+      <glyph
+         unicode=""
+         d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z"
+         id="glyph196" />
+      <glyph
+         unicode=""
+         d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph198" />
+      <glyph
+         unicode=""
+         d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph200" />
+      <glyph
+         unicode=""
+         d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z"
+         id="glyph202" />
+      <glyph
+         unicode=""
+         d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z"
+         id="glyph204" />
+      <glyph
+         unicode=""
+         d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph206" />
+      <glyph
+         unicode=""
+         d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z"
+         id="glyph208" />
+      <glyph
+         unicode=""
+         d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z"
+         id="glyph210" />
+      <glyph
+         unicode=""
+         d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph212" />
+      <glyph
+         unicode=""
+         d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph214" />
+      <glyph
+         unicode=""
+         d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph216" />
+      <glyph
+         unicode=""
+         d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z"
+         id="glyph218" />
+      <glyph
+         unicode=""
+         d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z"
+         id="glyph220" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z"
+         id="glyph222" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z"
+         id="glyph224" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z"
+         id="glyph226" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z"
+         id="glyph228" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z"
+         id="glyph230" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z"
+         id="glyph232" />
+      <glyph
+         unicode=""
+         d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z"
+         id="glyph234" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z"
+         id="glyph236" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z"
+         id="glyph238" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z"
+         id="glyph240" />
+      <glyph
+         unicode=""
+         d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z"
+         id="glyph242" />
+      <glyph
+         unicode=""
+         d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z"
+         id="glyph244" />
+      <glyph
+         unicode=""
+         d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z"
+         id="glyph246" />
+      <glyph
+         unicode=""
+         d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph248" />
+      <glyph
+         unicode=""
+         d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z"
+         id="glyph250" />
+      <glyph
+         unicode=""
+         d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z"
+         id="glyph252" />
+      <glyph
+         unicode=""
+         d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z"
+         id="glyph254" />
+      <glyph
+         unicode=""
+         d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z"
+         id="glyph256" />
+      <glyph
+         unicode=""
+         d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z"
+         id="glyph258" />
+      <glyph
+         unicode=""
+         d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z"
+         id="glyph260" />
+      <glyph
+         unicode=""
+         d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z"
+         id="glyph262" />
+      <glyph
+         unicode=""
+         d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z"
+         id="glyph264" />
+      <glyph
+         unicode=""
+         d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z"
+         id="glyph266" />
+      <glyph
+         unicode=""
+         d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z"
+         id="glyph268" />
+      <glyph
+         unicode=""
+         d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z"
+         id="glyph270" />
+      <glyph
+         unicode=""
+         d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z"
+         id="glyph272" />
+      <glyph
+         unicode=""
+         d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z"
+         id="glyph274" />
+      <glyph
+         unicode=""
+         d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z"
+         id="glyph276" />
+      <glyph
+         unicode=""
+         d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z"
+         id="glyph278" />
+      <glyph
+         unicode=""
+         d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z"
+         id="glyph280" />
+      <glyph
+         unicode=""
+         d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z"
+         id="glyph282" />
+      <glyph
+         unicode=""
+         d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z"
+         id="glyph284" />
+      <glyph
+         unicode=""
+         d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z"
+         id="glyph286" />
+      <glyph
+         unicode=""
+         d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z"
+         id="glyph288" />
+      <glyph
+         unicode=""
+         d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z"
+         id="glyph290" />
+      <glyph
+         unicode=""
+         d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z"
+         id="glyph292" />
+      <glyph
+         unicode=""
+         d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z"
+         id="glyph294" />
+      <glyph
+         unicode=""
+         d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z"
+         id="glyph296" />
+      <glyph
+         unicode=""
+         d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z"
+         id="glyph298" />
+      <glyph
+         unicode=""
+         d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z"
+         id="glyph300" />
+      <glyph
+         unicode=""
+         d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z"
+         id="glyph302" />
+      <glyph
+         unicode=""
+         d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph304" />
+      <glyph
+         unicode=""
+         d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z"
+         id="glyph306" />
+      <glyph
+         unicode=""
+         d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph308" />
+      <glyph
+         unicode=""
+         d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph310" />
+      <glyph
+         unicode=""
+         d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph312" />
+      <glyph
+         unicode=""
+         d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z"
+         id="glyph314" />
+      <glyph
+         unicode=""
+         d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z"
+         id="glyph316" />
+      <glyph
+         unicode=""
+         d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z"
+         id="glyph318" />
+      <glyph
+         unicode=""
+         d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z"
+         id="glyph320" />
+      <glyph
+         unicode=""
+         d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z"
+         id="glyph322" />
+      <glyph
+         unicode=""
+         d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z"
+         id="glyph324" />
+      <glyph
+         unicode=""
+         d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z"
+         id="glyph326" />
+      <glyph
+         unicode=""
+         horiz-adv-x="1220"
+         d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z "
+         id="glyph328" />
+      <glyph
+         unicode=""
+         d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z"
+         id="glyph330" />
+      <glyph
+         unicode=""
+         d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z"
+         id="glyph332" />
+      <glyph
+         unicode=""
+         d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z"
+         id="glyph334" />
+      <glyph
+         unicode=""
+         d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z"
+         id="glyph336" />
+      <glyph
+         unicode=""
+         d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z"
+         id="glyph338" />
+      <glyph
+         unicode=""
+         d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z"
+         id="glyph340" />
+      <glyph
+         unicode=""
+         d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z"
+         id="glyph342" />
+      <glyph
+         unicode=""
+         d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z"
+         id="glyph344" />
+      <glyph
+         unicode=""
+         d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z"
+         id="glyph346" />
+      <glyph
+         unicode=""
+         d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z"
+         id="glyph348" />
+      <glyph
+         unicode=""
+         d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z"
+         id="glyph350" />
+      <glyph
+         unicode=""
+         d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z"
+         id="glyph352" />
+      <glyph
+         unicode=""
+         d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z "
+         id="glyph354" />
+      <glyph
+         unicode=""
+         d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z "
+         id="glyph356" />
+      <glyph
+         unicode=""
+         d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z"
+         id="glyph358" />
+      <glyph
+         unicode=""
+         d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z"
+         id="glyph360" />
+      <glyph
+         unicode=""
+         d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z"
+         id="glyph362" />
+      <glyph
+         unicode=""
+         d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z"
+         id="glyph364" />
+      <glyph
+         unicode=""
+         d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z"
+         id="glyph366" />
+      <glyph
+         unicode=""
+         d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z"
+         id="glyph368" />
+      <glyph
+         unicode=""
+         d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z"
+         id="glyph370" />
+      <glyph
+         unicode=""
+         d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z"
+         id="glyph372" />
+      <glyph
+         unicode=""
+         d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z"
+         id="glyph374" />
+      <glyph
+         unicode=""
+         d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z"
+         id="glyph376" />
+      <glyph
+         unicode=""
+         d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z"
+         id="glyph378" />
+      <glyph
+         unicode=""
+         d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z"
+         id="glyph380" />
+      <glyph
+         unicode=""
+         d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z"
+         id="glyph382" />
+      <glyph
+         unicode=""
+         d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z"
+         id="glyph384" />
+      <glyph
+         unicode=""
+         d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z"
+         id="glyph386" />
+      <glyph
+         unicode=""
+         d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z"
+         id="glyph388" />
+      <glyph
+         unicode=""
+         d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z"
+         id="glyph390" />
+      <glyph
+         unicode=""
+         d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z"
+         id="glyph392" />
+      <glyph
+         unicode=""
+         d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z"
+         id="glyph394" />
+      <glyph
+         unicode=""
+         d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z"
+         id="glyph396" />
+      <glyph
+         unicode=""
+         d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z"
+         id="glyph398" />
+      <glyph
+         unicode=""
+         d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z"
+         id="glyph400" />
+      <glyph
+         unicode=""
+         d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph402" />
+      <glyph
+         unicode=""
+         d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z"
+         id="glyph404" />
+      <glyph
+         unicode=""
+         d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z"
+         id="glyph406" />
+      <glyph
+         unicode=""
+         d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z"
+         id="glyph408" />
+      <glyph
+         unicode=""
+         d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z"
+         id="glyph410" />
+      <glyph
+         unicode=""
+         d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z"
+         id="glyph412" />
+      <glyph
+         unicode=""
+         d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z"
+         id="glyph414" />
+      <glyph
+         unicode=""
+         d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z"
+         id="glyph416" />
+      <glyph
+         unicode=""
+         d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z"
+         id="glyph418" />
+      <glyph
+         unicode=""
+         d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph420" />
+      <glyph
+         unicode=""
+         d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z "
+         id="glyph422" />
+      <glyph
+         unicode=""
+         d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z"
+         id="glyph424" />
+      <glyph
+         unicode=""
+         d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z"
+         id="glyph426" />
+      <glyph
+         unicode=""
+         d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z"
+         id="glyph428" />
+      <glyph
+         unicode=""
+         d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z"
+         id="glyph430" />
+      <glyph
+         unicode=""
+         d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z"
+         id="glyph432" />
+      <glyph
+         unicode=""
+         d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z"
+         id="glyph434" />
+      <glyph
+         unicode=""
+         d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z"
+         id="glyph436" />
+      <glyph
+         unicode=""
+         d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z"
+         id="glyph438" />
+      <glyph
+         unicode=""
+         d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z"
+         id="glyph440" />
+      <glyph
+         unicode=""
+         d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z"
+         id="glyph442" />
+      <glyph
+         unicode=""
+         d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph444" />
+      <glyph
+         unicode=""
+         d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z"
+         id="glyph446" />
+      <glyph
+         unicode=""
+         d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z"
+         id="glyph448" />
+      <glyph
+         unicode=""
+         d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z"
+         id="glyph450" />
+      <glyph
+         unicode=""
+         d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z"
+         id="glyph452" />
+      <glyph
+         unicode=""
+         d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z"
+         id="glyph454" />
+      <glyph
+         unicode=""
+         d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z"
+         id="glyph456" />
+      <glyph
+         unicode=""
+         d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z"
+         id="glyph458" />
+      <glyph
+         unicode=""
+         d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z"
+         id="glyph460" />
+      <glyph
+         unicode=""
+         d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z"
+         id="glyph462" />
+      <glyph
+         unicode=""
+         d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z"
+         id="glyph464" />
+      <glyph
+         unicode=""
+         d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph466" />
+      <glyph
+         unicode=""
+         d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph468" />
+      <glyph
+         unicode=""
+         d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph470" />
+      <glyph
+         unicode=""
+         d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph472" />
+      <glyph
+         unicode=""
+         d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph474" />
+      <glyph
+         unicode=""
+         d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph476" />
+      <glyph
+         unicode=""
+         d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z"
+         id="glyph478" />
+      <glyph
+         unicode=""
+         d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z"
+         id="glyph480" />
+      <glyph
+         unicode=""
+         d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z"
+         id="glyph482" />
+      <glyph
+         unicode=""
+         d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph484" />
+      <glyph
+         unicode=""
+         d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z"
+         id="glyph486" />
+      <glyph
+         unicode=""
+         d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z "
+         id="glyph488" />
+      <glyph
+         unicode=""
+         d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z"
+         id="glyph490" />
+      <glyph
+         unicode=""
+         d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z"
+         id="glyph492" />
+      <glyph
+         unicode=""
+         d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z"
+         id="glyph494" />
+      <glyph
+         unicode=""
+         d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z"
+         id="glyph496" />
+      <glyph
+         unicode=""
+         d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z"
+         id="glyph498" />
+      <glyph
+         unicode=""
+         d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z"
+         id="glyph500" />
+      <glyph
+         unicode=""
+         d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z"
+         id="glyph502" />
+      <glyph
+         unicode=""
+         d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z"
+         id="glyph504" />
+      <glyph
+         unicode=""
+         d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z"
+         id="glyph506" />
+      <glyph
+         unicode=""
+         d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z"
+         id="glyph508" />
+      <glyph
+         unicode=""
+         d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z"
+         id="glyph510" />
+      <glyph
+         unicode=""
+         d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z"
+         id="glyph512" />
+      <glyph
+         unicode=""
+         d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z"
+         id="glyph514" />
+      <glyph
+         unicode=""
+         d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z"
+         id="glyph516" />
+      <glyph
+         unicode=""
+         d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z"
+         id="glyph518" />
+      <glyph
+         unicode=""
+         d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z"
+         id="glyph520" />
+      <glyph
+         unicode=""
+         d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z"
+         id="glyph522" />
+      <glyph
+         unicode=""
+         d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z"
+         id="glyph524" />
+      <glyph
+         unicode=""
+         d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z"
+         id="glyph526" />
+      <glyph
+         unicode=""
+         d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z"
+         id="glyph528" />
+      <glyph
+         unicode=""
+         d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph530" />
+      <glyph
+         unicode=""
+         d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z"
+         id="glyph532" />
+      <glyph
+         unicode=""
+         d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z"
+         id="glyph534" />
+      <glyph
+         unicode=""
+         d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z"
+         id="glyph536" />
+      <glyph
+         unicode=""
+         d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z"
+         id="glyph538" />
+      <glyph
+         unicode=""
+         d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z"
+         id="glyph540" />
+      <glyph
+         unicode=""
+         d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z"
+         id="glyph542" />
+      <glyph
+         unicode=""
+         d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z"
+         id="glyph544" />
+      <glyph
+         unicode=""
+         d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z"
+         id="glyph546" />
+      <glyph
+         unicode=""
+         d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z"
+         id="glyph548" />
+      <glyph
+         unicode=""
+         d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z"
+         id="glyph550" />
+      <glyph
+         unicode=""
+         d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z"
+         id="glyph552" />
+      <glyph
+         unicode=""
+         d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z"
+         id="glyph554" />
+      <glyph
+         unicode=""
+         d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z"
+         id="glyph556" />
+      <glyph
+         unicode=""
+         d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z"
+         id="glyph558" />
+      <glyph
+         unicode="🔑"
+         d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z"
+         id="glyph560" />
+      <glyph
+         unicode="🚪"
+         d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z"
+         id="glyph562" />
+    </font>
+  </defs>
+  <rect
+     style="fill:none;fill-opacity:1;stroke:#010b00;stroke-width:5.58900023;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:22.3560009,5.58900023;stroke-dashoffset:24.03270097;stroke-opacity:1;paint-order:normal;stroke-linecap:butt"
+     id="rect1376"
+     width="90"
+     height="89.999992"
+     x="5"
+     y="5" />
+</svg>
diff --git a/src/core/pics/select.svg.png b/src/core/pics/select.svg.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e6cb042abe92ae3648cdadca65b8b7e0ad79616
Binary files /dev/null and b/src/core/pics/select.svg.png differ
diff --git a/src/core/webcaosdb.xsl b/src/core/webcaosdb.xsl
index 89fdfacc077c40c4913bd2332d820125ab5a07e5..e6dccff3c21c0d422937dc3c716db1d5ae5c0d5c 100644
--- a/src/core/webcaosdb.xsl
+++ b/src/core/webcaosdb.xsl
@@ -47,10 +47,10 @@
                 <xsl:call-template name="caosdb-data-container" />
                 <xsl:call-template name="paging-panel"/>
             </body>
-			<footer>
-				See data policy statement 
-				<a href="https://indiscale.com/?page_id=156">here </a>
-			</footer>
+            <footer>
+                See data policy statement 
+                <a href="https://indiscale.com/?page_id=156">here </a>
+            </footer>
         </html>
     </xsl:template>
 
diff --git a/src/core/xsl/entity.xsl b/src/core/xsl/entity.xsl
index 73c8261b6c75461b9c81ffae5578f9a175333f8f..5fc967a32680c166165bd0ed980f5f5384dc9a1c 100644
--- a/src/core/xsl/entity.xsl
+++ b/src/core/xsl/entity.xsl
@@ -282,39 +282,44 @@
     <xsl:param name="value"/>
     <xsl:param name="reference"/>
     <xsl:param name="boolean"/>
-    <xsl:if test="normalize-space($value)!=''">
-      <xsl:choose>
-        <xsl:when test="$reference='true' and normalize-space($value)!=''">
-          <!-- this is a reference -->
-          <a class="btn btn-default btn-sm caosdb-resolvable-reference">
-            <xsl:attribute name="href">
-              <xsl:value-of select="concat($entitypath,normalize-space($value))"/>
-            </xsl:attribute>
-            <span class="caosdb-id caosdb-id-button">
+    <xsl:choose>
+      <xsl:when test="normalize-space($value)!=''">
+        <xsl:choose>
+          <xsl:when test="$reference='true' and normalize-space($value)!=''">
+            <!-- this is a reference -->
+            <a class="btn btn-default btn-sm caosdb-resolvable-reference">
+              <xsl:attribute name="href">
+                <xsl:value-of select="concat($entitypath,normalize-space($value))"/>
+              </xsl:attribute>
+              <span class="caosdb-id caosdb-id-button">
+                <xsl:value-of select="normalize-space($value)"/>
+              </span>
+              <span class="caosdb-resolve-reference-target"/>
+            </a>
+          </xsl:when>
+          <xsl:when test="$boolean='true'">
+            <xsl:element name="span">
+              <xsl:attribute name="class">
+                <xsl:value-of select="concat('caosdb-boolean-',normalize-space($value)='TRUE')"/>
+              </xsl:attribute>
               <xsl:value-of select="normalize-space($value)"/>
+            </xsl:element>
+          </xsl:when>
+          <xsl:otherwise>
+            <span class="caosdb-property-text-value">
+              <xsl:call-template name="trim">
+                <xsl:with-param name="str">
+                  <xsl:value-of select="$value"/>
+                </xsl:with-param>
+              </xsl:call-template>
             </span>
-            <span class="caosdb-resolve-reference-target"/>
-          </a>
-        </xsl:when>
-        <xsl:when test="$boolean='true'">
-          <xsl:element name="span">
-            <xsl:attribute name="class">
-              <xsl:value-of select="concat('caosdb-boolean-',normalize-space($value)='TRUE')"/>
-            </xsl:attribute>
-            <xsl:value-of select="normalize-space($value)"/>
-          </xsl:element>
-        </xsl:when>
-        <xsl:otherwise>
-          <span class="caosdb-property-text-value">
-            <xsl:call-template name="trim">
-              <xsl:with-param name="str">
-                <xsl:value-of select="$value"/>
-              </xsl:with-param>
-            </xsl:call-template>
-          </span>
-        </xsl:otherwise>
-      </xsl:choose>
-    </xsl:if>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+        <span class="caosdb-property-text-value"/>
+      </xsl:otherwise>
+    </xsl:choose>
   </xsl:template>
   <xsl:template match="Property" mode="property-reference-value-list">
     <xsl:param name="reference"/>
diff --git a/src/core/xsl/filesystem.xsl b/src/core/xsl/filesystem.xsl
index 35ce1d7140db69fbba3fc5dc3d84a6f547b497a1..1d9c189a029bf2459d67bd5cb0069f1fceb3149f 100644
--- a/src/core/xsl/filesystem.xsl
+++ b/src/core/xsl/filesystem.xsl
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
  * ** header v3.0
  * This file is a part of the CaosDB Project.
diff --git a/src/core/xsl/main.xsl b/src/core/xsl/main.xsl
index 3028e45f15414880d24b07d6fb7a53363ace44f2..3237037bdf43de2f3f5db1b17f23d1b93a31e266 100644
--- a/src/core/xsl/main.xsl
+++ b/src/core/xsl/main.xsl
@@ -45,55 +45,90 @@
     <xsl:element name="link">
       <xsl:attribute name="rel">stylesheet</xsl:attribute>
       <xsl:attribute name="href">
-        <xsl:value-of select="concat($basepath,'webinterface/css/bootstrap.css')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/css/bootstrap.css')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="link">
       <xsl:attribute name="rel">stylesheet</xsl:attribute>
       <xsl:attribute name="href">
-        <xsl:value-of select="concat($basepath,'webinterface/css/webcaosdb.css')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/css/webcaosdb.css')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="link">
       <xsl:attribute name="rel">stylesheet</xsl:attribute>
       <xsl:attribute name="href">
-        <xsl:value-of select="concat($basepath,'webinterface/css/tour.css')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/css/dropzone.css')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="link">
+      <xsl:attribute name="rel">stylesheet</xsl:attribute>
+      <xsl:attribute name="href">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/css/tour.css')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="link">
+      <xsl:attribute name="rel">stylesheet</xsl:attribute>
+      <xsl:attribute name="href">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/css/leaflet.css')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="link">
+      <xsl:attribute name="rel">stylesheet</xsl:attribute>
+      <xsl:attribute name="href">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/css/leaflet-coordinates.css')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="link">
+      <xsl:attribute name="rel">stylesheet</xsl:attribute>
+      <xsl:attribute name="href">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/css/bootstrap-select.css')"/>
       </xsl:attribute>
     </xsl:element>
     <!--CSS_EXTENSIONS-->
   </xsl:template>
   <xsl:template name="caosdb-head-js">
     <script>
+        var caosdb_webui_build_number = "__BUILD_NUMBER__";
         window.sessionStorage.caosdbBasePath = "<xsl:value-of select="$basepath"/>";
     </script>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/jquery.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/jquery.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/bootstrap.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/bootstrap.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/state-machine.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/bootstrap-select.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/showdown.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/state-machine.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/dropzone.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/showdown.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/webcaosdb.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/dropzone.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/loglevel.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/webcaosdb.js')"/>
       </xsl:attribute>
     </xsl:element>
     <script>
@@ -101,42 +136,82 @@
     </script>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/caosdb.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/caosdb.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/form_elements.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/preview.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/ext_references.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/ext_xls_download.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/query_shortcuts.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/annotation.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/edit_mode.js')"/>
+      </xsl:attribute>
+    </xsl:element>
+    <xsl:element name="script">
+      <xsl:attribute name="src">
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/leaflet.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/preview.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/leaflet-graticule.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/ext_references.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/leaflet-latlng-graticule.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/ext_xsl_download.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/leaflet-coordinates.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/templates_ext.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/proj4.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/annotation.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/proj4leaflet.js')"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/tour.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/tour.js)"/>
       </xsl:attribute>
     </xsl:element>
     <xsl:element name="script">
       <xsl:attribute name="src">
-        <xsl:value-of select="concat($basepath,'webinterface/js/edit_mode.js')"/>
+        <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/js/ext_map.js')"/>
       </xsl:attribute>
     </xsl:element>
     <!--JS_EXTENSIONS-->
diff --git a/src/core/xsl/messages.xsl b/src/core/xsl/messages.xsl
index eab7d2ce421a9b191d9a026183bf2246c47a36c9..392d6e37e51e7426feafff8726382abb4012376b 100644
--- a/src/core/xsl/messages.xsl
+++ b/src/core/xsl/messages.xsl
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
  * ** header v3.0
  * This file is a part of the CaosDB Project.
diff --git a/src/core/xsl/navbar.xsl b/src/core/xsl/navbar.xsl
index 0619beccd65bbbb76e826e6539b7c0f4decf8c9f..9152e5bae513b95afb9e85dfad6b2faab987780c 100644
--- a/src/core/xsl/navbar.xsl
+++ b/src/core/xsl/navbar.xsl
@@ -52,7 +52,7 @@
             <xsl:element name="img">
               <xsl:attribute name="class">caosdb-logo</xsl:attribute>
               <xsl:attribute name="src">
-                <xsl:value-of select="concat($basepath,'webinterface/pics/caosdb_logo_medium.png')"/>
+                <xsl:value-of select="concat($basepath,'webinterface/__BUILD_NUMBER__/pics/caosdb_logo_medium.png')"/>
               </xsl:attribute>
             </xsl:element>
                         CaosDB
diff --git a/src/core/xsl/query.xsl b/src/core/xsl/query.xsl
index c1ff4805149d2191e12402b074b5158da41fffb6..7aa9a80cf425767b9d49d9ed52170618f66317f7 100644
--- a/src/core/xsl/query.xsl
+++ b/src/core/xsl/query.xsl
@@ -109,7 +109,7 @@
                     </p>
                     <p>
                     <a class="caosdb-v-query-select-data-xsl" onclick="downloadXLS(this)" href="#selected_data.xsl" download="">
-                      Download XSL File
+                      Download XLS File
                       </a>
                     </p>
                     <hr/>
diff --git a/src/core/xsl/server_properties.xsl b/src/core/xsl/server_properties.xsl
new file mode 100644
index 0000000000000000000000000000000000000000..06790a4c3a5c3e3017277ea8d256cb4d159ae5b2
--- /dev/null
+++ b/src/core/xsl/server_properties.xsl
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2018 Research Group Biomedical Physics,
+ * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+-->
+<xsl:stylesheet version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+    <xsl:output method="html" />
+
+    <xsl:template match="/Properties">
+        <html lang="en">
+            <head>
+                <meta charset="utf-8" />
+            </head>
+            <body>
+                <form method="POST">
+                    <xsl:apply-templates select="./*"/>
+                    <input type="submit"/>
+                </form>
+            </body>
+        </html>
+    </xsl:template>
+
+    <xsl:template match="/Properties/*">
+        <div>
+            <xsl:value-of select="name()"/>
+            <input>
+                <xsl:choose>
+                  <xsl:when test="contains(name(), 'PASS')">
+                      <xsl:attribute name="type">password</xsl:attribute>
+                  </xsl:when>
+                  <xsl:otherwise>
+                      <xsl:attribute name="type">text</xsl:attribute>
+                  </xsl:otherwise>
+                </xsl:choose>
+                <xsl:attribute name="value"><xsl:value-of select="text()"/></xsl:attribute>
+                <xsl:attribute name="name"><xsl:value-of select="name()"/></xsl:attribute>
+            </input>
+        </div>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/core/xsl/welcome.xsl b/src/core/xsl/welcome.xsl
index d59e9583f0072c548d120f37740e94c6cfc28948..88b2a6e733b6f0726cae02a83c6e88579fdd1918 100644
--- a/src/core/xsl/welcome.xsl
+++ b/src/core/xsl/welcome.xsl
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
  * ** header v3.0
  * This file is a part of the CaosDB Project.
diff --git a/test/core/html/form_elements_example_1.html b/test/core/html/form_elements_example_1.html
new file mode 100644
index 0000000000000000000000000000000000000000..eacc71f5346b1f5469d84fc409ce21ed0aff459f
--- /dev/null
+++ b/test/core/html/form_elements_example_1.html
@@ -0,0 +1,392 @@
+<div class="caosdb-f-form-wrapper">
+  <form action="#" class="form-horizontal" method="post" name="sample_creation.py">
+    <div class="form-group caosdb-f-field caosdb-property-row caosdb-f-form-field-required caosdb-f-form-field-cached" data-field-name="ice_core" data-groups="(part1)">
+      <label class="control-label col-sm-3" data-property-name="ice_core" for="ice_core">Ice Core</label>
+      <div class="col-sm-9">
+        <div class="dropdown bootstrap-select form-control bs3">
+          <select class="selectpicker form-control" name="ice_core" tabindex="-98" title="Nothing selected">
+            <option class="bs-title-option" value=""></option>
+            <option disabled="disabled" selected="selected" style="display: none" value=""></option>
+            <option value="6344">EGRIP15</option>
+            <option value="6345">EGRIP16</option>
+            <option value="6346">EGRIP17</option>
+            <option value="6347">EGRIP18</option>
+            <option value="6348">EGRIP19</option>
+          </select>
+          <button aria-expanded="false" class="btn dropdown-toggle btn-default" data-toggle="dropdown" role="button" title="EGRIP15" type="button">
+            <div class="filter-option">
+              <div class="filter-option-inner">
+                <div class="filter-option-inner-inner">EGRIP15</div>
+              </div> </div>
+            <span class="bs-caret">
+              <span class="caret"></span>
+            </span>
+          </button>
+          <div class="dropdown-menu open" role="combobox" style="max-height: 744px; overflow: hidden; min-height: 92px;">
+            <div aria-expanded="false" class="inner open" role="listbox" style="max-height: 732px; overflow-y: auto; min-height: 80px;" tabindex="-1">
+              <ul class="dropdown-menu inner ">
+                <li class="disabled selected active">
+                  <a aria-disabled="true" aria-selected="true" class="selected active" role="option" style="display: none;" tabindex="-1">
+                    <span class="text"></span>
+                  </a>
+                </li>
+                <li class="selected active">
+                  <a aria-disabled="false" aria-selected="true" class="selected active" role="option" tabindex="0">
+                    <span class="text">EGRIP15</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">EGRIP16</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">EGRIP17</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">EGRIP18</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">EGRIP19</span>
+                  </a>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="orig_sample_type" data-groups="(part1)">
+      <label class="control-label col-sm-3" data-property-name="orig_sample_type" for="orig_sample_type">Original Sample Type</label>
+      <div class="col-sm-9">
+        <div class="dropdown bootstrap-select form-control bs3">
+          <select class="selectpicker form-control" name="orig_sample_type" tabindex="-98" title="Nothing selected">
+            <option class="bs-title-option" value=""></option>
+            <option disabled="disabled" selected="selected" style="display: none" value=""></option>
+            <option value="104">Bag</option>
+            <option value="6306">IceCore</option>
+            <option value="6318">IceSample</option>
+            <option value="6335">Subsample</option>
+            <option value="6338">PP_Sample</option>
+            <option value="6340">LASM_Sample</option>
+          </select>
+          <button aria-expanded="false" class="btn dropdown-toggle btn-default" data-toggle="dropdown" role="button" title="IceSample" type="button">
+            <div class="filter-option">
+              <div class="filter-option-inner">
+                <div class="filter-option-inner-inner">IceSample</div>
+              </div> </div>
+            <span class="bs-caret">
+              <span class="caret"></span>
+            </span>
+          </button>
+          <div class="dropdown-menu open" role="combobox" style="max-height: 690.2px; overflow: hidden; min-height: 92px;">
+            <div aria-expanded="false" class="inner open" role="listbox" style="max-height: 678.2px; overflow-y: auto; min-height: 80px;" tabindex="-1">
+              <ul class="dropdown-menu inner ">
+                <li class="disabled selected active">
+                  <a aria-disabled="true" aria-selected="true" class="selected active" role="option" style="display: none;" tabindex="-1">
+                    <span class="text"></span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">Bag</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">IceCore</span>
+                  </a>
+                </li>
+                <li class="selected active">
+                  <a aria-disabled="false" aria-selected="true" class="selected active" role="option" tabindex="0">
+                    <span class="text">IceSample</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">Subsample</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">PP_Sample</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">LASM_Sample</span>
+                  </a>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="form-group caosdb-f-field caosdb-property-row caosdb-f-field-disabled" data-field-name="logging_protocol" data-groups="(part2)" style="display: none;">
+      <label class="control-label col-sm-3" data-property-name="logging_protocol" for="logging_protocol">Logging Protocol</label>
+      <div class="col-sm-9">
+        <div class="dropdown bootstrap-select form-control bs3">
+          <select class="selectpicker form-control" name="logging_protocol" tabindex="-98" title="Nothing selected">
+            <option class="bs-title-option" value=""></option>
+            <option disabled="disabled" selected="selected" style="display: none" value=""></option>
+            <option value="6350">/logging_protocol_2019-06-15.pdf</option>
+          </select>
+          <button class="btn dropdown-toggle btn-default bs-placeholder" data-toggle="dropdown" role="button" title="Nothing selected" type="button">
+            <div class="filter-option">
+              <div class="filter-option-inner">
+                <div class="filter-option-inner-inner">Nothing selected</div>
+              </div> </div>
+            <span class="bs-caret">
+              <span class="caret"></span>
+            </span>
+          </button>
+          <div class="dropdown-menu open" role="combobox">
+            <div aria-expanded="false" class="inner open" role="listbox" tabindex="-1">
+              <ul class="dropdown-menu inner "></ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="cutting_protocol" data-groups="(part3)" style="">
+      <label class="control-label col-sm-3" data-property-name="cutting_protocol" for="cutting_protocol">Cutting Protocol</label>
+      <div class="col-sm-9">
+        <div class="dropdown bootstrap-select form-control bs3">
+          <select class="selectpicker form-control" name="cutting_protocol" tabindex="-98" title="Nothing selected">
+            <option class="bs-title-option" value=""></option>
+            <option disabled="disabled" selected="selected" style="display: none" value=""></option>
+            <option value="6349">/cutting_protocol_2019-08-15.pdf</option>
+          </select>
+          <button aria-expanded="false" class="btn dropdown-toggle btn-default" data-toggle="dropdown" role="button" title="/cutting_protocol_2019-08-15.pdf" type="button">
+            <div class="filter-option">
+              <div class="filter-option-inner">
+                <div class="filter-option-inner-inner">/cutting_protocol_2019-08-15.pdf</div>
+              </div> </div>
+            <span class="bs-caret">
+              <span class="caret"></span>
+            </span>
+          </button>
+          <div class="dropdown-menu open" role="combobox" style="max-height: 636.4px; overflow: hidden; min-height: 0px;">
+            <div aria-expanded="false" class="inner open" role="listbox" style="max-height: 624.4px; overflow-y: auto; min-height: 0px;" tabindex="-1">
+              <ul class="dropdown-menu inner ">
+                <li class="disabled selected active">
+                  <a aria-disabled="true" aria-selected="true" class="selected active" role="option" style="display: none;" tabindex="-1">
+                    <span class="text"></span>
+                  </a>
+                </li>
+                <li class="selected active">
+                  <a aria-disabled="false" aria-selected="true" class="selected active" role="option" tabindex="0">
+                    <span class="text">/cutting_protocol_2019-08-15.pdf</span>
+                  </a>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="form-group caosdb-f-field caosdb-property-row caosdb-f-form-field-required" data-field-name="cutting_date" data-groups="(part2)(part3)" style="">
+      <label class="control-label col-sm-3" data-property-name="cutting_date" for="cutting_date">Cutting Date</label>
+      <div class="caosdb-property-value col-sm-9">
+        <input class="form-control caosdb-property-text-value" name="cutting_date" type="date"/>
+      </div>
+    </div>
+    <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="bag_numbers" data-groups="(part2)(part3)" style="">
+      <label class="control-label col-sm-3" data-property-name="bag_numbers" for="bag_numbers">Bag Numbers</label>
+      <div class="caosdb-f-field caosdb-property-row" data-field-name="bag_numbers_from">
+        <label class="control-label col-sm-1" data-property-name="bag_numbers_from" for="bag_numbers_from">from</label>
+        <div class="caosdb-property-value col-sm-3">
+          <input class="form-control caosdb-property-text-value" name="bag_numbers_from" step="1" type="number"/>
+        </div>
+      </div>
+      <div class="caosdb-f-field caosdb-property-row" data-field-name="bag_numbers_to">
+        <label class="control-label col-sm-1 col-sm-offset-1" data-property-name="bag_numbers_to" for="bag_numbers_to">to</label>
+        <div class="caosdb-property-value col-sm-3">
+          <input class="form-control caosdb-property-text-value" name="bag_numbers_to" step="1" type="number"/>
+        </div>
+      </div>
+    </div>
+    <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="box_of_new_samples" data-groups="(part2)(part3)" style="">
+      <label class="control-label col-sm-3" data-property-name="box_of_new_samples" for="box_of_new_samples">Box of New Samples</label>
+      <div class="col-sm-9">
+        <div class="dropdown bootstrap-select form-control bs3">
+          <select class="selectpicker form-control" name="box_of_new_samples" tabindex="-98" title="Nothing selected">
+            <option class="bs-title-option" value=""></option>
+            <option disabled="disabled" selected="selected" style="display: none" value=""></option>
+            <option value="242">0284</option>
+            <option value="244">0062</option>
+            <option value="245">0063</option>
+            <option value="250">0089</option>
+            <option value="2112">1101</option>
+            <option value="2123">1112</option>
+            <option value="4434">6053</option>
+          </select>
+          <button aria-expanded="false" class="btn dropdown-toggle btn-default" data-toggle="dropdown" role="button" title="0062" type="button">
+            <div class="filter-option">
+              <div class="filter-option-inner">
+                <div class="filter-option-inner-inner">0062</div>
+              </div> </div>
+            <span class="bs-caret">
+              <span class="caret"></span>
+            </span>
+          </button>
+          <div class="dropdown-menu open" role="combobox" style="max-height: 467.8px; overflow: hidden; min-height: 92px;">
+            <div aria-expanded="false" class="inner open" role="listbox" style="max-height: 455.8px; overflow-y: auto; min-height: 80px;" tabindex="-1">
+              <ul class="dropdown-menu inner ">
+                <li class="disabled selected active">
+                  <a aria-disabled="true" aria-selected="true" class="selected active" role="option" style="display: none;" tabindex="-1">
+                    <span class="text"></span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">0284</span>
+                  </a>
+                </li>
+                <li class="selected active">
+                  <a aria-disabled="false" aria-selected="true" class="selected active" role="option" tabindex="0">
+                    <span class="text">0062</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">0063</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">0089</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">1101</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">1112</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="text">6053</span>
+                  </a>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="new_subsamples_selector" data-groups="(part3)" style="">
+      <label class="control-label col-sm-3" data-property-name="new_subsamples_selector" for="new_subsamples_selector">New Subsamples</label>
+      <div class="col-sm-9">
+        <div class="dropdown bootstrap-select show-tick form-control bs3">
+          <select class="selectpicker form-control" multiple="multiple" name="new_subsamples_selector" tabindex="-98" title="Nothing selected">
+            <option value="6335">Subsample</option>
+            <option value="6338">PP_Sample</option>
+            <option value="6340">LASM_Sample</option>
+          </select>
+          <button aria-expanded="false" class="btn dropdown-toggle btn-default" data-toggle="dropdown" role="button" title="Subsample, PP_Sample" type="button">
+            <div class="filter-option">
+              <div class="filter-option-inner">
+                <div class="filter-option-inner-inner">Subsample, PP_Sample</div>
+              </div> </div>
+            <span class="bs-caret">
+              <span class="caret"></span>
+            </span>
+          </button>
+          <div class="dropdown-menu open" role="combobox" style="max-height: 414px; overflow: hidden; min-height: 0px;">
+            <div aria-expanded="false" class="inner open" role="listbox" style="max-height: 402px; overflow-y: auto; min-height: 0px;" tabindex="-1">
+              <ul class="dropdown-menu inner ">
+                <li class="selected">
+                  <a aria-disabled="false" aria-selected="true" class="selected" role="option" tabindex="0">
+                    <span class="glyphicon glyphicon-ok check-mark"></span>
+                    <span class="text">Subsample</span>
+                  </a>
+                </li>
+                <li class="selected">
+                  <a aria-disabled="false" aria-selected="true" class="selected" role="option" tabindex="0">
+                    <span class="glyphicon glyphicon-ok check-mark"></span>
+                    <span class="text">PP_Sample</span>
+                  </a>
+                </li>
+                <li>
+                  <a aria-disabled="false" aria-selected="false" role="option" tabindex="0">
+                    <span class="glyphicon glyphicon-ok check-mark"></span>
+                    <span class="text">LASM_Sample</span>
+                  </a>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="col-sm-9 col-sm-offset-3 row" style="background-color: rgb(255, 255, 255);">
+      <fieldset class="form-inline caosdb-f-form-elements-subform" data-subform-name="new_subsamples" id="new_subsamples_6335" style="padding-left: 15px; padding-right: 15px;">
+        <legend>Subsample</legend>
+        <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="type">
+          <div class="caosdb-property-value col-sm-9">
+            <input class="form-control caosdb-property-text-value" name="type" type="hidden" value="6335"/>
+          </div>
+        </div>
+        <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="width" style="margin-left: 15px; margin-right: 15px;">
+          <label class="control-label" data-property-name="width" for="width">width (cm)</label>
+          <div class="caosdb-property-value">
+            <input class="form-control caosdb-property-text-value" name="width" step="any" type="number"/>
+          </div>
+        </div>
+        <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="height" style="margin-left: 15px; margin-right: 15px;">
+          <label class="control-label" data-property-name="height" for="height">height (cm)</label>
+          <div class="caosdb-property-value">
+            <input class="form-control caosdb-property-text-value" name="height" step="any" type="number"/>
+          </div>
+        </div>
+        <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="rectangular" style="margin-left: 15px; margin-right: 15px;">
+          <label class="control-label" data-property-name="rectangular" for="rectangular">rectangular</label>
+          <div class="caosdb-property-value">
+            <input class="caosdb-property-text-value" name="rectangular" type="checkbox"/>
+          </div>
+        </div>
+      </fieldset>
+      <fieldset class="form-inline caosdb-f-form-elements-subform" data-subform-name="new_subsamples" id="new_subsamples_6338" style="padding-left: 15px; padding-right: 15px;">
+        <legend>PP_Sample</legend>
+        <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="type">
+          <div class="caosdb-property-value col-sm-9">
+            <input class="form-control caosdb-property-text-value" name="type" type="hidden" value="6338"/>
+          </div>
+        </div>
+        <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="width" style="margin-left: 15px; margin-right: 15px;">
+          <label class="control-label" data-property-name="width" for="width">width (cm)</label>
+          <div class="caosdb-property-value">
+            <input class="form-control caosdb-property-text-value" name="width" step="any" type="number"/>
+          </div>
+        </div>
+        <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="height" style="margin-left: 15px; margin-right: 15px;">
+          <label class="control-label" data-property-name="height" for="height">height (cm)</label>
+          <div class="caosdb-property-value">
+            <input class="form-control caosdb-property-text-value" name="height" step="any" type="number"/>
+          </div>
+        </div>
+        <div class="form-group caosdb-f-field caosdb-property-row" data-field-name="rectangular" style="margin-left: 15px; margin-right: 15px;">
+          <label class="control-label" data-property-name="rectangular" for="rectangular">rectangular</label>
+          <div class="caosdb-property-value">
+            <input class="caosdb-property-text-value" name="rectangular" type="checkbox"/>
+          </div>
+        </div>
+      </fieldset>
+    </div>
+    <div class="text-right caosdb-f-form-elements-footer">
+      <button class="caosdb-f-form-elements-submit-button btn btn-primary btn-default" type="submit">Submit</button>
+      <button class="caosdb-f-form-elements-cancel-button btn btn-primary btn-default" type="button">Cancel</button>
+    </div>
+  </form>
+</div>
diff --git a/test/core/index.html b/test/core/index.html
index bf90345cf17223188986872eddc6f6464304a291..4f2c6b81fbe798ffc16f100678abd56c52237001 100644
--- a/test/core/index.html
+++ b/test/core/index.html
@@ -27,14 +27,20 @@
   <title>WebCaosDB Unit Tests</title>
   <link rel="stylesheet" href="css/qunit.css"/>
   <link rel="stylesheet" href="css/webcaosdb.css"/>
+  <link rel="stylesheet" href="css/leaflet.css"/>
 </head>
 <body>
   <div id="qunit"></div>
   <div id="qunit-fixture"></div>
   <script src="js/jquery.js"></script>
+  <script src="js/loglevel.js"></script>
   <script src="js/bootstrap.js"></script>
+  <script src="js/bootstrap-select.js"></script>
   <script src="js/webcaosdb.js"></script>
-  <script>caosdb_modules.auto_init = false;</script>
+  <script>
+      caosdb_modules.auto_init = false;
+      log.setLevel("trace");
+  </script>
   <script src="js/caosdb.js"></script>
   <script src="js/state-machine.js"></script>
   <script src="js/showdown.js"></script>
@@ -44,13 +50,17 @@
   <script src="js/preview.js"></script>
   <script src="js/annotation.js"></script>
   <script src="js/edit_mode.js"></script>
-  <script src="js/templates_ext.js"></script>
+  <script src="js/query_shortcuts.js"></script>
   <script src="js/ext_references.js"></script>
-  <script src="js/ext_xsl_download.js"></script>
+  <script src="js/ext_xls_download.js"></script>
+  <script src="js/form_elements.js"></script>
+  <script src="js/leaflet.js"></script>
+  <script src="js/leaflet-graticule.js"></script>
+  <script src="js/leaflet-latlng-graticule.js"></script>
+  <script src="js/ext_map.js"></script>
   <!--EXTENSIONS-->
   <script src="js/modules/webcaosdb.js.js"></script>
   <script src="js/modules/caosdb.js.js"></script>
-  <script src="js/modules/webcaosdb.css.js"></script>
   <script src="js/modules/common.xsl.js"></script>
   <script src="js/modules/entity.xsl.js"></script>
   <script src="js/modules/welcome.xsl.js"></script>
@@ -58,7 +68,10 @@
   <script src="js/modules/annotation.xsl.js"></script>
   <script src="js/modules/navbar.xsl.js"></script>
   <script src="js/modules/edit_mode.js.js"></script>
-  <script src="js/modules/ext_xsl_download.js.js"></script>
-  <script src="js/modules/templates_ext.js.js"></script>
+  <script src="js/modules/ext_xls_download.js.js"></script>
+  <script src="js/modules/query_shortcuts.js.js"></script>
+  <script src="js/modules/form_elements.js.js"></script>
+  <script src="js/modules/ext_references.js.js"></script>
+  <script src="js/modules/ext_map.js.js"></script>
 </body>
 </html>
diff --git a/test/core/js/modules/caosdb.js.js b/test/core/js/modules/caosdb.js.js
index 292686e50e712fad2e52e0b3332b2fc7b2f569c1..35a1834083d0b849a62b5f9552a3b7f1259c56c4 100644
--- a/test/core/js/modules/caosdb.js.js
+++ b/test/core/js/modules/caosdb.js.js
@@ -5,11 +5,22 @@
  **/
 
 
+
 // Module initialization
 QUnit.module("caosdb.js", {
+    setTestDocument: function(varname, done, xml) {
+        var xml_test_document = str2xml(xml);
+
+        transformation.transformEntities(xml_test_document).then(x => {
+            this[varname] = x;
+            done();
+        }, err => {console.log(err);});
+
+    },
+    
     before: function(assert) {
-        var done = assert.async();
-        let string_test_document = `
+        var done = assert.async(3);
+        this.setTestDocument("x", done, `
 <Response>
   <Record name="nameofrecord">
     <Parent name="bla" />
@@ -54,26 +65,26 @@ QUnit.module("caosdb.js", {
   </Record>
 
 </Response>
-`;
-        var donecounter = 0;
-        var donemax = 2;
+`);
 
-        doneinc = function() {
-            donecounter++;
-            if (donecounter == donemax) {
-                done();
-            }
-        };
-
-        this.xml_test_document = str2xml(string_test_document);
 
-        transformation.transformEntities(this.xml_test_document).then(x => {
-            this.x = x;
-            doneinc();
-        }, err => {console.log(err);});
+            this.setTestDocument("userInfoTest", done, `
+<Response>
+  <UserInfo username="max" realm="PAM">
+    <Roles>
+        <Role>administration</Role>
+    </Roles>
+  </UserInfo>
 
+  <Record name="nameofrecord">
+    <Parent name="bla" />
+    <Property name="A" datatype="TEXT">245</Property>
+  </Record>
 
-            let string_test_document2 = `
+</Response>`);
+        
+        // Test document for unset references
+        this.setTestDocument("unsetReferencesTest", done, `
 <Response>
   <UserInfo username="max" realm="PAM">
     <Roles>
@@ -83,18 +94,24 @@ QUnit.module("caosdb.js", {
 
   <Record name="nameofrecord">
     <Parent name="bla" />
-    <Property name="A" datatype="TEXT">245</Property>
+    <Property name="A" datatype="UBoot"></Property>
   </Record>
 
-</Response>
+  <Record>
+    <Parent name="bla" />
+    <Property name="A" datatype="UBoot">17</Property>
+  </Record>
 
-        `;
-        this.xml_test_document2 = str2xml(string_test_document2);
+  <Record name="nameofrecord">
+    <Parent name="bla" />
+    <Property name="A" datatype="REFERENCE"></Property>
+  </Record>
 
-        transformation.transformEntities(this.xml_test_document2).then(x => {
-            this.userInfoTest = x;
-            doneinc();
-        }, err => {console.log(err);});
+  <Record name="nameofrecord">
+    <Parent name="bla" />
+    <Property name="A" datatype="REFERENCE">289</Property>
+  </Record>
+</Response>`);
     }
 });
 
@@ -175,7 +192,7 @@ QUnit.test("getParents", function(assert) {
   * Test whether lists and references are parsed correctly.
   */
 QUnit.test("listProperties", function(assert) {
-    console.log(this.x[3]);
+    // console.log(this.x[3]);
     assert.equal(getPropertyElements(this.x[3]).length, 6);
     ps = getProperties(this.x[3]);
     assert.equal(ps.length, 6);
@@ -188,13 +205,13 @@ QUnit.test("listProperties", function(assert) {
     assert.equal(ps[1].reference, false);
     assert.equal(ps[1].list, false);
 
-    console.log(ps[2]);
+    // console.log(ps[2]);
     assert.equal(ps[2].datatype, "LIST<INTEGER>");
     assert.equal(ps[2].reference, false);
     assert.equal(ps[2].list, true);
     assert.deepEqual(ps[2].value, ["245"]);
 
-    console.log(ps[3]);
+    // console.log(ps[3]);
     assert.equal(ps[3].datatype, "LIST<INTEGER>");
     assert.equal(ps[3].reference, false);
     assert.equal(ps[3].list, true);
@@ -208,7 +225,17 @@ QUnit.test("listProperties", function(assert) {
     assert.equal(ps[5].datatype, "LIST<Uboot>");
     assert.equal(ps[5].reference, true);
     assert.equal(ps[5].list, true);
-    
+});
+
+/**
+  * @author Alexander Schlemmer
+  * Test whether list properties have the attribute listDatatype.
+  */
+QUnit.test("listProperties", function(assert) {
+    // For clarity, duplication of above assertions:
+    assert.equal(ps[5].datatype, "LIST<Uboot>");
+    assert.equal(ps[5].list, true);
+    assert.equal(ps[5].listDatatype, "Uboot");
 });
 
 /**
@@ -330,7 +357,7 @@ QUnit.test("replicationOfEntities", function(assert) {
                 assert.equal(pars[i].id, oldpars[i].id);
             }
             funj += 1;
-            console.log(funj, maxfunccall);
+            // console.log(funj, maxfunccall);
             if (funj == maxfunccall) {
                 done();
             }
@@ -401,3 +428,27 @@ QUnit.test("getProperty", function(assert) {
     assert.equal(getProperty(testCase, "A", case_sensitive=false), "245");
     assert.equal(getProperty(testCase, "a", case_sensitive=false), "245");
 });
+
+QUnit.test("getEntityRole", function(assert) {
+    var records = [
+        $('<div data-entity-role="record"/>'),
+        $('<div><div data-entity-role="record"/></div>'),
+        $('<div><div class="caosdb-f-entity-role">record</div></div>'),
+        $('<div class="caosdb-f-entity-role">record</div>')];
+    for (const record of records) {
+        assert.equal(getEntityRole(record), "record", "role detected");
+    }
+
+});
+
+
+// Test for bug #53
+// https://gitlab.com/caosdb/caosdb-webui/issues/53
+QUnit.test("unset_entity_references", function(assert) {
+    console.log(this.unsetReferencesTest);
+    for (var i=0; i<this.unsetReferencesTest.length; i++) {
+        console.log(i);
+        var r = this.unsetReferencesTest[i];
+        assert.equal(getProperties(r)[0].reference, true);
+    }
+});
diff --git a/test/core/js/modules/edit_mode.js.js b/test/core/js/modules/edit_mode.js.js
index 5a5ac030121e82e2581f3cfa30210aeb94f2135b..20ad9e0edecbae7c23883d2d1609764c22691879 100644
--- a/test/core/js/modules/edit_mode.js.js
+++ b/test/core/js/modules/edit_mode.js.js
@@ -26,6 +26,10 @@
 QUnit.module("edit_mode.js", {
     before: function(assert) {
         var done = assert.async();
+        // overwrite query
+        edit_mode.query = async function(str) {
+            return [];
+        }
         retrieveTestEntities("edit_mode/getProperties_1.xml").then(entities => {
             this.testEntity_getProperties_1 = entities[0];
             this.testEntity_make_property_editable_1 = entities[0];
@@ -427,6 +431,8 @@ QUnit.test("remove_delete_button", function(assert){
         return str2xml("<Response><Property id=\"newId\" name=\"TestProperty\" datatype=\"TEXT\"/></Response>");
     }
     // click save button
+    var updated_entity = main_panel.find(".caosdb-entity-panel .caosdb-id:contains('newId')");
+    assert.equal(updated_entity.length, 0, "entity with id not yet in main panel");
     save_button.click();
 
     while(app.state === "changed" || app.state === "wait" ) {
@@ -439,6 +445,14 @@ QUnit.test("remove_delete_button", function(assert){
     var response = $("#newId");
     assert.equal(response.length, 1, "entity added");
 
+    // entity has been added to main panel
+    updated_entity = main_panel.find(".caosdb-entity-panel .caosdb-id:contains('newId')");
+    assert.equal(updated_entity.length, 1, "entity with new id now in main panel");
+
+    //https://gitlab.com/caosdb/caosdb-webui/issues/47
+    assert.equal(main_panel.find(".caosdb-entity-panel .caosdb-entity-actions-panel").length, 1, "general actions panel there");
+    assert.equal(main_panel.find(".caosdb-entity-panel .caosdb-f-edit-mode-entity-actions-panel").length, 1, "edit_mode actions panel there (BUG caosdb-webui#47)");
+
     main_panel.remove();
     test_tool_box.remove();
 
@@ -448,3 +462,5 @@ QUnit.test("remove_delete_button", function(assert){
   });
 
 }
+
+
diff --git a/test/core/js/modules/entity.xsl.js b/test/core/js/modules/entity.xsl.js
index eb626612e529c158bb6ad7a7e618528d58e24bbf..b6d461ce9461ca8d9dd2f9d82c5b580a268aa7c9 100644
--- a/test/core/js/modules/entity.xsl.js
+++ b/test/core/js/modules/entity.xsl.js
@@ -187,7 +187,7 @@ QUnit.test("single-value template with reference property.", function(assert) {
         'value': '',
         'reference': 'true',
         'boolean': 'false'
-    })), "", "empty value produces nothing.");
+    })), "<span xmlns=\"http://www.w3.org/1999/xhtml\" class=\"caosdb-property-text-value\"></span>", "empty value produces empty span.");
     let link = callTemplate(this.entityXSL, 'single-value', {
         'value': '1234',
         'reference': 'true',
diff --git a/test/core/js/modules/ext_map.js.js b/test/core/js/modules/ext_map.js.js
new file mode 100644
index 0000000000000000000000000000000000000000..74573b522926cc4093411989821c00771095eea7
--- /dev/null
+++ b/test/core/js/modules/ext_map.js.js
@@ -0,0 +1,95 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2019 IndiScale GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+
+'use strict';
+
+QUnit.module("ext_map.js");
+
+QUnit.test("availability", function(assert) {
+    assert.equal(caosdb_map.version, "0.2", "test version");
+    assert.ok(caosdb_map.init, "init available");
+});
+
+QUnit.test("default config", function(assert) {
+    assert.ok(caosdb_map._default_config);
+    assert.equal(caosdb_map._default_config.version, caosdb_map.version, "version");
+});
+
+QUnit.test("load_config", async function(assert) {
+    assert.ok(caosdb_map.load_config, "available");
+    assert.ok(await caosdb_map.load_config(), "returns something");
+});
+
+QUnit.test("check_config", function(assert) {
+    assert.ok(caosdb_map.check_config(caosdb_map._default_config), "default config ok");
+    assert.throws(()=>caosdb_map.check_config({"version": "wrong version",}), /The version of the configuration does not match the version of this implementation of the caosdb_map module. Should be '.*', was 'wrong version'./, "wrong version");
+});
+
+QUnit.test("check dependencies", function(assert) {
+    assert.ok(caosdb_map.check_dependencies, "available");
+    assert.propEqual(caosdb_map.dependencies, ["log", {"L": ["latlngGraticule", "Proj"]}, "navbar", "caosdb_utils"]);
+    assert.ok(caosdb_map.check_dependencies(), "deps available");
+});
+
+QUnit.test("create_toggle_map_button", function(assert) {
+    assert.ok(caosdb_map.create_toggle_map_button, "available");
+    var button = caosdb_map.create_toggle_map_button();
+    assert.equal(button.tagName, "BUTTON", "is button");
+    assert.ok($(button).hasClass("caosdb-f-toggle-map-button"),"has caosdb-f-toggle-map-button class");
+    assert.equal($(button).text(), "Map", "button says 'Map'");
+
+    // set other content:
+    button = caosdb_map.create_toggle_map_button("Karte");
+    assert.equal(button.tagName, "BUTTON", "is button");
+    assert.ok($(button).hasClass("caosdb-f-toggle-map-button"),"has caosdb-f-toggle-map-button class");
+    assert.equal($(button).text(), "Karte", "button says 'Karte'");
+
+});
+
+QUnit.test("bind_toggle_map", function(assert) {
+    let button = $("<button/>")[0];
+    let done = assert.async();
+
+    assert.ok(caosdb_map.bind_toggle_map, "available");
+    assert.throws(()=>caosdb_map.bind_toggle_map(button), /parameter 'toggle_cb'.* was undefined/, "no function throws");
+    assert.throws(()=>caosdb_map.bind_toggle_map("test", ()=>{}), /parameter 'button'.* was string/, "string button throws");
+    assert.equal(caosdb_map.bind_toggle_map(button, done), button, "call returns button");
+
+    // button click calls 'done'
+    $(button).click();
+});
+
+
+QUnit.test("create_map", function(assert) {
+    assert.equal(typeof caosdb_map.create_map_view, "function", "function available");
+
+});
+
+QUnit.test("create_map_panel", function(assert) {
+    assert.ok(caosdb_map.create_map_panel, "available");
+    let panel = caosdb_map.create_map_panel();
+    assert.equal(panel.tagName, "DIV", "is div");
+    assert.ok($(panel).hasClass("caosdb-f-map-panel"), "has class caosdb-f-map-panel");
+    assert.ok($(panel).hasClass("container"), "has class container");
+});
+
+
diff --git a/test/core/js/modules/ext_references.js.js b/test/core/js/modules/ext_references.js.js
index 04ea35609b9c53064cb92b5b76de07c10b5836dd..a82af8e2b7da861404abd03e4f7bfd131ff3a32e 100644
--- a/test/core/js/modules/ext_references.js.js
+++ b/test/core/js/modules/ext_references.js.js
@@ -47,3 +47,46 @@ QUnit.test("update_single_resolvable_reference", function(assert){
 QUnit.test("references", function(assert){
     assert.ok(resolve_references.references);
 });
+
+
+
+/*
+ * This test checks whether all required
+ * HTML elements are present.
+ */
+QUnit.test("check_structure_html", function(assert){
+    var done = assert.async();
+    let string_test_document = `
+<Response>
+<Record description="This record has no name.">
+    <Parent name="bla" />
+
+    <Property name="A" datatype="INTEGER">245</Property>
+
+    <Property name="A" datatype="Uboot">245</Property>
+
+    <Property name="A" datatype="LIST&#60;Uboot&#62;">
+      <Value>245</Value>
+      <Value>245</Value>
+    </Property>
+  </Record>
+</Response>
+`;
+    var xmltestdocument = str2xml(string_test_document);
+    transformation.transformEntities(xmltestdocument).then(x => {
+        console.log(x);
+
+        // Check that there are only three resolvable references:
+        var elms = x[0].getElementsByClassName("caosdb-resolvable-reference");
+        assert.equal(elms.length, 3);
+
+        // Check that each of the elements of the list has a grand parent with a specific class:
+        for (var i=1; i<elms.length; i++) {
+            assert.equal(elms[i].parentElement.parentElement.classList.contains("caosdb-value-list"), true);
+        }
+        // but the first element does NOT:
+        assert.equal(elms[0].parentElement.parentElement.classList.contains("caosdb-value-list"), false);
+        
+        done();
+    }, err => {console.log(err);});
+});
diff --git a/test/core/js/modules/ext_xsl_download.js.js b/test/core/js/modules/ext_xsl_download.js.js
index 06a9f745651c1a656fa22012580991fb1a9b71f3..360b389725eec2bc6a4e4115e9cc46cd91e33d69 100644
--- a/test/core/js/modules/ext_xsl_download.js.js
+++ b/test/core/js/modules/ext_xsl_download.js.js
@@ -21,7 +21,7 @@
  */
 'use strict';
 
-QUnit.module("ext_xsl_download");
+QUnit.module("ext_xls_download");
 
 {
   const sleep = function sleep(ms) {
@@ -29,7 +29,7 @@ QUnit.module("ext_xsl_download");
   }
 
   QUnit.test("call downloadXLS", async function(assert) {
-    var done = assert.async();
+    var done = assert.async(2);
 
     connection.runScript = async function(exec, param){
         assert.equal(exec, "xls_from_csv.py", "call xls_from_csv.py");
@@ -37,6 +37,13 @@ QUnit.module("ext_xsl_download");
         return str2xml('<response><script code="0" /><stdout>bla</stdout></response>');
     }
 
+    _go_to_script_results = function(xls_link, filename) {
+        xls_link.setAttribute(
+            "href",
+            location.protocol + "//" +location.host + "/Shared/" + filename);
+        done();
+    }
+
     var tsv_data = $('<a id="caosdb-f-query-select-data-tsv" />');
     $(document.body).append(tsv_data);
 
diff --git a/test/core/js/modules/form_elements.js.js b/test/core/js/modules/form_elements.js.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f5930cd4253f408edf785045db10290697cd6c3
--- /dev/null
+++ b/test/core/js/modules/form_elements.js.js
@@ -0,0 +1,543 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2019 IndiScale GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+
+'use strict';
+
+QUnit.module("form_elements.js", {
+    before: function(assert) {
+        markdown.init();
+        var entities = [
+            $('<div><div class="caosdb-id" data-entity-name="name12">id12</div></div>')[0],
+            $('<div><div class="caosdb-id" data-entity-name="name13">id13</div></div>')[0],
+            $('<div><div class="caosdb-id" data-entity-name="name14">id14</div></div>')[0],
+            $('<div><div class="caosdb-id" data-entity-name="name15">id15</div></div>')[0],
+        ];
+
+        form_elements._query = async function(query) {
+            return entities;
+        };
+        this.get_example_1 = async function() {
+            return $(await $.ajax("html/form_elements_example_1.html"))[0];
+        };
+    },
+    after: function(assert) {
+        form_elements._init_functions();
+    }
+});
+
+QUnit.test("availability", function(assert) {
+    assert.equal(form_elements.version, "0.1", "test version");
+    assert.ok(form_elements.init, "init available");
+    assert.ok(form_elements.version, "version available");
+});
+
+QUnit.test("make_reference_option", function(assert) {
+    assert.equal(typeof form_elements.make_reference_option, "function", "function available");
+    assert.throws(()=>form_elements.make_reference_option(), /is expected to be a string/, "noargs throws");
+    var option = form_elements.make_reference_option("id15");
+    assert.equal($(option).val(), "id15", "value");
+    assert.equal($(option).text(), "id15", "text");
+    option = form_elements.make_reference_option("id16", "desc16");
+    assert.equal($(option).val(), "id16", "value");
+    assert.equal($(option).text(), "desc16", "text");
+});
+
+
+QUnit.test("make_reference_select", async function(assert) {
+    assert.equal(typeof form_elements.make_reference_select, "function", "function available");
+    //assert.throws(()=> unasync(form_elements.make_reference_select), /param `entities` is expected to be an array/, "undefined entities throws");
+    //assert.throws(()=> unasync(form_elements.make_reference_select, "test"), /param `entities` is expected to be an array/, "string entities throws");
+    var select = await form_elements.make_reference_select([
+        {dataset: {entityId : "id17"}},
+        {dataset: {entityId : "id18"}},
+    ]);
+    assert.ok($(select).hasClass("selectpicker"), "selectpicker class from bootstrap-select");
+    assert.notOk($(select).val(), "unselected");
+    $(select).val(["id18"]);
+    assert.equal($(select).val(), "id18", "select id18");
+    $(select).val("id17");
+    assert.equal($(select).val(), "id17", "select id17");
+
+
+    // multiple
+    $(select).prop("multiple", true);
+    $(select).val(["id17", "id18"]);
+    assert.propEqual($(select).val(), ["id17", "id18"], "select multiple");
+
+});
+
+
+QUnit.test("make_script_form", async function(assert) {
+    assert.equal(typeof form_elements.make_script_form, "function", "function available");
+
+    // TODO
+    //assert.throws(()=>form_elements.make_script_form(), /param `script` is expected to be a string, was undefined/, "no param call throws");
+    //assert.throws(()=>form_elements.make_script_form("test"), /param `config` is expected to be a object, was undefined/, "empty object config call throws");
+
+
+    var done = assert.async(3);
+    var config = {
+        groups: [
+            { name: "group1", fields: ["date"], enabled: false },
+        ],
+        fields: [
+            {type: "date", name: "baldate"},
+        ],
+    };
+
+    var script_form = await form_elements.make_script_form(config, "test_script");
+    $(document.body).append(script_form);
+    assert.equal(script_form.tagName, "FORM", "is form");
+
+    var submit_button = $(script_form).find("button[type='submit']");
+    assert.equal(submit_button.length, 1, "has submit button");
+
+    var cancel_button = $(script_form).find("button[type='button']:contains('Cancel')");
+    assert.equal(cancel_button.length, 1, "has cancel button");
+
+    var field = $(script_form).find(".caosdb-f-field");
+    assert.equal(field.length, 1, "has one field");
+    assert.equal(field.find("input[type='date']").length, 1, "has date input");
+
+    script_form.addEventListener("caosdb.form.cancel", function(e) {
+        done();
+    }, true);
+    cancel_button.click();
+
+
+    script_form.addEventListener("caosdb.form.error", function(e) {
+        assert.equal($(script_form).find(".caosdb-f-form-elements-message-error").length, 2, "error message there (call and stderr)");
+        done();
+        script_form.remove();
+    });
+
+    form_elements._run_script = async function(script, params) {
+        done();
+        return {code: "1", stderr: "Autsch!", call: "none"};
+    };
+
+    assert.equal($(script_form).find(".caosdb-f-form-error-message").length, 0, "no error message");
+    submit_button.click();
+
+
+
+
+});
+
+
+QUnit.test("make_date_input", function(assert) {
+    assert.equal(typeof form_elements.make_date_input, "function", "function available");
+
+    var config = {
+        type: "date",
+        name: "thedate",
+        label: "Birthday",
+    }
+    var field = form_elements.make_date_input(config);
+    var input = $(field).find("input");
+    assert.equal(input.length, 1, "has input");
+    assert.equal(input.attr("name"), "thedate", "input has name");
+
+    var label = $(field).find("label");
+    assert.equal(label.length, 1, "has label");
+    assert.equal(label.attr("for"), "thedate", "label has for");
+    assert.equal(label.text(), "Birthday", "label has text");
+
+});
+
+QUnit.test("make_range_input", async function(assert) {
+    assert.equal(typeof form_elements.make_range_input, "function", "function available");
+
+    var config = {
+        type: "range",
+        from: {
+            name: "from_bla",
+        },
+        to: {
+            name: "to_bla",
+        },
+        name: "seats",
+        label: "seat numbers",
+    }
+    var field = await form_elements.make_range_input(config);
+    var input = $(field).find("input");
+    assert.equal(input.length, 2, "has two inputs");
+    assert.equal(input.first().attr("name"), "from_bla", "input 1 has name");
+    assert.equal(input.last().attr("name"), "to_bla", "input 2 has name");
+
+    var label = $(field).find("label");
+    assert.equal(label.length, 1, "has label");
+    assert.equal(label.attr("for"), "seats", "label has for");
+    assert.equal(label.text(), "seat numbers", "label has text");
+
+
+});
+
+QUnit.test("make_form_field", async function(assert) {
+    assert.equal(typeof form_elements.make_form_field, "function", "function available");
+
+    var cached = false; 
+    for ( var t of ["date", "range", "reference_drop_down", "subform", "checkbox", "double", "integer"] ) {
+        cached = !cached;
+        var config = {
+            help: {title: "HELP", content: "help me, help me, help me-e-e!"},
+            type: t,
+            cached: cached,
+            name: "a name",
+            label: "a label",
+            from: {name: "from_bla"},
+            to: {name: "to_bla"},
+            query: "FIND something",
+            make_desc: getEntityName,
+            fields: [],
+        };
+        var field = await form_elements.make_form_field(config);
+        assert.equal($(field).hasClass("caosdb-f-form-field-cached"), cached, t + " cache initialized");
+        assert.ok(field instanceof HTMLElement, "returns HTMLElement");
+        t === "subform" || assert.equal($(field).children("label").length, 1, t + " has label");
+        t === "subform" || assert.equal($(field).find(".caosdb-f-form-help").length, 1, t + " has help");
+    }
+
+});
+
+
+QUnit.test("make_subform", async function(assert) {
+    assert.equal(typeof form_elements.make_reference_drop_down, "function", "function available");
+
+    const config = {
+        type: "subform",
+        name: "subbla",
+        fields: [
+
+        ],
+    }
+
+    var subform = $(await form_elements.make_subform(config));
+    assert.ok(subform[0].tagName, "DIV", "is div");
+    assert.ok(subform.hasClass("caosdb-f-form-elements-subform"), "has caosdb-f-form-elements-subform class");
+    assert.equal(subform.data("subform-name"), "subbla", "has name");
+
+});
+
+
+QUnit.test("make_reference_drop_down", async function(assert) {
+    assert.equal(typeof form_elements.make_reference_drop_down, "function", "function available");
+
+    var config = {
+        type: "reference_drop_down",
+        name: "icecore",
+        label: "IceCore",
+        query: "FIND Record IceCore",
+        make_desc: getEntityName,
+    }
+    var field = await form_elements.make_reference_drop_down(config);
+
+    var label = $(field).find("label");
+    assert.equal(label.length, 1, "has label");
+    assert.equal(label.attr("for"), "icecore", "label has for");
+    assert.equal(label.text(), "IceCore", "label has text");
+});
+
+QUnit.test("make_checkbox_input", function(assert) {
+    assert.equal(typeof form_elements.make_checkbox_input, "function", "function available");
+
+
+    var config = {
+        type: "checkbox",
+        name: "approved",
+        label: "Approval",
+        checked: true,
+        value: "yes!!!",
+    }
+    var field = form_elements.make_checkbox_input(config);
+    var input = $(field).find("input:checkbox");
+    assert.equal(input.length, 1, "has checkbox input");
+    assert.equal(input.attr("name"), "approved", "input has name");
+    assert.ok(input.is(":checked"), "input is checked");
+
+    var obj = form_elements.form_to_object(field);
+    assert.equal(obj["approved"], "yes!!!", "checked value");
+
+
+    config["checked"] = false;
+    config["value"] = "notherval";
+    field = form_elements.make_checkbox_input(config);
+    input = $(field).find("input:checkbox");
+    assert.equal(input.length, 1, "has checkbox input");
+    assert.equal(input.attr("name"), "approved", "input has name");
+    assert.notOk(input.is(":checked"), "input is not checked");
+
+    obj = form_elements.form_to_object(field);
+    assert.equal(typeof obj["approved"], "undefined", "no checked value");
+
+
+});
+
+QUnit.test("form_to_object", async function(assert) {
+    assert.equal(typeof form_elements.form_to_object, "function", "function available");
+
+    var config = {
+        fields: [
+            { type: "date", name: "the-date" },
+            { type: "reference_drop_down", name: "icecore", query: "FIND Record IceCore"},
+            { type: "range", name: "the-range", from: {name: "fromblla"}, to: {name: "toblla"}},
+            { type: "subform", name: "subform1", fields: [
+                { type: "date", name: "the-other-date", },
+                { type: "checkbox", name: "rectangular", },
+            ],},
+        ],
+    };
+
+    var form = await form_elements.make_script_form(config, "bla");
+
+    var json = form_elements.form_to_object(form);
+
+    assert.equal(typeof json["cancel"], "undefined", "cancel button not serialized");
+    assert.equal(json["the-date"], "", "date");
+    assert.equal(json["icecore"], null, "reference_drop_down");
+    assert.equal(json["fromblla"], "", "range from");
+    assert.equal(json["toblla"], "", "range to");
+    assert.equal(typeof json["the-other-date"], "undefined", "subform element not on root level");
+
+    var subform = json["subform1"];
+    assert.equal(typeof subform, "object", "subform1");
+    assert.equal(subform["the-other-date"], "", "subform date");
+    assert.equal(typeof subform["rectangular"], "undefined", "subform checkbox not checked");
+    console.log(json);
+
+});
+
+
+QUnit.test("make_double_input", function(assert) {
+    assert.equal(typeof form_elements.make_double_input, "function", "function available");
+
+    var config = {type: "double", name: "d"};
+    var input = $(form_elements.make_double_input(config)).find("input");
+    assert.ok(input.is("[type='number'][step='any']"), "double input");
+
+    assert.ok(input.val("15").prop("validity").valid, "15 valid");
+    assert.ok(input.val("1.5").prop("validity").valid, "1.5 valid");
+    assert.equal(input.val("abc").val(), "", "abc not accepted");
+
+});
+
+QUnit.test("make_integer_input", function(assert) {
+    assert.equal(typeof form_elements.make_integer_input, "function", "function available");
+
+    var config = {type: "integer", name: "i"};
+    var input = $(form_elements.make_integer_input(config)).find("input");
+    assert.ok(input.is("[type='number'][step='1']"), "integer input");
+
+    assert.ok(input.val("15").prop("validity").valid, "15 valid");
+    assert.notOk(input.val("1.5").prop("validity").valid, "1.5 not valid");
+    assert.equal(input.val("abc").val(), "", "abc not valid");
+});
+
+QUnit.test("make_form", function(assert) {
+    assert.equal(typeof form_elements.make_form, "function", "function available");
+
+    var form1 = form_elements.make_form({fields: []});
+    assert.equal(form1.tagName, "DIV", "wrapper is div");
+    assert.ok($(form1).hasClass("caosdb-f-form-wrapper"), "div has caosdb-f-form-wrapper class");
+    assert.equal($(form1).find(".h3").length, 0, "no header");
+
+    var form2 = form_elements.make_form({fields: [], header: "bla"});
+    assert.equal(form2.tagName, "DIV", "wrapper is div");
+    assert.equal($(form2).find(".h3").length, 1, "one header");
+    assert.equal($(form2).find(".h3").text(), "bla", "header text set");
+});
+
+QUnit.test("enable/disable_group", function(assert) {
+    assert.equal(typeof form_elements.disable_group, "function", "function available");
+    assert.equal(typeof form_elements.enable_group, "function", "function available");
+
+    var form = $('<form><div class="caosdb-f-field">test</div></form>');
+
+    form_elements.disable_group(form, "group1");
+    assert.notOk(form.find(".caosdb-f-field").hasClass("caosdb-f-field-disabled"), "not disabled");
+
+    form = $('<form><div class="caosdb-f-field" data-groups="(group1)" >test</div></form>');
+
+    form_elements.disable_group(form, "group1");
+    assert.ok(form.find(".caosdb-f-field").hasClass("caosdb-f-field-disabled"), "disabled");
+    form_elements.enable_group(form, "group1");
+    assert.notOk(form.find(".caosdb-f-field").hasClass("caosdb-f-field-disabled"), "disabled again");
+
+    form.append('<div class="caosdb-f-field caosdb-f-field-disabled">test2</div>');
+    form.append('<div class="caosdb-f-field caosdb-f-field-disabled" data-groups="(group3)" >test3</div>');
+
+    form_elements.disable_group(form, "group1");
+    assert.equal(form.find(".caosdb-f-field").length, 3, "three fields");
+    assert.equal(form.find(".caosdb-f-field[data-groups*='(group1)']").length, 1, "one field in group1");
+    assert.equal(form.find(".caosdb-f-field[data-groups*='(group2)']").length, 0, "no fields in group2");
+    assert.equal(form.find(".caosdb-f-field[data-groups*='(group3)']").length, 1, "one field in group3");
+    form_elements.d
+    assert.equal(form.find(".caosdb-f-field-disabled").length, 3, "three fields disabled");
+
+    form_elements.enable_group(form, "group1");
+    assert.equal(form.find(".caosdb-f-field-disabled").length, 2, "two fields disabled");
+
+    form_elements.enable_group(form, "group1");
+    assert.equal(form.find(".caosdb-f-field-disabled").length, 2, "still, two fields disabled");
+    form_elements.enable_group(form, "group3");
+    assert.equal(form.find(".caosdb-f-field-disabled").length, 1, "one field disabled");
+
+    form_elements.enable_group(form, "group2");
+    assert.equal(form.find(".caosdb-f-field-disabled").length, 1, "still, one field disabled");
+
+    form_elements.disable_group(form, "group2");
+    assert.equal(form.find(".caosdb-f-field-disabled").length, 1, "still, one field disabled");
+
+    form_elements.disable_group(form, "group3");
+    assert.equal(form.find(".caosdb-f-field-disabled").length, 2, "two field disabled again");
+
+});
+
+
+QUnit.test("parse_script_result", function(assert) {
+    assert.equal(typeof form_elements.parse_script_result, "function", "function available");
+
+    var result = str2xml(
+`<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="https://localhost:10443/webinterface/webcaosdb.xsl" ?>
+<Response username="admin" realm="PAM" srid="256c14970dac2b2b5649973d52e4c06a" timestamp="1570785591824" baseuri="https://localhost:10443">
+  <UserInfo username="admin" realm="PAM">
+    <Roles>
+      <Role>administration</Role>
+    </Roles>
+  </UserInfo>
+  <script code="127">
+    <call>sample_creation.py .upload_files/form.json</call>
+    <stdout />
+    <stderr>/usr/bin/env: ‘python’: No such file or directory</stderr>
+  </script>
+</Response>
+`
+    );
+    var parsed = form_elements.parse_script_result(result);
+    assert.equal(parsed.code, "127", "code parsed");
+    assert.equal(parsed.call, "sample_creation.py .upload_files/form.json", "call parsed");
+    assert.equal(parsed.stderr, "/usr/bin/env: ‘python’: No such file or directory", "stderr parsed");
+    assert.equal(parsed.stdout, "", "stdout parsed");
+
+
+});
+
+
+QUnit.test("disable_name", function(assert) {
+    assert.equal(typeof form_elements.disable_name, "function", "function available");
+});
+
+QUnit.test("enable_name", function(assert) {
+    assert.equal(typeof form_elements.enable_name, "function", "function available");
+});
+
+QUnit.test("add_field_to_group", function(assert) {
+    assert.equal(typeof form_elements.add_field_to_group, "function", "function available");
+
+    var field = $(form_elements._make_field_wrapper("field1"))[0];
+    form_elements.add_field_to_group(field, "group1");
+    assert.equal($(field).attr("data-groups"), "(group1)", "group1 added");
+    form_elements.add_field_to_group(field, "group2");
+    assert.equal($(field).attr("data-groups"), "(group1)(group2)", "group2 added");
+
+});
+
+QUnit.test("cache_form", async function(assert) {
+    var form = await this.get_example_1();
+    assert.equal($(form).find("form").length, 1, "example form available");
+
+    var cache = {};
+    var field = $(form_elements.get_fields(form, "ice_core"));
+    field.find(":input").val("6345");
+
+
+    form_elements.cache_form(cache, form);
+    assert.equal(cache[form_elements.get_cache_key(form, field[0])], "6345");
+});
+
+
+QUnit.test("load_cached", async function(assert) {
+    var done = assert.async();
+    var form = await this.get_example_1();
+    assert.equal($(form).find("form").length, 1, "example form available");
+
+
+    var field = $(form_elements.get_fields(form, "ice_core"));
+    var cache = {};
+    cache[form_elements.get_cache_key(form, field[0])] = "6346";
+
+
+    assert.equal(field.find(":input").val(), null, "field unset before");
+    field[0].addEventListener(form_elements.field_changed_event.type,
+        (e) => {
+            done();
+            assert.equal(field.find(":input").val(), "6346", "field set after");
+        }, true);
+    form_elements.load_cached(cache, form);
+
+});
+
+
+QUnit.test("field_ready", function(assert) {
+    var done = assert.async(3);
+    var field1 = $('<div id="f1"><div class="caosdb-f-field-not-ready"/></div>')[0];
+    var field2 = $('<div id="f2" class="caosdb-f-field-not-ready"/>')[0];
+    var field3 = $('<div id="f3"/>')[0];
+    var field4 = $('<div id="f4"><div class="caosdb-f-field-not-ready"/></div>')[0];
+
+    form_elements.field_ready(field1).then(field => {
+        assert.equal($(field)
+            .find(".caosdb-f-field-not-ready")
+            .length, 0, "caosdb-f-field-not-ready class removed");
+        assert.equal(field.id, "f1", "field1 ready");
+        done();
+    });
+    // remove class and send field_ready
+    $(field1).find(".caosdb-f-field-not-ready")
+        .removeClass("caosdb-f-field-not-ready");
+    field1.dispatchEvent(form_elements.field_ready_event);
+
+    form_elements.field_ready(field2).then(field => {
+        assert.equal($(field).find(".caosdb-f-field-not-ready")
+            .length, 0, "caosdb-f-field-not-ready class removed");
+        assert.equal(field.id, "f2", "field2 ready");
+        done();
+    });
+
+    // send field_ready
+    $(field2).removeClass("caosdb-f-field-not-ready");
+    field2.dispatchEvent(form_elements.field_ready_event);
+
+    form_elements.field_ready(field3).then(field => {
+        assert.equal($(field).find(".caosdb-f-field-not-ready")
+            .length, 0, "no caosdb-f-field-not-ready");
+        assert.equal(field.id, "f3", "field3 ready");
+        done();
+    });
+    // nothing to do for field3
+
+    form_elements.field_ready(field4).then(field => {
+        assert.ok(false, "field4 should never be ready!");
+    });
+});
+
diff --git a/test/core/js/modules/query_shortcuts.js.js b/test/core/js/modules/query_shortcuts.js.js
new file mode 100644
index 0000000000000000000000000000000000000000..f088b729001daac8a42ed276507e2370f3e08679
--- /dev/null
+++ b/test/core/js/modules/query_shortcuts.js.js
@@ -0,0 +1,286 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2018 Research Group Biomedical Physics,
+ * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com), Göttingen
+ * Copyright (C) 2019 IndiScale GmbH, Göttingen
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+
+/* SETUP query_shortcuts test module */
+QUnit.module("query_shortcuts.js", {
+    before: function(assert) {
+        query_shortcuts._shortcuts_property_description_name = "templateDescription";
+        query_shortcuts._shortcuts_property_query_name = "Query";
+        query_shortcuts._shortcuts_record_type_name = "UserTemplate";
+
+        query_shortcuts._shortcuts_property_description_id = "1234";
+        query_shortcuts._shortcuts_property_query_id = "2345";
+        query_shortcuts._shortcuts_record_type_id = "3456";
+
+        markdown.init();
+        connection._init();
+    },
+    after: function(assert) {
+        connection._init();
+    }
+});
+
+QUnit.test("available", function(assert) {
+    assert.ok(query_shortcuts);
+});
+
+QUnit.test("init", function(assert) {
+    assert.ok(query_shortcuts.init);
+});
+
+QUnit.test("generate_shortcut_form", function(assert) {
+    assert.ok(query_shortcuts.generate_shortcut_form);
+});
+
+QUnit.test("find_placeholders", function(assert) {
+    assert.propEqual(query_shortcuts.find_placeholders("{test1}"), ["test1"]);
+    assert.propEqual(query_shortcuts.find_placeholders("asdf {test1}"), ["test1"]);
+    assert.propEqual(query_shortcuts.find_placeholders("asdf {test1} sdfg"), ["test1"]);
+    assert.propEqual(query_shortcuts.find_placeholders("asdf {test1} sdfg {test2}"), ["test1", "test2"]);
+    assert.propEqual(query_shortcuts.find_placeholders("asdf {test1} sdfg {test2} wert"), ["test1", "test2"]);
+});
+
+
+QUnit.test("replace_placeholders_with_values", function(assert) {
+    assert.equal(query_shortcuts.replace_placeholders_with_values("FIND RECORD WITH date IN {bla}", {"bla":"2018"}), "FIND RECORD WITH date IN 2018");
+    assert.equal(query_shortcuts.replace_placeholders_with_values("FIND RECORD WITH date IN {bla} and {bla}", {"bla":"2018"}), "FIND RECORD WITH date IN 2018 and 2018");
+});
+
+QUnit.test("extract_placeholder_values", function(assert) {
+    var form = $('<div class="shortcut-form"/>');
+
+    form.append('<input name="test1" value="val1"/>');
+    assert.propEqual(query_shortcuts.extract_placeholder_values(form[0]), {"test1": "val1"});
+
+    form.append('<input name="test2" value="val2"/>');
+    assert.propEqual(query_shortcuts.extract_placeholder_values(form[0]), {"test1": "val1", "test2": "val2"});
+
+});
+
+QUnit.test("replace_placeholders_with_inputs", function(assert) {
+    assert.equal(query_shortcuts.replace_placeholders_with_inputs("{test1}"), " <input type=\"text\" name=\"test1\" title=\"test1\"/> ");
+    assert.equal(query_shortcuts.replace_placeholders_with_inputs("asdf {test1}"), "asdf  <input type=\"text\" name=\"test1\" title=\"test1\"/> ");
+    assert.equal(query_shortcuts.replace_placeholders_with_inputs("asdf {test1} sdfg"), "asdf  <input type=\"text\" name=\"test1\" title=\"test1\"/>  sdfg");
+    assert.equal(query_shortcuts.replace_placeholders_with_inputs("asdf {test1} sdfg {test2}"), "asdf  <input type=\"text\" name=\"test1\" title=\"test1\"/>  sdfg  <input type=\"text\" name=\"test2\" title=\"test2\"/> ");
+    assert.equal(query_shortcuts.replace_placeholders_with_inputs("asdf {test1} sdfg {test2} wert"), "asdf  <input type=\"text\" name=\"test1\" title=\"test1\"/>  sdfg  <input type=\"text\" name=\"test2\" title=\"test2\"/>  wert");
+});
+
+QUnit.test("retrieve_global_shortcuts", async function(assert) {
+    assert.ok(query_shortcuts.retrieve_global_shortcuts);
+    var done = assert.async();
+
+
+    // mock simple shortcut
+    query_shortcuts._query_global_shortcuts = async function() {
+        done();
+        return [{description: "help-text-bla", query: "FIND blabla"}];
+    }
+
+    var arr = await query_shortcuts.retrieve_global_shortcuts();
+    assert.equal(arr.length, 1, "array with one element");
+    assert.equal($(arr[0]).find("span.caosdb-f-query-shortcut-form").text(), "help-text-bla", "desc text inserted");
+});
+
+QUnit.test("retrieve_user_shortcuts", async function(assert) {
+    assert.ok(query_shortcuts.retrieve_user_shortcuts);
+    var done = assert.async();
+
+
+    // TODO return something meaningful
+    query_shortcuts._query_user_shortcuts = async function() {
+        done();
+        return [];
+    }
+
+    var userShortcuts = await query_shortcuts.retrieve_user_shortcuts();
+    assert.ok($.isArray(userShortcuts), "returned array");
+    assert.equal(userShortcuts.length, 0, "array is empty");
+});
+
+QUnit.test("init_delete_shortcut_form", function(assert) {
+    assert.equal(typeof query_shortcuts.init_delete_shortcut_form, "function", "function available");
+
+    // test panel
+    var panel = $('<div/>');
+    var header = $('<span class="h3">Shortcuts</span>');
+    panel.append(header);
+    var orig_children = panel.children();
+    $('body').append(panel);
+
+
+    // before
+    assert.equal(orig_children.is(":visible"), true, "panel content visible before");
+    assert.equal(panel.find("form").length, 0, "no form before");
+
+    query_shortcuts.init_delete_shortcut_form(panel[0]);
+
+    // after
+    assert.equal(orig_children.is(":visible"), false, "original panel content not visible after");
+    assert.equal(panel.find(".caosdb-f-form-wrapper").length, 1, "panel has form after");
+
+    // test cancel button
+    panel[0].addEventListener("caosdb.form.cancel", function(e) {
+        assert.equal(panel.find("form").length, 0, "form is gone");
+        done();
+    }, true);
+
+    panel.find("button.caosdb-f-form-elements-cancel-button").click();
+
+
+
+    // clean up
+    panel.remove();
+});
+
+QUnit.test("make_delete_form", function(assert) {
+    assert.equal(typeof query_shortcuts.make_delete_form, "function", "function available");
+    var done = assert.async();
+
+    // test panel
+    var panel = $('<div/>');
+    var header = $('<span class="h3">Shortcuts</span>');
+    var userTemplate1 = query_shortcuts.generate_user_shortcut("the_description", "FIND nothing", "id28");
+    var userTemplate2 = query_shortcuts.generate_user_shortcut("the_description", "FIND nothing", "id29");
+    var userTemplate3 = query_shortcuts.generate_user_shortcut("the_description", "FIND nothing", "id39");
+    var globalTemplate = query_shortcuts.generate_shortcut_form("the_other_description", "FIND anything");
+
+    panel.append(header);
+    panel.append(userTemplate1);
+    panel.append(userTemplate2);
+    panel.append(userTemplate3);
+    panel.append(globalTemplate);
+
+    query_shortcuts._deleteEntities = function(dels) {
+        assert.propEqual(dels, ["id28","id29"], "deleteEntities called");
+        done();
+        return str2xml("<root/>");
+    };
+
+    var delete_callback = async function(delform) {
+        assert.equal(delform, $(form).find("form")[0], "form calls delete_callback");
+        var dels = query_shortcuts.get_checked_ids(delform);
+        assert.propEqual(dels, ["id28", "id29"], "get_checked_ids(form) = [id28 id29]");
+        var ret = await query_shortcuts.delete_callback(delform);
+        return ret;
+    }
+
+    var form = query_shortcuts.make_delete_form(panel[0], delete_callback);
+
+    // wait for form
+    form.addEventListener("caosdb.form.ready", function(e) {
+
+        assert.equal($(form).hasClass("caosdb-f-form-wrapper"), true, "is form");
+        assert.equal($(form).find("input[type='checkbox']").length, 3, "three checkboxes (for three user-defined shortcuts)");
+
+        // check two
+        $(form).find(":checkbox[name='id28']").click();
+        $(form).find(":checkbox[name='id29']").click();
+        $(form).find("[type='submit']").click();
+
+        $(form).find("button.caosdb-f-form-elements-cancel-button").click();
+
+    }, true);
+
+    $('body').append(form);
+
+});
+
+QUnit.test("transform_entities", async function(assert) {
+    var result = str2xml(`<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="https://localhost:44301/webinterface/webcaosdb.xsl" ?>
+<Response username="tf" realm="PAM" srid="e32b9552475ef9ca12a2b5f49aa58c1c" timestamp="1571305648225" baseuri="https://localhost:44301" count="1">
+  <Record id="2735" name="Test Template (User 1)">
+    <Info code="10" description="This entity has been deleted successfully." />
+    <Parent id="2733" name="UserTemplate" />
+    <Property id="2731" name="Query" datatype="TEXT" importance="FIX">
+      FIND Thing1
+    </Property>
+    <Property id="2732" name="templateDescription" datatype="TEXT" importance="FIX">
+      Test Template (User 1)
+    </Property>
+  </Record>
+</Response>`);
+   var transformed = await query_shortcuts.transform_entities(result);
+    assert.ok(Array.isArray(transformed), "transformed is array");
+    assert.ok(transformed[0] instanceof HTMLElement, "transformed[0] is html element");
+});
+
+QUnit.test("make_create_form", function(assert) {
+
+    var done = assert.async();
+    var panel = $('<div/>');
+    var form = query_shortcuts.make_create_form(panel[0], () => {});
+    assert.ok($(form).hasClass("caosdb-f-form-wrapper"), "form created");
+
+    $('body').append(form);
+
+    form.addEventListener(form_elements.form_ready_event.type, function(e) {
+        $(form).find(":input[name='templateDescription']").val("NEW DESC");
+        $(form).find(":input[name='Query']").val("NEW QUERY");
+
+        var entity = getEntityXML(form);
+        assert.equal(xml2str(entity), "<Record><Parent name=\"UserTemplate\"/><Property name=\"templateDescription\">NEW DESC</Property><Property name=\"Query\">NEW QUERY</Property></Record>", "entity extracted");
+
+        form_elements.dismiss_form(form);
+        done();
+
+    }, true);
+
+});
+
+QUnit.test("make_update_form", function(assert) {
+
+    var done = assert.async();
+    var panel = $('<div/>');
+    var header = $('<span class="h3">Shortcuts</span>');
+    var userTemplate1 = query_shortcuts.generate_user_shortcut("the_description", "FIND nothing", "id28");
+    var userTemplate2 = query_shortcuts.generate_user_shortcut("the_description", "FIND nothing", "id29");
+    var userTemplate3 = query_shortcuts.generate_user_shortcut("the_description", "FIND nothing", "id39");
+    var globalTemplate = query_shortcuts.generate_shortcut_form("the_other_description", "FIND anything");
+
+    panel.append(header);
+    panel.append(userTemplate1);
+    panel.append(userTemplate2);
+    panel.append(userTemplate3);
+    panel.append(globalTemplate);
+
+    var form = query_shortcuts.make_update_form(panel[0],"id28", () => {}, ()=>{}, ()=>{});
+    assert.ok($(form).hasClass("caosdb-f-form-wrapper"), "form created");
+
+    $('body').append(form);
+
+    form.addEventListener(form_elements.form_ready_event.type, function(e) {
+        $(form).find(":input[name='templateDescription']").val("NEW DESC");
+        $(form).find(":input[name='Query']").val("NEW QUERY");
+
+        var entity = getEntityXML(form);
+        assert.equal(xml2str(entity), "<Record id=\"id28\"><Parent name=\"UserTemplate\"/><Property name=\"templateDescription\">NEW DESC</Property><Property name=\"Query\">NEW QUERY</Property></Record>", "entity extracted");
+
+        form_elements.dismiss_form(form);
+        done();
+
+    }, true);
+
+});
diff --git a/test/core/js/modules/templates_ext.js.js b/test/core/js/modules/templates_ext.js.js
deleted file mode 100644
index ee63764f4ae825abc1cb1cb552daf1a358255bc5..0000000000000000000000000000000000000000
--- a/test/core/js/modules/templates_ext.js.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-/* SETUP ext_references module */
-QUnit.module("templates_ext.js", {
-    before: function(assert) {
-    }
-});
-
-QUnit.test("available", function(assert) {
-    assert.ok(templates_ext);
-});
-
-QUnit.test("init", function(assert) {
-    assert.ok(templates_ext.init);
-});
-
-QUnit.test("generate_template", function(assert) {
-    assert.ok(templates_ext.generate_template);
-});
-
-QUnit.test("add_templates", async function(assert) {
-    assert.ok(templates_ext.add_templates);
-    var done = assert.async();
-
-
-    // mock simple template
-    templates_ext.getTemplatesConfig = async function() {
-        done();
-        return [{help: "help-text-bla", query: "FIND blabla"}];
-    }
-
-    var arr = await templates_ext.add_templates();
-    assert.equal(arr.length, 1, "array with one element");
-    assert.equal($(arr[0]).find("span.caosdb-f-query-template-form").text(), "help-text-bla", "help text inserted");
-});
-
-QUnit.test("add_user_templates", async function(assert) {
-    assert.ok(templates_ext.add_user_templates);
-    var done = assert.async(5);
-
-    // throw warnings
-    templates_ext.warning = function(warning) {
-        console.log(warning);
-        throw warning;
-    }
-
-    // mock query with 401
-    errmsg = `GET Entity/?query=FIND Record UserTemplate returned with
- HTTP status 401 - Unauthorized`;
-    templates_ext.queryUserTemplates = async function() {
-        done();
-        assert.equal(typeof errmsg, "string", "errmsg is string");
-        throw new Error(errmsg);
-    }
-
-    try {
-        await templates_ext.add_user_templates();
-    } catch (err) {
-        assert.equal(err.message, errmsg, "401 was caught and passed issued a warning");
-        done();
-    }
-
-    // mock query with 404
-    errmsg = `GET Entity/?query=FIND Record UserTemplate returned with
- HTTP status 404 - Not found`;
-    templates_ext.queryUserTemplates = async function() {
-        done();
-        assert.equal(typeof errmsg, "string", "errmsg is string");
-        throw new Error(errmsg);
-    }
-
-    try {
-        await templates_ext.add_user_templates();
-    } catch (err) {
-        assert.equal(err.message, errmsg, "404 was caught and passed issued a warning");
-        done();
-    }
-
-    // TODO return something meaningful
-    templates_ext.queryUserTemplates = async function() {
-        done();
-        return [];
-    }
-
-    var userTemplates = await templates_ext.add_user_templates();
-    assert.ok($.isArray(userTemplates), "returned array");
-    assert.equal(userTemplates.length, 0, "array is empty");
-});
-
diff --git a/test/core/js/modules/webcaosdb.css.js b/test/core/js/modules/webcaosdb.css.js
deleted file mode 100644
index 45e532daba0afb6255d6cbbeb96457d43542d4ae..0000000000000000000000000000000000000000
--- a/test/core/js/modules/webcaosdb.css.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-/* These unit tests are for the css style sheet 'webcaosdb.css' */
-
-/* SETUP */
-QUnit.module("webcaosdb.css", {
-	before : function(assert) {
-		this.stylesheet = document.styleSheets[1];
-	}
-});
-
-/* TESTS */
-QUnit.test("availability", function(assert) {
-	assert.equal(document.styleSheets.length, 2);
-	var href = this.stylesheet.href;
-	assert.equal(href.substring(href.length - 14, href.length),
-			"/webcaosdb.css");
-});
diff --git a/test/core/js/modules/webcaosdb.js.js b/test/core/js/modules/webcaosdb.js.js
index 62f5ba91f1cf878ba3302a79e55e657c00f58e4a..590f05bba438c940dbe9a04551cdc4d35a5e209e 100644
--- a/test/core/js/modules/webcaosdb.js.js
+++ b/test/core/js/modules/webcaosdb.js.js
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2019 Timm Fitschen (t.fitschen@indiscale.com), Göttingen
+ * Copyright (C) 2019 IndiScale GmbH, Göttingen
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,17 +24,16 @@
  */
 /* testing webcaosdb's javascript sources */
 
-QUnit.testStart(function(details) {
-    connection._init();
-        markdown.toHtml = function(textElement){
-            return textElement;
-        };
-});
 
 /* SETUP general module */
 QUnit.module("webcaosdb.js", {
     before: function(assert) {
-    }
+        markdown.init();
+        connection._init();
+    },
+    after: function(assert) {
+        connection._init();
+    },
 });
 
 /* TESTS */
@@ -184,7 +185,7 @@ QUnit.test("retrieveXsltScript", function(assert) {
         done();
     });
     transformation.retrieveXsltScript("asdfasdfasdf.xsl").then(xsl => xsl, err => {
-        assert.equal(err.toString().split(" - ")[0], "Error: GET webinterface/xsl/asdfasdfasdf.xsl returned with HTTP status 404", "not found.");
+        assert.equal(err.toString().split(" - ")[0], "Error: GET webinterface/__BUILD_NUMBER__/xsl/asdfasdfasdf.xsl returned with HTTP status 404", "not found.");
         done();
     });
 });
@@ -979,63 +980,70 @@ QUnit.test("createCarouselNav", function(assert) {
     let ref_property_elem = $('<div><div class="caosdb-property-value"></div></div>');
     let original_get = connection.get;
     ref_property_elem.find('div').append(refLinks);
-    QUnit.test("initProperty", function(assert) {
-        //$(document.body).append(ref_property_elem);
-        let done = assert.async();
+
+    const sleep = function sleep(ms) {
+      return new Promise(resolve => setTimeout(resolve, ms));
+    }
+
+    QUnit.test("initProperty", async function(assert) {
+        var done = assert.async(2);
         assert.ok(preview.initProperty, "function available");
+
         let app = preview.initProperty(ref_property_elem[0]);
-        assert.equal(app.state, 'showLinks', 'app returned');
+        assert.equal(app.state, 'showLinks', 'app returned in showLinks state');
 
         let showPreviewButton = $(ref_property_elem).find('.' + preview.classNameShowPreviewButton);
         assert.equal(showPreviewButton.length, 1, 'one show preview button.');
 
-        connection.get = function(uri) {
+        // test case for error in get method
+        connection.get = async function(uri) {
             assert.equal(uri, "Entity/1234&2345&3456&4567", "get called with correct uri");
-            return new Promise(function(ok, err) {
-                setTimeout(() => {
-                    err('test error');
-                }, 200);
-            });
+            await sleep(1000);
+            done();
+            throw "test error";
         };
 
         showPreviewButton.click();
+        await sleep(200);
+        assert.equal(app.state, 'waiting', 'app is now in waiting state');
 
-        setTimeout(() => {
-            assert.equal(app.state, 'showLinks', 'after reset in showLinks state');
-            connection.get = function(uri) {
-                if (uri === "webinterface/xsl/entity.xsl" || uri === "webinterface/xsl/messages.xsl") {
-                    console.log("returning");
-                    return original_get(uri);
-                }
-                return new Promise(function(ok, err) {
-                    setTimeout(() => {
-                        ok(xmlResponse);
-                    }, 200);
-                });
-            };
-            showPreviewButton.click();
-            assert.equal(app.state, 'waiting', 'app is now in waiting state');
 
-            setTimeout(() => {
-                assert.equal(app.state, 'showPreview', 'app is now in showPreview state');
+        // reset after error was thrown
+        await sleep(1200);
+        assert.equal(app.state, 'showLinks', 'after reset in showLinks state');
 
-                let hidePreviewButton = $(ref_property_elem).find('.' + preview.classNameHidePreviewButton);
-                assert.equal(hidePreviewButton.length, 1, 'one hidePreviewButton');
-                hidePreviewButton.click();
-                assert.equal(app.state, 'showLinks', 'again in showLinks state.');
+        // test case for mockup-preview data
+        connection.get = async function(uri) {
+            if (uri.match(/webinterface/g)) {
+                return await original_get(uri);
+            }
+            assert.equal(uri, "Entity/1234&2345&3456&4567", "get called with correct uri agai againn");
+            await sleep(1000);
+            done();
+            return xmlResponse;
+        };
 
-                connection.get = function(uri) {
-                    assert.ok(null, 'get was called: ' + uri);
-                }
-                showPreviewButton.click();
-                assert.equal(app.state, 'showPreview', 'again in showPreview state but without calling connection.get again.');
-                app.resetApp();
-                assert.equal($(ref_property_elem).find('.' + preview.classNamePreview).length, 0, 'no carousel after reset');
-                done();
+        showPreviewButton.click();
+        await sleep(200);
+        assert.equal(app.state, 'waiting', 'app is now in waiting state again');
+
+        await sleep(2000);
+        // the preview data arrived
+        assert.equal(app.state, 'showPreview', 'app is now in showPreview state');
+
+        let hidePreviewButton = $(ref_property_elem).find('.' + preview.classNameHidePreviewButton);
+        assert.equal(hidePreviewButton.length, 1, 'one hidePreviewButton');
+        hidePreviewButton.click();
+        assert.equal(app.state, 'showLinks', 'again in showLinks state.');
 
-            }, 600);
+        connection.get = function(uri) {
+            assert.ok(null, 'get was called: ' + uri);
+        }
+        showPreviewButton.click();
+        assert.equal(app.state, 'showPreview', 'again in showPreview state but without calling connection.get again.');
+        app.resetApp();
+        assert.equal($(ref_property_elem).find('.' + preview.classNamePreview).length, 0, 'no carousel after reset');
 
-        }, 400);
 
 
     });
@@ -1431,6 +1439,7 @@ QUnit.test("getPageHref", function(assert) {
 /* MODULE annotation */
 QUnit.module("webcaosdb.js - annotation", {
     before: function(assert) {
+        markdown.init();
         // overwrite (we don't actually want to send any post requests)
         annotation.postCommentXml = function(xml) {
             return new Promise(resolve => setTimeout(resolve, 1000, str2xml("<Response/>")));
@@ -1506,7 +1515,7 @@ QUnit.test("convertNewCommentResponse", function(assert) {
     assert.ok(convertNewAnnotationResponse, "function exists.");
     let done = assert.async();
     let testResponse = '<Response><Record><Property name="annotationOf"/><History transaction="INSERT" datetime="2015-12-24T20:15:00" username="someuser"/><Property name="comment">This is a comment</Property></Record></Response>';
-    let expectedResult = "<li xmlns=\"http://www.w3.org/1999/xhtml\" class=\"list-group-item\"><div class=\"media\"><div class=\"media-left\"><h3>»</h3></div><div class=\"media-body\"><h4 class=\"media-heading\">someuser<small><i> posted on 2015-12-24T20:15:00</i></small></h4><p class=\"caosdb-comment-annotation-text\">This is a comment</p></div></div></li>";
+    let expectedResult = "<li xmlns=\"http://www.w3.org/1999/xhtml\" class=\"list-group-item markdowned\"><div class=\"media\"><div class=\"media-left\"><h3>»</h3></div><div class=\"media-body\"><h4 class=\"media-heading\">someuser<small><i> posted on 2015-12-24T20:15:00</i></small></h4><p class=\"caosdb-comment-annotation-text\"><p>This is a comment</p></p></div></div></li>";
     convertNewAnnotationResponse(str2xml(testResponse), annotation.loadAnnotationXsl("../../")).then(function(result) {
         assert.equal(result.length, 1, "one element returned.");
         assert.equal(xml2str(result[0]), expectedResult, "result converted correctly");
@@ -1623,7 +1632,7 @@ QUnit.test("convertNewCommentResponse error", function(assert) {
         </Response>';
 
     let done = assert.async();
-    let expectedResult = "<divxmlns=\"http://www.w3.org/1999/xhtml\"class=\"alertalert-dangercaosdb-new-comment-erroralert-dismissable\"><buttonclass=\"close\"data-dismiss=\"alert\"aria-label=\"close\">×</button><strong>Error!</strong>Thiscommenthasnotbeeninserted.<pclass=\"small\"><pre><code>&lt;record&gt;&lt;errorcode=\"114\"description=\"Entityhasunqualifiedproperties.\"&gt;&lt;/error&gt;&lt;warningcode=\"0\"description=\"Entityhasnoname.\"&gt;&lt;/warning&gt;&lt;parentname=\"CommentAnnotation\"&gt;&lt;errorcode=\"101\"description=\"Entitydoesnotexist.\"&gt;&lt;/error&gt;&lt;/parent&gt;&lt;propertyname=\"comment\"importance=\"FIX\"&gt;sdfasdfasdf&lt;errorcode=\"101\"description=\"Entitydoesnotexist.\"&gt;&lt;/error&gt;&lt;errorcode=\"110\"description=\"Propertyhasnodatatype.\"&gt;&lt;/error&gt;&lt;/property&gt;&lt;propertyname=\"annotationOf\"importance=\"FIX\"&gt;20&lt;errorcode=\"101\"description=\"Entitydoesnotexist.\"&gt;&lt;/error&gt;&lt;errorcode=\"110\"description=\"Propertyhasnodatatype.\"&gt;&lt;/error&gt;&lt;/property&gt;&lt;/record&gt;</code></pre></p></div>";
+    let expectedResult = "<divxmlns=\"http://www.w3.org/1999/xhtml\"class=\"alertalert-dangercaosdb-new-comment-erroralert-dismissablemarkdowned\"><buttonclass=\"close\"data-dismiss=\"alert\"aria-label=\"close\">×</button><strong>Error!</strong>Thiscommenthasnotbeeninserted.<pclass=\"small\"><pre><code>&lt;record&gt;&lt;errorcode=\"114\"description=\"Entityhasunqualifiedproperties.\"&gt;&lt;/error&gt;&lt;warningcode=\"0\"description=\"Entityhasnoname.\"&gt;&lt;/warning&gt;&lt;parentname=\"CommentAnnotation\"&gt;&lt;errorcode=\"101\"description=\"Entitydoesnotexist.\"&gt;&lt;/error&gt;&lt;/parent&gt;&lt;propertyname=\"comment\"importance=\"FIX\"&gt;sdfasdfasdf&lt;errorcode=\"101\"description=\"Entitydoesnotexist.\"&gt;&lt;/error&gt;&lt;errorcode=\"110\"description=\"Propertyhasnodatatype.\"&gt;&lt;/error&gt;&lt;/property&gt;&lt;propertyname=\"annotationOf\"importance=\"FIX\"&gt;20&lt;errorcode=\"101\"description=\"Entitydoesnotexist.\"&gt;&lt;/error&gt;&lt;errorcode=\"110\"description=\"Propertyhasnodatatype.\"&gt;&lt;/error&gt;&lt;/property&gt;&lt;/record&gt;</code></pre></p></div>";
     annotation.convertNewCommentResponse(str2xml(errorStr), annotation.loadAnnotationXsl("../../")).then(function(result) {
         assert.equal(xml2str(result[0]).replace(/[\t\n\ ]/g, ""), expectedResult.replace(/[\t\n\ ]/g, ""), "transformed into an error div.");
         done();
@@ -1657,7 +1666,7 @@ QUnit.test("NewCommentApp convertNewCommentResponse", function(assert) {
 
     app.observe("onEnterRead", () => {
         assert.equal(app.state, "read", "finally in read state");
-        assert.equal($(annotationSection).find(".caosdb-comment-annotation-text")[0].innerHTML, "This is a comment", "new comment appended.");
+        assert.equal($(annotationSection).find(".caosdb-comment-annotation-text")[0].innerHTML, "<p>This is a comment</p>", "new comment appended.");
 
         let button = annotation.getNewCommentButton(annotationSection);
         assert.ok(button.onclick, "button click is enabled.");
diff --git a/test/core/js/setup.js b/test/core/js/setup.js
index c6431e130e98c7a1eeedc09d57373dee86058323..701195ce7cef08190a1dbf066f240a9ed52a5dce 100644
--- a/test/core/js/setup.js
+++ b/test/core/js/setup.js
@@ -32,6 +32,23 @@ function getQueryValue(key) {
     console.log("found loggerPort: " + loggerPort);
     if (loggerPort) {
         console.log("logging QUnit results to http://127.0.0.1:" + loggerPort);
+
+
+        QUnit.log(function(obj) {
+            // TODO
+            if(!obj.result) {
+                var failed_assertion = {
+                    "Actual": obj.actual,
+                    "Expected": obj.expected,
+                    "Message": obj.message,
+                    "Source": obj.source,
+                    "Module": obj.module,
+                    "Name": obj.name,
+                }
+                $.post("http://127.0.0.1:" + loggerPort + "/log", JSON.stringify(failed_assertion, null, 2));
+            }
+        });
+
         QUnit.testDone( function( details ) {
           var result = {
             "Module name": details.module,
@@ -47,7 +64,7 @@ function getQueryValue(key) {
           };
 
           $.post("http://127.0.0.1:" + loggerPort + "/log", JSON.stringify( result, null, 2 ));
-            
+
         } );
 
         QUnit.done(function( details ) {