commit c137512e09e9118b546bbb02d26ea72bed3e95eb
Author: Oto Šťáva <oto.stava@gmail.com>
Date:   Mon Mar 15 09:00:57 2021 +0100

    Add original application sources

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..258908a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+**/*.pro.user
diff --git a/README.md b/README.md
index 67e7ab8..e6b7a73 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
-# Konfigurovatelný dashboard zobrazování senzorových dat - Virtual Surreality
+# Převedení vizualizace scény pro rehabilitaci paže pomocí rehabilitačního robota do virtuální reality
 
+**Tým:** Virtual Surreality
diff --git a/db_browser/Doxyfile b/db_browser/Doxyfile
new file mode 100644
index 0000000..54a9308
--- /dev/null
+++ b/db_browser/Doxyfile
@@ -0,0 +1,2427 @@
+﻿# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Editor databáze"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Aplikace sloužící k přidávání pacientů a indikací do databáze"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = Czech
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES 
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             = ./doc
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/db_browser/db/cviceni.sql b/db_browser/db/cviceni.sql
new file mode 100644
index 0000000..c96cc99
--- /dev/null
+++ b/db_browser/db/cviceni.sql
@@ -0,0 +1,327 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 10.5
+-- Dumped by pg_dump version 10.5
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- Name: DATABASE "Cviceni"; Type: COMMENT; Schema: -; Owner: postgres
+--
+
+COMMENT ON DATABASE "Cviceni" IS 'Datab�ze obsahuj�c� �daje p��slu�n� k 3d cvi�ebn�mu stroji';
+
+
+--
+-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: 
+--
+
+CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
+
+
+--
+-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: 
+--
+
+COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
+
+
+SET default_tablespace = '';
+
+SET default_with_oids = false;
+
+--
+-- Name: indications; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE public.indications (
+    ind_id integer NOT NULL,
+    indication text,
+    description text,
+    curve_name text,
+    procedure_time integer
+);
+
+
+ALTER TABLE public.indications OWNER TO postgres;
+
+--
+-- Name: TABLE indications; Type: COMMENT; Schema: public; Owner: postgres
+--
+
+COMMENT ON TABLE public.indications IS 'Indikace pacientů';
+
+
+--
+-- Name: Indications_Ind_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE public."Indications_Ind_id_seq"
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public."Indications_Ind_id_seq" OWNER TO postgres;
+
+--
+-- Name: Indications_Ind_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE public."Indications_Ind_id_seq" OWNED BY public.indications.ind_id;
+
+
+--
+-- Name: actual_indication; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE public.actual_indication (
+    id_p integer NOT NULL,
+    id_ind integer NOT NULL
+);
+
+
+ALTER TABLE public.actual_indication OWNER TO postgres;
+
+--
+-- Name: patient; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE public.patient (
+    id integer NOT NULL,
+    name text,
+    surname text NOT NULL,
+    birthdate date NOT NULL,
+    id_number text NOT NULL
+);
+
+
+ALTER TABLE public.patient OWNER TO postgres;
+
+--
+-- Name: TABLE patient; Type: COMMENT; Schema: public; Owner: postgres
+--
+
+COMMENT ON TABLE public.patient IS 'Seznam pacientů a příslušných údajů';
+
+
+--
+-- Name: patient_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE public.patient_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.patient_id_seq OWNER TO postgres;
+
+--
+-- Name: patient_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE public.patient_id_seq OWNED BY public.patient.id;
+
+
+--
+-- Name: results; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE public.results (
+    p_id integer NOT NULL,
+    ind_id integer NOT NULL,
+    cycles integer NOT NULL,
+    result integer[],
+    result_id integer NOT NULL
+);
+
+
+ALTER TABLE public.results OWNER TO postgres;
+
+--
+-- Name: results_result_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+CREATE SEQUENCE public.results_result_id_seq
+    AS integer
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+
+ALTER TABLE public.results_result_id_seq OWNER TO postgres;
+
+--
+-- Name: results_result_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
+--
+
+ALTER SEQUENCE public.results_result_id_seq OWNED BY public.results.result_id;
+
+
+--
+-- Name: indications ind_id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.indications ALTER COLUMN ind_id SET DEFAULT nextval('public."Indications_Ind_id_seq"'::regclass);
+
+
+--
+-- Name: patient id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.patient ALTER COLUMN id SET DEFAULT nextval('public.patient_id_seq'::regclass);
+
+
+--
+-- Name: results result_id; Type: DEFAULT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.results ALTER COLUMN result_id SET DEFAULT nextval('public.results_result_id_seq'::regclass);
+
+
+--
+-- Data for Name: actual_indication; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY public.actual_indication (id_p, id_ind) FROM stdin;
+\.
+
+
+--
+-- Data for Name: indications; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY public.indications (ind_id, indication, description, curve_name, procedure_time) FROM stdin;
+\.
+
+
+--
+-- Data for Name: patient; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY public.patient (id, name, surname, birthdate, id_number) FROM stdin;
+\.
+
+
+--
+-- Data for Name: results; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY public.results (p_id, ind_id, cycles, result, result_id) FROM stdin;
+\.
+
+
+--
+-- Name: Indications_Ind_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('public."Indications_Ind_id_seq"', 5, true);
+
+
+--
+-- Name: patient_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('public.patient_id_seq', 9, true);
+
+
+--
+-- Name: results_result_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('public.results_result_id_seq', 7, true);
+
+
+--
+-- Name: patient id_num; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.patient
+    ADD CONSTRAINT id_num UNIQUE (id_number);
+
+
+--
+-- Name: indications indication_name; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.indications
+    ADD CONSTRAINT indication_name UNIQUE (indication);
+
+
+--
+-- Name: indications indications_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.indications
+    ADD CONSTRAINT indications_pkey PRIMARY KEY (ind_id);
+
+
+--
+-- Name: patient patient_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.patient
+    ADD CONSTRAINT patient_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: results results_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.results
+    ADD CONSTRAINT results_pkey PRIMARY KEY (result_id);
+
+
+--
+-- Name: actual_indication id_ind; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.actual_indication
+    ADD CONSTRAINT id_ind FOREIGN KEY (id_p) REFERENCES public.indications(ind_id);
+
+
+--
+-- Name: actual_indication id_p; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.actual_indication
+    ADD CONSTRAINT id_p FOREIGN KEY (id_p) REFERENCES public.patient(id);
+
+
+--
+-- Name: results indication; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.results
+    ADD CONSTRAINT indication FOREIGN KEY (p_id) REFERENCES public.indications(ind_id);
+
+
+--
+-- Name: results patient; Type: FK CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.results
+    ADD CONSTRAINT patient FOREIGN KEY (p_id) REFERENCES public.patient(id);
+
+
+--
+-- PostgreSQL database dump complete
+--
+
diff --git a/db_browser/db/psql_win7_install.txt b/db_browser/db/psql_win7_install.txt
new file mode 100644
index 0000000..ea9f9f5
--- /dev/null
+++ b/db_browser/db/psql_win7_install.txt
@@ -0,0 +1,14 @@
+1. instalace postgres
+2. instalace firefox
+3. cmd -> do Program Files\Postgres\10\bin
+    createuser -U postgres -P -d embitron
+
+4.  createdb -U embitron Cviceni
+5. psql -U postgres Cviceni < cviceni_data.sql
+6. pak v pgadmin "grant all for embitron" - na vse v db Cviceni dat grant all
+
+upgrade db
+----------
+1. v pgadminu Delete/Drop DB
+2. createdb -U embitron Cviceni
+3. psql -U embitron Cviceni < cviceni.sql
diff --git a/db_browser/db_browser.pro b/db_browser/db_browser.pro
new file mode 100644
index 0000000..1a42dcf
--- /dev/null
+++ b/db_browser/db_browser.pro
@@ -0,0 +1,53 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2018-09-07T07:31:10
+#
+#-------------------------------------------------
+
+QT       += core gui widgets sql
+
+TARGET = db_browser
+TEMPLATE = app
+
+# The following define makes your compiler emit warnings if you use
+# any feature of Qt which has been marked as deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if you use deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
+
+include(libQsLog/QsLog.pri)
+
+CONFIG += c++11
+
+SOURCES += \
+        main.cpp \
+        dbbrowser.cpp \
+    dbaccess.cpp \
+    infodialog.cpp \
+    ../cv_stroj_3d/curvedialog.cpp
+
+HEADERS += \
+        dbbrowser.h \
+    dbaccess.h \
+    infodialog.h \
+    ../cv_stroj_3d/curvedialog.h
+
+FORMS += \
+        dbbrowser.ui \
+    infodialog.ui \
+    ../cv_stroj_3d/curvedialog.ui
+
+TRANSLATIONS += lang\db_browser_cs.ts
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
+
+RESOURCES += \
+    ../cv_stroj_3d/resources.qrc
diff --git a/db_browser/dbaccess.cpp b/db_browser/dbaccess.cpp
new file mode 100644
index 0000000..7ac3463
--- /dev/null
+++ b/db_browser/dbaccess.cpp
@@ -0,0 +1,516 @@
+#include "dbaccess.h"
+#include <QSqlQueryModel>
+#include <QSqlQuery>
+#include <QSqlError>
+#include <QSqlRecord>
+#include <QDate>
+#include <QList>
+#include "QsLog.h"
+
+#include <QtDebug>
+
+dbAccess::dbAccess(QObject *parent) : QObject(parent)
+{
+    db = new QSqlDatabase( QSqlDatabase::addDatabase("QPSQL") );
+    if (!db->isValid()) {
+        QLOG_ERROR() << "db connection err: " << db->lastError().text();
+    }
+    result_query = new QSqlQuery(*db);
+}
+
+dbAccess::~dbAccess()
+{
+    if (db->isOpen()) {
+        db->close();
+    }
+    QString cn = db->database().connectionName();
+    db->removeDatabase(cn);
+}
+
+//! Připojení k databázi
+/*!
+  Funkce slouží pro připojení na databázi, kterou aplikace bude využívat. Databázový server může být
+  kdekoliv v síti, takže mezi parametry je i IP adresa a síťový port.
+  \param server Adresa server, na kterém je databáze.
+  \param userName Uživatelské jméno.
+  \param password Heslo.
+  \param port Port, na kterém naslouchá databázový server.
+  \param dbName Jméno databáze.
+  \return True, pokud se podaří k databázi připojit, false pokud ne.
+*/
+bool dbAccess::connect(QString server, QString userName, QString password, int port, QString dbName)
+{
+    db->setConnectOptions();
+    db->setHostName(server);
+    db->setPort(port);
+    db->setDatabaseName(dbName);
+    db->setUserName(userName);
+    db->setPassword(password);
+
+    if(db->open()) {
+        return true;
+    }
+    else {
+        QLOG_ERROR() << "db connect err: " << db->lastError().text();
+        return false;
+    }
+}
+
+//! Vytvoření databázového modelu tabulky pacientů
+/*!
+  Funkce vytvoří databázový model kompletní tabulky pacientů, tento model lze posléze zobrazit v předem připraveném dialogu
+  \param *m Ukazatel na objekt typu QSqlQueryModel.
+*/
+void dbAccess::getPatientsQueryModel(QSqlQueryModel *m)
+{
+    m->setQuery("select name, surname, birthdate, id_number, ind_id from patient", *db);
+    if (m->lastError().isValid())
+        qDebug() << m->lastError();
+    m->setHeaderData(0, Qt::Horizontal, QObject::tr("Name"));
+    m->setHeaderData(1, Qt::Horizontal, QObject::tr("Surname"));
+    m->setHeaderData(2, Qt::Horizontal, QObject::tr("Birthdate"));
+    m->setHeaderData(3, Qt::Horizontal, QObject::tr("ID number"));
+    m->setHeaderData(4, Qt::Horizontal, QObject::tr("Indication ID"));
+}
+
+//! Vytvoření databázového modelu tabulky indikací
+/*!
+  Funkce vytvoří databázový model kompletní tabulky indikací, tento model lze posléze zobrazit v předem připraveném dialogu
+  \param *m Ukazatel na objekt typu QSqlQueryModel.
+*/
+void dbAccess::getIndicationsQueryModel(QSqlQueryModel *m)
+{
+    m->setQuery("select indication, description, curve_name, procedure_time from indications", *db);
+    if (m->lastError().isValid())
+        qDebug() << m->lastError();
+    m->setHeaderData(0, Qt::Horizontal, QObject::tr("Name"));
+    m->setHeaderData(1, Qt::Horizontal, QObject::tr("Description"));
+    m->setHeaderData(2, Qt::Horizontal, QObject::tr("Curve name"));
+    m->setHeaderData(3, Qt::Horizontal, QObject::tr("Procedure time"));
+}
+
+//! Vytvoření databázového modelu tabulky výsledků
+/*!
+  Funkce vytvoří databázový model tabulky výsledků, tento model lze posléze zobrazit v předem připraveném dialogu.
+  Model nemusí vytvořit pohled na celou tabulku, ale výsledky lze filtrovat podle ID pacienta a podle ID indikace.
+  \param *m Ukazatel na objekt typu QSqlQueryModel.
+  \param p_id ID pacienta
+  \param ind_id ID indikace
+*/
+void dbAccess::getResultsQueryModel(QSqlQueryModel *m, int p_id, int ind_id)
+{
+    QString queryText = "SELECT p_id, ind_id, series, res_number, date, cycles, result FROM results";
+
+    if (p_id != 0) {
+        queryText += " WHERE p_id=" + QString::number(p_id);
+        if (ind_id != 0) {
+            queryText += " AND ind_id=" + QString::number(ind_id);
+        }
+    } else {
+        if (ind_id != 0) {
+            queryText += " WHERE ind_id=" + QString::number(ind_id);
+        }
+    }
+    m->setQuery(queryText, *db);
+    if (m->lastError().isValid())
+        qDebug() << m->lastError();
+    m->setHeaderData(0, Qt::Horizontal, QObject::tr("Patient ID"));
+    m->setHeaderData(1, Qt::Horizontal, QObject::tr("Indication ID"));
+    m->setHeaderData(2, Qt::Horizontal, QObject::tr("Series number"));
+    m->setHeaderData(3, Qt::Horizontal, QObject::tr("Result number"));
+    m->setHeaderData(4, Qt::Horizontal, QObject::tr("Date"));
+    m->setHeaderData(5, Qt::Horizontal, QObject::tr("Cycles"));
+    m->setHeaderData(6, Qt::Horizontal, QObject::tr("Results"));
+}
+
+//! Přidání nového pacienta do databáze
+/*!
+  Funkce je použita pro přidání údajů o novém pacientovi do databáze.
+  \param name Jméno
+  \param surname Příjmení
+  \param birthdate Datum narození
+  \param idNo Identifikační číslo pacienta (může to být RČ, nebo pořadové číslo....)
+  \param indNo Indikace přiřazená danému pacientovi
+*/
+int dbAccess::addNewPatient(QString name, QString surname, QDate birthdate, QString idNo, QString indNo)
+{
+    QSqlQuery query(*db);
+
+    query.prepare("INSERT INTO patient (name, surname, birthdate, id_number, ind_id)"
+                  "VALUES (:name, :surname, :birthdate, :id_number, :ind_id)");
+    query.bindValue(":name", name);
+    query.bindValue(":surname", surname);
+    query.bindValue(":birthdate", birthdate);
+    query.bindValue(":id_number", idNo);
+    query.bindValue(":ind_id", indNo);
+
+    db->transaction();
+    if (query.exec()) {
+        db->commit();
+
+        return ALL_OK;
+    } else {
+        qDebug() << query.lastError();
+        db->rollback();
+        return OTHER_ERR;
+    }
+}
+
+//! Přidání nové indikace do databáze
+/*!
+  Funkce je použita pro přidání údajů o nové indikaci do databáze.
+  \param name Jméno
+  \param description Popis
+  \param curveName Jméno cvičené křivky, odpovídající indikaci
+  \param time Čas (v minutách), pokterý se bude daná křivka cvičit
+ */
+int dbAccess::addNewIndication(QString name, QString description, QString curveName, int time)
+{
+    QSqlQuery query(*db);
+
+    query.prepare("INSERT INTO indications (indication, description, curve_name, procedure_time)"
+                  "VALUES (:name, :description, :curve_name, :time)");
+    query.bindValue(":name", name);
+    query.bindValue(":description", description);
+    query.bindValue(":curve_name", curveName);
+    query.bindValue(":time", time);
+
+    db->transaction();
+    if (query.exec()) {
+        db->commit();
+        return ALL_OK;
+    } else {
+        qDebug() << query.lastError();
+        db->rollback();
+        return OTHER_ERR;
+    }
+    return ALL_OK;
+}
+
+//! Získání interního id pacienta
+/*!
+  Funkce je použita pro získání interního id daného pacienta na základě znalosti jeho identifikačního
+  čísla. Interní ID se používá v dalších databázových dotazech
+  \param pid Identifikační číslo pacienta
+  \return Interní číslo pacienta
+*/
+int dbAccess::getPatientId(QString pid)
+{
+    QSqlQuery query(*db);
+    int p_id = 0;
+
+    if (query.exec("SELECT id FROM patient WHERE id_number=\'" + pid + "\'"))
+    {
+        while (query.next()) {
+            p_id = query.value(0).toInt();
+        }
+    } else {
+        qDebug() << query.lastError();
+    }
+    return p_id;
+}
+
+//! Získání interního id indikace
+/*!
+  Funkce je použita pro získání interního id dané indikace na základě znalosti jejího jména.
+  Interní ID se používá v dalších databázových dotazech
+  \param name Jméno indikace
+  \return Interní číslo indikace
+*/
+int dbAccess::getIndicationId(QString name)
+{
+    QSqlQuery query(*db);
+    int ind_id = 0;
+
+    if (query.exec("SELECT ind_id FROM indications WHERE indication=\'" + name + "\'"))
+    {
+        while (query.next()) {
+            ind_id = query.value(0).toInt();
+        }
+    } else {
+        qDebug() << query.lastError();
+    }
+    return ind_id;
+}
+
+//! Získání údajů o indikaci
+/*!
+  Funkce je použita pro získání dalších informací o indikaci na základě znalosti jejího interního ID.
+  \param[in] indId interní ID
+  \param[out] *pTime doba trvání cvičení
+  \param[out] *cName Jméno křivky
+  \return True - data se podařilo načíst, False - data nelze načíst
+*/
+bool dbAccess::getIndicationInfo(int indId, int *pTime, QString *cName)
+{
+    QSqlQuery query(*db);
+
+    if (query.exec("SELECT curve_name, procedure_time FROM indications WHERE ind_id=\'" + QString::number(indId) + "\'"))
+    {
+        while (query.next()) {
+            *cName = query.value(0).toString();
+            *pTime = query.value(1).toInt();
+        }
+    } else {
+        qDebug() << query.lastError();
+        return false;
+    }
+    return true;
+
+}
+
+//! Získání názvů všech indikací
+/*!
+  Funkce je použita pro získání názvů a interních ID všech indikací uložených v databázi.
+  \param[out] *allIndIds Výsledný seznam všech interních ID
+  \param[out] *allNames Seznam všech jmen indikací
+  \return True - data se podařilo načíst, False - data nelze načíst
+*/
+bool dbAccess::getAllIndicationsName(QList<int> *allIndIds, QStringList *allNames)
+{
+    QSqlQuery query(*db);
+
+    if (query.exec("SELECT ind_id, indication FROM indications")) {
+        while (query.next()) {
+            allIndIds->append(query.value(0).toInt());
+            allNames->append(query.value(1).toString());
+        }
+    } else {
+        qDebug() << query.lastError();
+        return false;
+    }
+    return true;
+}
+
+//! Získání jmen všech pacientů
+/*!
+  Funkce je použita pro získání jmen a příjmení a interních ID všech pacientů uložených v databázi.
+  \param[out] *allPIds Výsledný seznam všech interních ID
+  \param[out] *allNames Seznam všech jmen pacientů
+  \return True - data se podařilo načíst, False - data nelze načíst
+*/
+bool dbAccess::getAllPatientsName(QList<int> *allPIds, QStringList *allNames)
+{
+    QSqlQuery query(*db);
+
+    if (query.exec("SELECT id, name, surname  FROM patient")) {
+        while (query.next()) {
+            allPIds->append(query.value(0).toInt());
+            allNames->append(query.value(1).toString() + " " + query.value(2).toString());
+        }
+    } else {
+        qDebug() << query.lastError();
+        return false;
+    }
+    return true;
+}
+
+bool dbAccess::setActualIndication(int p_id, int ind_id)
+{
+    QSqlQuery query(*db);
+    bool p_id_exists = false;
+
+    if (query.exec("SELECT * FROM actual_indication WHERE id_p=" + QString::number(p_id))) {
+        while (query.next()) {
+            p_id_exists = true;
+        }
+    } else {
+        qDebug() << query.lastError();
+        return false;
+    }
+
+    if (p_id_exists) { //update
+        if (query.exec("UPDATE actual_indication set id_ind=" + QString::number(ind_id) + " WHERE id_p=" + QString::number(p_id)))
+            return true;
+        else
+            qDebug() << query.lastError();
+    } else { //insert
+        if (query.exec("INSERT INTO actual_indication VALUES (" + QString::number(p_id) + "," + QString::number(ind_id) +")"))
+            return true;
+        else
+            qDebug() << query.lastError();
+    }
+
+    return false;
+
+}
+
+//! Získání pořadového čísla poslední série
+/*!
+  Funkce je použita pro získání pořadového čísla poslední série procedur pro pacienta s daným
+interním identifikačním číslem
+  \param p_id Interní identifikační číslo pacienta
+  \return Pořadové číslo poslední série procedur
+*/
+int dbAccess::getLastSeriesNo(int p_id)
+{
+    int nRet = 0;
+    QSqlQuery query(*db);
+    QString seriesStr = QString::number(p_id);
+
+    if (query.exec("SELECT series FROM results WHERE p_id=" + seriesStr + "ORDER BY series DESC LIMIT 1"))
+    {
+        while (query.next()) {
+            nRet = query.value(0).toInt();
+        }
+    }
+    return nRet;
+}
+
+//! Získání pořadového čísla poslední procedury v sérii
+/*!
+  Funkce je použita pro získání pořadového čísla poslední procedury v zadané sérii pro pacienta s daným
+interním identifikačním číslem
+  \param p_id Interní identifikační číslo pacienta
+  \param series Pořadové číslo série, ke které se má vyhledat poslední procedura
+  \return Pořadové číslo poslední procedury v dané sérii
+*/
+int dbAccess::getLastSeriesResultNo(int p_id, int series)
+{
+    int nRet = 0;
+    QSqlQuery query(*db);
+    QString seriesStr = QString::number(series);
+
+    if (query.exec("SELECT res_number FROM results WHERE p_id=" + QString::number(p_id) + "AND series=" + seriesStr + "ORDER BY res_number DESC LIMIT 1"))
+    {
+        while (query.next()) {
+            nRet = query.value(0).toInt();
+        }
+    }
+    return nRet;
+}
+
+//! Vložení výsledku procedury
+/*!
+  Funkce je použita pro vložení výsledku procedury v zadané sérii pro prčitého pacienta a indikaci. Pořadové číslo procedury
+se zvýší automaticky při zadání nového výsledku.
+  \param p_id Interní identifikační číslo pacienta
+  \param ind_id Interní identifikační číslo indikace
+  \param series Pořadové číslo série, ke které se ukládá výsledek
+  \param quality Seznam kvalit jednotlivých cyklů procedury
+  \return True - výsledek se podařilo uložit, False - chyba při ukládání výsledku
+*/
+bool dbAccess::addResult(int p_id, int ind_id, int series, QList<int> quality)
+{
+    QSqlQuery query(*db);
+    QString queryText;
+    int res_no = getLastSeriesResultNo(p_id, series)+1;
+    QDateTime now = QDateTime::currentDateTime();
+
+    queryText = "INSERT INTO results(p_id, ind_id, series, res_number, date, cycles, result) VALUES (" + QString::number(p_id) + "," + QString::number(ind_id) + ",";
+    queryText += QString::number(series) + ",";
+    queryText += QString::number(res_no) + ",";
+    queryText += " TIMESTAMP \'" + now.toString("yyyy-MM-dd hh:mm:ss") + "\',";
+    queryText += QString::number(quality.size()) + ",'{";
+
+    for(auto &val: quality) { //C++ 11 use
+        queryText += QString::number(val) + ",";
+    }
+    queryText.chop(1);
+    queryText += "}')";
+
+    if (!query.exec(queryText)) {
+        qDebug() << query.lastError();
+        return false;
+    }
+
+    return true;
+}
+
+/*! Získání jednotlivého výsledku
+ Po volání funkce getResultsNumber lze použít tuto funkci, která při každém volání vrátí výsledky další procedury
+ \param[out] *cycles Počet cyklů procedury
+ \param[out] *quality Seznam kvalit cvičení pro každý cyklus procedury
+ \return true - dotaz byl ukončen úspěšně, false - chyba při volání dotazu
+ \sa getResultsNumber()
+ */
+bool dbAccess::getNextResult(int *cycles, QString *quality)
+{
+    if (result_query->isActive()) {
+        if (result_query->next()) {
+            *cycles = result_query->value(0).toInt();
+            *quality = result_query->value(1).toString();
+            return true;
+        }
+    }
+    return false;
+}
+
+//! Získání průměrné hodnoty kvality cvičení pro každou proceduru v dané sérii
+/*!
+  Funkce je použita pro získání průměrné hodnoty kvality cvičení pro každou proceduru
+ v dané sérii pro pacienta s požadovaným interním identifikačním číslem
+  \param p_id Interní identifikační číslo pacienta
+  \param series Pořadové číslo série, ke které se mají vyhledat průměry
+  \param *avg - pole, které bude obsahovat jednotlivé průměry kvality cvičení
+  \return Pořadové číslo poslední procedury v dané sérii
+*/
+bool dbAccess::getSeriesResultAvg(int p_id, int series, QList<int> *avg)
+{
+    QString res, queryText = "SELECT result FROM results";
+    QStringList partQ;
+    int quality;
+    QSqlQuery query(*db);
+
+    queryText += " WHERE p_id=" + QString::number(p_id);
+    queryText += " AND series=" + QString::number(series);
+    queryText += "ORDER BY res_number ASC";
+
+    avg->clear();
+
+    if (query.exec(queryText)) {
+        while (query.next()) {
+            res = query.value(0).toString();
+            //remove '{' and '}' from result string
+            if (res.contains('{'))
+                res.remove(0,1);
+            if (res.contains('}'))
+                res.chop(1);
+            partQ = res.split(",");
+            quality = 0;
+            for (auto &str : partQ ) {
+                quality += str.toInt();
+            }
+            avg->append(quality/partQ.size());
+        }
+    } else {
+        qDebug() << result_query->lastError();
+        return false;
+    }
+    return true;
+}
+
+/*! Získání počtu výsledků
+ *!
+ Funkce slouží pro získání celkového počtu výsledků pro zadané číslo pacienta a procedury. Pokud je číslo pacienta, nebo procedury 0,
+ vyhledávají se výsledky pro všechny pacienty, nebo indikace. Funkce také slouží jako start pro iteraci přes jednotlivé výsledky. Pro iteraci slouží funkce
+ getNextResult()
+ \param[in] p_id Interní číslo pacienta
+ \param[in] ind_id Interní číslo indikace
+ \param[out] *results_count počet výsledků, které odpovídají zadaným parametrům p_id a ind_id
+ \return true - dotaz byl ukončen úspěšně, false - chyba při volání dotazu
+ \sa getNextResult()
+*/
+bool dbAccess::getResultsNumber(int p_id, int ind_id, int *results_count)
+{
+    QString queryText = "SELECT cycles, result FROM results";
+
+    if (p_id != 0) {
+        queryText += " WHERE p_id=" + QString::number(p_id);
+        if (ind_id != 0) {
+            queryText += " AND ind_id=" + QString::number(ind_id);
+        }
+    } else {
+        if (ind_id != 0) {
+            queryText += " WHERE ind_id=" + QString::number(ind_id);
+        }
+    }
+
+    if (result_query->exec(queryText)) {
+        *results_count = result_query->size();
+    } else {
+        qDebug() << result_query->lastError();
+        return false;
+    }
+    return true;
+}
diff --git a/db_browser/dbaccess.h b/db_browser/dbaccess.h
new file mode 100644
index 0000000..0b28728
--- /dev/null
+++ b/db_browser/dbaccess.h
@@ -0,0 +1,70 @@
+#ifndef DBACCESS_H
+#define DBACCESS_H
+
+#include <QObject>
+#include <QSqlDatabase>
+#include <QSqlQuery>
+#include <QList>
+
+#define ALL_OK      0
+#define REC_EXISTS  1
+#define OTHER_ERR   2
+
+class QSqlQueryModel;
+
+//!  Třída pro přímou práci s databází
+/*!
+  Třída slouží pro zápis, nebo čtení dat pacientů, indikací a výsledků
+*/
+
+class dbAccess : public QObject
+{
+    Q_OBJECT
+public:
+    //! Konstruktor.
+    /*!
+      V kostruktoru je vytvořen hlavní objekt, který bude použit pro přístup k databázi postgres
+    */
+    explicit dbAccess(QObject *parent = nullptr);
+    //! Destruktor.
+    /*!
+      Slouží pro uzavření databázového spojení
+    */
+    ~dbAccess();
+    bool connect(QString server, QString userName, QString password, int port, QString dbName);
+    void getPatientsQueryModel(QSqlQueryModel *m);
+    void getIndicationsQueryModel(QSqlQueryModel *m);
+    void getResultsQueryModel(QSqlQueryModel *m, int p_id, int ind_id);
+    int addNewPatient(QString name, QString surname, QDate birthdate, QString idNo, QString indNo);
+    int addNewIndication(QString name, QString description, QString curveName, int time);
+    int getPatientId(QString pid);
+    int getIndicationId(QString name);
+    bool getIndicationInfo(int indId, int *pTime, QString *cName);
+    bool getAllIndicationsName(QList<int> *allIndIds, QStringList *allNames);
+    bool getAllPatientsName(QList<int> *allPIds, QStringList *allNames);
+    bool setActualIndication(int p_id, int ind_id);
+    bool addResult(int p_id, int ind_id, int series, QList<int> quality);
+    int getLastSeriesNo(int p_id);
+    int getLastSeriesResultNo(int p_id, int series);
+    bool getResultsNumber(int p_id, int ind_id, int *results_count);
+    bool getNextResult(int *cycles, QString *quality);
+    bool getSeriesResultAvg(int p_id, int series, QList<int> *avg);
+
+signals:
+
+public slots:
+
+private:
+    //! Privátní proměnná - DB spojení
+    /*!
+      Proměnná je použita pro spojení s databází
+    */
+    QSqlDatabase *db;
+    //! Privátní proměnná - výsledek dotazu
+    /*!
+      Proměnná je použita pro sdílení výsledku dotazu mezi funkcemi
+    */
+    QSqlQuery *result_query;
+};
+
+#endif // DBACCESS_H
diff --git a/db_browser/dbbrowser.cpp b/db_browser/dbbrowser.cpp
new file mode 100644
index 0000000..547c755
--- /dev/null
+++ b/db_browser/dbbrowser.cpp
@@ -0,0 +1,398 @@
+#include "dbbrowser.h"
+#include "ui_dbbrowser.h"
+#include "infodialog.h"
+#include "../cv_stroj_3d/curvedialog.h"
+
+#include <QLabel>
+#include <QSqlQueryModel>
+#include <QDate>
+#include <QIntValidator>
+#include <QList>
+#include <QFile>
+#include <QFileDialog>
+#include <QTextStream>
+
+#define PATIENTS_TAB    0
+#define INDICATIONS_TAB 1
+#define RESULTS_TAB     2
+
+//! Konstruktor.
+/*!
+  V kostruktoru se inicializuje uživatelské rozhraní a připojení k databázi
+*/
+dbBrowser::dbBrowser(QWidget *parent) :
+    QMainWindow(parent),
+    ui(new Ui::dbBrowser)
+{
+    ui->setupUi(this);
+    db = new dbAccess();
+
+    dbConnected = db->connect("localhost", "embitron", "embitron", 5432, "Cviceni");
+
+    model = new QSqlQueryModel;
+
+    connect(ui->exitBtn, SIGNAL(clicked()), qApp, SLOT(quit()));
+    connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
+    connect(ui->addPatientBtn, SIGNAL(clicked()), this, SLOT(addPatientClicked()));
+    connect(ui->addIndicationBtn, SIGNAL(clicked()), this, SLOT(addIndicationClicked()));
+
+    /*connect(ui->resultBtn, SIGNAL(clicked()), this, SLOT(setResult()));*/
+    connect(ui->getResultsBtn, SIGNAL(clicked()), this, SLOT(getResult()));
+    connect(ui->saveResultsBtn, SIGNAL(clicked()), this, SLOT(saveResults()));
+
+    connect(ui->curveSelectBtn, SIGNAL(clicked()), this, SLOT(curveSelect()));
+
+    statusBarText = new QLabel;
+    statusBarText->setFixedSize(120,30);
+    QFont font;
+    font.setPixelSize(14);
+    statusBarText->setFont(font);
+    statusBarText->setAlignment(Qt::AlignCenter);
+    if (!dbConnected) {
+        statusBarText->setText(tr("DB not connected"));
+        statusBarText->setStyleSheet("background-color: rgb(255,0,0)");
+    } else {
+        statusBarText->setText(tr("DB connected"));
+        statusBarText->setStyleSheet("background-color: rgb(0,255,0)");
+    }
+    statusBar()->addPermanentWidget(statusBarText);
+
+    ui->tabWidget->setCurrentIndex(0);
+    ui->usersTableView->setSelectionMode(QAbstractItemView::SingleSelection);
+    ui->usersTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+    ui->indicationsTableView->setSelectionMode(QAbstractItemView::SingleSelection);
+    ui->indicationsTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+    db->getPatientsQueryModel(model);
+    ui->usersTableView->setModel(model);
+    ui->usersTableView->horizontalHeader()->resizeSections(QHeaderView::Stretch);
+
+    QStringList pNames;
+    QList<int> pId;
+    ui->patientNameCombo->clear();
+    ui->patientNameCombo->addItem(tr("---ALL---"), QVariant(0));
+    if (db->getAllPatientsName(&pId, &pNames)) {
+        for(int i=0; i<pId.size();i++) {
+            ui->patientNameCombo->addItem(pNames.at(i), QVariant(pId.at(i)));
+        }
+    }
+    ui->indNameCombo->clear();
+    ui->indNameCombo->addItem(tr("---ALL---"), QVariant(0));
+    ui->indNameCombo2->clear();
+    ui->indNameCombo2->addItem(tr("---ALL---"), QVariant(0));
+    pId.clear();pNames.clear();
+    if (db->getAllIndicationsName(&pId, &pNames)) {
+        for(int i=0; i<pId.size();i++) {
+            ui->indNameCombo->addItem(pNames.at(i), QVariant(pId.at(i)));
+            ui->indNameCombo2->addItem(pNames.at(i), QVariant(pId.at(i)));
+        }
+    }
+
+    QIntValidator *iv = new QIntValidator(0,999, this);
+    ui->timeEdit->setValidator(iv);
+
+    cName = "";
+
+    qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
+}
+
+//! Destruktor.
+/*!
+  Slouží pro zrušení vytvořených objektů
+*/
+dbBrowser::~dbBrowser()
+{
+    delete db;
+    delete ui;
+}
+
+//! Změna jazyka dialogu
+/*!
+  Pokud se změní jazyk aplikace, funkce změní text v dialogu, aby odpovídal
+  nastavenému jazyku
+  \param *e Ukazatel na objekt, který obsahuje posílanou událost
+*/
+void dbBrowser::changeEvent(QEvent *e)
+{
+    QMainWindow::changeEvent(e);
+    switch (e->type()) {
+    case QEvent::LanguageChange:
+        ui->retranslateUi(this);
+        break;
+    default:
+        break;
+    }
+}
+
+//! Info o změně zobrazované části dialogu
+/*!
+  Informace o změně zobrazované části dialogu. Funkce připraví nová data,
+  aby zobrazované hodnoty odpovídaly požadavku.
+  \param index Pořadové číslo žádané časti dialogu, která se má zobrazit
+*/
+void dbBrowser::tabChanged(int index)
+{
+    switch(index) {
+    case PATIENTS_TAB:
+        db->getPatientsQueryModel(model);
+        ui->usersTableView->setModel(model);
+        ui->usersTableView->horizontalHeader()->resizeSections(QHeaderView::Stretch);
+        break;
+    case INDICATIONS_TAB:
+        db->getIndicationsQueryModel(model);
+        ui->indicationsTableView->setModel(model);
+        ui->indicationsTableView->horizontalHeader()->resizeSections(QHeaderView::Stretch);
+        break;
+    case RESULTS_TAB:
+        getResult();
+        break;
+    }
+}
+
+//! Přidání pacienta do databáze
+/*!
+  Funkce vyčte hodnoty z editačního okna, a tyto hodnoty uloží do databáze
+  jako nového pacienta
+*/
+void dbBrowser::addPatientClicked()
+{
+    infoDialog dlg;
+    auto name = ui->nameEdit->text();
+    auto surname = ui->surnameEdit->text();
+    auto idNo = ui->idnumberEdit->text();
+    auto indId = ui->indNameCombo2->currentData().toString();
+
+    if (name.isEmpty() || surname.isEmpty() || idNo.isEmpty()) {
+        // err, one of items is empty
+        dlg.setInfoText(tr("Error"), tr("One item is empty. Please fill all items."));
+        dlg.exec();
+        return;
+    }
+
+    auto nRet = db->addNewPatient(name, surname, ui->birthdateEdit->date(), idNo, indId);
+
+    if (nRet != ALL_OK) {
+        dlg.setInfoText(tr("Error"), tr("Could not insert new patient data"));
+    } else {
+        dlg.setInfoText(tr("Success"), tr("OK. Patient data inserted succesfully"));
+        db->getPatientsQueryModel(model);
+        ui->usersTableView->setModel(model);
+        ui->usersTableView->horizontalHeader()->resizeSections(QHeaderView::Stretch);
+
+        QStringList pNames;
+        QList<int> pId;
+        ui->patientNameCombo->clear();
+        ui->patientNameCombo->addItem(tr("---ALL---"), QVariant(0));
+        if (db->getAllPatientsName(&pId, &pNames)) {
+            for(int i=0; i<pId.size();i++) {
+                ui->patientNameCombo->addItem(pNames.at(i), QVariant(pId.at(i)));
+            }
+        }
+    }
+    dlg.exec();
+}
+
+//! Přidání indikace do databáze
+/*!
+  Funkce vyčte hodnoty z editačního okna, a tyto hodnoty uloží do databáze
+  jako novou indikaci
+*/
+void dbBrowser::addIndicationClicked()
+{
+    infoDialog dlg;
+    auto name = ui->indNameEdit->text();
+    auto time = ui->timeEdit->text().toInt();
+
+    if (name.isEmpty() || cName.isEmpty()) {
+        // err, one of items is empty
+        dlg.setInfoText(tr("Error"), tr("One item is empty. Please fill all items."));
+        dlg.exec();
+        return;
+    }
+
+    auto nRet = db->addNewIndication(name, ui->descriptionEdit->text(), cName, time);
+
+    if (nRet != ALL_OK) {
+        dlg.setInfoText(tr("Error"), tr("Could not insert new indication data"));
+    } else {
+        dlg.setInfoText(tr("Success"), tr("OK. Indication data inserted succesfully"));
+        db->getIndicationsQueryModel(model);
+        ui->indicationsTableView->setModel(model);
+        ui->indicationsTableView->horizontalHeader()->resizeSections(QHeaderView::Stretch);
+
+        QStringList pNames;
+        QList<int> pId;
+        ui->indNameCombo->clear();
+        ui->indNameCombo->addItem(tr("---ALL---"), QVariant(0));
+        ui->indNameCombo2->clear();
+        ui->indNameCombo2->addItem(tr("---ALL---"), QVariant(0));
+        pId.clear();pNames.clear();
+        if (db->getAllIndicationsName(&pId, &pNames)) {
+            for(int i=0; i<pId.size();i++) {
+                ui->indNameCombo->addItem(pNames.at(i), QVariant(pId.at(i)));
+                ui->indNameCombo2->addItem(pNames.at(i), QVariant(pId.at(i)));
+            }
+        }
+    }
+    dlg.exec();
+}
+
+//! Výběr křivky pro novou indikaci
+/*!
+  Funkce zobrazí dialog, který slouží k výběru křiky, kterou má pacient s
+  vytvářenou indikací cvičit.
+*/
+void dbBrowser::curveSelect()
+{
+    curveDialog dlg;
+    int actCurveType, actCurveAngle, actCurveRot, pronSupVal;
+
+    if (dlg.exec() == QDialog::Accepted) {
+        dlg.getCurve(&actCurveType, &actCurveAngle, &actCurveRot, &pronSupVal);
+        cName = QString::number(actCurveType) + "_" + QString::number(actCurveAngle) +
+                "_" + QString::number(actCurveRot) + "_" + QString::number(pronSupVal);
+        switch(actCurveType) {
+        case CURVE_CIRCLE:
+            ui->curveSelectBtn->setText(tr("Circle"));
+            break;
+        case CURVE_ELLIPSE:
+            ui->curveSelectBtn->setText(tr("Ellipse"));
+            break;
+        case CURVE_KARD:
+            ui->curveSelectBtn->setText(tr("Cardiotide"));
+            break;
+        case CURVE_LEMN:
+            ui->curveSelectBtn->setText(tr("Lemniscate"));
+            break;
+        case CURVE_LINE:
+            ui->curveSelectBtn->setText(tr("Line"));
+            break;
+        case CURVE_NONE:
+            ui->curveSelectBtn->setText(tr("None"));
+            break;
+        case CURVE_EXTERN:
+            ui->curveSelectBtn->setText(tr("External"));
+            break;
+        default:
+            ui->curveSelectBtn->setText(tr(""));
+        }
+    }
+}
+
+//! Uložení výsledku
+/*!
+  Pouze testovací funkce. Funkce je použitá při testování ukládání/zobrazování výsledků cvičení.
+*/
+void dbBrowser::setResult()
+{
+    int res_count, cycles;
+    QStringList arr;
+    QList<int> intArr;
+    QString resVals, resultList;
+    infoDialog dlg;
+    int vals = qrand() % 101 + 200;
+
+    /*for(int i=0; i<vals; i++)
+        intArr.append(qrand()%30+40);
+    db->addResult(4, 2, 1,intArr);*/
+    db->getResultsNumber(2,2, &res_count);
+    while(db->getNextResult(&cycles, &resultList)) {
+        resultList.chop(1);resultList.remove(0,1); //remove '{' and '}' from result string
+        arr = resultList.split(",");
+        resVals = "Cycles: " + QString::number(cycles);
+        for(auto val: arr) {
+            resVals += " ," + val;
+        }
+        dlg.setInfoText("2,2", resVals);
+        dlg.exec();
+    }
+    db->getResultsNumber(2,0, &res_count);
+    while(db->getNextResult(&cycles, &resultList)) {
+        resultList.chop(1);resultList.remove(0,1); //remove '{' and '}' from result string
+        arr = resultList.split(",");
+        resVals = "Cycles: " + QString::number(cycles);
+        for(auto val: arr) {
+            resVals += " ," + val;
+        }
+        dlg.setInfoText("2,0", resVals);
+        dlg.exec();
+    }
+    db->getResultsNumber(0,1, &res_count);
+    while(db->getNextResult(&cycles, &resultList)) {
+        resultList.chop(1);resultList.remove(0,1); //remove '{' and '}' from result string
+        arr = resultList.split(",");
+        resVals = "Cycles: " + QString::number(cycles);
+        for(auto val: arr) {
+            resVals += " ," + val;
+        }
+        dlg.setInfoText("0,1", resVals);
+        dlg.exec();
+    }
+    db->getResultsNumber(0,0, &res_count);
+    while(db->getNextResult(&cycles, &resultList)) {
+        resultList.chop(1);resultList.remove(0,1); //remove '{' and '}' from result string
+        arr = resultList.split(",");
+        resVals = "Cycles: " + QString::number(cycles);
+        for(auto val: arr) {
+            resVals += " ," + val;
+        }
+        dlg.setInfoText("0,0", resVals);
+        dlg.exec();
+    }
+}
+
+//! Získání výsledků
+/*!
+  Funkce je použitá při testování zobrazování výsledků cvičení. Funkce vyčte z dialogu
+  parametry, podle kterých je možno výsledky filtrovat.
+*/
+void dbBrowser::getResult()
+{
+    int pId = ui->patientNameCombo->currentData().toInt();
+    int indId = ui->indNameCombo->currentData().toInt();
+
+    db->getResultsQueryModel(model, pId, indId);
+    ui->resultsTableView->setModel(model);
+    ui->resultsTableView->horizontalHeader()->resizeSections(QHeaderView::Stretch);
+}
+
+//! Uložení výsledků
+/*!
+  Funkce je použitá pro uložení zobrazených výsledků cvičení. Uložený soubor
+  je ve formátu CSV.
+*/
+void dbBrowser::saveResults()
+{
+    int size = ui->resultsTableView->model()->rowCount(),i;
+    QString res, date;
+    int pId, indId, cycles, series, resNo;
+    QString filename = QFileDialog::getSaveFileName(this, tr("Save CSV"), "", tr("CSV files (.csv)"));
+    if (!filename.endsWith("csv"))
+        filename += ".csv";
+    QFile data(filename);
+
+    if(data.open(QFile::WriteOnly |QFile::Truncate))
+    {
+        QTextStream output(&data);
+        output << "Patient ID; Indication ID; Series; Result number; Date; Cycles count; result\n";
+
+        for(i=0;i<size;i++) {
+            pId = ui->resultsTableView->model()->index(i,0).data().toInt();
+            indId = ui->resultsTableView->model()->index(i,1).data().toInt();
+            series = ui->resultsTableView->model()->index(i,2).data().toInt();
+            resNo = ui->resultsTableView->model()->index(i,3).data().toInt();
+            date = ui->resultsTableView->model()->index(i,4).data().toString();
+            cycles = ui->resultsTableView->model()->index(i,5).data().toInt();
+            res = ui->resultsTableView->model()->index(i,6).data().toString();
+
+            //remove '{' and '}' from result string
+            if (res.contains('{'))
+                res.remove(0,1);
+            if (res.contains('}'))
+                res.chop(1);
+            res.replace(',',';');
+            output << pId << ";" << indId << ";" << series << ";" << resNo << ";" << date <<";" << cycles << ";" << res << "\n";
+        }
+        data.close();
+    }
+}
diff --git a/db_browser/dbbrowser.h b/db_browser/dbbrowser.h
new file mode 100644
index 0000000..b278396
--- /dev/null
+++ b/db_browser/dbbrowser.h
@@ -0,0 +1,75 @@
+#ifndef DBBROWSER_H
+#define DBBROWSER_H
+
+#include <QMainWindow>
+#include "dbaccess.h"
+
+class QLabel;
+class QSqlQueryModel;
+
+namespace Ui {
+class dbBrowser;
+}
+
+//!  Třída pro zobrazení dat z databáze
+/*!
+  Třída slouží pro zobrazení dat z databáze. UI se skládá ze třech částí. První část slouží pro zadání nového pacienta do databáze.
+  Druhá část slouží pro zadání nové indikace a třetí část slouží pro zobrazení a export výsledků procedur. Výsledky lze filtrovat
+podle pacienta i podle indikace
+*/
+
+class dbBrowser : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    explicit dbBrowser(QWidget *parent = nullptr);
+    ~dbBrowser();
+
+protected:
+    void changeEvent(QEvent *e);
+
+private:
+    //! Ukazatel na UI
+    /*!
+      Ukazatel na vytvořené uživatelské rozhraní
+    */
+    Ui::dbBrowser *ui;
+    //! Ukazatel na UI
+    /*!
+      Ukazatel na vytvořené spojení s databázovým objektem
+    */
+    dbAccess *db;
+    //! Info o spojení s databází
+    /*!
+      Proměnná obsahuje ukazatel na objekt, který je používán pro informaci
+      o spojení s databází
+    */
+    QLabel *statusBarText;
+    //! Stav spojení s databází
+    /*!
+      Proměnná obsahuje stav spojení s databází
+    */
+    bool dbConnected;
+    //! Model použitý pro zobrazení informací z databáze
+    /*!
+      Proměnná obsahuje model použitý pro zobrazení informací z databáze
+    */
+    QSqlQueryModel *model;
+    //! Jméno křivky
+    /*!
+      Proměnná obsahuje jméno křivky, která bude použitá pro cvičení pacienta
+    */
+    QString cName;
+
+private slots:
+    void tabChanged(int index);
+    void addPatientClicked(void);
+    void addIndicationClicked(void);
+    void curveSelect(void);
+    void setResult(void);
+    void getResult(void);
+    void saveResults(void);
+};
+
+#endif // DBBROWSER_H
diff --git a/db_browser/dbbrowser.ui b/db_browser/dbbrowser.ui
new file mode 100644
index 0000000..8b5b5ad
--- /dev/null
+++ b/db_browser/dbbrowser.ui
@@ -0,0 +1,580 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>dbBrowser</class>
+ <widget class="QMainWindow" name="dbBrowser">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1065</width>
+    <height>694</height>
+   </rect>
+  </property>
+  <property name="font">
+   <font>
+    <pointsize>14</pointsize>
+    <kerning>true</kerning>
+   </font>
+  </property>
+  <property name="windowTitle">
+   <string>Database browser</string>
+  </property>
+  <property name="toolTipDuration">
+   <number>-1</number>
+  </property>
+  <property name="tabShape">
+   <enum>QTabWidget::Rounded</enum>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <layout class="QGridLayout" name="gridLayout_7">
+    <item row="0" column="0">
+     <widget class="QTabWidget" name="tabWidget">
+      <property name="font">
+       <font>
+        <pointsize>14</pointsize>
+       </font>
+      </property>
+      <property name="styleSheet">
+       <string notr="true">QTabBar::tab { height: 50px; width: 150px; }</string>
+      </property>
+      <property name="tabShape">
+       <enum>QTabWidget::Rounded</enum>
+      </property>
+      <property name="currentIndex">
+       <number>0</number>
+      </property>
+      <property name="elideMode">
+       <enum>Qt::ElideNone</enum>
+      </property>
+      <property name="usesScrollButtons">
+       <bool>true</bool>
+      </property>
+      <property name="documentMode">
+       <bool>false</bool>
+      </property>
+      <property name="tabsClosable">
+       <bool>false</bool>
+      </property>
+      <property name="movable">
+       <bool>false</bool>
+      </property>
+      <property name="tabBarAutoHide">
+       <bool>false</bool>
+      </property>
+      <widget class="QWidget" name="usersTab">
+       <attribute name="title">
+        <string>Users</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_4">
+        <item row="0" column="0">
+         <widget class="QGroupBox" name="groupBox_2">
+          <property name="font">
+           <font>
+            <pointsize>14</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Add users</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_3">
+           <item row="0" column="0">
+            <widget class="QLabel" name="label">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Name</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QLabel" name="label_2">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Surname</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2">
+            <widget class="QLabel" name="label_3">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Birthdate</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="3">
+            <widget class="QLabel" name="label_4">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>ID number</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="4">
+            <widget class="QLabel" name="label_11">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>indication ID</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="5" rowspan="2">
+            <widget class="QPushButton" name="addPatientBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>80</height>
+              </size>
+             </property>
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Add</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QLineEdit" name="nameEdit">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QLineEdit" name="surnameEdit">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="2">
+            <widget class="QDateEdit" name="birthdateEdit">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="3">
+            <widget class="QLineEdit" name="idnumberEdit">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="4">
+            <widget class="QComboBox" name="indNameCombo2">
+             <property name="minimumSize">
+              <size>
+               <width>160</width>
+               <height>40</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QGroupBox" name="groupBox">
+          <property name="font">
+           <font>
+            <pointsize>14</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Users list</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout">
+           <item row="0" column="0">
+            <widget class="QTableView" name="usersTableView">
+             <property name="styleSheet">
+              <string notr="true">QHeaderView { font-size: 14pt; }
+
+QTableView { font-size: 14pt; }
+</string>
+             </property>
+             <property name="sizeAdjustPolicy">
+              <enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
+             </property>
+             <attribute name="horizontalHeaderCascadingSectionResizes">
+              <bool>true</bool>
+             </attribute>
+             <attribute name="horizontalHeaderDefaultSectionSize">
+              <number>150</number>
+             </attribute>
+             <attribute name="horizontalHeaderMinimumSectionSize">
+              <number>150</number>
+             </attribute>
+             <attribute name="horizontalHeaderStretchLastSection">
+              <bool>true</bool>
+             </attribute>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="tab">
+       <attribute name="title">
+        <string>Indications</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_6">
+        <item row="0" column="0">
+         <widget class="QGroupBox" name="groupBox_4">
+          <property name="font">
+           <font>
+            <pointsize>14</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Add indication</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_5">
+           <item row="3" column="3">
+            <widget class="QLineEdit" name="timeEdit">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="maxLength">
+              <number>10</number>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QLineEdit" name="descriptionEdit">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QLabel" name="label_6">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Description</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QLineEdit" name="indNameEdit">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0">
+            <widget class="QLabel" name="label_5">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Name</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="3">
+            <widget class="QLabel" name="label_8">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Time [min]</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="4" rowspan="4">
+            <widget class="QPushButton" name="addIndicationBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>80</height>
+              </size>
+             </property>
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Add</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2" rowspan="4">
+            <widget class="QPushButton" name="curveSelectBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>80</height>
+              </size>
+             </property>
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="styleSheet">
+              <string notr="true"/>
+             </property>
+             <property name="text">
+              <string>Curve selection</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QGroupBox" name="groupBox_3">
+          <property name="font">
+           <font>
+            <pointsize>14</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Indications list</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_2">
+           <item row="0" column="0">
+            <widget class="QTableView" name="indicationsTableView">
+             <property name="styleSheet">
+              <string notr="true">QHeaderView { font-size: 14pt; }
+
+QTableView { font-size: 14pt; }
+</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="resultsTab">
+       <attribute name="title">
+        <string>Results</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_10">
+        <item row="0" column="0" rowspan="2" colspan="2">
+         <widget class="QGroupBox" name="groupBox_6">
+          <property name="font">
+           <font>
+            <pointsize>14</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Filter</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_9">
+           <item row="0" column="0">
+            <widget class="QLabel" name="label_9">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Patient Name</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QLabel" name="label_10">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Indication Name</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2" rowspan="2">
+            <widget class="QPushButton" name="getResultsBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>80</height>
+              </size>
+             </property>
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Show results</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="3" rowspan="2">
+            <widget class="QPushButton" name="saveResultsBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>80</height>
+              </size>
+             </property>
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="text">
+              <string>Save results</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QComboBox" name="patientNameCombo">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>40</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QComboBox" name="indNameCombo">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>40</height>
+              </size>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="2" column="0" colspan="2">
+         <widget class="QGroupBox" name="groupBox_5">
+          <property name="font">
+           <font>
+            <pointsize>14</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Results</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_8">
+           <item row="0" column="0">
+            <widget class="QTableView" name="resultsTableView">
+             <property name="font">
+              <font>
+               <pointsize>14</pointsize>
+              </font>
+             </property>
+             <property name="styleSheet">
+              <string notr="true">QHeaderView { font-size: 14pt; }
+
+QTableView { font-size: 14pt; }
+</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </widget>
+    </item>
+    <item row="1" column="0">
+     <widget class="QPushButton" name="exitBtn">
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>50</height>
+       </size>
+      </property>
+      <property name="text">
+       <string>Exit</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>1065</width>
+     <height>20</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QToolBar" name="mainToolBar">
+   <property name="font">
+    <font>
+     <pointsize>14</pointsize>
+     <kerning>true</kerning>
+    </font>
+   </property>
+   <property name="windowTitle">
+    <string>Database browser</string>
+   </property>
+   <property name="toolTipDuration">
+    <number>-1</number>
+   </property>
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/db_browser/doc/db_browser.JPG b/db_browser/doc/db_browser.JPG
new file mode 100644
index 0000000..f24c384
Binary files /dev/null and b/db_browser/doc/db_browser.JPG differ
diff --git a/db_browser/infodialog.cpp b/db_browser/infodialog.cpp
new file mode 100644
index 0000000..1f2ed7c
--- /dev/null
+++ b/db_browser/infodialog.cpp
@@ -0,0 +1,45 @@
+#include "infodialog.h"
+#include "ui_infodialog.h"
+
+infoDialog::infoDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::infoDialog)
+{
+    ui->setupUi(this);
+    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(accept()));
+}
+
+infoDialog::~infoDialog()
+{
+    delete ui;
+}
+
+//! Nastavení textu v dialogu
+/*!
+  Nastavení zadaného textu jak do hlavičky, tak do těla dialogu
+  \param title Text, který se zobrazí v hlavičce dialogu
+  \param infoText Text, který se objeví v těle dialogu
+*/
+void infoDialog::setInfoText(QString title, QString infoText)
+{
+    setWindowTitle(title);
+    ui->infoText->setText(infoText);
+}
+
+//! Změna jazyka dialogu
+/*!
+  Pokud se změní jazyk aplikace, funkce změní text v dialogu, aby odpovídal
+  nastavenému jazyku
+  \param *e Ukazatel na objekt, který obsahuje posílanou událost
+*/
+void infoDialog::changeEvent(QEvent *e)
+{
+    QDialog::changeEvent(e);
+    switch (e->type()) {
+    case QEvent::LanguageChange:
+        ui->retranslateUi(this);
+        break;
+    default:
+        break;
+    }
+}
diff --git a/db_browser/infodialog.h b/db_browser/infodialog.h
new file mode 100644
index 0000000..edbfbda
--- /dev/null
+++ b/db_browser/infodialog.h
@@ -0,0 +1,43 @@
+#ifndef INFODIALOG_H
+#define INFODIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class infoDialog;
+}
+
+//!  Třída pro zobrazování uživatelských informací a upozornění
+/*!
+  Třída slouží pro zobrazování uživatelských informací a upozornění
+*/
+
+class infoDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    //! Konstruktor.
+    /*!
+      V kostruktoru se inicializuje UI
+    */
+    explicit infoDialog(QWidget *parent = nullptr);
+    //! Destruktor.
+    /*!
+      Slouží pro správné ukončení dialogu
+    */
+    ~infoDialog();
+    void setInfoText(QString title, QString infoText);
+
+protected:
+    void changeEvent(QEvent *e);
+
+private:
+    //! Ukazatel na UI
+    /*!
+      Ukazatel na vytvořené uživatelské rozhraní
+    */
+    Ui::infoDialog *ui;
+};
+
+#endif // INFODIALOG_H
diff --git a/db_browser/infodialog.ui b/db_browser/infodialog.ui
new file mode 100644
index 0000000..b7a5484
--- /dev/null
+++ b/db_browser/infodialog.ui
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>infoDialog</class>
+ <widget class="QDialog" name="infoDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="infoText">
+     <property name="font">
+      <font>
+       <pointsize>14</pointsize>
+      </font>
+     </property>
+     <property name="frameShape">
+      <enum>QFrame::Box</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignHCenter|Qt::AlignTop</set>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QPushButton" name="pushButton">
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>50</height>
+      </size>
+     </property>
+     <property name="font">
+      <font>
+       <pointsize>14</pointsize>
+      </font>
+     </property>
+     <property name="text">
+      <string>OK</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/db_browser/lang/db_browser_cs.ts b/db_browser/lang/db_browser_cs.ts
new file mode 100644
index 0000000..4e0e8a2
--- /dev/null
+++ b/db_browser/lang/db_browser_cs.ts
@@ -0,0 +1,451 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="cs_CZ">
+<context>
+    <name>QComboBox</name>
+    <message>
+        <source>---ALL---</source>
+        <translation>---VŠE---</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <location filename="../dbaccess.cpp" line="69"/>
+        <location filename="../dbaccess.cpp" line="86"/>
+        <source>Name</source>
+        <translation>Jméno</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="70"/>
+        <source>Surname</source>
+        <translation>příjmení</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="71"/>
+        <source>Birthdate</source>
+        <translation>Datum narození</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="72"/>
+        <source>ID number</source>
+        <translation>Identifikační číslo</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="87"/>
+        <source>Description</source>
+        <translation>Popis</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="88"/>
+        <source>Curve name</source>
+        <translation>Jméno křivky</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="89"/>
+        <source>Procedure time</source>
+        <translation>Doba procedury</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="117"/>
+        <source>Patient ID</source>
+        <translation>číslo pacienta</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="73"/>
+        <location filename="../dbaccess.cpp" line="118"/>
+        <source>Indication ID</source>
+        <translation>číslo indikace</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="119"/>
+        <source>Series number</source>
+        <translation>Číslo série</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="120"/>
+        <source>Result number</source>
+        <translation>Pořadí procedury</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="121"/>
+        <source>Date</source>
+        <translation>Datum</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="122"/>
+        <source>Cycles</source>
+        <translation>cyklů</translation>
+    </message>
+    <message>
+        <location filename="../dbaccess.cpp" line="123"/>
+        <source>Results</source>
+        <translation>výsledky</translation>
+    </message>
+</context>
+<context>
+    <name>curveDialog</name>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="20"/>
+        <source>Dialog</source>
+        <translation type="unfinished">Dialog</translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="39"/>
+        <source>Kruh</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="63"/>
+        <source>Elipsa</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="87"/>
+        <source>Lemniskáta</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="111"/>
+        <source>Kardiotida</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="135"/>
+        <source>Úsečka</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="159"/>
+        <source>Žádná
+křivka</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="180"/>
+        <source>Úhel sklonu křivky</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="210"/>
+        <source>45</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="247"/>
+        <source>90</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="271"/>
+        <source>0</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="337"/>
+        <source>135</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="358"/>
+        <source>Směr rotace</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="472"/>
+        <source>Pronace/Supinace</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="497"/>
+        <source>Úroveň 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="529"/>
+        <source>Úroveň 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="584"/>
+        <source>OK</source>
+        <translation type="unfinished">OK</translation>
+    </message>
+    <message>
+        <location filename="../../cv_stroj_3d/curvedialog.ui" line="602"/>
+        <source>Zrušit</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>dbBrowser</name>
+    <message>
+        <location filename="../dbbrowser.ui" line="20"/>
+        <location filename="../dbbrowser.ui" line="563"/>
+        <source>Database browser</source>
+        <translation>Práce s databází</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="66"/>
+        <source>Users</source>
+        <translation>Pacienti</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="77"/>
+        <source>Add users</source>
+        <translation>Přidat pacienta</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="88"/>
+        <location filename="../dbbrowser.ui" line="314"/>
+        <source>Name</source>
+        <translation>Jméno</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="100"/>
+        <source>Surname</source>
+        <translation>Příjmení</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="112"/>
+        <source>Birthdate</source>
+        <translation>Datum narození</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="124"/>
+        <source>ID number</source>
+        <translation>Identifikační číslo</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="136"/>
+        <source>indication ID</source>
+        <translation>ID indikace</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="154"/>
+        <location filename="../dbbrowser.ui" line="344"/>
+        <source>Add</source>
+        <translation>Přidat</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="215"/>
+        <source>Users list</source>
+        <translation>Seznam pacientů</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="250"/>
+        <source>Indications</source>
+        <translation>Indikace</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="261"/>
+        <source>Add indication</source>
+        <translation>Přidat indikaci</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="293"/>
+        <source>Description</source>
+        <translation>Popis</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="452"/>
+        <source>Show results</source>
+        <translation>Zobraz výsledky</translation>
+    </message>
+    <message>
+        <source>Curve name</source>
+        <translation>Název křivky</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="326"/>
+        <source>Time [min]</source>
+        <translation>Čas [min]</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="365"/>
+        <source>Curve selection</source>
+        <translation>Výběr křivky</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="380"/>
+        <source>Indications list</source>
+        <translation>Seznam indikací</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="400"/>
+        <location filename="../dbbrowser.ui" line="505"/>
+        <source>Results</source>
+        <translation>Výsledky</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="411"/>
+        <source>Filter</source>
+        <translation>Filtr</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="422"/>
+        <source>Patient Name</source>
+        <translation>Jméno pacienta</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="434"/>
+        <source>Indication Name</source>
+        <translation>Název indikace</translation>
+    </message>
+    <message>
+        <source>Get results</source>
+        <translation>Získat výsledky</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="470"/>
+        <source>Save results</source>
+        <translation>Export výsledků</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.ui" line="539"/>
+        <source>Exit</source>
+        <translation>Konec</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="52"/>
+        <source>DB not connected</source>
+        <translation>DB není připojena</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="55"/>
+        <source>DB connected</source>
+        <translation>DB připojena</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="73"/>
+        <location filename="../dbbrowser.cpp" line="80"/>
+        <location filename="../dbbrowser.cpp" line="82"/>
+        <location filename="../dbbrowser.cpp" line="185"/>
+        <location filename="../dbbrowser.cpp" line="226"/>
+        <location filename="../dbbrowser.cpp" line="228"/>
+        <source>---ALL---</source>
+        <translation>---VŠE---</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="167"/>
+        <location filename="../dbbrowser.cpp" line="175"/>
+        <location filename="../dbbrowser.cpp" line="208"/>
+        <location filename="../dbbrowser.cpp" line="216"/>
+        <source>Error</source>
+        <translation>Chyba</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="167"/>
+        <location filename="../dbbrowser.cpp" line="208"/>
+        <source>One item is empty. Please fill all items.</source>
+        <translation>Jedna položka je prázdná. Je třeba vyplnit vše.</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="175"/>
+        <source>Could not insert new patient data</source>
+        <translation>Nemůžu přidat nová data</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="177"/>
+        <location filename="../dbbrowser.cpp" line="218"/>
+        <source>Success</source>
+        <translation>Úspěch</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="177"/>
+        <source>OK. Patient data inserted succesfully</source>
+        <translation>Data úspěšně uložena</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="216"/>
+        <source>Could not insert new indication data</source>
+        <translation>Nepodařilo se přidat novou indikaci</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="218"/>
+        <source>OK. Indication data inserted succesfully</source>
+        <translation>Data úspěšně uložena</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="256"/>
+        <source>Circle</source>
+        <translation>Kružnice</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="259"/>
+        <source>Ellipse</source>
+        <translation>Elipsa</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="262"/>
+        <source>Cardiotide</source>
+        <translation>Kardiotida</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="265"/>
+        <source>Lemniscate</source>
+        <translation>Lemniskáta</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="268"/>
+        <source>Line</source>
+        <translation>Úsečka</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="271"/>
+        <source>None</source>
+        <translation>Žádná</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="274"/>
+        <source>External</source>
+        <translation>Z disku</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="369"/>
+        <source>Save CSV</source>
+        <translation>Uložit CSV</translation>
+    </message>
+    <message>
+        <location filename="../dbbrowser.cpp" line="369"/>
+        <source>CSV files (.csv)</source>
+        <translation>soubory CSV</translation>
+    </message>
+</context>
+<context>
+    <name>infoDialog</name>
+    <message>
+        <location filename="../infodialog.ui" line="14"/>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <location filename="../infodialog.ui" line="55"/>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+</context>
+<context>
+    <name>selectPatientDlg</name>
+    <message>
+        <source>Dialog</source>
+        <translation>Dialog</translation>
+    </message>
+    <message>
+        <source>Users list</source>
+        <translation>Seznam pacientů</translation>
+    </message>
+    <message>
+        <source>Indications list</source>
+        <translation>Seznam indikací</translation>
+    </message>
+    <message>
+        <source>Select</source>
+        <translation>Výběr</translation>
+    </message>
+    <message>
+        <source>Exit</source>
+        <translation>Konec</translation>
+    </message>
+</context>
+</TS>
diff --git a/db_browser/main.cpp b/db_browser/main.cpp
new file mode 100644
index 0000000..3651ed4
--- /dev/null
+++ b/db_browser/main.cpp
@@ -0,0 +1,25 @@
+#include "dbbrowser.h"
+#include <QApplication>
+#include <QTranslator>
+
+/*! \mainpage Editor databáze
+ *
+ *  Tato aplikace slouží k přidávání údajů o nových pacientech a indikacích do databáze.
+ *  Taktéž lze použít pro prohlížení výsledků jednotlivých cvičení
+ *  \image html db_view.jpg
+ *  \image latex db_view.eps "Hlavní okno aplikace" width=10cm
+ */
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+
+    QTranslator myappTranslator;
+    myappTranslator.load("db_browser_cs");
+    a.installTranslator(&myappTranslator);
+
+    dbBrowser w;
+    w.show();
+
+    return a.exec();
+}
diff --git a/deltarobot/Doxyfile b/deltarobot/Doxyfile
new file mode 100644
index 0000000..3f3a8d6
--- /dev/null
+++ b/deltarobot/Doxyfile
@@ -0,0 +1,2427 @@
+﻿# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Ovládání cvičebního stroje"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "Aplikace sloužící k ovládání cvičebního stroje"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = Czech
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = YES
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = libQsLog
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = ui_* moc*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/deltarobot/curvedialog.cpp b/deltarobot/curvedialog.cpp
new file mode 100644
index 0000000..f643f05
--- /dev/null
+++ b/deltarobot/curvedialog.cpp
@@ -0,0 +1,142 @@
+#include "curvedialog.h"
+#include "ui_curvedialog.h"
+
+curveDialog::curveDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::curveDialog)
+{
+    ui->setupUi(this);
+    ui->buttonGroup->setId(ui->circleBtn, CURVE_CIRCLE);
+    ui->buttonGroup->setId(ui->ellipseBtn, CURVE_ELLIPSE);
+    ui->buttonGroup->setId(ui->lemnBtn, CURVE_LEMN);
+    ui->buttonGroup->setId(ui->kardBtn, CURVE_KARD);
+    ui->buttonGroup->setId(ui->lineBtn, CURVE_LINE);
+    ui->buttonGroup->setId(ui->noCurveBtn, CURVE_NONE);
+
+    ui->buttonGroupAngle->setId(ui->angle0Btn, ANGLE_0);
+    ui->buttonGroupAngle->setId(ui->angle45Btn, ANGLE_45);
+    ui->buttonGroupAngle->setId(ui->angle90Btn, ANGLE_90);
+    ui->buttonGroupAngle->setId(ui->angle135Btn, ANGLE_135);
+
+    ui->buttonGroupRot->setId(ui->cwRotBtn, ROTATE_CLKWISE);
+    ui->buttonGroupRot->setId(ui->ccwRotBtn, ROTATE_CNTRCLKWISE);
+
+    connect(ui->buttonGroup, SIGNAL(buttonPressed(int)), this, SLOT(curveBtnClicked(int)));
+    connect(ui->buttonGroupAngle, SIGNAL(buttonPressed(int)), this, SLOT(angleBtnClicked(int)));
+    connect(ui->buttonGroupRot, SIGNAL(buttonPressed(int)), this, SLOT(rotBtnClicked(int)));
+    connect(ui->acceptBtn, SIGNAL(clicked()), this, SLOT(accept()));
+    connect(ui->cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
+
+    connect(ui->pronSup1Btn, SIGNAL(pressed()), this, SLOT(pressPronSupBtn()));
+    connect(ui->pronSup2Btn, SIGNAL(pressed()), this, SLOT(pressPronSupBtn()));
+
+    curveType = CURVE_CIRCLE;
+    curveAngle = ANGLE_0;
+    curveRotation = ROTATE_CLKWISE;
+    pronSupVal = PRON_SUP_NOT;
+    ui->circleBtn->toggle();
+}
+
+//! V dialogovém oknu je označený typ křivky
+/*!
+ * Je voláno, pokud je v dialogovém oknu vybrán typ křivky. Lze vybrat z následujících typů:
+ * \li Kruh
+ * \li Elipsa
+ * \li Lemniskáta
+ * \li Kariodtida
+ * \li Žádná křivka - speciální případ, poku je žádano provádění pouze pronace/supinace
+ *
+ * ID typu se přiřadí do interní proměnné
+ *
+ * \param id Identifikační číslo vybraného typu křivky
+ */
+void curveDialog::curveBtnClicked(int id)
+{
+    curveType = id;
+}
+
+//! V dialogovém oknu je označený úhel sklonu křivky
+/*!
+ * Je voláno, pokud je v dialogovém oknu vybrán úhel sklonu křivky. Sklon lze vybrat z
+ * hodnot 0, 45, 90 a 135 stupňů. ID se přiřadí do interní proměnné
+ *
+ * \param id Identifikační číslo vybraného typu křivky
+ */
+void curveDialog::angleBtnClicked(int id)
+{
+    curveAngle = id;
+}
+
+//! V dialogovém oknu je označený směr rotace křivky
+/*!
+ * Je voláno, pokud je v dialogovém oknu vybrán směr rotace křivky. Lze vybrat rotaci po a proti směru
+ * hodinových ručiček
+ *
+ * \param id Identifikační číslo vybraného směru rotace
+ */
+void curveDialog::rotBtnClicked(int id)
+{
+    curveRotation = id;
+}
+
+//! V dialogovém oknu se změnil vybraná velikost pronace/supinace
+/*!
+ * Je voláno, pokud se v dialogovém oknu změní výběr velikosti provádění pronace/supinace.
+ * Lze vybrat žádnou (pokud není stisknuto ani jedno z tlačítek), malou (Úroveň 1) a velkou (Úroveň 2)
+ *
+ * \param id Identifikační číslo vybraného typu pronace/supinace
+ */
+void curveDialog::pressPronSupBtn()
+{
+    QAbstractButton* button = static_cast<QAbstractButton*>(sender());
+    if (button->isChecked()) {
+        ui->buttonGroupPS->setExclusive(false);
+        pronSupVal = PRON_SUP_NOT;
+    } else {
+        ui->buttonGroupPS->setExclusive(true);
+        if (button == ui->pronSup1Btn)
+            pronSupVal = PRON_SUP_1;
+        else if (button == ui->pronSup2Btn)
+            pronSupVal = PRON_SUP_2;
+    }
+}
+
+//! Vrací vybraný typ křivky
+/*!
+ * Vrací vybraný typ křivky, který bude předpočítán a poslán do stroje.
+ *
+ * \param *cType Typ křivky
+ * \param *cAngle Úhel sklonu křivky
+ * \param *cRot Směr rotace křivky
+ * \param *ps Velikost pronace/supinace
+ */
+void curveDialog::getCurve(int *cType, int *cAngle, int *cRot, int *ps)
+{
+    *cType = curveType;
+    *cAngle = curveAngle;
+    *cRot = curveRotation;
+    *ps = pronSupVal;
+}
+
+curveDialog::~curveDialog()
+{
+    delete ui;
+}
+
+//! Změna jazyka dialogu
+/*!
+  Pokud se změní jazyk aplikace, funkce změní text v dialogu, aby odpovídal
+  nastavenému jazyku
+  \param *e Ukazatel na objekt, který obsahuje posílanou událost
+*/
+void curveDialog::changeEvent(QEvent *e)
+{
+    QDialog::changeEvent(e);
+    switch (e->type()) {
+    case QEvent::LanguageChange:
+        ui->retranslateUi(this);
+        break;
+    default:
+        break;
+    }
+}
diff --git a/deltarobot/curvedialog.h b/deltarobot/curvedialog.h
new file mode 100644
index 0000000..03acaa4
--- /dev/null
+++ b/deltarobot/curvedialog.h
@@ -0,0 +1,84 @@
+#ifndef CURVEDIALOG_H
+#define CURVEDIALOG_H
+
+#include <QDialog>
+
+#define CURVE_EXTERN    0
+#define CURVE_CIRCLE    1
+#define CURVE_ELLIPSE   2
+#define CURVE_LEMN      3
+#define CURVE_KARD      4
+#define CURVE_LINE      5
+#define CURVE_NONE      6
+
+#define ANGLE_0     0
+#define ANGLE_45    1
+#define ANGLE_90    2
+#define ANGLE_135   3
+
+#define ROTATE_CLKWISE        0
+#define ROTATE_CNTRCLKWISE    1
+
+#define PRON_SUP_NOT    0
+#define PRON_SUP_1      1
+#define PRON_SUP_2      2
+#define PRON_SUP_3      3
+
+namespace Ui {
+class curveDialog;
+}
+
+//!  Třída pro uživatelské rozhraní výběru křivky
+/*!
+ * Třída slouží pro výběr křivky, kterou by měl pacient cvičit. Po výběru všech parametrů
+ * se křivka vygeneruje v aplikaci
+ *
+ *  \image html select_curve.jpg "Dialog výběru křivky"
+ *  \image latex select_curve.eps "Dialog výběru křivky" width=10cm
+ *
+*/
+class curveDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    //! Konstruktor.
+    /*!
+      V kostruktoru se inicializuje UI
+    */
+    explicit curveDialog(QWidget *parent = 0);
+    void getCurve(int *cType, int *cAngle, int *cRot, int *ps);
+    //! Destruktor.
+    /*!
+      Slouží pro správné ukončení dialogu
+    */
+    ~curveDialog();
+
+protected:
+    void changeEvent(QEvent *e);
+
+private slots:
+    void curveBtnClicked(int id);
+    void angleBtnClicked(int id);
+    void rotBtnClicked(int id);
+    void pressPronSupBtn(void);
+
+private:
+    //! Ukazatel na UI
+    /*!
+      Ukazatel na vytvořené uživatelské rozhraní
+    */
+    Ui::curveDialog *ui;
+    //! Parametry křivky
+    /*!
+     * Proměné obsahující typ, úhel naklonění, směr rotace a údaj o pronaci/supinaci vybrané křivky
+     */
+    /**@{*/
+    int curveType;
+    int curveAngle;
+    int curveRotation;
+    int pronSupVal;
+    /**@}*/
+};
+
+#endif // CURVEDIALOG_H
diff --git a/deltarobot/curvedialog.ui b/deltarobot/curvedialog.ui
new file mode 100644
index 0000000..7e7ee37
--- /dev/null
+++ b/deltarobot/curvedialog.ui
@@ -0,0 +1,633 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>curveDialog</class>
+ <widget class="QDialog" name="curveDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>662</width>
+    <height>674</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_4">
+   <item row="0" column="0" colspan="3">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QPushButton" name="circleBtn">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>90</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>15</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Kruh</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string notr="true">buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="ellipseBtn">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>90</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>15</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Elipsa</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string notr="true">buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="lemnBtn">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>90</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>15</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Lemniskáta</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string notr="true">buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="kardBtn">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>90</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>15</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Kardiotida</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string notr="true">buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="lineBtn">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>90</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>15</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Úsečka</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string notr="true">buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="noCurveBtn">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>90</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>15</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Žádná
+křivka</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string notr="true">buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="0" colspan="3">
+    <widget class="QGroupBox" name="groupBox_3">
+     <property name="font">
+      <font>
+       <pointsize>15</pointsize>
+      </font>
+     </property>
+     <property name="title">
+      <string>Úhel sklonu křivky</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_3">
+      <item row="0" column="4">
+       <spacer name="horizontalSpacer_6">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>30</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="3">
+       <widget class="QPushButton" name="angle45Btn">
+        <property name="minimumSize">
+         <size>
+          <width>90</width>
+          <height>90</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>15</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>45</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroupAngle</string>
+        </attribute>
+       </widget>
+      </item>
+      <item row="0" column="6">
+       <spacer name="horizontalSpacer_7">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>30</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="5">
+       <widget class="QPushButton" name="angle90Btn">
+        <property name="minimumSize">
+         <size>
+          <width>90</width>
+          <height>90</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>15</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>90</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroupAngle</string>
+        </attribute>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QPushButton" name="angle0Btn">
+        <property name="minimumSize">
+         <size>
+          <width>90</width>
+          <height>90</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>15</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>0</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroupAngle</string>
+        </attribute>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <spacer name="horizontalSpacer_3">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>30</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="2">
+       <spacer name="horizontalSpacer_5">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>30</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="8">
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>30</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="7">
+       <widget class="QPushButton" name="angle135Btn">
+        <property name="minimumSize">
+         <size>
+          <width>90</width>
+          <height>90</height>
+         </size>
+        </property>
+        <property name="font">
+         <font>
+          <pointsize>15</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>135</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroupAngle</string>
+        </attribute>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="3">
+    <widget class="QGroupBox" name="groupBox">
+     <property name="font">
+      <font>
+       <pointsize>15</pointsize>
+      </font>
+     </property>
+     <property name="title">
+      <string>Směr rotace</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0" rowspan="2">
+       <spacer name="horizontalSpacer_8">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>115</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="1" rowspan="2">
+       <widget class="QPushButton" name="cwRotBtn">
+        <property name="minimumSize">
+         <size>
+          <width>90</width>
+          <height>90</height>
+         </size>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="icon">
+         <iconset resource="resources.qrc">
+          <normaloff>:/img/if_rotate-cw.png</normaloff>:/img/if_rotate-cw.png</iconset>
+        </property>
+        <property name="iconSize">
+         <size>
+          <width>64</width>
+          <height>64</height>
+         </size>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroupRot</string>
+        </attribute>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <spacer name="horizontalSpacer_9">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>115</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="3" rowspan="2">
+       <widget class="QPushButton" name="ccwRotBtn">
+        <property name="minimumSize">
+         <size>
+          <width>90</width>
+          <height>90</height>
+         </size>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="icon">
+         <iconset resource="resources.qrc">
+          <normaloff>:/img/if_rotate-ccw.png</normaloff>:/img/if_rotate-ccw.png</iconset>
+        </property>
+        <property name="iconSize">
+         <size>
+          <width>64</width>
+          <height>64</height>
+         </size>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroupRot</string>
+        </attribute>
+       </widget>
+      </item>
+      <item row="1" column="4">
+       <spacer name="horizontalSpacer_10">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>115</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="3">
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="font">
+      <font>
+       <pointsize>15</pointsize>
+      </font>
+     </property>
+     <property name="title">
+      <string>Pronace/Supinace</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0">
+       <spacer name="horizontalSpacer_11">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>115</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="1">
+       <widget class="QPushButton" name="pronSup1Btn">
+        <property name="minimumSize">
+         <size>
+          <width>90</width>
+          <height>90</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Úroveň 1</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroupPS</string>
+        </attribute>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <spacer name="horizontalSpacer_12">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>115</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="0" column="3">
+       <widget class="QPushButton" name="pronSup2Btn">
+        <property name="minimumSize">
+         <size>
+          <width>90</width>
+          <height>90</height>
+         </size>
+        </property>
+        <property name="text">
+         <string>Úroveň 2</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <attribute name="buttonGroup">
+         <string notr="true">buttonGroupPS</string>
+        </attribute>
+       </widget>
+      </item>
+      <item row="0" column="4">
+       <spacer name="horizontalSpacer_13">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>115</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <spacer name="horizontalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>158</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="4" column="1">
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QPushButton" name="acceptBtn">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>90</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>15</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>OK</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="cancelBtn">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>90</height>
+        </size>
+       </property>
+       <property name="font">
+        <font>
+         <pointsize>15</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Zrušit</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="4" column="2">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>168</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+ <buttongroups>
+  <buttongroup name="buttonGroupAngle"/>
+  <buttongroup name="buttonGroup"/>
+  <buttongroup name="buttonGroupRot"/>
+  <buttongroup name="buttonGroupPS"/>
+ </buttongroups>
+</ui>
diff --git a/deltarobot/element/arrow.cpp b/deltarobot/element/arrow.cpp
new file mode 100644
index 0000000..aad69ee
--- /dev/null
+++ b/deltarobot/element/arrow.cpp
@@ -0,0 +1,49 @@
+#include "arrow.hpp"
+
+const float Arrow::QUAD_HEIGHT = 0.7f;
+const float Arrow::QUAD_WIDTH = 0.1f;
+const float Arrow::ARROW_TOP = 0.8f;
+const float Arrow::ROOF_WIDTH = 0.2f;
+
+Arrow::Arrow(bool important): Element(important ? Element::ARROW : Element::ARROW_SPECIAL)
+{
+    // Body pro kvadr tvorici zaklad sipky.
+    
+    float halfQuadWidth = QUAD_WIDTH / 2.0f;
+    
+    QVector3D quadF0 = QVector3D(-1.0f * halfQuadWidth, 0.0f, halfQuadWidth);
+    QVector3D quadF1 = QVector3D(-1.0f * halfQuadWidth, QUAD_HEIGHT, halfQuadWidth);
+    QVector3D quadF2 = QVector3D(halfQuadWidth, QUAD_HEIGHT, halfQuadWidth);
+    QVector3D quadF3 = QVector3D(halfQuadWidth, 0.0f, halfQuadWidth);
+    
+    QVector3D quadB0 = QVector3D(-1.0f * halfQuadWidth, 0.0f, -1.0f * halfQuadWidth);
+    QVector3D quadB1 = QVector3D(-1.0f * halfQuadWidth, QUAD_HEIGHT, -1.0f * halfQuadWidth);
+    QVector3D quadB2 = QVector3D(halfQuadWidth, QUAD_HEIGHT, -1.0f * halfQuadWidth);
+    QVector3D quadB3 = QVector3D(halfQuadWidth, 0.0f, -1.0f * halfQuadWidth);
+    
+    // Body pro "strechu" sipky.
+    
+    float halfRoofWidth = ROOF_WIDTH / 2.0f;
+    
+    QVector3D roofF0 = QVector3D(-1.0f * halfRoofWidth, QUAD_HEIGHT, halfRoofWidth);
+    QVector3D roofB0 = QVector3D(-1.0f * halfRoofWidth, QUAD_HEIGHT, -1.0f * halfRoofWidth);
+    QVector3D roofB1 = QVector3D(halfRoofWidth, QUAD_HEIGHT, -1.0f * halfRoofWidth);
+    QVector3D roofF1 = QVector3D(halfRoofWidth, QUAD_HEIGHT, halfRoofWidth);
+    QVector3D roofTop = QVector3D(0.0f, ARROW_TOP, 0.0f);
+    
+    // Vytvoreni kvadru.
+    
+    addTetragon(quadB0, quadF0, quadF3, quadB3); // Spodni krytka.
+    addTetragon(quadF0, quadF1, quadF2, quadF3); // Obdelnik vpredu.
+    addTetragon(quadB0, quadB1, quadF1, quadF0); // Obdelnik zleva.
+    addTetragon(quadB3, quadB2, quadB1, quadB0); // Obdelnik vzadu.
+    addTetragon(quadF3, quadF2, quadB2, quadB3); // Obdelnik zprava.
+    
+    // Vytvoreni strisky.
+    
+    addTetragon(roofB0, roofF0, roofF1, roofB1); // Zaklad strechy (horni krytka kvadru).
+    addTriangle(roofF1, roofTop, roofF0); // Trojuhelnik vpredu.
+    addTriangle(roofF0, roofTop, roofB0); // Trojuhelnik zleva.
+    addTriangle(roofB0, roofTop, roofB1); // Trojuhelnik vzadu.
+    addTriangle(roofB1, roofTop, roofF1); // Trojuhelnik zprava.
+}
diff --git a/deltarobot/element/arrow.hpp b/deltarobot/element/arrow.hpp
new file mode 100644
index 0000000..c0acb09
--- /dev/null
+++ b/deltarobot/element/arrow.hpp
@@ -0,0 +1,29 @@
+#ifndef _ARROW_HPP
+#define _ARROW_HPP
+
+#include "element.hpp"
+
+/// Třída Arrow představuje vykreslovanou šipku, umístěnou do počátku soustavy
+/// souřadnic bez jakékoli úpravy.
+class Arrow: public Element
+{
+    public:
+        /// Konstruktor. Konstruktor nastavuje, jestli se jedná o důležitou křivku.
+        /// @param bool important - jestli se jedná o tu důležitější křivku.
+        Arrow(bool important);
+        
+    private:
+        /// Výška kvádru pod stříškou.
+        static const float QUAD_HEIGHT;
+        
+        /// Šířka kvádru pod stříškou.
+        static const float QUAD_WIDTH;
+        
+        /// Velikost šipky (souřadnice vrcholu stříšky na ose Y).
+        static const float ARROW_TOP;
+        
+        /// Šířka základu stříšky.
+        static const float ROOF_WIDTH;
+};
+
+#endif
diff --git a/deltarobot/element/element.cpp b/deltarobot/element/element.cpp
new file mode 100644
index 0000000..acd89a4
--- /dev/null
+++ b/deltarobot/element/element.cpp
@@ -0,0 +1,63 @@
+#include "element.hpp"
+
+const int Element::DATA_COUNT_FOR_VERTEX = 7;
+const int Element::TRAJECTORY = 0;
+const int Element::SPHERE = 1;
+const int Element::SPHERE_FIXED = 2;
+const int Element::ARROW = 3;
+const int Element::ARROW_SPECIAL = 4;
+const int Element::WALL = 5;
+
+Element::Element(const int category)
+{
+    this->category = category;
+}
+
+const float *Element::getData() const
+{
+    return data.data();
+}
+
+int Element::dataCount() const
+{
+    return data.size();
+}
+
+int Element::vertexCount() const
+{
+    return dataCount() / DATA_COUNT_FOR_VERTEX;
+}
+
+void Element::addVertex(const QVector3D &v, const QVector3D &n)
+{
+    data.insert(data.end(), {v.x(), v.y(), v.z(), n.x(), n.y(), n.z(), (float) category});
+}
+
+void Element::addTetragon(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d)
+{
+    QVector3D n = normal(a, d, b);
+    addTriangleWithNormal(a, d, b, n);
+    addTriangleWithNormal(c, b, d, n);
+}
+
+void Element::addTriangle(const QVector3D &a, const QVector3D &b, const QVector3D &c)
+{
+    addTriangleWithNormal(a, b, c, normal(a, b, c));
+}
+
+QVector3D Element::normal(const QVector3D &a, const QVector3D &b, const QVector3D &c)
+{
+    return QVector3D::normal(b - a, c - a);
+}
+
+void Element::clear()
+{
+    data.clear();
+}
+
+void Element::addTriangleWithNormal(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n)
+{
+    addVertex(a, n);
+    addVertex(b, n);
+    addVertex(c, n);
+}
diff --git a/deltarobot/element/element.hpp b/deltarobot/element/element.hpp
new file mode 100644
index 0000000..4f014fa
--- /dev/null
+++ b/deltarobot/element/element.hpp
@@ -0,0 +1,97 @@
+#ifndef _ELEMENT_HPP
+#define _ELEMENT_HPP
+
+#include <QVector3D>
+#include <vector>
+using namespace std;
+
+/// Třída Element je rodičem pro všechny prvky, které se objevují ve vykreslované
+/// scéně (dráha, koule, ... ).
+class Element
+{
+    public:
+        /// Určuje, kolik hodnot za sebou ve vektoru DATA odpovídá jednomu vrcholu.
+        static const int DATA_COUNT_FOR_VERTEX;
+        
+        /// Konstruktro. Konstruktor nastavuje typ prvku, tj. jestli se jedná o dráhu, kouli,
+        /// apod. Typ prvku pak jde do OpenGL shader programu, kde se určuje,
+        /// jaké natočení, posunutí, barva, atd. se má použít pro daný prvek.
+        /// @param const int category - typ prvku.
+        Element(const int category);
+        
+        /// @return konstantní ukazatel na hodnoty uložené ve vektoru DATA.
+        const float *getData() const;
+        
+        /// @return počet hodnot uložených ve vektoru DATA.
+        int dataCount() const;
+        
+        /// @return počet vrcholu, pro které jsou uloženy informace ve vektoru DATA.
+        int vertexCount() const;
+        
+    protected:
+        /// Identifikátor dráhy.
+        /// Identifikátor dráhy.
+        static const int TRAJECTORY;
+        
+        /// Identifikátor koule.
+        static const int SPHERE;
+
+        /// Identifikátor statické koule.
+        static const int SPHERE_FIXED;
+
+        /// Identifikátor šipky.
+        static const int ARROW;
+        
+        /// Identifikátor speciální šipky (šipka, která je pouze informativní).
+        static const int ARROW_SPECIAL;
+        
+        /// Identifikátor stěny.
+        static const int WALL;
+        
+        // Nastavený typ prvku, tj. jestli se jedná o drahu, kouli, apod.
+        int category;
+        
+        /// Uloží do vektoru DATA hodnoty týkající se daného vrcholu v.
+        /// @param const QVector3D &v - souřadnice daného vrcholu.
+        /// @param const QVector3D &n - normála pro vrchol v.
+        void addVertex(const QVector3D &v, const QVector3D &n);
+        
+        /// Ze vstupních bodů vytvoří ctyřúhelník, který rozdělí na dva trojúhelníky.
+        /// Poté, pro oba trojúhelníky, vypočte normály a zavolá funkci
+        /// addTriangleWithNormal().
+        /// @param const QVector3D &a - souřadnice prvního vrcholu.
+        /// @param const QVector3D &b - souřadnice druhého vrcholu.
+        /// @param const QVector3D &c - souřadnice třetího vrcholu.
+        /// @param const QVector3D &d - souřadnice čtvrtého vrcholu.
+        void addTetragon(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d);
+        
+        /// Ze vstupních bodů vytvoří trojúhelník, vypočte normálu a zavolá
+        /// funkci addTriangleWithNormal().
+        /// @param const QVector3D &a - souřadnice prvního vrcholu.
+        /// @param const QVector3D &b - souřadnice druhého vrcholu.
+        /// @param const QVector3D &c - souřadnice třetího vrcholu.
+        void addTriangle(const QVector3D &a, const QVector3D &b, const QVector3D &c);
+        
+        /// Funkce pro vypočtení normály daného trojuhelníka.
+        /// @param const QVector3D &a - souřadnice prvního vrcholu.
+        /// @param const QVector3D &b - souřadnice druhého vrcholu.
+        /// @param const QVector3D &c - souřadnice třetího vrcholu.
+        /// @return vypoctenou normálu pro dany trojúhelník.
+        QVector3D normal(const QVector3D &a, const QVector3D &b, const QVector3D &c);
+        
+        /// Vyčistí vektor DATA (využíváno, když se přepínají dráhy).
+        void clear();
+        
+    private:
+        /// Datová struktura pro uložení informací (reálnych hodnot) pro každý vrchol.
+        vector<float> data;
+        
+        /// Pouze volá, pro každý vrchol, funkci addVertex().
+        /// @param const QVector3D &a - souřadnice prvního vrcholu.
+        /// @param const QVector3D &b - souřadnice druhého vrcholu.
+        /// @param const QVector3D &c - souřadnice třetího vrcholu.
+        /// @param const QVector3D &n - normála pro trojúhelník ABC.
+        void addTriangleWithNormal(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n);
+};
+
+#endif
diff --git a/deltarobot/element/sphere.cpp b/deltarobot/element/sphere.cpp
new file mode 100644
index 0000000..8dd292d
--- /dev/null
+++ b/deltarobot/element/sphere.cpp
@@ -0,0 +1,115 @@
+#include "sphere.hpp"
+
+const float Sphere::RADIUS = 300.0f;
+const float Sphere::MAX_SCALING = 1.3f;
+const float Sphere::MIN_SCALING = 0.8f;
+const int Sphere::SMOOTHING = 5;
+
+const QVector3D Sphere::middlePoint(const QVector3D &a, const QVector3D &b)
+{
+    return QVector3D((a + b) / 2.0f);
+}
+
+float Sphere::getMaxRadius()
+{
+    return RADIUS * MAX_SCALING;
+}
+
+Sphere::Sphere(bool moving): Element(moving ? Element::SPHERE : Element::SPHERE_FIXED)
+{
+    // Predni polokoule.
+    QVector3D v1(0.0f, RADIUS, 0.0f);
+    QVector3D v2(0.0f, 0.0f, RADIUS);
+    QVector3D v3(RADIUS, 0.0f, 0.0f);
+    subdivide(v1, v2, v3, SMOOTHING);
+    
+    QVector3D v4(0.0f, RADIUS, 0.0f);
+    QVector3D v5(-1.0f * RADIUS, 0.0f, 0.0f);
+    QVector3D v6(0.0f, 0.0f, RADIUS);
+    subdivide(v4, v5, v6, SMOOTHING);
+    
+    QVector3D v13(0.0f, -1.0f * RADIUS, 0.0f);
+    QVector3D v14(RADIUS, 0.0f, 0.0f);
+    QVector3D v15(0.0f, 0.0f, RADIUS);
+    subdivide(v13, v14, v15, SMOOTHING);
+    
+    QVector3D v16(0.0f, -1.0f * RADIUS, 0.0f);
+    QVector3D v17(0.0f, 0.0f, RADIUS);
+    QVector3D v18(-1.0f * RADIUS, 0.0f, 0.0f);
+    subdivide(v16, v17, v18, SMOOTHING);
+    
+    // Zadni polokoule.
+    QVector3D v7(0.0f, RADIUS, 0.0f);
+    QVector3D v8(RADIUS, 0.0f, 0.0f);
+    QVector3D v9(0.0f, 0.0f, -1.0f * RADIUS);
+    subdivide(v7, v8, v9, SMOOTHING);
+    
+    QVector3D v10(0.0f, RADIUS, 0.0f);
+    QVector3D v11(0.0f, 0.0f, -1.0f * RADIUS);
+    QVector3D v12(-1.0f * RADIUS, 0.0f, 0.0f);
+    subdivide(v10, v11, v12, SMOOTHING);
+    
+    QVector3D v19(0.0f, -1.0f * RADIUS, 0.0f);
+    QVector3D v20(0.0f, 0.0f, -1.0f * RADIUS);
+    QVector3D v21(RADIUS, 0.0f, 0.0f);
+    subdivide(v19, v20, v21, SMOOTHING);
+    
+    QVector3D v22(0.0f, -1.0f * RADIUS, 0.0f);
+    QVector3D v23(-1.0f * RADIUS, 0.0f, 0.0f);
+    QVector3D v24(0.0f, 0.0f, -1.0f * RADIUS);
+    subdivide(v22, v23, v24, SMOOTHING);
+    
+    set = false;
+}
+
+void Sphere::setRangeZ(const float minimumZ, const float maximumZ)
+{
+    this->minimumZ = minimumZ;
+    this->maximumZ = maximumZ;
+    set = false;
+}
+
+float Sphere::getCurrentScaling()
+{
+    return MIN_SCALING + (position.z() - minimumZ) / (maximumZ - minimumZ) * (MAX_SCALING - MIN_SCALING);
+}
+
+void Sphere::setPosition(const QVector3D &position)
+{
+    this->position = position;
+    set = true;
+}
+
+const QVector3D Sphere::getPosition()
+{
+    return position;
+}
+
+bool Sphere::isSet()
+{
+    return set;
+}
+
+void Sphere::subdivide(const QVector3D &a, const QVector3D &b, const QVector3D &c, const int level)
+{
+    if (level < 1) {
+        // Jedna se o konec rekurzivniho volani, pouze vytvoreni trojuhelnika.
+        addTriangle(a, b, c);
+    } else {
+        // Stredni body.
+        QVector3D mAB = middlePoint(a, b);
+        QVector3D mBC = middlePoint(b, c);
+        QVector3D mCA = middlePoint(c, a);
+        
+        // Nastaveni velikosti vektoru (velikost polomeru koule).
+        mAB *= RADIUS / mAB.length();
+        mBC *= RADIUS / mBC.length();
+        mCA *= RADIUS / mCA.length();
+        
+        // Rozdeleni trojuhelnika na dalsi ctyri.
+        subdivide(a,  mAB, mCA, level - 1);
+        subdivide(b, mBC,  mAB, level - 1);
+        subdivide(c, mCA, mBC, level - 1);
+        subdivide(mAB, mBC, mCA, level - 1); // Trojuhelnik ve stredu.
+    }
+}
diff --git a/deltarobot/element/sphere.hpp b/deltarobot/element/sphere.hpp
new file mode 100644
index 0000000..81c3504
--- /dev/null
+++ b/deltarobot/element/sphere.hpp
@@ -0,0 +1,77 @@
+#ifndef _SPHERE_HPP
+#define _SPHERE_HPP
+
+#include "element.hpp"
+
+/// Třída Sphere představuje vykreslovanou kouli umístěnou do počátku soustavy
+/// souřadnic bez jakékoli úpravy.
+class Sphere: public Element
+{
+    public:
+        /// Poloměr koule.
+        static const float RADIUS;
+        
+        /// @return souřadnice prostředního bodu mezi vrcholy A a B.
+        /// @param const QVector3D &a - první bod.
+        /// @param const QVector3D &b - druhý bod.
+        static const QVector3D middlePoint(const QVector3D &a, const QVector3D &b);
+        
+        /// @return jaký poloměr koule má při největší velikosti.
+        static float getMaxRadius();
+        
+        /// Konstruktor vytvoří prvních osm trojúhelníků, představujících tu
+        /// nejhrubší možnou kouli. Pak volá funkci subdivide(), která rekurzivně
+        /// provádí vyhlazování koule.
+        /// @param bool moving - jestli se jedná o pohyblivou, nebo statickou kouli.
+        Sphere(bool moving);
+        
+        /// Nastavuje hodnoty představující minimální a maximální možnou
+        /// souřadnici na ose Z.
+        /// @param const QVector3D &minimumZ - minimální souřadnice na ose Z.
+        /// @param const QVector3D &maximumZ - maximální souřadnice na ose Z.
+        void setRangeZ(const float minimumZ, const float maximumZ);
+        
+        /// @return jak moc má být koule zvětšena (zmenšena) na aktuální souřadnici Z.
+        float getCurrentScaling();
+        
+        /// Nastavuje pozici koule v prostoru.
+        /// @param const QVector3D &position - bod v prostoru.
+        void setPosition(const QVector3D &position);
+        
+        /// @return pozice koule v prostoru.
+        const QVector3D getPosition();
+        
+        /// @return jestli už byly nastaveny všechny informace potřebné pro
+        ///         vykreslení koule.
+        bool isSet();
+        
+    private:
+        /// Jak se má koule zvětšit (zmenšit) na maximální souřadnici na ose Z.
+        static const float MAX_SCALING;
+        
+        /// Jak se má koule zmenšit (zvětšit) na minimální souřadnici na ose Z.
+        static const float MIN_SCALING;
+        
+        /// Jak moc má být koule hladká (pouze hodnoty od 1 do 5).
+        static const int SMOOTHING;
+        
+        /// Minimální a maximální souřadnice Z, na které se koule může vyskytnout.
+        float minimumZ, maximumZ;
+        
+        /// Aktuální pozice koule v prostoru.
+        QVector3D position;
+        
+        /// Jestli jsou nastaveny všechny informace potřebné pro vykreslení koule.
+        /// Konkrétně se jedná o pozici v prostoru (s koulí se vykreslují i šipky).
+        bool set;
+
+        /// Funkce, ktera rekurzivně, podle dané urovně, provádí vyhlazování
+        /// koule, resp. trojůhelníků v ní. Každý trojůhelník rozdělí na další čtyři.
+        /// @param const QVector3D &a - souřadnice prvního vrcholu trojúhelníka.
+        /// @param const QVector3D &b - souřadnice druhého vrcholu trojúhelníka.
+        /// @param const QVector3D &c - souřadnice třetího vrcholu trojúhelníka.
+        /// @param const int level - aktuální úroveň vyhlazování.
+        void subdivide(const QVector3D &a, const QVector3D &b, const QVector3D &c, const int level);
+};
+
+#endif
diff --git a/deltarobot/element/trajectory.cpp b/deltarobot/element/trajectory.cpp
new file mode 100644
index 0000000..d797665
--- /dev/null
+++ b/deltarobot/element/trajectory.cpp
@@ -0,0 +1,212 @@
+#include "trajectory.hpp"
+
+const float Trajectory::MAX_RADIUS = 120.0f;
+const float Trajectory::MIN_RADIUS = 50.0f;
+const int Trajectory::SMOOTHING = 50;
+
+Trajectory::Trajectory(): Element(Element::TRAJECTORY)
+{
+    set = false;
+}
+
+bool Trajectory::isSet()
+{
+    return set;
+}
+
+void Trajectory::setNewCurve(QList<QVector3D> data, const float minimumZ, const float maximumZ)
+{
+    // Uvolneni pameti od stareho tubusu.
+    clear();
+
+    // Vyhozeni zbytecnych bodu.
+    QList<QVector3D> mData;
+    QVector3D lastPoint;
+    for (int i = 0; i < data.count(); i++)
+    {
+        if (i > 0 && (data.at(i) - lastPoint).length() < 50)
+        {
+            continue;
+        }
+        else
+        {
+            mData.append(data.at(i));
+            lastPoint = data.at(i);
+        }
+    }
+
+    data = mData;
+    int lastIndex = data.count() - 1;
+
+    // Vytvoreni vektoru mezi predchozim a nasledujicim bodem.
+    QVector3D dv[data.count()];
+    for (int i = 1; i < lastIndex; i++)
+    {
+        dv[i] = data.at(i + 1) - data.at(i - 1);
+    }
+    dv[0] = data.at(1) - data.at(0);
+    //pokud maji prvni dva body stejnou y osu - krivka se nevykresli (nevim proc) - pro jistotu pridame 1 ke kazde ose
+    dv[0] += QVector3D(1,1,1);
+    dv[lastIndex] = data.last() - data.at(data.count() - 2);
+    
+    // Inicializace prvniho normaloveho vektoru pro urceni bodu na kruznici.
+    QVector3D a(0,0,0);
+    int index = 0;
+    float smallest = dv[0].x();
+    if (dv[0].y() < smallest)
+    {
+        smallest = dv[0].y();
+        index = 1;
+    }
+    if (dv[0].z() < smallest)
+    {
+        index = 2;
+    }
+    switch (index)
+    {
+        case 0: a.setX(1.0f); break;
+        case 1: a.setY(1.0f); break;
+        default: a.setZ(1.0f); break;
+    }
+    
+    // Vypocteni rozsahu souradnic a radiusu.
+    float rangeZ = maximumZ - minimumZ;
+    float rangeRadius = MAX_RADIUS - MIN_RADIUS;
+    
+    // Jestli jde o uzavrenou krivku.
+    bool flSamePoints = data.at(0) == data.at(lastIndex);
+    
+    // Vytvoreni tubusu.
+    QVector3D vertices[data.count()][SMOOTHING];
+    for (int i = 0; i < data.count(); i++)
+    {
+        // a, b jsou normalove vektory definujici kruznici kolem daneho bodu.
+        QVector3D b = QVector3D::crossProduct(a, dv[i]).normalized();
+        a = QVector3D::crossProduct(dv[i], b).normalized();
+        
+        if (i != lastIndex || !flSamePoints)
+        {
+            float rTube = MIN_RADIUS + (data[i].z() - minimumZ) / rangeZ * rangeRadius;
+            for (int j = 0; j < SMOOTHING; j++)
+            {
+                double th = j * 2 * M_PI / SMOOTHING;
+                vertices[i][j] = data[i] + cos(th) * rTube * a + sin(th) * rTube * b;
+            }
+        }
+    }
+    
+    if (flSamePoints)
+    {
+        // Pokud jde o uzavrenou krivku, spojit prvni a posledni kruznici.
+        for (int i = 0; i < SMOOTHING; i++)
+        {
+            vertices[lastIndex][i] = vertices[0][i];
+        }
+    }
+    else
+    {
+        // Pokud nejde o uzavrenou krivku, vytvorit krytky koncu.
+        for (int i = 0; i < SMOOTHING; i++)
+        {
+            addTriangle(vertices[0][i], vertices[0][(i + 1) % SMOOTHING], data.at(0));
+            addTriangle(data.at(lastIndex), vertices[lastIndex][(i + 1) % SMOOTHING], vertices[lastIndex][i]);
+        }
+    }
+    
+    // Vytvoreni trojuhelnikove site.
+    for (int i = 0; i < lastIndex; i++)
+    {
+        for (int j = 0; j < SMOOTHING; j++)
+        {
+            addTetragon(vertices[i][j], vertices[i][(j + 1) % SMOOTHING], vertices[i+1][(j + 1) % SMOOTHING], vertices[i+1][j]);
+        }
+    }
+    // Nyni muze byt draha vykreslena.
+    set = true;
+}
+
+void Trajectory::addNewPointToCurve(QVector3D point, const bool start, const bool finish)
+{
+   if (start) {
+       clear();
+       curve.clear();
+       newCurvePointCount = 0;
+   }
+
+   if (curve.size() > 0 && (point - curve.last()).length() < 50)
+       return;
+
+   if (curve.size() > MAX_CURVE_SIZE)
+       return;
+
+   curve.append(point-QVector3D(0,0,4500));
+
+   if (curve.size() < 4)
+       return;
+
+   /*setNewCurve(curve, -4500,4500);
+   curve.clear();
+   return;*/
+
+   // Vytvoreni vektoru mezi predchozim a nasledujicim bodem.
+   QVector3D dv, dv1, dv0;
+   int pos = curve.count();
+
+   dv0 = curve.at(pos-3) - curve.at(pos-4);
+   dv0 += QVector3D(1,1,1);
+   dv = curve.last() - curve.at(pos-3);
+   dv1 = curve.at(pos-2) - curve.at(pos - 4);
+
+   // Inicializace prvniho normaloveho vektoru pro urceni bodu na kruznici.
+   QVector3D a(0,0,0), a1;
+   int index = 0;
+   float smallest = dv0.x();
+   if (dv0.y() < smallest)
+   {
+       smallest = dv0.y();
+       index = 1;
+   }
+   if (dv0.z() < smallest)
+   {
+       index = 2;
+   }
+   switch (index)
+   {
+   case 0: a.setX(1.0f); break;
+   case 1: a.setY(1.0f); break;
+   default: a.setZ(1.0f); break;
+   }
+
+   // Vypocteni rozsahu souradnic a radiusu.
+   float rangeZ = 9000;
+   float rangeRadius = MAX_RADIUS - MIN_RADIUS;
+
+   // Vytvoreni tubusu.
+   QVector3D vertices[2][SMOOTHING];
+   // a, b jsou normalove vektory definujici kruznici kolem daneho bodu.
+   a1 = a;
+   QVector3D b = QVector3D::crossProduct(a, dv).normalized();
+   QVector3D b1 = QVector3D::crossProduct(a, dv1).normalized();
+   a = QVector3D::crossProduct(dv, b).normalized();
+   a1 = QVector3D::crossProduct(dv1, b1).normalized();
+
+   float rTube = MIN_RADIUS + (curve.at(curve.count()-2).z() + 4500) / rangeZ * rangeRadius;
+   float rTube1 = MIN_RADIUS + (curve.at(curve.count()-3).z() + 4500) / rangeZ * rangeRadius;
+   for (int j = 0; j < SMOOTHING; j++)
+   {
+       double th = j * 2 * M_PI / SMOOTHING;
+       vertices[0][j] = curve.at(curve.count()-3) + cos(th) * rTube * a + sin(th) * rTube * b;
+       vertices[1][j] = curve.at(curve.count()-2) + cos(th) * rTube * a + sin(th) * rTube * b;
+   }
+
+   for (int j = 0; j < SMOOTHING; j++)
+   {
+       addTetragon(vertices[0][j], vertices[0][(j + 1) % SMOOTHING], vertices[1][(j + 1) % SMOOTHING], vertices[1][j]);
+   }
+
+   set = true;
+
+   if (finish) {
+       //end of tube
+   }
+}
diff --git a/deltarobot/element/trajectory.hpp b/deltarobot/element/trajectory.hpp
new file mode 100644
index 0000000..07b7809
--- /dev/null
+++ b/deltarobot/element/trajectory.hpp
@@ -0,0 +1,54 @@
+#ifndef _TRAJECTORY_HPP
+#define _TRAJECTORY_HPP
+
+#include <cmath>
+#include <QList>
+#include "element.hpp"
+
+#define MAX_CURVE_SIZE  2500
+/// Třída Trajectory představuje vykreslovanou dráhu umístěnou středem do počátku
+/// soustavy souřadnic. Dráha je v podobě tubusu. Tubus se zmenšuje a zvětšuje
+/// podle souřadnice na ose Z.
+class Trajectory: public Element
+{
+    public:
+        /// Maximální poloměr tubusu (poloměr na nejvetší souřadnici Z).
+        static const float MAX_RADIUS;
+
+        /// Konstruktor pouze nastavuje atribut SET na false.
+        Trajectory();
+        
+        /// Funkce pro vytvoření nového tubusu pro danou křivku.
+        /// @param QList<QVector3D> data - body představující křivku v prostoru.
+        /// @param const float minimumZ - minimální souřadnice na ose Z.
+        /// @param const float maximumZ - maximální souřadnice na ose Z.
+        void setNewCurve(QList<QVector3D> data, const float minimumZ, const float maximumZ);
+
+        /// Funkce pro přidání nového bodu do tubusu pro danou křivku.
+        /// @param QVector3D point - nový bod křivky v prostoru.
+        /// @param const bool start - nový bod je na počátku křivky.
+        /// @param const bool finish - nový bod je na konci křivky.
+        void addNewPointToCurve(QVector3D point, const bool start, const bool finish);
+        
+        /// @return jestli byly nastaveny potřebné informace pro vykreslení dráhy.
+        bool isSet();
+        
+    private:
+        /// Minimální poloměr tubusu (poloměr na nejmenší souřadnici Z).
+        static const float MIN_RADIUS;
+        
+        /// Jak moc má být tubus hladký (hodnoty od 3 do 50). Hladkost je určena
+        /// počtem obdélníků po obvodu tubusu mezi dvěma vrcholy křivky.
+        static const int SMOOTHING;
+        
+        /// Jestli byly nastaveny všechny informace potřebné pro vykresleni křivky.
+        bool set;
+
+        /// Aktuální křivka, do které jsou bodu přidávány
+        QList<QVector3D> curve;
+
+        /// Aktuální počet bodu křivky, do které se body přidávají
+        int newCurvePointCount;
+};
+
+#endif
diff --git a/deltarobot/element/wall.cpp b/deltarobot/element/wall.cpp
new file mode 100644
index 0000000..50981b4
--- /dev/null
+++ b/deltarobot/element/wall.cpp
@@ -0,0 +1,168 @@
+#include "wall.hpp"
+
+const float Wall::DEFORM = 0.5f;
+const float Wall::SCALING_FRONT = 1.2f;
+const float Wall::SCALING_BACK = 0.6f;
+const int Wall::FLOOR_SPLIT = 5;
+const int Wall::CEILING_SPLIT = 3;
+const int Wall::SIDE_SPLIT = 8;
+const int Wall::ENLARGE = 6;
+
+Wall::Wall(const TYPE type): Element(Element::WALL)
+{
+    this->type = type;
+}
+
+void Wall::setData(QVector3D minimum, QVector3D maximum, float sphereRadius)
+{
+    // Odstranit ulozene hodnoty ke "stare" zdi.
+    clear();
+    
+    // Minimalni kvadr rozsirit tak, aby se do mistnosti vesly i sipky (podle
+    // polomeru koule).
+    sphereRadius *= ENLARGE;
+    minimum += QVector3D(-1.0f * sphereRadius, -1.0f * sphereRadius, -1.0f * sphereRadius);
+    maximum += QVector3D(sphereRadius, sphereRadius, sphereRadius);
+    
+    // Urceni poloviny vysledneho rozsahu pro osy X a Y pro predni a zadni stenu.
+    float rangeFrontX = abs(maximum.x() - minimum.x()) * SCALING_FRONT / 2.0f;
+    float rangeBackX = abs(maximum.x() - minimum.x()) * SCALING_BACK / 2.0f;
+    float rangeFrontY = abs(maximum.y() - minimum.y()) * SCALING_FRONT / 2.0f;
+    float rangeBackY = abs(maximum.y() - minimum.y()) * SCALING_BACK / 2.0f;
+    
+    // Urceni souradnic "deformovaneho" kvadru.
+    QVector3D F00 = QVector3D(-1.0f * rangeFrontX, -1.0f * rangeFrontY, maximum.z());
+    QVector3D F10 = QVector3D(-1.0f * rangeFrontX, rangeFrontY, maximum.z());
+    QVector3D F11 = QVector3D(rangeFrontX, rangeFrontY, maximum.z());
+    QVector3D F01 = QVector3D(rangeFrontX, -1.0f * rangeFrontY, maximum.z());
+    
+    QVector3D B00 = QVector3D(-1.0f * rangeBackX, -1.0f * rangeBackY, minimum.z());
+    QVector3D B10 = QVector3D(-1.0f * rangeBackX, rangeBackY, minimum.z());
+    QVector3D B11 = QVector3D(rangeBackX, rangeBackY, minimum.z());
+    QVector3D B01 = QVector3D(rangeBackX, -1.0f * rangeBackY, minimum.z());
+    
+    // Rozdeleni steny na mensi casti, do kterych bude vykreslovana textura.
+    if (type == TYPE::FLOOR)
+    {
+        // Podlaha
+        split(F01, F00, B00, B01, FLOOR_SPLIT);
+    }
+    else if (type == TYPE::CEILING)
+    {
+        // Strop
+        split(F10, F11, B11, B10, CEILING_SPLIT);
+    }
+    else
+    {
+        // Stena vzadu
+        split(B00, B10, B11, B01, SIDE_SPLIT, false);
+        // Stena nalevo
+        split(F00, F10, B10, B00, SIDE_SPLIT);
+        // Stena napravo
+        split(F11, F01, B01, B11, SIDE_SPLIT);
+    }
+}
+
+void Wall::split(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d, const int parts, const bool deform)
+{
+    // Obecny ctyruhelnik. Deformace smerem doprava (pokud je nastavena), tj. od AB do DC.
+    //    b
+    //         c
+    //
+    //  a        d
+    
+    // Urceni bocnich vektoru (zdola nahoru), ktere definuji vysku jednoho pruhu.
+    // Vyska pruhu se deformovat nemusi vubec, je pro kazdy pruh stejna.
+    QVector3D leftUp = (b - a) / (float) parts;
+    QVector3D rightUp = (c - d) / (float) parts;
+    
+    for (int y = 0; y < parts; y++)
+    {
+        // Zjisteni souradnic ctyruhelnika predstavujici jeden pruh.
+        QVector3D leftBottom = a + y * leftUp;
+        QVector3D leftTop = a + (y + 1) * leftUp;
+        QVector3D rightBottom = d + y * rightUp;
+        QVector3D rightTop = d + (y + 1) * rightUp;
+        
+        // Urceni horniho a dolniho vektoru (zleva doprava), ktere definuji sirku
+        // jednoho sloupce (dany sloupec ma ve vsech pruzich stejnou sirku).
+        // Pokud je nastavena deformace, bude se tykat prave sirek sloupcu, viz dale.
+        QVector3D topRight = (rightTop - leftTop) / (float) parts;
+        QVector3D bottomRight = (rightBottom - leftBottom) / (float) parts;
+        
+        QVector3D topRightFirst, topRightDiff, bottomRightFirst, bottomRightDiff, topRightAct, bottomRightAct, topOneOnRightAct, bottomOneOnRightAct;
+        if (deform)
+        {
+            // Jestlize ma dochazet k deformaci, vypocitani sirky prvniho sloupce
+            // a rozdilu sirek mezi dvema sloupci.
+            
+            // Horni sirka prvniho sloupce (nejvice vlevo).
+            topRightFirst = (1.0f + DEFORM) * topRight;
+            // O kolik se ma linearne snizovat horni sirka sloupce.
+            topRightDiff = (topRightFirst - (1.0f - DEFORM) * topRight) / (float) (parts - 1);
+            
+            // Dolni sirka prvniho sloupce (nejvice vlevo).
+            bottomRightFirst = (1.0f + DEFORM) * bottomRight;
+            // O kolik se ma linearne snizovat dolni sirka sloupce.
+            bottomRightDiff = (bottomRightFirst - (1.0f - DEFORM) * bottomRight) / (float) (parts - 1);
+            
+            // Nastaveni souradnic prvniho ctyruhelnika.
+            topRightAct = leftTop;
+            bottomRightAct = leftBottom;
+            topOneOnRightAct = topRightAct + topRightFirst;
+            bottomOneOnRightAct = bottomRightAct + bottomRightFirst;
+        }
+        
+        for (int x = 0; x < parts; x++)
+        {
+            if (!deform)
+            {
+                // Pokud nema dojit k deformaci - rovnomerne rozdeleni.
+                bottomRightAct = leftBottom + x * bottomRight;
+                bottomOneOnRightAct = leftBottom + (x + 1) * bottomRight;
+                topRightAct = leftTop + x * topRight;
+                topOneOnRightAct = leftTop + (x + 1) * topRight;
+            }
+            
+            // Ulozit ctyruhelnik.
+            addTetragon(bottomRightAct, topRightAct, topOneOnRightAct, bottomOneOnRightAct);
+            
+            if (deform)
+            {
+                // Pokud dochazi k deformaci, snizit sirku sloupce, presunout se
+                // na zacatek dalsiho a urcit jeho prave souradnice.
+                
+                topRightAct = topOneOnRightAct;
+                bottomRightAct = bottomOneOnRightAct;
+                
+                topRightFirst -= topRightDiff;
+                bottomRightFirst -= bottomRightDiff;
+                
+                topOneOnRightAct += topRightFirst;
+                bottomOneOnRightAct += bottomRightFirst;
+            }
+        }
+    }
+}
+
+void Wall::addTetragon(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d)
+{
+    // Obecny ctyruhelnik - mapovani na souradnice textury (souradnice UV).
+    //    b [0,1]
+    //         c [1,1]
+    //  a [0,0]    d [1,0]
+    
+    QVector3D n = normal(a, d, b);
+    
+    // Pro kazdy vrchol upravovat ukladanou kategorii (typ prvku), ktera u "zdi"
+    // predstavuje vrchol textury (ctyri vrcholy textury se musi namapovat na
+    // vrcholy ctyruhelnika).
+    category = Element::WALL + 0;
+    addVertex(a, n);
+    category = Element::WALL + 2;
+    addVertex(d, n);
+    category = Element::WALL + 3;
+    addVertex(c, n);
+    category = Element::WALL + 1;
+    addVertex(b, n);
+}
\ No newline at end of file
diff --git a/deltarobot/element/wall.hpp b/deltarobot/element/wall.hpp
new file mode 100644
index 0000000..5c034cf
--- /dev/null
+++ b/deltarobot/element/wall.hpp
@@ -0,0 +1,101 @@
+#ifndef _WALL_HPP
+#define _WALL_HPP
+
+#include "element.hpp"
+
+/// Instance třídy Wall představují vykreslované stěny. Jednotlivé typy stěn mohou
+/// mít jiné textury (viz výčtovy typ TYPE). Stěny se odsadí od křivky podle
+/// poloměru koule a nastaveného atributu ENLARGE. Zvětšení (zmenšení) přední a
+/// zadní stěny mají na starosti atributy SCALING_*. Ke každému typu stěny je
+/// přidělen atribut představující, na kolik částí se má daná stěna rozdělit, resp.
+/// kolikrát se do ní má vykreslit textura, viz atributy *_SPLIT. Kvůli posílení
+/// dojmu hloubky stěn dochází k deformaci i při rozdělovani stěn. Sloupce na
+/// stěnách dále od pozorovatele se zužují. Atribut DEFORM definuje, kolikrát má
+/// být sloupec nejblíže k pozorovateli širší a kolikrát má být sloupec nejdále
+/// od pozorovatele užší. Zužování sloupců pak probíhá lineárně. DEFORMACE PROBÍHÁ
+/// SMĚREM DOPRAVA PRO KAŽDOU STĚNU, JE TEDY NUTNÉ SPRAVNĚ ZADAT VRCHOLY DEFINUJÍCÍ
+/// DANOU STĚNU.
+class Wall: public Element
+{
+    public:
+        /// Pro každý typ jiná textura.
+        enum TYPE
+        {
+            /// Identifikátor podlahy.
+            FLOOR = 0,
+            /// Identifikátor stropu.
+            CEILING,
+            /// Identifikátor stěn.
+            SIDE
+        };
+        
+        /// Pouze nastavuje typ stěny.
+        /// @param const TYPE type - typ stěny.
+        Wall(const TYPE type);
+        
+        /// Funkce pro vytvoření "místnosti".
+        /// @param QVector3D minimum - minimální bod (nejmenší možné souřadnice)
+        ///                            kvádru, ve kterém se nachází křivka.
+        /// @param QVector3D maximum - maximální bod kvádru pro křivku.
+        /// @param float sphereRadius - poloměr koule kvůli odsazení zdi od křivky.
+        void setData(QVector3D minimum, QVector3D maximum, float sphereRadius);
+        
+    protected:
+        /// Překrytá funkce. Před každým uložením bodu se musí změnit typ prvku v
+        /// rodiči. Sice se jedná o stěnu, ale k tomuto identifikátoru se musí
+        /// pridat hodnota představující UV souřadnici rohu textury, abychom pak
+        /// v shaderu mohli napojit texturu na body.
+        /// @param const QVector3D &a - souřadnice prvního vrcholu.
+        /// @param const QVector3D &b - souřadnice druhého vrcholu.
+        /// @param const QVector3D &c - souřadnice třetího vrcholu.
+        /// @param const QVector3D &d - souřadnice ctvrtého vrcholu.
+        void addTetragon(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d);
+        
+    private:
+        /// Kolikrát se ma rozšířit sloupec nejblíže k pozorovateli a kolikrát
+        /// se má zúžit sloupec nejdále od pozorovatele. Deformace je lineární.
+        /// Nastavujte reálnou hodnotu od 0 do 1.
+        static const float DEFORM;
+        
+        /// Jak moc se ma zvětšit stěna blíže k uživateli (přední stěna se sice
+        /// nevykresluje z důvodu zoomování, ale hrany, blíže k uživateli,
+        /// ostatních stěn tvoří jakýsi ctyřúhelník, který představuje neviditelnou
+        /// stěnu). Doporučené hodnoty od 0 do 1.
+        static const float SCALING_FRONT;
+        
+        /// Jak moc má být zmenšena zadní stěna (stěna za křivkou, tj. nejdále od
+        /// pozorovatele). Opět doporučené hodnoty od 0 do 1.
+        static const float SCALING_BACK;
+        
+        /// Na kolik horizontálních a vertikálních částí se má rozdělit podlaha.
+        static const int FLOOR_SPLIT;
+        
+        /// Na kolik horizontálních a vertikálních částí se má rozdělit strop.
+        static const int CEILING_SPLIT;
+        
+        /// Na kolik horizontálních a vertikálních částí se mají rozdělit bočni
+        /// stěny.
+        static const int SIDE_SPLIT;
+        
+        /// Podle poloměru koule k-krát navýšit odsazení stěn od křivky.
+        static const int ENLARGE;
+        
+        /// O jaký typ stěny se jedná.
+        TYPE type;
+        
+        /// Rozděluje stěnu podle toho, kolikrát se do ní má vejít textura.
+        /// Stěna se kromě jednoduchého rozdělení deformuje, aby byla zdůrazněna
+        /// perspektiva. Deformace se vždy provádí do pravé strany čtyřúhelníka!
+        /// Je tedy nutné zadat čtyřúhelník tak, aby se deformace správne provedla.
+        /// @param const QVector3D &a - souřadnice prvního vrcholu čtyřúhelníka.
+        /// @param const QVector3D &b - souřadnice druhého vrcholu čtyřúhelníka.
+        /// @param const QVector3D &c - souřadnice třetího vrcholu čtyřúhelníka.
+        /// @param const QVector3D &d - souřadnice čtvrtého vrcholu čtyřúhelnika.
+        /// @param const int parts - na kolik horizontálních a vertikálních částí
+        ///                          se má stěna rozdelit.
+        /// @param const bool deform - jestli má dojít k deformaci stěny. U zadní
+        ///                            stěny se totiž deformace nesmí provádet.
+        void split(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d, const int parts, const bool deform = true);
+};
+
+#endif
diff --git a/deltarobot/gl/camera.cpp b/deltarobot/gl/camera.cpp
new file mode 100644
index 0000000..4c355a0
--- /dev/null
+++ b/deltarobot/gl/camera.cpp
@@ -0,0 +1,49 @@
+#include "camera.hpp"
+
+const int Camera::MIN_DIST = 1000;
+const int Camera::MAX_DIST = 40000;
+
+Camera::Camera(): QMatrix4x4()
+{
+}
+
+void Camera::set(QVector3D position)
+{
+    this->position = position;
+    this->center = QVector3D(0.0f, 0.0f, 0.0f);
+    lookAt();
+}
+
+void Camera::zoomIn()
+{
+    if (getPosition().length() > MIN_DIST)
+    {
+        position -= getVectorToPosition() * 0.1f;
+        lookAt();
+    }
+}
+
+void Camera::zoomOut()
+{
+    if (getPosition().length() < MAX_DIST)
+    {
+        position += getVectorToPosition() * 0.1f;
+        lookAt();
+    }
+}
+
+QVector3D Camera::getPosition()
+{
+    return position;
+}
+
+QVector3D Camera::getVectorToPosition()
+{
+    return position - center;
+}
+
+void Camera::lookAt()
+{
+    setToIdentity();
+    QMatrix4x4::lookAt(position, center, QVector3D(0.0f, 1.0f, 0.0f));
+}
diff --git a/deltarobot/gl/camera.hpp b/deltarobot/gl/camera.hpp
new file mode 100644
index 0000000..ca126aa
--- /dev/null
+++ b/deltarobot/gl/camera.hpp
@@ -0,0 +1,51 @@
+#ifndef _CAMERA_HPP
+#define _CAMERA_HPP
+
+#include <QMatrix4x4>
+#include <QVector3D>
+
+/// Třída Camera představuje kameru, neboli pohled pozorovatele.
+class Camera: public QMatrix4x4
+{
+    public:
+        /// Konstruktor.
+        /// Prázdný konstruktor.
+        Camera();
+        
+        /// Nastavení pozice kamery v prostoru. Vždy bude směrovat do středu.
+        /// @param QVector3D position - pozice kamery v prostoru.
+        void set(QVector3D position);
+        
+        /// Provede přiblížení kamery ke středu.
+        void zoomIn();
+        
+        /// Provede oddálení kamery od středu.
+        void zoomOut();
+
+        /// Vrátí pozici kamery v prostoru
+        /// @return pozice kamery v prostoru.
+        QVector3D getPosition();
+        
+    private:
+        /// Atribut k určení spodní hranice délky vektoru (pozice kamery).
+        static const int MIN_DIST;
+        
+        /// Atribut k určení horní hranice délky vektoru (pozice kamery).
+        static const int MAX_DIST;
+        
+        /// Pozice kamery v prostoru.
+        QVector3D position;
+        
+        /// Střed, vždy počátek soustavy souřadnic [0, 0, 0].
+        QVector3D center;
+        
+        /// @return vektor od středu do pozice kamery.
+        QVector3D getVectorToPosition();
+        
+        /// Nastaví jednotkovou matici. Vynásobí ji maticí pohledu, která je
+        /// odvozena od bodu, ve kterém se nachází kamera, od směru pohledu a
+        /// od směru nahoru od kamery (vždy [0, 1, 0]).
+        void lookAt();
+};
+
+#endif
diff --git a/deltarobot/gl/scene.cpp b/deltarobot/gl/scene.cpp
new file mode 100644
index 0000000..4879b2e
--- /dev/null
+++ b/deltarobot/gl/scene.cpp
@@ -0,0 +1,534 @@
+#include "scene.hpp"
+
+const int Scene::TRAJECTORY_I = 0;
+const int Scene::SPHERE_I = 1;
+const int Scene::SPHERE_II = 2;
+const int Scene::FIRST_ARROW_I = 3;
+const float Scene::FIRST_ARROW_WIDTH_SCALING = 750.0f;
+const float Scene::SECOND_ARROW_WIDTH_SCALING = 400.0f;
+const QVector3D Scene::MODIFY_LIGHT_POSITION = QVector3D(0, 0, 0);
+const int Scene::ROTATE_REDUCTION = 25;
+
+Scene::Scene(QWidget *parent): QOpenGLWidget(parent)
+{
+    xAngle = 0;
+    yAngle = 0;
+    eyeAngle = 45;
+    shaderProgram = NULL;
+    
+    // Vytvoreni grafickych prvku.
+    elements[TRAJECTORY_I] = (Element *) new Trajectory();
+    elements[SPHERE_I] = (Element *) new Sphere(true);
+    elements[SPHERE_II] = (Element *) new Sphere(false);
+    elements[FIRST_ARROW_I] = (Element *) new Arrow(true);
+    elements[FIRST_ARROW_I + 1] = (Element *) new Arrow(false);
+    elements[FIRST_TYPE_WALL_I] = (Element *) new Wall(Wall::TYPE::FLOOR);
+    elements[FIRST_TYPE_WALL_I + 1] = (Element *) new Wall(Wall::TYPE::CEILING);
+    elements[FIRST_TYPE_WALL_I + 2] = (Element *) new Wall(Wall::TYPE::SIDE);
+    
+    // Cesty k vyuzivanym texturam.
+    texturePath[0] = tr(":/img/floor.png");
+    texturePath[1] = tr(":/img/ceiling_1013.png");
+    texturePath[2] = tr(":/img/tile.png");
+    
+    // Barva pozadi, zde je zbytecne nastavovat alfa kanal.
+    backgroundColor = QVector3D(0.702f, 1, 1);
+    // Barva tubusu predstavujici krivku.
+    colorValues[0] = QVector4D(1, 0.737f, 0.231f, 0.7f);
+    // Barva koule, která se pohybuje.
+    colorValues[1] = QVector4D(0, 0.4f, 1, 0.7f);
+    //Barva statické koule
+    colorValues[2] = QVector4D(0, 0.8f, 0.4f, 0.0f);
+    // Barva prvni (dulezitejsi) krivky.
+    colorValues[3] = QVector4D(0, 1, 0, 1);
+    // Barva druhe (mene dulezite) krivky. Zmena pruhlednosti = zmena alfa kanalu.
+    colorValues[4] = QVector4D(1, 0, 0, 0.75f);
+}
+
+Scene::~Scene()
+{
+    clear();
+    // Uvolnit zbyvajici alokovanou pamet (uz zbyvaji pouze graficke prvky, ktere
+    // jsou vytvoreny na zacatku a vyuzivany po celou dobu behu programu - nejsou
+    // nejak napojeny na jadro OpenGL, hodnoty v techto objektech se vzdy
+    // prekopiruji do celkoveho pole, ktere se pak ulozi do bufferu).
+    for (int i = 0; i < FIRST_TYPE_WALL_I + 3; i++)
+    {
+        delete elements[i];
+    }
+}
+
+void Scene::setCurve(QList<QVector4D> curve)
+{
+    // Vyhledani minimalnich a maximalnich souradnic.
+    QList<QVector3D> curve3d;
+    QVector3D minimum = curve.at(0).toVector3D();
+    QVector3D maximum = curve.at(0).toVector3D();
+    int itemCount = curve.size();
+#if 0
+    for (int i = 1; i < curve.count(); i++)
+    {
+        if (curve.at(i).x() < minimum.x())
+        {
+            minimum.setX(curve.at(i).x());
+        }
+        else if (curve.at(i).x() > maximum.x())
+        {
+            maximum.setX(curve.at(i).x());
+        }
+        if (curve.at(i).y() < minimum.y())
+        {
+            minimum.setY(curve.at(i).y());
+        }
+        else if (curve.at(i).y() > maximum.y())
+        {
+            maximum.setY(curve.at(i).y());
+        }
+        if (curve.at(i).z() < minimum.z())
+        {
+            minimum.setZ(curve.at(i).z());
+        }
+        else if (curve.at(i).z() > maximum.z())
+        {
+            maximum.setZ(curve.at(i).z());
+        }
+    }
+#else
+    //max a min nepocitat podle kriky, ale mit vzdycky maximalni rozsah
+    minimum = QVector3D(-3200,-3200,0);
+    maximum = QVector3D(3200,3200,9000);
+#endif
+
+    // Posunout stred krivky do pocatku soustavy souradnic (kvuli ruznym upravam).
+    // Uchovat stred puvodne umistene krivky kvuli prichozim bodum predstavujici
+    // pozici koule (souradnice tohoto bodu se take musi upravit pro presne zobrazeni).
+    center = Sphere::middlePoint(minimum, maximum);
+    minimum -= center;
+    maximum -= center;
+    curve3d.clear();
+    if (itemCount > MAX_CURVE_SIZE)
+        itemCount = MAX_CURVE_SIZE;
+    for (int i = 0; i < itemCount; i++)
+    {
+        curve3d.append(curve[i].toVector3D() - center);
+    }
+    
+    // Zjisteni a nastaveni optimalni polohy kamery na ose Z.
+    QVector3D marginForTube(Trajectory::MAX_RADIUS, Trajectory::MAX_RADIUS, Trajectory::MAX_RADIUS);
+    QVector3D marginForSphere(Sphere::getMaxRadius(), Sphere::getMaxRadius(), Sphere::getMaxRadius());
+    float tg = tan((eyeAngle / 2) * M_PI / 180);
+    QVector3D heights = QVector3D(maximum + marginForTube + marginForSphere) / tg;
+    camera.set(QVector3D(0, 0, maximum.z() + max(heights.x(), heights.y())));
+    
+    // Nastaveni atributu vykreslovanych objektu.
+    ((Trajectory *) (elements[TRAJECTORY_I]))->setNewCurve(curve3d, minimum.z(), maximum.z());
+    ((Sphere *) (elements[SPHERE_I]))->setRangeZ(minimum.z(), maximum.z());
+#ifdef USE_STATIC_SPHERE
+    ((Sphere *) (elements[SPHERE_II]))->setRangeZ(minimum.z(), maximum.z());
+#else
+    ((Sphere *) (elements[SPHERE_II]))->setRangeZ(0,0);
+    ((Sphere *) (elements[SPHERE_II]))->setPosition(QVector3D(0,0,-3200));
+#endif
+    for (int i = FIRST_TYPE_WALL_I; i < ELEMENT_COUNT; i++)
+    {
+        ((Wall *) (elements[i]))->setData(minimum, maximum, ((Sphere *) (elements[SPHERE_I]))->getMaxRadius());
+    }
+    
+    // Upravit data v bufferu.
+    updateBufferData();
+    
+    // Prenastavit pozici svetla.
+    shaderProgram->bind();
+    shaderProgram->setUniformValue(lightLocation, camera.getPosition() + MODIFY_LIGHT_POSITION);
+    int colorLocation = shaderProgram->uniformLocation("un_Color[0]");
+    shaderProgram->setUniformValue(colorLocation, colorValues[0]);
+    shaderProgram->release();
+    
+    // Vynulovat pripadnou rotaci.
+    setXAngle(0); setYAngle(0);
+    
+    // Vykreslit.
+    update();
+}
+
+void Scene::setSphereData(const QVector3D &position, const QVector3D &fArrow, const QVector3D &sArrow)
+{
+    // Zmenit vektory pro prvni a druhou sipku.
+    firstArrow = fArrow;
+    secondArrow = sArrow;
+    // Zmenit pozici koule.
+    ((Sphere *) (elements[SPHERE_I]))->setPosition(position - center);
+    // Prekreslit scenu.
+    update();
+}
+
+void Scene::setTestSphereData(const QVector3D &position)
+{
+#ifdef USE_STATIC_SPHERE
+    // Zmenit pozici koule.
+    ((Sphere *) (elements[SPHERE_II]))->setPosition(position - center);
+    // Prekreslit scenu.
+    update();
+#endif
+}
+
+QVector3D Scene::getArrow(bool first)
+{
+    return first ? firstArrow : secondArrow;
+}
+
+void Scene::setArrow(bool first, QVector3D vector)
+{
+    first ? firstArrow = vector : secondArrow = vector;
+}
+
+void Scene::setTubusColor(QVector4D color)
+{
+    colorValues[0] = color;
+}
+
+void Scene::addSphereData(QVector3D position, const bool start, const bool finish)
+{
+    QVector3D minimum = QVector3D(-3200,-3200,0);
+    QVector3D maximum = QVector3D(3200,3200,9000);
+
+    // Posunout stred krivky do pocatku soustavy souradnic (kvuli ruznym upravam).
+    // Uchovat stred puvodne umistene krivky kvuli prichozim bodum predstavujici
+    // pozici koule (souradnice tohoto bodu se take musi upravit pro presne zobrazeni).
+    center = Sphere::middlePoint(minimum, maximum);
+    minimum -= center;
+    maximum -= center;
+    //position -= center;
+
+    if (start) {
+        // Zjisteni a nastaveni optimalni polohy kamery na ose Z.
+        QVector3D marginForTube(Trajectory::MAX_RADIUS, Trajectory::MAX_RADIUS, Trajectory::MAX_RADIUS);
+        QVector3D marginForSphere(Sphere::getMaxRadius(), Sphere::getMaxRadius(), Sphere::getMaxRadius());
+        float tg = tan((eyeAngle / 2) * M_PI / 180);
+        QVector3D heights = QVector3D(maximum + marginForTube + marginForSphere) / tg;
+        camera.set(QVector3D(0, 0, maximum.z() + max(heights.x(), heights.y())));
+
+        // Nastaveni atributu vykreslovanych objektu.
+    }
+    ((Trajectory *) (elements[TRAJECTORY_I]))->addNewPointToCurve(position, start, finish);
+    if (start) {
+        ((Sphere *) (elements[SPHERE_I]))->setRangeZ(minimum.z(), maximum.z());
+        ((Sphere *) (elements[SPHERE_II]))->setRangeZ(minimum.z(), maximum.z());
+        for (int i = FIRST_TYPE_WALL_I; i < ELEMENT_COUNT; i++)
+        {
+            ((Wall *) (elements[i]))->setData(minimum, maximum, ((Sphere *) (elements[SPHERE_I]))->getMaxRadius());
+        }
+    }
+
+    // Upravit data v bufferu.
+    updateBufferData();
+
+    // Prenastavit pozici svetla.
+    shaderProgram->bind();
+    shaderProgram->setUniformValue(lightLocation, camera.getPosition() + MODIFY_LIGHT_POSITION);
+    int colorLocation = shaderProgram->uniformLocation("un_Color[0]");
+    shaderProgram->setUniformValue(colorLocation, colorValues[0]);
+    shaderProgram->release();
+
+    // Vynulovat pripadnou rotaci.
+    setXAngle(0); setYAngle(0);
+
+    // Vykreslit.
+    update();
+}
+
+QSize Scene::minimumSizeHint() const
+{
+    return QSize(100, 100);
+}
+
+QSize Scene::sizeHint() const
+{
+    return QSize(500, 500);
+}
+
+void Scene::initializeGL()
+{
+    // V prubehu chodu aplikace muze dojit ke zruseni sceny a k jejimu opetovnemu
+    // vytvoreni (opetovnemu zavolani initializeGL()). Proto je vhodne po sobe
+    // uklidit v pripade teto nastale udalosti.
+    QObject::connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(clear()));
+    
+    // Vytvoreni GLSL podprogramu. Pridani zdrojovych souboru a napojeni attribute
+    // promennych na hodnoty, ktere budou vyuzivany pri mapovani hodnot.
+    shaderProgram = new QOpenGLShaderProgram();
+    shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/glsl/shader.vert");
+    shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/glsl/shader.frag");
+    shaderProgram->bindAttributeLocation("vertex", 0);
+    shaderProgram->bindAttributeLocation("normal", 1);
+    shaderProgram->bindAttributeLocation("group", 2);
+    shaderProgram->link();
+    
+    shaderProgram->bind();
+    
+    // Vytvoreni textur a pocatecni inicializace uniform atributu TEXTURE.
+    for (int i = 0; i < TEXTURE_COUNT; i++)
+    {
+        textures[i] = new QOpenGLTexture(QImage(texturePath[i]).mirrored());
+    }
+    shaderProgram->setUniformValue("texture", 0);
+    
+    // Zjisteni lokaci ostatnich uniform atributu.
+    projectionLocation = shaderProgram->uniformLocation("un_Projection");
+    lightLocation = shaderProgram->uniformLocation("un_Light");
+    for (int i = 0; i < FIRST_TYPE_WALL_I; i++)
+    {
+        normalLocations[i] = shaderProgram->uniformLocation(QString("un_Normal[%1]").arg(i));
+        mvLocations[i] = shaderProgram->uniformLocation(QString("un_ModelView[%1]").arg(i));
+        
+        // U barev rovnou nastavit i obsah promennych.
+        int colorLocation = shaderProgram->uniformLocation(QString("un_Color[%1]").arg(i));
+        shaderProgram->setUniformValue(colorLocation, colorValues[i]);
+    }
+    
+    // Pocatecni inicializace pozice svetla a spusteni shader programu.
+    shaderProgram->setUniformValue(lightLocation, QVector3D(0, 0, 0));
+    shaderProgram->release();
+    
+    // Pro jistotu, manualni vytvoreni pole pro vrcholy a spojeni se scenou.
+    vao.create();
+    QOpenGLVertexArrayObject::Binder vaoBinder(&vao);
+    
+    // Vytvoreni buffer pro vrcholy.
+    buffer.create();
+    buffer.bind();
+    
+    // Namapovani hodnot z bufferu na attribute promenne v shaderu.
+    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
+    f->glEnableVertexAttribArray(0);
+    f->glEnableVertexAttribArray(1);
+    f->glEnableVertexAttribArray(2);
+    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, Element::DATA_COUNT_FOR_VERTEX * sizeof(GLfloat), reinterpret_cast<void *>(0 * sizeof(GLfloat)));
+    f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, Element::DATA_COUNT_FOR_VERTEX * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
+    f->glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, Element::DATA_COUNT_FOR_VERTEX * sizeof(GLfloat), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
+    buffer.release();
+    
+    // Nastaveni vykreslovacich modu.
+    glEnable(GL_DEPTH_TEST);
+    glEnable(GL_CULL_FACE);
+    glEnable(GL_MULTISAMPLE); // Anti-aliasing (s QSurfaceFormat::setSamples(4)).
+    glEnable(GL_BLEND); // Pruhlednost.
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void Scene::paintGL()
+{
+    QOpenGLVertexArrayObject::Binder vaoBinder(&vao);
+    shaderProgram->bind();
+    
+    // Nastaveni zmenenych globalnich promennych shaderum.
+    shaderProgram->setUniformValue(projectionLocation, projection);
+    for (int i = 0; i < FIRST_TYPE_WALL_I; i++)
+    {
+        shaderProgram->setUniformValue(normalLocations[i], worlds[i].normalMatrix());
+        shaderProgram->setUniformValue(mvLocations[i], camera * worlds[i]);
+
+        // U vsech vykreslovanych prvku nastavit globalni rotaci.
+        worlds[i].setToIdentity();
+        worlds[i].rotate(xAngle / (float) ROTATE_REDUCTION, QVector3D(1, 0, 0));
+        worlds[i].rotate(yAngle / (float) ROTATE_REDUCTION, QVector3D(0, 1, 0));
+        
+        if (i > TRAJECTORY_I)
+        {
+            float sphereScaling;
+            if (i == SPHERE_II) {
+                worlds[i].translate(((Sphere *) (elements[SPHERE_II]))->getPosition());
+                sphereScaling = ((Sphere *) elements[SPHERE_II])->getCurrentScaling();
+            } else {
+                // Jak pro kouli, tak pro sipky, provest posunuti do nastaveneho bodu.
+                worlds[i].translate(((Sphere *) (elements[SPHERE_I]))->getPosition());
+                sphereScaling = ((Sphere *) elements[SPHERE_I])->getCurrentScaling();
+            }
+            
+            if (i == SPHERE_I)
+            {
+                // Pro kouli provest danou zmenu meritka.
+                worlds[i].scale(sphereScaling);
+            } else if (i == SPHERE_II) {
+                worlds[i].scale(sphereScaling);
+            } else {
+                QVector3D top = QVector3D(0, 1, 0);
+                
+                QVector3D arrow;
+                float arrowScaling;
+                if (i == FIRST_ARROW_I)
+                {
+                    arrow = firstArrow;
+                    arrowScaling = FIRST_ARROW_WIDTH_SCALING;
+                }
+                else
+                {
+                    arrow = secondArrow;
+                    arrowScaling = SECOND_ARROW_WIDTH_SCALING;
+                }
+                
+                // Pro obe sipky urcit, podle jakeho vektoru ma byt provedena
+                // rotace, o jaky uhel maji byt orotovany a podle velikosti
+                // vektoru nastavit i zmenu meritka.
+                float angle = acos(QVector3D::dotProduct(arrow, top) / (arrow.length() * top.length())) * 180 / M_PI;
+                QVector3D normal = QVector3D::crossProduct(top, arrow);
+                worlds[i].rotate(angle, normal);
+                worlds[i].scale(sphereScaling * arrowScaling, sphereScaling * arrow.length(), sphereScaling * arrowScaling);
+            }
+        }
+    }
+    
+    // Nastavit kam ma byt provedeno vykreslovani a vycistit 3D scenu.
+    glViewport(0, 0, width(), height());
+    glClearColor(backgroundColor.x(), backgroundColor.y(), backgroundColor.z(), 1);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    
+    if (((Trajectory *) elements[TRAJECTORY_I])->isSet())
+    {
+        // Pomocna promenna pro urceni pocatecnich indexu vykreslovacich komponent.
+        int vertCount = 0;
+
+        // Vykresleni vsech grafickych prvku az na zdi.
+        int i;
+        int auxVertexCount = 0;
+        bool sphereIsSet = ((Sphere *) elements[SPHERE_I])->isSet();
+        //bool staticSphereIsSet = ((Sphere *) elements[SPHERE_II])->isSet();
+        for (i = 0; i < FIRST_TYPE_WALL_I; i++)
+        {
+            vertCount += elements[i]->vertexCount();
+            if (!sphereIsSet && i > 0)
+            {
+                auxVertexCount += elements[i]->vertexCount();
+            }
+        }
+        // Pokud neni nastavena pozice pro kouli a sipky, vykreslit pouze trajektorii.
+        glDrawArrays(GL_TRIANGLES, 0, vertCount - auxVertexCount);
+
+        // Vykresleni zdi, stropu a podlah.
+        for (int j = 0; j < TEXTURE_COUNT; j++, i++)
+        {
+            textures[j]->bind();
+            glDrawArrays(GL_QUADS, vertCount, elements[i]->vertexCount());
+            vertCount += elements[i]->vertexCount();
+        }
+    }
+
+    shaderProgram->release();
+    buffer.release();
+}
+
+void Scene::resizeGL(int w, int h)
+{
+    // Nastavit matici projekce pri kazde zmene velikosti okna.
+    projection.setToIdentity();
+    projection.perspective(eyeAngle, w / (float) h, 1, 40000);
+}
+
+void Scene::mousePressEvent(QMouseEvent *event)
+{
+    // Pri kazdem stisknuti tlacitka ulozit, kde je kurzor (kvuli otaceni).
+    lastPosition = event->pos();
+}
+
+void Scene::mouseMoveEvent(QMouseEvent *event)
+{
+    if (event->buttons() == Qt::LeftButton || event->buttons() == Qt::RightButton)
+    {
+        // Pro obe tlacitka otacet stejne, konkretne podle osy X a Y.
+        int dx = event->x() - lastPosition.x();
+        int dy = event->y() - lastPosition.y();
+        lastPosition = event->pos();
+        setXAngle(xAngle + 5 * dy);
+        setYAngle(yAngle + 5 * dx);
+        update();
+    }
+}
+
+void Scene::wheelEvent(QWheelEvent *e)
+{
+    // Pri pohybu kolecka na mysi priblizovat ci oddalovat scenu (resp. kameru
+    // k/od pocatku soustavy souradnic).
+    if (e != NULL)
+    {
+        if (e->delta() > 0)
+        {
+            camera.zoomOut();
+        }
+        else
+        {
+            camera.zoomIn();
+        }
+    }
+}
+
+void Scene::updateBufferData()
+{
+    int resultDataCount = 0;
+    for (int i = 0; i < ELEMENT_COUNT; i++)
+    {
+        resultDataCount += elements[i]->dataCount();
+    }
+    
+    // Vytvoreni pole s hodnotami pro vsechny vykreslovane prvky.
+    GLfloat *resultData = new GLfloat[resultDataCount];
+    int resultDataIndex = 0;
+    for (int i = 0; i < ELEMENT_COUNT; i++)
+    {
+        const GLfloat *data = elements[i]->getData();
+        for (int j = 0; j < elements[i]->dataCount(); j++)
+        {
+            resultData[resultDataIndex++] = data[j];
+        }
+    }
+    
+    // Prenastavit obsah bufferu.
+    buffer.bind();
+    buffer.allocate(resultData, resultDataCount * sizeof(GLfloat));
+    delete[] resultData;
+}
+
+void Scene::setXAngle(int angle)
+{
+    angle %= 360 * ROTATE_REDUCTION;
+    
+    if (angle != xAngle)
+    {
+        xAngle = angle;
+    }
+}
+
+void Scene::setYAngle(int angle)
+{
+    angle %= 360 * ROTATE_REDUCTION;
+    
+    if (angle != yAngle)
+    {
+        yAngle = angle;
+    }
+}
+
+void Scene::clear()
+{
+    if (shaderProgram != NULL)
+    {
+        makeCurrent();
+        
+        // Zruseni vytvoreneho bufferu pro data pro vrcholy.
+        // Uvolneni pameti od alokovaneho pole pro vsechny hodnoty vsech vrcholu
+        // viz updateBufferData().
+        buffer.destroy();
+        
+        // Zruseni GLSL podprogramu.
+        delete shaderProgram;
+        shaderProgram = NULL;
+        
+        // Vycisteni pameti od alokovanych textur.
+        for (int i = 0; i < TEXTURE_COUNT; i++)
+        {
+            textures[i]->destroy();
+            textures[i] = NULL;
+        }
+        
+        doneCurrent();
+    }
+}
diff --git a/deltarobot/gl/scene.hpp b/deltarobot/gl/scene.hpp
new file mode 100644
index 0000000..15a4878
--- /dev/null
+++ b/deltarobot/gl/scene.hpp
@@ -0,0 +1,208 @@
+#ifndef _SCENE_HPP
+#define _SCENE_HPP
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions>
+#include <QOpenGLVertexArrayObject>
+#include <QOpenGLBuffer>
+#include <QOpenGLShaderProgram>
+#include <QOpenGLTexture>
+#include <QVector4D>
+#include <QMatrix4x4>
+#include <QMouseEvent>
+#include <QWheelEvent>
+
+#include "camera.hpp"
+#include "../element/trajectory.hpp"
+#include "../element/sphere.hpp"
+#include "../element/arrow.hpp"
+#include "../element/wall.hpp"
+
+/// Instance třídy představuje vykreslovanou 3D scénu.
+class Scene: public QOpenGLWidget
+{
+    Q_OBJECT
+    
+    public:
+        /// Konstruktor.
+        /// Vytvoření instancí vykreslovaných prvků, nastavení cest k texturám,
+        /// nastavení barev a inicializace dalších instančních atributů.
+        /// @param QWidget *parent - reference na rodiče.
+        Scene(QWidget *parent = 0);
+
+        /// Destruktor.
+        /// Uvolení alokované paměti.
+        ~Scene();
+        
+        /// Nastavení křivky. Zjištění rozsahu souřadnic a jejich středu. Podle
+        /// středu pak provedeno posunutí do počátku soustavy souřadnic. Nastavení
+        /// hodnot pro dráhu, kouli a zdi. Změna kamery, pozice světla. Vynulování
+        /// rotace.
+        /// @param QList<QVector4D> curve - seznam bodů definující křivku.
+        void setCurve(QList<QVector4D> curve);
+        
+        /// Nastaveni pozice koule a vektoru pro obě šipky.
+        /// @param const QVector3D &position - pozice koule.
+        /// @param const QVector3D &fArrow - vektor pro první (důležitějši) šipku.
+        /// @param const QVector3D &sArrow - vektor pro druhou šipku.
+        void setSphereData(const QVector3D &position, const QVector3D &fArrow, const QVector3D &sArrow);
+
+        void setTestSphereData(const QVector3D &position);
+        
+        /// @return vektor definující danou šipku.
+        /// @param bool first - jestli se má vrátit vektor první nebo druhé šipky.
+        QVector3D getArrow(bool first);
+        
+        /// Nastavi dane šipce její vektor.
+        /// @param bool first - jestli se má vektor nastavit první šipce.
+        /// @param QVector3D vector - vektor šipky.
+        void setArrow(bool first, QVector3D vector);
+
+        /// Nastavení barvy křivky.
+        void setTubusColor(QVector4D color);
+
+        /// Nastavení dalšího bodu křivky.
+        /// Přidá další bod do křivky.
+        /// @param position QVector3D position - pozice dalšího bodu
+        /// @param bool start - příznak prvního bodu křivky
+        /// @param bool finish - příznak posledního bodu křivky
+        void addSphereData(QVector3D position, const bool start, const bool finish);
+
+    protected:
+        // Protected funkce jsou vsechny prekryte, detailni komentare naleznete
+        // v QT dokumentaci.
+        
+        // Minimální velikost okna 100x100.
+        QSize minimumSizeHint() const override;
+        
+        // Defaultní velikost okna 500x500.
+        QSize sizeHint() const override;
+        
+        // Inicializace OpenGL scény.
+        void initializeGL() override;
+        
+        // Vykresleni (prekresleni) sceny.
+        void paintGL() override;
+        
+        // Zmena velikost OpenGL sceny.
+        void resizeGL(int width, int height) override;
+        
+        // Pri stisknuti tlacitka zapamatovat jeho souradnici kvuli globalni rotaci.
+        void mousePressEvent(QMouseEvent *event) override;
+        
+        // Pri pohybu mysi provest rotaci podle osy X a Y.
+        void mouseMoveEvent(QMouseEvent *event) override;
+        
+        // Pri pohybu koleckem mysi provest problizeni/oddaleni sceny (kamery).
+        void wheelEvent(QWheelEvent *e) override;
+        
+    private:
+        /// Index v poli ELEMENTS, kde se nachází dráha.
+        static const int TRAJECTORY_I;
+        
+        /// Index v poli ELEMENTS, kde se nachází koule.
+        static const int SPHERE_I;
+        static const int SPHERE_II;
+
+        /// Index v poli ELEMENTS, kde se nachází první šipka.
+        static const int FIRST_ARROW_I;
+        
+        /// Jak široká má být první šipka (resp. jak moc se má změnit měřítko pro
+        /// tloušťku šipky).
+        static const float FIRST_ARROW_WIDTH_SCALING;
+        
+        /// Jak široká má být druhá šipka (resp. jak moc se má změnit měřítko pro
+        /// tloušťku šipky).
+        static const float SECOND_ARROW_WIDTH_SCALING;
+        
+        /// Světlo se defaultně umistujě na pozici kamery, tento atribut umožňuje
+        /// jeho posunutí v závislosti na pozici kamery (čím blíže k počátku
+        /// soustavy souřadnic, tím menší osvětlení).
+        static const QVector3D MODIFY_LIGHT_POSITION;
+        
+        /// Atribut sloužící pro zmenšení nastavených úhlů pro rotaci kolem X a Y.
+        static const int ROTATE_REDUCTION;
+        
+        /// Kamera pohledu představující matici pohledu.
+        Camera camera;
+        
+        /// O kolik stupňů se ma provést rotace podle osy X a Y.
+        int xAngle, yAngle;
+        
+        /// Poslední pozice kurzoru (když uživatel stiskne tlačítko myši).
+        QPoint lastPosition;
+        
+        /// Kolik prvků bude vykreslováno a vytvořeni pole referencí pro tyto prvky.
+        static const int ELEMENT_COUNT = 8;
+        /// Kolik prvků bude vykreslováno a vytvořeni pole referencí pro tyto prvky.
+        Element *elements[ELEMENT_COUNT];
+        
+        /// Kolik bude využíváno textur, vytvoření pole referencí pro tyto textury
+        /// a vytvoření pole pro cesty k texturám.
+        static const int TEXTURE_COUNT = 3;
+        /// Kolik bude využíváno textur, vytvoření pole referencí pro tyto textury
+        /// a vytvoření pole pro cesty k texturám.
+        QOpenGLTexture *textures[TEXTURE_COUNT];
+        /// Kolik bude využíváno textur, vytvoření pole referencí pro tyto textury
+        /// a vytvoření pole pro cesty k texturám.
+        QString texturePath[TEXTURE_COUNT];
+        
+        /// Pole pro vrcholy grafických prvků.
+        QOpenGLVertexArrayObject vao;
+        /// Pameť pro hodnoty týkajících se vrcholů grafických prvků.
+        QOpenGLBuffer buffer;
+        /// GLSL podprogram.
+        QOpenGLShaderProgram *shaderProgram;
+        
+        /// Atributy pro lokaci uniform (globálních) proměnných v shader programu.
+        /// Kromě klasických atributů se vytváří i pole, protože pro každý grafický
+        /// prvek (az na zdi) potřebujeme znát lokaci atributu představující jeho
+        /// vlastní normálovou a model-view matici.
+        /**@{*/
+        static const int FIRST_TYPE_WALL_I = 5; // Index prvni zdi (v seznamu prvku jsou nakonci).
+        int projectionLocation; // Lokace uniform atributu matice projekce.
+        int lightLocation; // Lokace uniform atributu svetla.
+        int normalLocations[FIRST_TYPE_WALL_I]; // Pro pro normalove matice.
+        int mvLocations[FIRST_TYPE_WALL_I]; // Pole pro model-view matice.
+        /**@}*/
+        
+        /// Barvy využívané při vykreslování.
+        /**@{*/
+        QVector3D backgroundColor; // Barva pozadi cele sceny.
+        QVector4D colorValues[FIRST_TYPE_WALL_I]; // Barvy pro vsechny graficke prvky.
+        /**@}*/
+
+        /// Zorný ůhel na grafickou scénu.
+        float eyeAngle;
+        
+        /// Matice projekce.
+        QMatrix4x4 projection;
+        
+        /// Matice pro celou scénu, kterými nastavuje rotaci, posunutí, apod.
+        QMatrix4x4 worlds[FIRST_TYPE_WALL_I];
+        
+        /// Vektory šipek.
+        QVector3D firstArrow, secondArrow;
+        
+        /// Vektor středu původní křivky (než se posunula do počátku soustavy souřadnic).
+        QVector3D center;
+        
+        /// Přenastaví data v bufferu. Využíváno, když se změní data grafických
+        /// prvků.
+        void updateBufferData();
+        
+        /// Nastaví daný počet stupňů atributu XANGLE.
+        /// @param int angle - o kolik má být provedena rotace podle osy X.
+        void setXAngle(int angle);
+        
+        /// Nastaví daný počet stupňů atributu YANGLE.
+        /// @param int angle - o kolik má být provedena rotace podle osy Y.
+        void setYAngle(int angle);
+        
+    private slots:
+        /// Vyčištění paměti od bufferu s hodnotami pro vrcholy a uvolnění
+        /// paměti od vytvořeného GLSL podprogramu.
+        void clear();
+};
+
+#endif
diff --git a/deltarobot/glsl/shader.frag b/deltarobot/glsl/shader.frag
new file mode 100644
index 0000000..936c0d6
--- /dev/null
+++ b/deltarobot/glsl/shader.frag
@@ -0,0 +1,30 @@
+// Textura.
+uniform sampler2D texture;
+
+// Typ grafickeho prvku, ktery je sdilen s VERTEX casti shader programu.
+varying float v_Group;
+// Intezita svetla pro dany vrchol.
+varying float v_Light;
+// Barva daneho vrcholu.
+varying vec4 v_Color;
+// Jaka UV souradnice odpovida danemu vrcholu (pouze u group >= 4, coz jsou zdi).
+varying vec2 v_Coord;
+
+// Pri kazdem prekresleni se zavola pro kazdy pixel.
+void main()
+{
+    // Hodnota v_Group se pohybuje kolem nastavene konstanty.
+    vec4 color;
+    if (abs(v_Group - 5.0) < 0.00001)
+    {
+        // Zjistit barvu daneho rohu textury.
+        color = texture2D(texture, v_Coord);
+    }
+    else
+    {
+        color = v_Color;
+    }
+    
+    // Zduraznit osvetleni a urcit finalni barvu pixelu.
+    gl_FragColor = vec4(clamp(color.xyz * 0.4 + color.xyz * 0.6 * v_Light, 0.0, 1.0), color.w);
+}
diff --git a/deltarobot/glsl/shader.vert b/deltarobot/glsl/shader.vert
new file mode 100644
index 0000000..cbc5c1f
--- /dev/null
+++ b/deltarobot/glsl/shader.vert
@@ -0,0 +1,48 @@
+// Matice projekce.
+uniform mat4 un_Projection;
+// Pozice svetla.
+uniform vec3 un_Light;
+// Model-view matice pro kazdy graficky prvek (az na zdi, pro ty se matice shoduji
+// s matici trajektorie).
+uniform mat4 un_ModelView[5];
+// Normalova matice pro kazdy graficky prvek (az na zdi).
+uniform mat3 un_Normal[5];
+// Barvy pro kazdy graficky prvek (az na zdi, u tech je barva urcena texturou).
+uniform vec4 un_Color[5];
+
+// Souradnice vrcholu.
+attribute vec3 vertex;
+// Normala pridelena k danemu vrcholu.
+attribute vec3 normal;
+// K jakemu grafickemu prvku vrchol patri.
+attribute float group;
+
+// Typ grafickeho prvku, ktery je sdilen s FRAGMENT casti shader programu.
+varying float v_Group;
+// Intezita svetla pro dany vrchol.
+varying float v_Light;
+// Barva daneho vrcholu.
+varying vec4 v_Color;
+// Jaka UV souradnice textury odpovida danemu vrcholu (pouze u group >= 4, coz
+// jsou zdi).
+varying vec2 v_Coord;
+
+// Pri kazdem prekresleni se zavola pro kazdy vrchol.
+void main()
+{
+    v_Group = group;
+    if (v_Group >= 5.0)
+    {
+        int corner = int(v_Group) - 5; // O jaky roh textury jde.
+        v_Coord = vec2(corner == 2 || corner == 3, corner == 1 || corner == 3);
+        v_Group = 5.0; // Pro vsechny zdi stejna pravidla (az na barvy).
+    }
+    
+    // a mod b = a - (b * floor(a/b))
+    int index = int(v_Group) - (5 * int(floor(v_Group / 5.0))); // 5 = zed - bez jakychkoli uprav, stejne jako 0 = trajektorie.
+    v_Light = max(dot(normalize(un_Normal[index] * normal), normalize(un_Light - vertex)), 0.0);
+    v_Color = un_Color[index];
+    
+    // Vysledna pozice (pixel).
+    gl_Position = un_Projection * un_ModelView[index] * vec4(vertex, 1.0);
+}
diff --git a/deltarobot/img/ceiling.png b/deltarobot/img/ceiling.png
new file mode 100644
index 0000000..8e21492
Binary files /dev/null and b/deltarobot/img/ceiling.png differ
diff --git a/deltarobot/img/ceiling_1013.png b/deltarobot/img/ceiling_1013.png
new file mode 100644
index 0000000..503fe63
Binary files /dev/null and b/deltarobot/img/ceiling_1013.png differ
diff --git a/deltarobot/img/ceiling_1015.png b/deltarobot/img/ceiling_1015.png
new file mode 100644
index 0000000..69c10e0
Binary files /dev/null and b/deltarobot/img/ceiling_1015.png differ
diff --git a/deltarobot/img/ceiling_7035.png b/deltarobot/img/ceiling_7035.png
new file mode 100644
index 0000000..6b99fe4
Binary files /dev/null and b/deltarobot/img/ceiling_7035.png differ
diff --git a/deltarobot/img/floor.png b/deltarobot/img/floor.png
new file mode 100644
index 0000000..e08a376
Binary files /dev/null and b/deltarobot/img/floor.png differ
diff --git a/deltarobot/img/if_rotate-ccw.png b/deltarobot/img/if_rotate-ccw.png
new file mode 100644
index 0000000..a56cfc8
Binary files /dev/null and b/deltarobot/img/if_rotate-ccw.png differ
diff --git a/deltarobot/img/if_rotate-cw.png b/deltarobot/img/if_rotate-cw.png
new file mode 100644
index 0000000..2e59b4d
Binary files /dev/null and b/deltarobot/img/if_rotate-cw.png differ
diff --git a/deltarobot/img/tile.png b/deltarobot/img/tile.png
new file mode 100644
index 0000000..09484fc
Binary files /dev/null and b/deltarobot/img/tile.png differ
diff --git a/deltarobot/img/up-down.png b/deltarobot/img/up-down.png
new file mode 100644
index 0000000..6253143
Binary files /dev/null and b/deltarobot/img/up-down.png differ
diff --git a/deltarobot/infodialog.cpp b/deltarobot/infodialog.cpp
new file mode 100644
index 0000000..1f2ed7c
--- /dev/null
+++ b/deltarobot/infodialog.cpp
@@ -0,0 +1,45 @@
+#include "infodialog.h"
+#include "ui_infodialog.h"
+
+infoDialog::infoDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::infoDialog)
+{
+    ui->setupUi(this);
+    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(accept()));
+}
+
+infoDialog::~infoDialog()
+{
+    delete ui;
+}
+
+//! Nastavení textu v dialogu
+/*!
+  Nastavení zadaného textu jak do hlavičky, tak do těla dialogu
+  \param title Text, který se zobrazí v hlavičce dialogu
+  \param infoText Text, který se objeví v těle dialogu
+*/
+void infoDialog::setInfoText(QString title, QString infoText)
+{
+    setWindowTitle(title);
+    ui->infoText->setText(infoText);
+}
+
+//! Změna jazyka dialogu
+/*!
+  Pokud se změní jazyk aplikace, funkce změní text v dialogu, aby odpovídal
+  nastavenému jazyku
+  \param *e Ukazatel na objekt, který obsahuje posílanou událost
+*/
+void infoDialog::changeEvent(QEvent *e)
+{
+    QDialog::changeEvent(e);
+    switch (e->type()) {
+    case QEvent::LanguageChange:
+        ui->retranslateUi(this);
+        break;
+    default:
+        break;
+    }
+}
diff --git a/deltarobot/infodialog.h b/deltarobot/infodialog.h
new file mode 100644
index 0000000..edbfbda
--- /dev/null
+++ b/deltarobot/infodialog.h
@@ -0,0 +1,43 @@
+#ifndef INFODIALOG_H
+#define INFODIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class infoDialog;
+}
+
+//!  Třída pro zobrazování uživatelských informací a upozornění
+/*!
+  Třída slouží pro zobrazování uživatelských informací a upozornění
+*/
+
+class infoDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    //! Konstruktor.
+    /*!
+      V kostruktoru se inicializuje UI
+    */
+    explicit infoDialog(QWidget *parent = nullptr);
+    //! Destruktor.
+    /*!
+      Slouží pro správné ukončení dialogu
+    */
+    ~infoDialog();
+    void setInfoText(QString title, QString infoText);
+
+protected:
+    void changeEvent(QEvent *e);
+
+private:
+    //! Ukazatel na UI
+    /*!
+      Ukazatel na vytvořené uživatelské rozhraní
+    */
+    Ui::infoDialog *ui;
+};
+
+#endif // INFODIALOG_H
diff --git a/deltarobot/infodialog.ui b/deltarobot/infodialog.ui
new file mode 100644
index 0000000..b7a5484
--- /dev/null
+++ b/deltarobot/infodialog.ui
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>infoDialog</class>
+ <widget class="QDialog" name="infoDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="infoText">
+     <property name="font">
+      <font>
+       <pointsize>14</pointsize>
+      </font>
+     </property>
+     <property name="frameShape">
+      <enum>QFrame::Box</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignHCenter|Qt::AlignTop</set>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QPushButton" name="pushButton">
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>50</height>
+      </size>
+     </property>
+     <property name="font">
+      <font>
+       <pointsize>14</pointsize>
+      </font>
+     </property>
+     <property name="text">
+      <string>OK</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/deltarobot/libQsLog/.gitignore b/deltarobot/libQsLog/.gitignore
new file mode 100644
index 0000000..6fdeb0e
--- /dev/null
+++ b/deltarobot/libQsLog/.gitignore
@@ -0,0 +1,2 @@
+*.pro.user
+build-*
diff --git a/deltarobot/libQsLog/LICENSE.txt b/deltarobot/libQsLog/LICENSE.txt
new file mode 100644
index 0000000..af90342
--- /dev/null
+++ b/deltarobot/libQsLog/LICENSE.txt
@@ -0,0 +1,24 @@
+Copyright (c) 2014, Razvan Petru
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+* The name of the contributors may not be used to endorse or promote products
+  derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/deltarobot/libQsLog/QsLog.cpp b/deltarobot/libQsLog/QsLog.cpp
new file mode 100644
index 0000000..a9d56a0
--- /dev/null
+++ b/deltarobot/libQsLog/QsLog.cpp
@@ -0,0 +1,279 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "QsLog.h"
+#include "QsLogDest.h"
+#ifdef QS_LOG_SEPARATE_THREAD
+#include <QThreadPool>
+#include <QRunnable>
+#endif
+#include <QMutex>
+#include <QVector>
+#include <QDateTime>
+#include <QtGlobal>
+#include <cstdlib>
+#include <stdexcept>
+
+namespace QsLogging
+{
+typedef QVector<DestinationPtr> DestinationList;
+
+static const char TraceString[] = "TRACE";
+static const char DebugString[] = "DEBUG";
+static const char InfoString[]  = "INFO ";
+static const char WarnString[]  = "WARN ";
+static const char ErrorString[] = "ERROR";
+static const char FatalString[] = "FATAL";
+
+// not using Qt::ISODate because we need the milliseconds too
+static const QString fmtDateTime("yyyy-MM-ddThh:mm:ss.zzz");
+
+static Logger* sInstance = 0;
+
+static const char* LevelToText(Level theLevel)
+{
+    switch (theLevel) {
+        case TraceLevel:
+            return TraceString;
+        case DebugLevel:
+            return DebugString;
+        case InfoLevel:
+            return InfoString;
+        case WarnLevel:
+            return WarnString;
+        case ErrorLevel:
+            return ErrorString;
+        case FatalLevel:
+            return FatalString;
+        case OffLevel:
+            return "";
+        default: {
+            Q_ASSERT(!"bad log level");
+            return InfoString;
+        }
+    }
+}
+
+#ifdef QS_LOG_SEPARATE_THREAD
+class LogWriterRunnable : public QRunnable
+{
+public:
+    LogWriterRunnable(QString message, Level level);
+    virtual void run();
+
+private:
+    QString mMessage;
+    Level mLevel;
+};
+#endif
+
+class LoggerImpl
+{
+public:
+    LoggerImpl();
+
+#ifdef QS_LOG_SEPARATE_THREAD
+    QThreadPool threadPool;
+#endif
+    QMutex logMutex;
+    Level level;
+    DestinationList destList;
+    bool includeTimeStamp;
+    bool includeLogLevel;
+};
+
+#ifdef QS_LOG_SEPARATE_THREAD
+LogWriterRunnable::LogWriterRunnable(QString message, Level level)
+    : QRunnable()
+    , mMessage(message)
+    , mLevel(level)
+{
+}
+
+void LogWriterRunnable::run()
+{
+    Logger::instance().write(mMessage, mLevel);
+}
+#endif
+
+
+LoggerImpl::LoggerImpl()
+    : level(InfoLevel)
+    , includeTimeStamp(true)
+    , includeLogLevel(true)
+{
+    // assume at least file + console
+    destList.reserve(2);
+#ifdef QS_LOG_SEPARATE_THREAD
+    threadPool.setMaxThreadCount(1);
+    threadPool.setExpiryTimeout(-1);
+#endif
+}
+
+
+Logger::Logger()
+    : d(new LoggerImpl)
+{
+}
+
+Logger& Logger::instance()
+{
+    if (!sInstance)
+        sInstance = new Logger;
+
+    return *sInstance;
+}
+
+void Logger::destroyInstance()
+{
+    delete sInstance;
+    sInstance = 0;
+}
+
+// tries to extract the level from a string log message. If available, conversionSucceeded will
+// contain the conversion result.
+Level Logger::levelFromLogMessage(const QString& logMessage, bool* conversionSucceeded)
+{
+    if (conversionSucceeded)
+        *conversionSucceeded = true;
+
+    if (logMessage.startsWith(QLatin1String(TraceString)))
+        return TraceLevel;
+    if (logMessage.startsWith(QLatin1String(DebugString)))
+        return DebugLevel;
+    if (logMessage.startsWith(QLatin1String(InfoString)))
+        return InfoLevel;
+    if (logMessage.startsWith(QLatin1String(WarnString)))
+        return WarnLevel;
+    if (logMessage.startsWith(QLatin1String(ErrorString)))
+        return ErrorLevel;
+    if (logMessage.startsWith(QLatin1String(FatalString)))
+        return FatalLevel;
+
+    if (conversionSucceeded)
+        *conversionSucceeded = false;
+    return OffLevel;
+}
+
+Logger::~Logger()
+{
+#ifdef QS_LOG_SEPARATE_THREAD
+    d->threadPool.waitForDone();
+#endif
+    delete d;
+    d = 0;
+}
+
+void Logger::addDestination(DestinationPtr destination)
+{
+    Q_ASSERT(destination.data());
+    d->destList.push_back(destination);
+}
+
+void Logger::setLoggingLevel(Level newLevel)
+{
+    d->level = newLevel;
+}
+
+Level Logger::loggingLevel() const
+{
+    return d->level;
+}
+
+void Logger::setIncludeTimestamp(bool e)
+{
+    d->includeTimeStamp = e;
+}
+
+bool Logger::includeTimestamp() const
+{
+    return d->includeTimeStamp;
+}
+
+void Logger::setIncludeLogLevel(bool l)
+{
+    d->includeLogLevel = l;
+}
+
+bool Logger::includeLogLevel() const
+{
+    return d->includeLogLevel;
+}
+
+//! creates the complete log message and passes it to the logger
+void Logger::Helper::writeToLog()
+{
+    const char* const levelName = LevelToText(level);
+    QString completeMessage;
+    Logger &logger = Logger::instance();
+    if (logger.includeLogLevel()) {
+        completeMessage.
+                append(levelName).
+                append(' ');
+    }
+    if (logger.includeTimestamp()) {
+        completeMessage.
+                append(QDateTime::currentDateTime().toString(fmtDateTime)).
+                append(' ');
+    }
+    completeMessage.append(buffer);
+    Logger::instance().enqueueWrite(completeMessage, level);
+}
+
+Logger::Helper::~Helper()
+{
+    try {
+        writeToLog();
+    }
+    catch(std::exception&) {
+        // you shouldn't throw exceptions from a sink
+        Q_ASSERT(!"exception in logger helper destructor");
+        throw;
+    }
+}
+
+//! directs the message to the task queue or writes it directly
+void Logger::enqueueWrite(const QString& message, Level level)
+{
+#ifdef QS_LOG_SEPARATE_THREAD
+    LogWriterRunnable *r = new LogWriterRunnable(message, level);
+    d->threadPool.start(r);
+#else
+    write(message, level);
+#endif
+}
+
+//! Sends the message to all the destinations. The level for this message is passed in case
+//! it's useful for processing in the destination.
+void Logger::write(const QString& message, Level level)
+{
+    QMutexLocker lock(&d->logMutex);
+    for (DestinationList::iterator it = d->destList.begin(),
+        endIt = d->destList.end();it != endIt;++it) {
+        (*it)->write(message, level);
+    }
+}
+
+} // end namespace
diff --git a/deltarobot/libQsLog/QsLog.h b/deltarobot/libQsLog/QsLog.h
new file mode 100644
index 0000000..c1beae2
--- /dev/null
+++ b/deltarobot/libQsLog/QsLog.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef QSLOG_H
+#define QSLOG_H
+
+#include "QsLogLevel.h"
+#include "QsLogDest.h"
+#include <QDebug>
+#include <QString>
+
+#define QS_LOG_VERSION "2.0b3"
+
+namespace QsLogging
+{
+class Destination;
+class LoggerImpl; // d pointer
+
+class QSLOG_SHARED_OBJECT Logger
+{
+public:
+    static Logger& instance();
+    static void destroyInstance();
+    static Level levelFromLogMessage(const QString& logMessage, bool* conversionSucceeded = 0);
+
+    ~Logger();
+
+    //! Adds a log message destination. Don't add null destinations.
+    void addDestination(DestinationPtr destination);
+    //! Logging at a level < 'newLevel' will be ignored
+    void setLoggingLevel(Level newLevel);
+    //! The default level is INFO
+    Level loggingLevel() const;
+    //! Set to false to disable timestamp inclusion in log messages
+    void setIncludeTimestamp(bool e);
+    //! Default value is true.
+    bool includeTimestamp() const;
+    //! Set to false to disable log level inclusion in log messages
+    void setIncludeLogLevel(bool l);
+    //! Default value is true.
+    bool includeLogLevel() const;
+
+    //! The helper forwards the streaming to QDebug and builds the final
+    //! log message.
+    class QSLOG_SHARED_OBJECT Helper
+    {
+    public:
+        explicit Helper(Level logLevel) :
+            level(logLevel),
+            qtDebug(&buffer)
+        {}
+        ~Helper();
+        QDebug& stream(){ return qtDebug; }
+
+    private:
+        void writeToLog();
+
+        Level level;
+        QString buffer;
+        QDebug qtDebug;
+	};
+
+private:
+    Logger();
+    Logger(const Logger&);            // not available
+    Logger& operator=(const Logger&); // not available
+
+    void enqueueWrite(const QString& message, Level level);
+    void write(const QString& message, Level level);
+
+    LoggerImpl* d;
+
+    friend class LogWriterRunnable;
+};
+
+} // end namespace
+
+//! Logging macros: define QS_LOG_LINE_NUMBERS to get the file and line number
+//! in the log output.
+#ifndef QS_LOG_LINE_NUMBERS
+#define QLOG_TRACE() \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::TraceLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::TraceLevel).stream()
+#define QLOG_DEBUG() \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::DebugLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::DebugLevel).stream()
+#define QLOG_INFO()  \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::InfoLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::InfoLevel).stream()
+#define QLOG_WARN()  \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::WarnLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::WarnLevel).stream()
+#define QLOG_ERROR() \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::ErrorLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::ErrorLevel).stream()
+#define QLOG_FATAL() \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::FatalLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::FatalLevel).stream()
+#else
+#define QLOG_TRACE() \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::TraceLevel) {} \
+    else  QsLogging::Logger::Helper(QsLogging::TraceLevel).stream() << __FILE__ << '@' << __LINE__
+#define QLOG_DEBUG() \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::DebugLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::DebugLevel).stream() << __FILE__ << '@' << __LINE__
+#define QLOG_INFO()  \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::InfoLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::InfoLevel).stream() << __FILE__ << '@' << __LINE__
+#define QLOG_WARN()  \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::WarnLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::WarnLevel).stream() << __FILE__ << '@' << __LINE__
+#define QLOG_ERROR() \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::ErrorLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::ErrorLevel).stream() << __FILE__ << '@' << __LINE__
+#define QLOG_FATAL() \
+    if (QsLogging::Logger::instance().loggingLevel() > QsLogging::FatalLevel) {} \
+    else QsLogging::Logger::Helper(QsLogging::FatalLevel).stream() << __FILE__ << '@' << __LINE__
+#endif
+
+#ifdef QS_LOG_DISABLE
+#include "QsLogDisableForThisFile.h"
+#endif
+
+#endif // QSLOG_H
diff --git a/deltarobot/libQsLog/QsLog.pri b/deltarobot/libQsLog/QsLog.pri
new file mode 100644
index 0000000..0dc60db
--- /dev/null
+++ b/deltarobot/libQsLog/QsLog.pri
@@ -0,0 +1,22 @@
+INCLUDEPATH += $$PWD
+#DEFINES += QS_LOG_LINE_NUMBERS    # automatically writes the file and line for each log message
+#DEFINES += QS_LOG_DISABLE         # logging code is replaced with a no-op
+#DEFINES += QS_LOG_SEPARATE_THREAD # messages are queued and written from a separate thread
+SOURCES += $$PWD/QsLogDest.cpp \
+    $$PWD/QsLog.cpp \
+    $$PWD/QsLogDestConsole.cpp \
+    $$PWD/QsLogDestFile.cpp \
+    $$PWD/QsLogDestFunctor.cpp
+
+HEADERS += $$PWD/QsLogDest.h \
+    $$PWD/QsLog.h \
+    $$PWD/QsLogDestConsole.h \
+    $$PWD/QsLogLevel.h \
+    $$PWD/QsLogDestFile.h \
+    $$PWD/QsLogDisableForThisFile.h \
+    $$PWD/QsLogDestFunctor.h
+
+OTHER_FILES += \
+    $$PWD/QsLogChanges.txt \
+    $$PWD/QsLogReadme.txt \
+    $$PWD/LICENSE.txt
diff --git a/deltarobot/libQsLog/QsLogChanges.txt b/deltarobot/libQsLog/QsLogChanges.txt
new file mode 100644
index 0000000..75d7a3d
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogChanges.txt
@@ -0,0 +1,45 @@
+-------------------
+QsLog version 2.0b4
+Fixes:
+Fixed file name case error for Linux.
+
+Misc:
+* Moved to separate git repository.
+
+-------------------
+QsLog version 2.0b3
+
+Changes:
+* added functor logging destination (thanks to Omar Carey for providing a patch)
+
+-------------------
+QsLog version 2.0b2
+
+Changes:
+* function signature redefinition for file destination creation
+* added shared library build configuration. Credit goes to Xavier Lamien <laxathom@fedoraproject.org>
+for the Linux-specific config.
+* removed Symbian support
+* this version does not guarantee support for Nokia N9 devices, although it should in theory still
+work with them
+* workaround for Issue 8 - when used from an executable and a plugin QsLog only logs from the
+executable.
+* utility function to parse the level from an existing log message
+
+Known issues:
+* The current version will crash at program exit when using QS_LOG_SEPARATE_THREAD and linking
+with QsLog dynamically.
+
+-------------------
+QsLog version 2.0b1
+
+Changes:
+* destination pointers use shared pointer semantics
+* the file destination supports log rotation. As a consequence, log files are encoded as UTF-8 and
+the log appends rather than truncating on every startup when rotation is enabled.
+* added the posibility of disabling logging either at run time or compile time.
+* added the possibility of using a separate thread for writing to the log destinations.
+
+Fixes:
+* renamed the main.cpp example to avoid QtCreator confusion
+* offer a way to check if the destination creation has failed (for e.g files)
diff --git a/deltarobot/libQsLog/QsLogDest.cpp b/deltarobot/libQsLog/QsLogDest.cpp
new file mode 100644
index 0000000..ff38807
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDest.cpp
@@ -0,0 +1,70 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "QsLogDest.h"
+#include "QsLogDestConsole.h"
+#include "QsLogDestFile.h"
+#include "QsLogDestFunctor.h"
+#include <QString>
+
+namespace QsLogging
+{
+
+Destination::~Destination()
+{
+}
+
+//! destination factory
+DestinationPtr DestinationFactory::MakeFileDestination(const QString& filePath,
+    LogRotationOption rotation, const MaxSizeBytes &sizeInBytesToRotateAfter,
+    const MaxOldLogCount &oldLogsToKeep)
+{
+    if (EnableLogRotation == rotation) {
+        QScopedPointer<SizeRotationStrategy> logRotation(new SizeRotationStrategy);
+        logRotation->setMaximumSizeInBytes(sizeInBytesToRotateAfter.size);
+        logRotation->setBackupCount(oldLogsToKeep.count);
+
+        return DestinationPtr(new FileDestination(filePath, RotationStrategyPtr(logRotation.take())));
+    }
+
+    return DestinationPtr(new FileDestination(filePath, RotationStrategyPtr(new NullRotationStrategy)));
+}
+
+DestinationPtr DestinationFactory::MakeDebugOutputDestination()
+{
+    return DestinationPtr(new DebugOutputDestination);
+}
+
+DestinationPtr DestinationFactory::MakeFunctorDestination(QsLogging::Destination::LogFunction f)
+{
+    return DestinationPtr(new FunctorDestination(f));
+}
+
+DestinationPtr DestinationFactory::MakeFunctorDestination(QObject *receiver, const char *member)
+{
+    return DestinationPtr(new FunctorDestination(receiver, member));
+}
+
+} // end namespace
diff --git a/deltarobot/libQsLog/QsLogDest.h b/deltarobot/libQsLog/QsLogDest.h
new file mode 100644
index 0000000..4ed6157
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDest.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef QSLOGDEST_H
+#define QSLOGDEST_H
+
+#include "QsLogLevel.h"
+#include <QSharedPointer>
+#include <QtGlobal>
+class QString;
+class QObject;
+
+#ifdef QSLOG_IS_SHARED_LIBRARY
+#define QSLOG_SHARED_OBJECT Q_DECL_EXPORT
+#elif QSLOG_IS_SHARED_LIBRARY_IMPORT
+#define QSLOG_SHARED_OBJECT Q_DECL_IMPORT
+#else
+#define QSLOG_SHARED_OBJECT
+#endif
+
+namespace QsLogging
+{
+
+class QSLOG_SHARED_OBJECT Destination
+{
+public:
+    typedef void (*LogFunction)(const QString &message, Level level);
+
+public:
+    virtual ~Destination();
+    virtual void write(const QString& message, Level level) = 0;
+    virtual bool isValid() = 0; // returns whether the destination was created correctly
+};
+typedef QSharedPointer<Destination> DestinationPtr;
+
+
+// a series of "named" paramaters, to make the file destination creation more readable
+enum LogRotationOption
+{
+    DisableLogRotation = 0,
+    EnableLogRotation  = 1
+};
+
+struct QSLOG_SHARED_OBJECT MaxSizeBytes
+{
+    MaxSizeBytes() : size(0) {}
+    explicit MaxSizeBytes(qint64 size_) : size(size_) {}
+    qint64 size;
+};
+
+struct QSLOG_SHARED_OBJECT MaxOldLogCount
+{
+    MaxOldLogCount() : count(0) {}
+    explicit MaxOldLogCount(int count_) : count(count_) {}
+    int count;
+};
+
+
+//! Creates logging destinations/sinks. The caller shares ownership of the destinations with the logger.
+//! After being added to a logger, the caller can discard the pointers.
+class QSLOG_SHARED_OBJECT DestinationFactory
+{
+public:
+    static DestinationPtr MakeFileDestination(const QString& filePath,
+        LogRotationOption rotation = DisableLogRotation,
+        const MaxSizeBytes &sizeInBytesToRotateAfter = MaxSizeBytes(),
+        const MaxOldLogCount &oldLogsToKeep = MaxOldLogCount());
+    static DestinationPtr MakeDebugOutputDestination();
+    // takes a pointer to a function
+    static DestinationPtr MakeFunctorDestination(Destination::LogFunction f);
+    // takes a QObject + signal/slot
+    static DestinationPtr MakeFunctorDestination(QObject *receiver, const char *member);
+};
+
+} // end namespace
+
+#endif // QSLOGDEST_H
diff --git a/deltarobot/libQsLog/QsLogDestConsole.cpp b/deltarobot/libQsLog/QsLogDestConsole.cpp
new file mode 100644
index 0000000..bfd9828
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDestConsole.cpp
@@ -0,0 +1,55 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "QsLogDestConsole.h"
+#include <QString>
+#include <QtGlobal>
+
+#if defined(Q_OS_WIN)
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+void QsDebugOutput::output( const QString& message )
+{
+   OutputDebugStringW(reinterpret_cast<const WCHAR*>(message.utf16()));
+   OutputDebugStringW(L"\n");
+}
+#elif defined(Q_OS_UNIX)
+#include <cstdio>
+void QsDebugOutput::output( const QString& message )
+{
+   fprintf(stderr, "%s\n", qPrintable(message));
+   fflush(stderr);
+}
+#endif
+
+void QsLogging::DebugOutputDestination::write(const QString& message, Level)
+{
+    QsDebugOutput::output(message);
+}
+
+bool QsLogging::DebugOutputDestination::isValid()
+{
+    return true;
+}
diff --git a/deltarobot/libQsLog/QsLogDestConsole.h b/deltarobot/libQsLog/QsLogDestConsole.h
new file mode 100644
index 0000000..d422c23
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDestConsole.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef QSLOGDESTCONSOLE_H
+#define QSLOGDESTCONSOLE_H
+
+#include "QsLogDest.h"
+
+class QString;
+
+class QsDebugOutput
+{
+public:
+   static void output(const QString& a_message);
+};
+
+namespace QsLogging
+{
+
+// debugger sink
+class DebugOutputDestination : public Destination
+{
+public:
+    virtual void write(const QString& message, Level level);
+    virtual bool isValid();
+};
+
+}
+
+#endif // QSLOGDESTCONSOLE_H
diff --git a/deltarobot/libQsLog/QsLogDestFile.cpp b/deltarobot/libQsLog/QsLogDestFile.cpp
new file mode 100644
index 0000000..0f8f804
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDestFile.cpp
@@ -0,0 +1,155 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "QsLogDestFile.h"
+#include <QTextCodec>
+#include <QDateTime>
+#include <QtGlobal>
+#include <iostream>
+
+const int QsLogging::SizeRotationStrategy::MaxBackupCount = 10;
+
+QsLogging::RotationStrategy::~RotationStrategy()
+{
+}
+
+QsLogging::SizeRotationStrategy::SizeRotationStrategy()
+    : mCurrentSizeInBytes(0)
+    , mMaxSizeInBytes(0)
+    , mBackupsCount(0)
+{
+}
+
+void QsLogging::SizeRotationStrategy::setInitialInfo(const QFile &file)
+{
+    mFileName = file.fileName();
+    mCurrentSizeInBytes = file.size();
+}
+
+void QsLogging::SizeRotationStrategy::includeMessageInCalculation(const QString &message)
+{
+    mCurrentSizeInBytes += message.toUtf8().size();
+}
+
+bool QsLogging::SizeRotationStrategy::shouldRotate()
+{
+    return mCurrentSizeInBytes > mMaxSizeInBytes;
+}
+
+// Algorithm assumes backups will be named filename.X, where 1 <= X <= mBackupsCount.
+// All X's will be shifted up.
+void QsLogging::SizeRotationStrategy::rotate()
+{
+    if (!mBackupsCount) {
+        if (!QFile::remove(mFileName))
+            std::cerr << "QsLog: backup delete failed " << qPrintable(mFileName);
+        return;
+    }
+
+     // 1. find the last existing backup than can be shifted up
+     const QString logNamePattern = mFileName + QString::fromUtf8(".%1");
+     int lastExistingBackupIndex = 0;
+     for (int i = 1;i <= mBackupsCount;++i) {
+         const QString backupFileName = logNamePattern.arg(i);
+         if (QFile::exists(backupFileName))
+             lastExistingBackupIndex = qMin(i, mBackupsCount - 1);
+         else
+             break;
+     }
+
+     // 2. shift up
+     for (int i = lastExistingBackupIndex;i >= 1;--i) {
+         const QString oldName = logNamePattern.arg(i);
+         const QString newName = logNamePattern.arg(i + 1);
+         QFile::remove(newName);
+         const bool renamed = QFile::rename(oldName, newName);
+         if (!renamed) {
+             std::cerr << "QsLog: could not rename backup " << qPrintable(oldName)
+                       << " to " << qPrintable(newName);
+         }
+     }
+
+     // 3. rename current log file
+     const QString newName = logNamePattern.arg(1);
+     if (QFile::exists(newName))
+         QFile::remove(newName);
+     if (!QFile::rename(mFileName, newName)) {
+         std::cerr << "QsLog: could not rename log " << qPrintable(mFileName)
+                   << " to " << qPrintable(newName);
+     }
+}
+
+QIODevice::OpenMode QsLogging::SizeRotationStrategy::recommendedOpenModeFlag()
+{
+    return QIODevice::Append;
+}
+
+void QsLogging::SizeRotationStrategy::setMaximumSizeInBytes(qint64 size)
+{
+    Q_ASSERT(size >= 0);
+    mMaxSizeInBytes = size;
+}
+
+void QsLogging::SizeRotationStrategy::setBackupCount(int backups)
+{
+    Q_ASSERT(backups >= 0);
+    mBackupsCount = qMin(backups, SizeRotationStrategy::MaxBackupCount);
+}
+
+
+QsLogging::FileDestination::FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy)
+    : mRotationStrategy(rotationStrategy)
+{
+    mFile.setFileName(filePath);
+    if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag()))
+        std::cerr << "QsLog: could not open log file " << qPrintable(filePath);
+    mOutputStream.setDevice(&mFile);
+    mOutputStream.setCodec(QTextCodec::codecForName("UTF-8"));
+
+    mRotationStrategy->setInitialInfo(mFile);
+}
+
+void QsLogging::FileDestination::write(const QString& message, Level)
+{
+    mRotationStrategy->includeMessageInCalculation(message);
+    if (mRotationStrategy->shouldRotate()) {
+        mOutputStream.setDevice(NULL);
+        mFile.close();
+        mRotationStrategy->rotate();
+        if (!mFile.open(QFile::WriteOnly | QFile::Text | mRotationStrategy->recommendedOpenModeFlag()))
+            std::cerr << "QsLog: could not reopen log file " << qPrintable(mFile.fileName());
+        mRotationStrategy->setInitialInfo(mFile);
+        mOutputStream.setDevice(&mFile);
+    }
+
+    mOutputStream << message << endl;
+    mOutputStream.flush();
+}
+
+bool QsLogging::FileDestination::isValid()
+{
+    return mFile.isOpen();
+}
+
diff --git a/deltarobot/libQsLog/QsLogDestFile.h b/deltarobot/libQsLog/QsLogDestFile.h
new file mode 100644
index 0000000..ee7b523
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDestFile.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef QSLOGDESTFILE_H
+#define QSLOGDESTFILE_H
+
+#include "QsLogDest.h"
+#include <QFile>
+#include <QTextStream>
+#include <QtGlobal>
+#include <QSharedPointer>
+
+namespace QsLogging
+{
+class RotationStrategy
+{
+public:
+    virtual ~RotationStrategy();
+
+    virtual void setInitialInfo(const QFile &file) = 0;
+    virtual void includeMessageInCalculation(const QString &message) = 0;
+    virtual bool shouldRotate() = 0;
+    virtual void rotate() = 0;
+    virtual QIODevice::OpenMode recommendedOpenModeFlag() = 0;
+};
+
+// Never rotates file, overwrites existing file.
+class NullRotationStrategy : public RotationStrategy
+{
+public:
+    virtual void setInitialInfo(const QFile &) {}
+    virtual void includeMessageInCalculation(const QString &) {}
+    virtual bool shouldRotate() { return false; }
+    virtual void rotate() {}
+    virtual QIODevice::OpenMode recommendedOpenModeFlag() { return QIODevice::Truncate; }
+};
+
+// Rotates after a size is reached, keeps a number of <= 10 backups, appends to existing file.
+class SizeRotationStrategy : public RotationStrategy
+{
+public:
+    SizeRotationStrategy();
+    static const int MaxBackupCount;
+
+    virtual void setInitialInfo(const QFile &file);
+    virtual void includeMessageInCalculation(const QString &message);
+    virtual bool shouldRotate();
+    virtual void rotate();
+    virtual QIODevice::OpenMode recommendedOpenModeFlag();
+
+    void setMaximumSizeInBytes(qint64 size);
+    void setBackupCount(int backups);
+
+private:
+    QString mFileName;
+    qint64 mCurrentSizeInBytes;
+    qint64 mMaxSizeInBytes;
+    int mBackupsCount;
+};
+
+typedef QSharedPointer<RotationStrategy> RotationStrategyPtr;
+
+// file message sink
+class FileDestination : public Destination
+{
+public:
+    FileDestination(const QString& filePath, RotationStrategyPtr rotationStrategy);
+    virtual void write(const QString& message, Level level);
+    virtual bool isValid();
+
+private:
+    QFile mFile;
+    QTextStream mOutputStream;
+    QSharedPointer<RotationStrategy> mRotationStrategy;
+};
+
+}
+
+#endif // QSLOGDESTFILE_H
diff --git a/deltarobot/libQsLog/QsLogDestFunctor.cpp b/deltarobot/libQsLog/QsLogDestFunctor.cpp
new file mode 100644
index 0000000..601139d
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDestFunctor.cpp
@@ -0,0 +1,57 @@
+// Copyright (c) 2014, Razvan Petru
+// Copyright (c) 2014, Omar Carey
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "QsLogDestFunctor.h"
+#include <cstddef>
+#include <QtGlobal>
+
+QsLogging::FunctorDestination::FunctorDestination(LogFunction f)
+    : QObject(NULL)
+    , mLogFunction(f)
+{
+}
+
+QsLogging::FunctorDestination::FunctorDestination(QObject *receiver, const char *member)
+    : QObject(NULL)
+    , mLogFunction(NULL)
+{
+    connect(this, SIGNAL(logMessageReady(QString,int)), receiver, member, Qt::QueuedConnection);
+}
+
+
+void QsLogging::FunctorDestination::write(const QString &message, QsLogging::Level level)
+{
+    if (mLogFunction)
+        mLogFunction(message, level);
+
+    if (level > QsLogging::TraceLevel)
+        emit logMessageReady(message, static_cast<int>(level));
+}
+
+bool QsLogging::FunctorDestination::isValid()
+{
+    return true;
+}
diff --git a/deltarobot/libQsLog/QsLogDestFunctor.h b/deltarobot/libQsLog/QsLogDestFunctor.h
new file mode 100644
index 0000000..e34631f
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDestFunctor.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2014, Razvan Petru
+// Copyright (c) 2014, Omar Carey
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef QSLOGDESTFUNCTOR_H
+#define QSLOGDESTFUNCTOR_H
+
+#include "QsLogDest.h"
+#include <QObject>
+
+namespace QsLogging
+{
+// Offers various types of function-like sinks.
+// This is an advanced destination type. Depending on your configuration, LogFunction might be
+// called from a different thread or even a different binary. You should not access QsLog from
+// inside LogFunction and should not perform any time-consuming operations.
+// logMessageReady is connected through a queued connection and trace messages are not included
+class FunctorDestination : public QObject, public Destination
+{
+    Q_OBJECT
+public:
+    explicit FunctorDestination(LogFunction f);
+    FunctorDestination(QObject *receiver, const char *member);
+
+    virtual void write(const QString &message, Level level);
+    virtual bool isValid();
+
+protected:
+    // int used to avoid registering a new enum type
+    Q_SIGNAL void logMessageReady(const QString &message, int level);
+
+private:
+    LogFunction mLogFunction;
+};
+}
+
+#endif // QSLOGDESTFUNCTOR_H
diff --git a/deltarobot/libQsLog/QsLogDisableForThisFile.h b/deltarobot/libQsLog/QsLogDisableForThisFile.h
new file mode 100644
index 0000000..c70af10
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogDisableForThisFile.h
@@ -0,0 +1,22 @@
+#ifndef QSLOGDISABLEFORTHISFILE_H
+#define QSLOGDISABLEFORTHISFILE_H
+
+#include <QtDebug>
+// When included AFTER QsLog.h, this file will disable logging in that C++ file. When included
+// before, it will lead to compiler warnings or errors about macro redefinitions.
+
+#undef QLOG_TRACE
+#undef QLOG_DEBUG
+#undef QLOG_INFO
+#undef QLOG_WARN
+#undef QLOG_ERROR
+#undef QLOG_FATAL
+
+#define QLOG_TRACE() if (1) {} else qDebug()
+#define QLOG_DEBUG() if (1) {} else qDebug()
+#define QLOG_INFO()  if (1) {} else qDebug()
+#define QLOG_WARN()  if (1) {} else qDebug()
+#define QLOG_ERROR() if (1) {} else qDebug()
+#define QLOG_FATAL() if (1) {} else qDebug()
+
+#endif // QSLOGDISABLEFORTHISFILE_H
diff --git a/deltarobot/libQsLog/QsLogLevel.h b/deltarobot/libQsLog/QsLogLevel.h
new file mode 100644
index 0000000..5032f27
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogLevel.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef QSLOGLEVEL_H
+#define QSLOGLEVEL_H
+
+namespace QsLogging
+{
+
+enum Level
+{
+    TraceLevel = 0,
+    DebugLevel,
+    InfoLevel,
+    WarnLevel,
+    ErrorLevel,
+    FatalLevel,
+    OffLevel
+};
+
+}
+
+#endif // QSLOGLEVEL_H
diff --git a/deltarobot/libQsLog/QsLogReadme.txt b/deltarobot/libQsLog/QsLogReadme.txt
new file mode 100644
index 0000000..a7a50e0
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogReadme.txt
@@ -0,0 +1,65 @@
+QsLog - the simple Qt logger
+-------------------------------------------------------------------------------
+QsLog is an easy to use logger that is based on Qt's QDebug class.
+
+Features
+-------------------------------------------------------------------------------
+    * Six logging levels (from trace to fatal)
+    * Logging level threshold configurable at runtime.
+    * Minimum overhead when logging is turned off.
+    * Multiple destinations, comes with file and debug destinations.
+    * Thread-safe
+    * Logging of common Qt types out of the box.
+    * Immediate logging or queueing messages in a separate thread.
+    * Small dependency: just drop it in your project directly.
+
+Usage
+-------------------------------------------------------------------------------
+By directly including QsLog in your project:
+    1. Include QsLog.pri in your pro file
+    2. Include QsLog.h in your C++ files. Include QsLogDest.h only where you create/add destinations.
+    3. Get the instance of the logger by calling QsLogging::Logger::instance();
+    4. Optionally set the logging level. Info is default.
+    5. Create as many destinations as you want by using the QsLogging::DestinationFactory.
+    6. Add the destinations to the logger instance by calling addDestination.
+    7. Start logging!
+    Note: when you want to use QsLog both from an executable and a shared library you have to
+          link dynamically with QsLog due to a limitation with static variables.
+
+By linking to QsLog dynamically:
+    1. Build QsLog using the QsLogSharedLibrary.pro.
+    2. Add the QsLog shared library to your LIBS project dependencies.
+    3. Follow the steps in "directly including QsLog in your project" starting with step 2.
+
+Configuration
+-------------------------------------------------------------------------------
+QsLog has several configurable parameters:
+    * defining QS_LOG_LINE_NUMBERS in the .pri file enables writing the file and line number
+      automatically for each logging call
+    * defining QS_LOG_SEPARATE_THREAD will route all log messages to a separate thread.
+
+Sometimes it's necessary to turn off logging. This can be done in several ways:
+    * globally, at compile time, by enabling the QS_LOG_DISABLE macro in the .pri file.
+    * globally, at run time, by setting the log level to "OffLevel".
+    * per file, at compile time, by including QsLogDisableForThisFile.h in the target file.
+
+Thread safety
+-------------------------------------------------------------------------------
+The Qt docs say: A thread-safe function can be called simultaneously from multiple threads,
+even when the invocations use shared data, because all references to the shared data are serialized.
+A reentrant function can also be called simultaneously from multiple threads, but only if each
+invocation uses its own data.
+
+Since sending the log message to the destinations is protected by a mutex, the logging macros are
+thread-safe provided that the log has been initialized - i.e: instance() has been called.
+The instance function and the setup functions (e.g: setLoggingLevel, addDestination) are NOT
+thread-safe and are NOT reentrant.
+
+IMPORTANT: when using a separate thread for logging, your program might crash at exit time on some
+           operating systems if you won't call Logger::destroyInstance() before your program exits.
+           This function can be called either before returning from main in a console app or
+           inside QCoreApplication::aboutToQuit in a Qt GUI app.
+           The reason is that the logging thread is still running as some objects are destroyed by
+           the OS. Calling destroyInstance will wait for the thread to finish.
+           Nothing will happen if you forget to call the function when not using a separate thread
+           for logging.
diff --git a/deltarobot/libQsLog/QsLogSharedLibrary.pro b/deltarobot/libQsLog/QsLogSharedLibrary.pro
new file mode 100644
index 0000000..5132068
--- /dev/null
+++ b/deltarobot/libQsLog/QsLogSharedLibrary.pro
@@ -0,0 +1,35 @@
+# This pro file will build QsLog as a shared library
+include(QsLog.pri)
+
+TARGET = QsLog
+VERSION = "2.0.0"
+QT -= gui
+CONFIG -= console
+CONFIG -= app_bundle
+CONFIG += shared
+TEMPLATE = lib
+
+DESTDIR = $$PWD/build-QsLogShared
+OBJECTS_DIR = $$DESTDIR/obj
+MOC_DIR = $$DESTDIR/moc
+
+win32 {
+    DEFINES += QSLOG_IS_SHARED_LIBRARY
+}
+
+unix:!macx {
+    # make install will install the shared object in the appropriate folders
+    headers.files = QsLog.h QsLogDest.h QsLogLevel.h
+    headers.path = /usr/include/$(QMAKE_TARGET)
+
+    other_files.files = *.txt
+    other_files.path = /usr/local/share/$(QMAKE_TARGET)
+
+    contains(QT_ARCH, x86_64) {
+        target.path = /usr/lib64
+    } else {
+        target.path = /usr/lib
+    }
+
+    INSTALLS += headers target other_files
+}
diff --git a/deltarobot/libQsLog/README.md b/deltarobot/libQsLog/README.md
new file mode 100644
index 0000000..94cc283
--- /dev/null
+++ b/deltarobot/libQsLog/README.md
@@ -0,0 +1,39 @@
+## QsLog - the simple Qt logger ##
+QsLog is an easy to use logger that is based on Qt's QDebug class. QsLog is released as open source, under the MIT license. 
+
+###Contribution policy###
+Bug fixes are welcome, larger changes however are not encouraged at this point due to the lack of time on my side for reviewing and integrating them. Your best bet in this case would be to open a ticket for your change or forking the project and implementing your change there, with the possibility of having it integrated in the future. 
+All contributions will be credited, license of the contributions should be MIT. 
+
+### Features ###
+* Six logging levels (from trace to fatal)
+* Logging level threshold configurable at runtime.
+* Minimum overhead when logging is turned off.
+* Supports multiple destinations, comes with file and debug destinations.
+* Thread-safe
+* Supports logging of common Qt types out of the box.
+* Small dependency: just drop it in your project directly.
+
+### Usage ###
+* Include QsLog.h. Include QsLogDest.h only where you create/add destinations.
+* Get the instance of the logger by calling QsLogging::Logger::instance();
+* Optionally set the logging level. Info is default.
+* Create as many destinations as you want by using the QsLogging::DestinationFactory.
+* Add the destinations to the logger instance by calling addDestination.
+
+**Note**: The logger does not take ownership of the destinations. Make sure that the destinations still exist when you call one of the logging macros. A good place to create the destinations is the program's main function.
+
+### Disabling logging ###
+Sometimes it's necessary to turn off logging. This can be done in several ways:
+
+* globally, at compile time, by enabling the QS_LOG_DISABLE macro in the supplied .pri file.
+* globally, at run time, by setting the log level to "OffLevel".
+* per file, at compile time, by including QsLogDisableForThisFile.h in the target file.
+
+### Thread safety ###
+The Qt docs say: 
+A **thread-safe** function can be called simultaneously from multiple threads, even when the invocations use shared data, because all references to the shared data are serialized.
+A **reentrant** function can also be called simultaneously from multiple threads, but only if each invocation uses its own data.
+
+Since sending the log message to the destinations is protected by a mutex, the logging macros are thread-safe provided that the log has been initialized - i.e: instance() has been called. 
+The instance function and the setup functions (e.g: setLoggingLevel, addDestination) are NOT thread-safe and are NOT reentrant.
\ No newline at end of file
diff --git a/deltarobot/libQsLog/example/log_example.pro b/deltarobot/libQsLog/example/log_example.pro
new file mode 100644
index 0000000..1d4be35
--- /dev/null
+++ b/deltarobot/libQsLog/example/log_example.pro
@@ -0,0 +1,6 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = ../QsLogSharedLibrary.pro \
+          log_example_shared.pro \
+          log_example_main.pro
diff --git a/deltarobot/libQsLog/example/log_example_main.cpp b/deltarobot/libQsLog/example/log_example_main.cpp
new file mode 100644
index 0000000..35a09a1
--- /dev/null
+++ b/deltarobot/libQsLog/example/log_example_main.cpp
@@ -0,0 +1,98 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "QsLog.h"
+#include "QsLogDest.h"
+#include "log_example_shared.h"
+#include <QLibrary>
+#include <QCoreApplication>
+#include <QDir>
+#include <iostream>
+
+void logFunction(const QString &message, QsLogging::Level level)
+{
+    std::cout << "From log function: " << qPrintable(message) << " " << static_cast<int>(level)
+              << std::endl;
+}
+
+// This small example shows how QsLog can be used inside a project.
+int main(int argc, char *argv[])
+{
+   QCoreApplication a(argc, argv);
+
+   using namespace QsLogging;
+
+   // 1. init the logging mechanism
+   Logger& logger = Logger::instance();
+   logger.setLoggingLevel(QsLogging::TraceLevel);
+   const QString sLogPath(QDir(a.applicationDirPath()).filePath("log.txt"));
+
+   // 2. add two destinations
+   DestinationPtr fileDestination(DestinationFactory::MakeFileDestination(
+     sLogPath, EnableLogRotation, MaxSizeBytes(512), MaxOldLogCount(2)));
+   DestinationPtr debugDestination(DestinationFactory::MakeDebugOutputDestination());
+   DestinationPtr functorDestination(DestinationFactory::MakeFunctorDestination(&logFunction));
+   logger.addDestination(debugDestination);
+   logger.addDestination(fileDestination);
+   logger.addDestination(functorDestination);
+
+   // 3. start logging
+   QLOG_INFO() << "Program started";
+   QLOG_INFO() << "Built with Qt" << QT_VERSION_STR << "running on" << qVersion();
+
+   QLOG_TRACE() << "Here's a" << QString::fromUtf8("trace") << "message";
+   QLOG_DEBUG() << "Here's a" << static_cast<int>(QsLogging::DebugLevel) << "message";
+   QLOG_WARN()  << "Uh-oh!";
+   qDebug() << "This message won't be picked up by the logger";
+   QLOG_ERROR() << "An error has occurred";
+   qWarning() << "Neither will this one";
+   QLOG_FATAL() << "Fatal error!";
+
+   logger.setLoggingLevel(QsLogging::OffLevel);
+   for (int i = 0;i < 10000000;++i) {
+       QLOG_ERROR() << QString::fromUtf8("this message should not be visible");
+   }
+   logger.setLoggingLevel(QsLogging::TraceLevel);
+
+   // 4. log from a shared library - should automatically share the same log instance as above
+   QLibrary myLib("log_example_shared");
+   typedef LogExampleShared* (*LogExampleGetter)();
+   typedef void(*LogExampleDeleter)(LogExampleShared*);
+   LogExampleGetter fLogCreator = (LogExampleGetter) myLib.resolve("createExample");
+   LogExampleDeleter fLogDeleter = (LogExampleDeleter)myLib.resolve("destroyExample");
+   LogExampleShared *logFromShared = 0;
+   if (fLogCreator && fLogDeleter) {
+       logFromShared = fLogCreator();
+       logFromShared->logSomething();
+       fLogDeleter(logFromShared);
+   } else if (!fLogCreator || !fLogDeleter) {
+       QLOG_ERROR() << "could not resolve shared library function(s)";
+   }
+
+   QLOG_DEBUG() << "Program ending";
+
+   QsLogging::Logger::destroyInstance();
+   return 0;
+}
diff --git a/deltarobot/libQsLog/example/log_example_main.pro b/deltarobot/libQsLog/example/log_example_main.pro
new file mode 100644
index 0000000..f7a990b
--- /dev/null
+++ b/deltarobot/libQsLog/example/log_example_main.pro
@@ -0,0 +1,21 @@
+#This project links with QsLog dynamically and outputs an executable file.
+
+QT -= gui
+TARGET = log_example
+CONFIG += console
+CONFIG -= app_bundle
+TEMPLATE = app
+SOURCES += log_example_main.cpp
+INCLUDEPATH += $$PWD/../
+DEFINES += QSLOG_IS_SHARED_LIBRARY_IMPORT
+
+LIBS += -L$$PWD/../build-QsLogShared
+win32 {
+    LIBS += -lQsLog2
+} else {
+    LIBS += -lQsLog
+}
+LIBS += -L$$PWD/../build-QsLogExample -llog_example_shared
+
+DESTDIR = $$PWD/../build-QsLogExample
+OBJECTS_DIR = $$DESTDIR/obj
diff --git a/deltarobot/libQsLog/example/log_example_shared.cpp b/deltarobot/libQsLog/example/log_example_shared.cpp
new file mode 100644
index 0000000..8128a62
--- /dev/null
+++ b/deltarobot/libQsLog/example/log_example_shared.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "log_example_shared.h"
+#include "QsLog.h"
+
+void LogExampleShared::logSomething()
+{
+    QLOG_INFO() << "this message is comming from a shared library";
+}
+
+LogExampleShared* createExample()
+{
+    return new LogExampleShared();
+}
+
+
+void destroyExample(LogExampleShared *example)
+{
+    delete example;
+}
diff --git a/deltarobot/libQsLog/example/log_example_shared.h b/deltarobot/libQsLog/example/log_example_shared.h
new file mode 100644
index 0000000..b3e8573
--- /dev/null
+++ b/deltarobot/libQsLog/example/log_example_shared.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2013, Razvan Petru
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this
+//   list of conditions and the following disclaimer in the documentation and/or other
+//   materials provided with the distribution.
+// * The name of the contributors may not be used to endorse or promote products
+//   derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef LOGEXAMPLESHARED_H
+#define LOGEXAMPLESHARED_H
+
+#include <QtGlobal>
+
+#ifdef EXAMPLE_IS_SHARED_LIBRARY
+#define EXAMPLE_SHARED_OBJECT Q_DECL_IMPORT
+#else
+#define EXAMPLE_SHARED_OBJECT Q_DECL_EXPORT
+#endif
+
+class EXAMPLE_SHARED_OBJECT LogExampleShared
+{
+public:
+    void logSomething();
+};
+
+extern "C" {
+    LogExampleShared *createExample();
+    void destroyExample(LogExampleShared *example);
+}
+
+#endif // LOGEXAMPLESHARED_H
diff --git a/deltarobot/libQsLog/example/log_example_shared.pro b/deltarobot/libQsLog/example/log_example_shared.pro
new file mode 100644
index 0000000..f4fdee7
--- /dev/null
+++ b/deltarobot/libQsLog/example/log_example_shared.pro
@@ -0,0 +1,22 @@
+#This project file links with QsLog dynamically and outputs a shared object.
+
+QT -= gui
+
+TARGET = log_example_shared
+TEMPLATE = lib
+
+DEFINES += EXAMPLE_IS_SHARED_LIBRARY QSLOG_IS_SHARED_LIBRARY_IMPORT
+SOURCES += log_example_shared.cpp
+HEADERS += log_example_shared.h
+INCLUDEPATH += $$PWD/../
+DESTDIR = $$PWD/../build-QsLogExample
+OBJECTS_DIR = $$DESTDIR/obj
+
+LIBS += -L$$PWD/../build-QsLogShared
+win32 {
+    LIBS += -lQsLog2
+} else {
+    LIBS += -lQsLog
+}
+
+
diff --git a/deltarobot/libQsLog/unittest/QtTestUtil/QtTestUtil.h b/deltarobot/libQsLog/unittest/QtTestUtil/QtTestUtil.h
new file mode 100644
index 0000000..cb5352f
--- /dev/null
+++ b/deltarobot/libQsLog/unittest/QtTestUtil/QtTestUtil.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008  Remko Troncon
+ * Licensed under the MIT license.
+ * See COPYING for license details.
+ */
+
+#ifndef QtTestUtil_H
+#define QtTestUtil_H
+
+#include <QObject>
+#include <QtTest/QtTest>
+#include "QtTestUtil/TestRegistration.h"
+
+/**
+ * A macro to register a test class.
+ *
+ * This macro will create a static variable which registers the
+ * testclass with the TestRegistry, and creates an instance of the 
+ * test class.
+ *
+ * Execute this macro in the body of your unit test's .cpp file, e.g.
+ *    class MyTest {
+ *			...
+ *		};
+ *
+ *		QTTESTUTIL_REGISTER_TEST(MyTest)
+ */
+#define QTTESTUTIL_REGISTER_TEST(TestClass) \
+	static QtTestUtil::TestRegistration<TestClass> TestClass##Registration
+
+#endif
diff --git a/deltarobot/libQsLog/unittest/QtTestUtil/SimpleChecker.cpp b/deltarobot/libQsLog/unittest/QtTestUtil/SimpleChecker.cpp
new file mode 100644
index 0000000..ab8ffd0
--- /dev/null
+++ b/deltarobot/libQsLog/unittest/QtTestUtil/SimpleChecker.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2008  Remko Troncon
+ * Licensed under the MIT license.
+ * See COPYING for license details.
+ */
+
+#include <QCoreApplication>
+
+#include "QtTestUtil/TestRegistry.h"
+
+/**
+ * Runs all tests registered with the QtTestUtil registry.
+ */
+int main(int argc, char* argv[]) {
+	QCoreApplication application(argc, argv);
+	return QtTestUtil::TestRegistry::getInstance()->runTests(argc, argv);
+}
diff --git a/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistration.h b/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistration.h
new file mode 100644
index 0000000..d228751
--- /dev/null
+++ b/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistration.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008  Remko Troncon
+ * Licensed under the MIT license.
+ * See COPYING for license details.
+ */
+
+#ifndef QtTestUtil_TestRegistration_H
+#define QtTestUtil_TestRegistration_H
+
+#include "QtTestUtil/TestRegistry.h"
+
+namespace QtTestUtil {
+
+	/**
+	 * A wrapper class around a test to manage registration and static
+	 * creation of an instance of the test class.
+	 * This class is used by QTTESTUTIL_REGISTER_TEST(), and you should not 
+	 * use this class directly.
+	 */
+	template<typename TestClass>
+	class TestRegistration {
+		public:
+			TestRegistration() {
+				test_ = new TestClass();
+				TestRegistry::getInstance()->registerTest(test_);
+			}
+
+			~TestRegistration() {
+				delete test_;
+			}
+		
+		private:
+			TestClass* test_;
+	};
+
+}
+
+#endif
diff --git a/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistry.cpp b/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistry.cpp
new file mode 100644
index 0000000..5460f40
--- /dev/null
+++ b/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistry.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008  Remko Troncon
+ * Licensed under the MIT license.
+ * See COPYING for license details.
+ */
+
+#include "QtTestUtil/TestRegistry.h"
+
+#include <QtTest/QtTest>
+
+namespace QtTestUtil {
+
+TestRegistry* TestRegistry::getInstance() {
+	static TestRegistry registry;
+	return &registry;
+}
+
+void TestRegistry::registerTest(QObject* test) {
+	tests_ += test;
+}
+
+int TestRegistry::runTests(int argc, char* argv[]) {
+	int result = 0;
+	foreach(QObject* test, tests_) {
+		result |= QTest::qExec(test, argc, argv);
+	}
+	return result;
+}
+
+}
diff --git a/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistry.h b/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistry.h
new file mode 100644
index 0000000..d91bd9e
--- /dev/null
+++ b/deltarobot/libQsLog/unittest/QtTestUtil/TestRegistry.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008  Remko Troncon
+ * Licensed under the MIT license.
+ * See COPYING for license details.
+ */
+
+#ifndef QtTestUtil_TestRegistry_H
+#define QtTestUtil_TestRegistry_H
+
+#include <QList>
+
+class QObject;
+
+namespace QtTestUtil {
+	
+	/**
+	 * A registry of QtTest test classes.
+	 * All test classes registered with QTTESTUTIL_REGISTER_TEST add 
+	 * themselves to this registry. All registered tests can then be run at 
+	 * once using runTests().
+	 */
+	class TestRegistry {
+		public:
+			/**
+			 * Retrieve the single instance of the registry.
+			 */
+			static TestRegistry* getInstance();
+
+			/**
+			 * Register a QtTest test. 
+			 * This method is called  by QTTESTUTIL_REGISTER_TEST, and you should 
+			 * not use this method directly.
+			 */
+			void registerTest(QObject*);
+
+			/**
+			 * Run all registered tests using QTest::qExec()
+			 */
+			int runTests(int argc, char* argv[]);
+
+		private:
+			TestRegistry() {}
+		
+		private:
+			QList<QObject*> tests_;
+	};
+}
+
+#endif
diff --git a/deltarobot/libQsLog/unittest/TestLog.cpp b/deltarobot/libQsLog/unittest/TestLog.cpp
new file mode 100644
index 0000000..4c07311
--- /dev/null
+++ b/deltarobot/libQsLog/unittest/TestLog.cpp
@@ -0,0 +1,202 @@
+#include "QtTestUtil/QtTestUtil.h"
+#include "QsLog.h"
+#include "QsLogDest.h"
+#include <QHash>
+#include <QSharedPointer>
+#include <QtGlobal>
+
+// A destination that tracks log messages
+class MockDestination : public QsLogging::Destination
+{
+public:
+    virtual void write(const QString &message, QsLogging::Level level)
+    {
+        Message m;
+        m.text = message;
+        m.level = level;
+        mMessages.push_back(m);
+        ++mCountByLevel[level];
+    }
+
+    virtual bool isValid()
+    {
+        return true;
+    }
+
+    struct Message
+    {
+        Message() : level(QsLogging::TraceLevel) {}
+        QString text;
+        QsLogging::Level level;
+    };
+
+    void clear()
+    {
+        mMessages.clear();
+        mCountByLevel.clear();
+    }
+
+    int messageCount() const
+    {
+        return mMessages.count();
+    }
+
+    int messageCountForLevel(QsLogging::Level level) const
+    {
+        return mCountByLevel.value(level);
+    }
+
+    bool hasMessage(const QString &messageContent, QsLogging::Level level) const
+    {
+        Q_FOREACH (const Message &m, mMessages) {
+            if (m.level == level && m.text.contains(messageContent))
+                return true;
+        }
+
+        return false;
+    }
+
+    const Message& messageAt(int index)
+    {
+        Q_ASSERT(index >= 0 && index < messageCount());
+        return mMessages.at(index);
+    }
+
+private:
+    QHash<QsLogging::Level,int> mCountByLevel;
+    QList<Message> mMessages;
+};
+
+// Autotests for QsLog
+class TestLog : public QObject
+{
+    Q_OBJECT
+public:
+    TestLog()
+        : mockDest1(new MockDestination)
+        , mockDest2(new MockDestination)
+    {
+    }
+
+private slots:
+    void initTestCase();
+    void testAllLevels();
+    void testMessageText();
+    void testLevelChanges();
+    void testLevelParsing();
+    void cleanupTestCase();
+
+private:
+    QSharedPointer<MockDestination> mockDest1;
+    QSharedPointer<MockDestination> mockDest2;
+};
+
+void TestLog::initTestCase()
+{
+    using namespace QsLogging;
+    QCOMPARE(Logger::instance().loggingLevel(), InfoLevel);
+    Logger::instance().setLoggingLevel(TraceLevel);
+    QCOMPARE(Logger::instance().loggingLevel(), TraceLevel);
+    Logger::instance().addDestination(mockDest1);
+    Logger::instance().addDestination(mockDest2);
+}
+
+void TestLog::testAllLevels()
+{
+    mockDest1->clear();
+    mockDest2->clear();
+
+    QLOG_TRACE() << "trace level";
+    QLOG_DEBUG() << "debug level";
+    QLOG_INFO() << "info level";
+    QLOG_WARN() << "warn level";
+    QLOG_ERROR() << "error level";
+    QLOG_FATAL() << "fatal level";
+
+    using namespace QsLogging;
+    QCOMPARE(mockDest1->messageCount(), 6);
+    QCOMPARE(mockDest1->messageCountForLevel(TraceLevel), 1);
+    QCOMPARE(mockDest1->messageCountForLevel(DebugLevel), 1);
+    QCOMPARE(mockDest1->messageCountForLevel(InfoLevel), 1);
+    QCOMPARE(mockDest1->messageCountForLevel(WarnLevel), 1);
+    QCOMPARE(mockDest1->messageCountForLevel(ErrorLevel), 1);
+    QCOMPARE(mockDest1->messageCountForLevel(FatalLevel), 1);
+    QCOMPARE(mockDest2->messageCount(), 6);
+    QCOMPARE(mockDest2->messageCountForLevel(TraceLevel), 1);
+    QCOMPARE(mockDest2->messageCountForLevel(DebugLevel), 1);
+    QCOMPARE(mockDest2->messageCountForLevel(InfoLevel), 1);
+    QCOMPARE(mockDest2->messageCountForLevel(WarnLevel), 1);
+    QCOMPARE(mockDest2->messageCountForLevel(ErrorLevel), 1);
+    QCOMPARE(mockDest2->messageCountForLevel(FatalLevel), 1);
+}
+
+void TestLog::testMessageText()
+{
+    mockDest1->clear();
+
+    QLOG_DEBUG() << "foobar";
+    QLOG_WARN() << "eiszeit";
+    QLOG_FATAL() << "ruh-roh!";
+    using namespace QsLogging;
+    QVERIFY(mockDest1->hasMessage("foobar", DebugLevel));
+    QVERIFY(mockDest1->hasMessage("eiszeit", WarnLevel));
+    QVERIFY(mockDest1->hasMessage("ruh-roh!", FatalLevel));
+    QCOMPARE(mockDest1->messageCount(), 3);
+}
+
+void TestLog::testLevelChanges()
+{
+    mockDest1->clear();
+    mockDest2->clear();
+
+    using namespace QsLogging;
+    Logger::instance().setLoggingLevel(WarnLevel);
+    QCOMPARE(Logger::instance().loggingLevel(), WarnLevel);
+
+    QLOG_TRACE() << "one";
+    QLOG_DEBUG() << "two";
+    QLOG_INFO() << "three";
+    QCOMPARE(mockDest1->messageCount(), 0);
+    QCOMPARE(mockDest2->messageCount(), 0);
+
+    QLOG_WARN() << "warning";
+    QLOG_ERROR() << "error";
+    QLOG_FATAL() << "fatal";
+    QCOMPARE(mockDest1->messageCountForLevel(WarnLevel), 1);
+    QCOMPARE(mockDest1->messageCountForLevel(ErrorLevel), 1);
+    QCOMPARE(mockDest1->messageCountForLevel(FatalLevel), 1);
+    QCOMPARE(mockDest1->messageCount(), 3);
+    QCOMPARE(mockDest2->messageCountForLevel(WarnLevel), 1);
+    QCOMPARE(mockDest2->messageCountForLevel(ErrorLevel), 1);
+    QCOMPARE(mockDest2->messageCountForLevel(FatalLevel), 1);
+    QCOMPARE(mockDest2->messageCount(), 3);
+}
+
+void TestLog::testLevelParsing()
+{
+    mockDest1->clear();
+
+    QLOG_TRACE() << "one";
+    QLOG_DEBUG() << "two";
+    QLOG_INFO() << "three";
+    QLOG_WARN() << "warning";
+    QLOG_ERROR() << "error";
+    QLOG_FATAL() << "fatal";
+
+    using namespace QsLogging;
+    for(int i = 0;i < mockDest1->messageCount();++i) {
+        bool conversionOk = false;
+        const MockDestination::Message& m = mockDest1->messageAt(i);
+        QCOMPARE(Logger::levelFromLogMessage(m.text, &conversionOk), m.level);
+        QCOMPARE(Logger::levelFromLogMessage(m.text), m.level);
+        QCOMPARE(conversionOk, true);
+    }
+}
+
+void TestLog::cleanupTestCase()
+{
+    QsLogging::Logger::destroyInstance();
+}
+
+QTTESTUTIL_REGISTER_TEST(TestLog);
+#include "TestLog.moc"
diff --git a/deltarobot/libQsLog/unittest/unittest.pro b/deltarobot/libQsLog/unittest/unittest.pro
new file mode 100644
index 0000000..e5c39ce
--- /dev/null
+++ b/deltarobot/libQsLog/unittest/unittest.pro
@@ -0,0 +1,21 @@
+QT += core
+
+TARGET = QsLogUnitTest
+CONFIG += console qtestlib
+CONFIG -= app_bundle
+TEMPLATE = app
+
+# test-case sources
+SOURCES += TestLog.cpp
+
+# component sources
+include(../QsLog.pri)
+
+SOURCES += \
+    ./QtTestUtil/TestRegistry.cpp \
+    ./QtTestUtil/SimpleChecker.cpp
+
+HEADERS += \
+    ./QtTestUtil/TestRegistry.h \
+    ./QtTestUtil/TestRegistration.h \
+    ./QtTestUtil/QtTestUtil.h
diff --git a/deltarobot/main.cpp b/deltarobot/main.cpp
new file mode 100644
index 0000000..c73cfef
--- /dev/null
+++ b/deltarobot/main.cpp
@@ -0,0 +1,51 @@
+#include "mainwindow.h"
+#include <QApplication>
+#include <QDir>
+#include "QsLog.h"
+#include "QsLogDest.h"
+#include <QStyleFactory>
+#include <QSettings>
+
+/*! \mainpage Aplikace pro práci s cvičebním strojem
+ *
+ *  Tato aplikace slouží pro práci s cvičebním strojem. Umožňuje vybírat
+ * křivky, které bude pacient cvičit v jednotlivých procedurách, ukládá i výsledky jednotlivých procedur.
+ * Je možno také vytvořit vlastní křivku a tuto uložit na disk a později ji i do stroje nahrát.
+ *
+ *  \image html main_view.jpg
+ *  \image latex main_view.eps "Hlavní okno aplikace" width=10cm
+ */
+
+int main(int argc, char *argv[])
+{
+    QApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true);
+    QApplication a(argc, argv);
+
+    // init the logging mechanism
+    QString stFname = qApp->applicationDirPath() + "/settings.ini";
+    QSettings st(stFname, QSettings::IniFormat);
+
+    unsigned int logLevel = st.value("Log/loglevel", QsLogging::ErrorLevel).toUInt();
+    if (logLevel > QsLogging::OffLevel)
+        logLevel = QsLogging::OffLevel;
+
+    QsLogging::Logger& logger = QsLogging::Logger::instance();
+    logger.setLoggingLevel((QsLogging::Level)logLevel);
+    const QString sLogPath(QDir(a.applicationDirPath()).filePath("log.txt"));
+    QsLogging::DestinationPtr fileDestination(
+            QsLogging::DestinationFactory::MakeFileDestination(sLogPath, QsLogging::EnableLogRotation,
+                                           QsLogging::MaxSizeBytes(65535), QsLogging::MaxOldLogCount(4)) );
+    logger.addDestination(fileDestination);
+
+    QLOG_DEBUG() << "Debug lebel = " << logLevel;
+
+    QStringList styles = QStyleFactory::keys();
+    if (styles.contains("Fusion"))
+        a.setStyle(QStyleFactory::create("Fusion"));
+
+    MainWindow w;
+
+    w.show();
+
+    return a.exec();
+}
diff --git a/deltarobot/mainwindow.cpp b/deltarobot/mainwindow.cpp
new file mode 100644
index 0000000..7d392da
--- /dev/null
+++ b/deltarobot/mainwindow.cpp
@@ -0,0 +1,1712 @@
+#include "mainwindow.h"
+#include "curvedialog.h"
+#include "infodialog.h"
+#include "selectpatientdlg.h"
+#include "ui_mainwindow.h"
+#include <QModbusTcpClient>
+#include <QList>
+#include <QVector3D>
+#include <QVector>
+#include <QTimer>
+#include <QTime>
+#include <QSettings>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QSqlQueryModel>
+#include <QScreen>
+
+//prehravani naucene krivky
+#define BIT_BPLAY           32772
+//cviceni naucene kriky
+#define BIT_BPLAY_ASSIST    32773
+
+//povoleni tenzometru
+#define BIT_BXYZ            32779
+//uceni krivky
+#define BIT_BTEACH          32780
+//poloha klicku - je to discrete input
+#define BIT_BKEY            32789
+//bezpecnostni tlacitko
+#define BIT_SAFETY_BTN      32785
+
+//polohovaci motor
+#define BIT_MOTOR_UP        32788
+#define BIT_MOTOR_DOWN      32789
+
+//reset pozice
+#define BIT_RESET_POS       32769
+
+#define BIT_WRITE_ENABLE    32868
+#define BIT_DATA_TO_PLC     32869
+#define BIT_DATA_TO_PC      32870
+#define BIT_RDY             32871
+#define BIT_PART_FINISHED   32873
+#define BIT_MEASUREMENT_TO_PC 32874
+
+//aktualni pozice
+#define REG_X       32768
+#define REG_Y       32769
+#define REG_Z       32770
+#define REG_A       32771
+
+//pozice vektoru, kam se tlaci
+#define REG_ACT_X   32772
+#define REG_ACT_Y   32773
+#define REG_ACT_Z   32774
+
+//pozice vektoru, kam se ma tlacit
+#define REG_DIR_X   32776
+#define REG_DIR_Y   32777
+#define REG_DIR_Z   32778
+
+#define REG_LEN     32866
+#define REG_INDEX   32867
+#define REG_DATA    32868
+
+#define REG_Q_1     32780
+#define REG_Q_TOT   32781
+#define REG_Q_PART  32782
+
+//rychlost cviceni
+#define REG_SPEED   32799
+
+#define NO_STATE        0
+#define SEND_CURVE      1
+#define SEND_PREP_CURVE 2
+#define SEND_WAIT_CURVE 3
+#define SEND_LAST_CURVE 4
+#define GET_CURVE       5
+#define GET_WAIT_CURVE  6
+#define GET_PART_CURVE  7
+#define GET_NEXT_PART   8
+#define GET_LAST_CURVE  9
+#define GET_MEAS_START  10
+#define GET_MEAS_WAIT   11
+#define GET_MEAS_LEN    12
+#define GET_MEAS_NEXT   13
+#define GET_MEAS_LAST   14
+
+//poloha aplikatoru v zakladnim stavu (tj. v reset pozici)
+#define RES_X_POS       1000
+#define RES_Y_POS       1000
+#define RES_Z_POS       3000
+
+MainWindow::MainWindow(QWidget *parent) :
+    QMainWindow(parent),
+    ui(new Ui::MainWindow)
+{
+    ui->setupUi(this);
+
+    mbClient = new QModbusTcpClient(this);
+    pendingRead = pendingWrite = lastPacket = initStep = bSpeedUpdated = false;
+    calcCurvePoints[0] = calcCurvePoints[1] = staticSpherePos = spherePos = QVector3D(0,0,0);
+    dirArrow = QVector3D(0,0,0);
+    actualArrow = QVector3D(0,0,0);
+    testSpherePos = QVector3D(0,0,0);
+    overallQ = oneCycleQ = tempQ = 0;
+    pId = indId = 0;
+    pronSupVal = PRON_SUP_NOT;
+    actSeries = 0;
+
+    itemCount = cntr = 0;
+
+    safetyBtnState = safetyBtnBlinkOn = keyAutoBtnBlinkOn = 0;
+
+    receivedDataSize = 0;
+
+    mbServerId = 1;
+
+    pd = waitDlg = nullptr;
+
+    checkTimer = new QTimer(this);
+    procedureTimer = new QTimer(this);
+    procedureTimeRemaining = 600;
+    ui->procTimeDial->setValue(10);
+
+    connect(mbClient, &QModbusClient::errorOccurred, this, &MainWindow::handleDeviceError);
+    connect(mbClient, &QModbusClient::stateChanged, this, &MainWindow::onStateChanged);
+
+    connect(ui->curveGenerateBtn, SIGNAL(clicked()), this, SLOT(curveGenerateClicked()));
+    connect(ui->curvePlayBtn, SIGNAL(toggled(bool)), this, SLOT(curvePlayChanged(bool)));
+    connect(ui->curveAssistPlayBtn, SIGNAL(toggled(bool)), this, SLOT(curveAssistChanged(bool)));
+    connect(ui->curveTeachBtn, SIGNAL(toggled(bool)), this, SLOT(curveTeachChanged(bool)));
+    connect(ui->curveStoreBtn, SIGNAL(clicked()), this, SLOT(curveStoreClicked()));
+    connect(ui->curveLoadBtn, SIGNAL(clicked()), this, SLOT(curveLoadClicked()));
+    connect(ui->measurementLoadBtn, SIGNAL(clicked()), this, SLOT(measurementLoadClicked()));
+    connect(ui->resetPosBtn, SIGNAL(clicked()), this, SLOT(deviceResetClicked()));
+    connect(ui->patientSelectBtn, SIGNAL(clicked()), this, SLOT(patientSelectClicked()));
+
+    connect(ui->procTimeDial, SIGNAL(sliderMoved(int)), this, SLOT(timeDialMoved(int)));
+    connect(ui->procTimeDial, SIGNAL(sliderReleased()), this, SLOT(timeDialReleased()));
+
+    connect(ui->upDownSlider, SIGNAL(sliderMoved(int)), this, SLOT(upDownSliderMoved(int)));
+    connect(ui->upDownSlider, SIGNAL(sliderReleased()), this, SLOT(movementSliderReleased()));
+
+    connect(checkTimer, SIGNAL(timeout()), this, SLOT(mainCycle()));
+    connect(procedureTimer, SIGNAL(timeout()), this, SLOT(updateAppTime()));
+
+
+    currState = numPoints = 0;
+
+    ui->connectionLabel->setStyleSheet("background-color: rgb(255,0,0)");
+    ui->dbConnectionStatusLabel->setStyleSheet("background-color: rgb(255,0,0)");
+
+    mbConnected = false;
+    bTeachStatus = bWriteEnable = bProcedureRunning = bPartState = bKeyState = bPlay = 0;
+
+    qualitySet = new QBarSet("Kvalita");
+    qualityData = new QBarSeries();
+    qualityData->append(qualitySet);
+
+    QFont font;
+    font.setPixelSize(18);
+
+    chart = new QChart();
+    chart->addSeries(qualityData);
+
+    axisy = new QValueAxis();
+    axisy->setRange(0.0, 100.0);
+    axisy->setLabelsFont(font);
+
+    //chart->createDefaultAxes(); // Preparing the axis
+    chart->setAxisY(axisy, qualityData);
+    //chart->axisX()->setRange(0,1);
+    //chart->axisX()->setLabelsFont(font);
+    //chart->axisY()->setLabelsFont(font);
+    //chart->axisY()->setRange(0,100);
+    chart->setTitle(tr("Graf kvality cvičení"));
+
+    // Same formatting
+    chart->setTitleFont(font);
+    chart->setBackgroundVisible(false);
+    chart->setMargins(QMargins(0,0,0,0));
+    //chart->layout()->setContentsMargins(0,0,0,0);
+    chart->legend()->hide();
+    chart->setPlotAreaBackgroundBrush(QBrush(Qt::black));
+    chart->setPlotAreaBackgroundVisible(true);
+    graphView = new QChartView(chart);
+    graphView->setMinimumSize(250,120);
+
+    ui->verticalLayout->addWidget(graphView);
+    ui->splitter->setStretchFactor(0,0);
+    ui->splitter->setStretchFactor(1,1);
+
+    QString stFname = qApp->applicationDirPath() + "/settings.ini";
+    QSettings st(stFname, QSettings::IniFormat);
+    serverIp = st.value("serverIP","192.168.254.20:502").toString();
+    actCurveType = st.value("curveType", CURVE_NONE).toInt();
+    actCurveFileName = st.value("curveFileName","").toString();
+    minDistanceFromTarget = st.value("minDistance", 400).toInt();
+    ui->splitter->restoreState(st.value("splitterSizes").toByteArray());
+    int cStep = st.value("curveStep", 1).toInt();
+    //ui->glwidget->setConfig(cStep);
+    calculatedCurve.clear();
+
+    //inicializace databaze
+    useDb = st.value("useDb", 0).toInt();
+    auto dbAddr = st.value("dbAddress", "localhost").toString();
+    auto dbUser = st.value("dbUser", "postgres").toString();
+    auto dbPassword = st.value("dbPassword", "").toString();
+    auto dbPort = st.value("dbPort", 5432).toInt();
+    auto dbName = st.value("dbName","Cviceni").toString();
+
+    db = new dbAccess();
+    model = new QSqlQueryModel;
+
+    if (useDb) {
+        dbConnected = db->connect(dbAddr, dbUser, dbPassword, dbPort, dbName);
+        if (dbConnected) {
+            QLOG_INFO() << tr("OK< db connection established");
+            ui->dbConnectionStatusLabel->setStyleSheet("background-color: rgb(0,255,0)");
+            ui->dbConnectionStatusLabel->setText(tr("DB připojena"));
+        }
+    }
+
+    //knofliky pro cviceni jsou pro zacatek disablovany
+    ui->resetPosBtn->setEnabled(false);
+    ui->curvePlayBtn->setEnabled(false);
+    ui->curveAssistPlayBtn->setEnabled(false);
+    ui->curveGenerateBtn->setEnabled(false);
+    //ui->curveGenerateBtn->setEnabled(true);
+    ui->curveTeachBtn->setEnabled(false);
+    ui->curveLoadBtn->setEnabled(false);
+    ui->curveStoreBtn->setEnabled(false);
+
+    QScreen *screen = QGuiApplication::primaryScreen();
+    QRect  screenGeometry = screen->geometry();
+    this->setFixedSize(screenGeometry.width(),screenGeometry.height());
+    //this->setFixedSize(1366,768);
+
+    QTimer::singleShot(100, this, SLOT(display3DScene())); //kvuli nakresleni zakladni sceny
+
+    connectionGuard = new QTime;
+    connectionGuard->start();
+    connectionEstablished = false;
+    connectClicked();
+        QLOG_DEBUG() << "Get part";
+#ifdef PROCEDURE_TEST
+    sphere.append(readPoints("kruh.txt"));
+    act.append(readPoints("act.txt"));
+    dir.append(readPoints("dir.txt"));
+    cur.clear();
+#endif
+}
+
+MainWindow::~MainWindow()
+{
+    QString stFname = qApp->applicationDirPath() + "/settings.ini";
+    QSettings st(stFname, QSettings::IniFormat);
+    st.setValue("splitterSizes",ui->splitter->saveState());
+    st.setValue("curveType", actCurveType);
+    st.setValue("curveFileName",actCurveFileName);
+
+    if (mbConnected) {
+        mbClient->disconnectDevice();
+    }
+    delete db;
+    delete ui;
+}
+
+//! Připojit/Odpojit modbus server
+/*!
+ * Funkce připojí, nebo odpojí modbus zařízení
+ */
+void MainWindow::connectClicked()
+{
+    const QUrl url = QUrl::fromUserInput(serverIp);
+
+#ifdef PROCEDURE_TEST
+        checkTimer->start(100);
+        //ui->glwidget->procedureState(true);
+        ui->curvePlayBtn->setEnabled(true);
+        ui->curveAssistPlayBtn->setEnabled(true);
+        ui->curveGenerateBtn->setEnabled(true);
+        ui->curveTeachBtn->setEnabled(true);
+        ui->curveLoadBtn->setEnabled(true);
+        ui->curveStoreBtn->setEnabled(true);
+        ui->safetyBtnLabel->setStyleSheet("background-color: rgb(0,255,0)");
+        ui->connectionLabel->setStyleSheet("background-color: rgb(0,255,0)");
+        ui->connectionLabel->setText(tr("Připojeno"));
+
+        return;
+#endif
+
+    if (!mbConnected) {
+        mbClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
+        mbClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());
+        mbClient->setTimeout(500);
+        mbClient->setNumberOfRetries(3);
+        if (!mbClient->connectDevice()) {
+            QLOG_ERROR() << "Err connecting";
+        }
+        connectionGuard->start();
+        checkTimer->start(500);
+    } else {
+        mbClient->disconnectDevice();
+    }
+}
+
+//! Funkce volána po ukončení učení křivky
+/*!
+ * Funkce je volána poté, co je dokončeno učení nové křivky. Začne se stahování
+ *  křivky do PC
+ */
+void MainWindow::changeClicked()
+{
+#ifndef FILE_TEST
+    file.setFileName("data.txt");
+    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+         store.setDevice(&file);
+
+         //QLOG_WARN() << "e";
+         store << "x;y;z;r" << endl;
+    }
+
+    currState = GET_CURVE;
+    calculatedCurve.clear();
+#else
+    QString line;
+    QStringList list;
+    int i = 0;
+    qint16 x,y,z,a;
+    file.setFileName("data.txt");
+    calculatedCurve.clear();
+    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+         store.setDevice(&file);
+
+         //QLOG_WARN() << "e";
+
+         while(!store.atEnd()) {
+             line = store.readLine();
+             list = line.split(';');
+             x = list.at(0).toShort();
+             y = list.at(1).toShort();
+             z = list.at(2).toShort();
+             a = list.at(3).toShort();
+             calculatedCurve.append(QVector3D(x,y,z,a));
+         }
+         file.close();
+    }
+    ui->glwidget->setCurve(calculatedCurve);
+#endif
+}
+
+//! Výběr předpočítané křivky
+/*!
+ * Po stisknutí tlačítka na výběr křivky. Zavolá se odpovídající dialog a po
+ *  úspěšném výběru parametrů křivky se tato předpočte a pošle do stroje
+ */
+void MainWindow::curveGenerateClicked()
+{
+    curveDialog dlg;
+
+    if (dlg.exec() == QDialog::Accepted) {
+        dlg.getCurve(&actCurveType, &actCurveAngle, &actCurveRot, &pronSupVal);
+        ui->glwidget->setTubusColor(QVector4D(1, 0.737f, 0.231f, 0.7f));
+        setCurveData();
+#ifdef PROCEDURE_TEST
+        itemCount = cntr = 0;
+#endif
+    }
+ }
+
+//! Připravení dat křivky
+/*!
+ * Připraví křivku, která pak bude poslána do stroje. Křika bude buďto předpočítaná na
+ *  základě vybraných parametrů, anebo bude načtena ze souboru na disku.
+ */
+void MainWindow::setCurveData()
+{
+    int stepcount = 250,i, tmpI;
+    double x, x1, y, y1, z, a, tmpdeg;
+
+#ifdef FILE_TEST
+    file.setFileName("data.txt");
+    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+         store.setDevice(&file);
+    }
+#endif
+
+    if (actCurveType == CURVE_EXTERN) {
+        if (!getCurveDataFromFile(actCurveFileName)) {
+            QMessageBox::critical(this, tr("Cvičební stroj"),
+                             tr("<font size=15>Nepodařilo se importovat křivku ze souboru.\nVyberte jiný soubor, nebo vygenerujte jinou křivku.</font>"),
+                             QMessageBox::Ok);
+
+            return;
+        }
+    } else {
+        calculatedCurve.clear();
+
+        //kdyz nebude pouzita zadna krivka - vymazat starou krivku
+        if (actCurveType == CURVE_NONE)
+            display3DScene();
+
+        for (i=0; i < stepcount+1; i++) {
+            if (actCurveRot == ROTATE_CLKWISE)
+                tmpI = stepcount - i;
+            else
+                tmpI = i;
+            tmpdeg = tmpI * (360.0/stepcount) * M_PI / 180.0;
+
+            switch(actCurveType) {
+            case CURVE_CIRCLE:
+                x = 1600 * cos(tmpdeg);
+                y = 1600 * sin(tmpdeg);
+                break;
+            case CURVE_ELLIPSE:
+                x = 1200 * cos(tmpdeg);
+                y = 1600 * sin(tmpdeg);
+                break;
+            case CURVE_LEMN:
+                x = sqrt(2)*(1400)*cos(tmpdeg)/(1+sin(tmpdeg)*sin(tmpdeg));
+                y = sqrt(2)*(3650)*sin(tmpdeg)*cos(tmpdeg)/(1+sin(tmpdeg)*sin(tmpdeg));
+                break;
+            case CURVE_KARD:
+                x = (750)*2*cos(tmpdeg)-(750)*cos(2*tmpdeg);
+                y = (750)*2*sin(tmpdeg)-(750)*sin(2*tmpdeg);
+                break;
+            case CURVE_LINE:
+                if (i < stepcount/2)
+                    tmpI = i * 2;
+                else
+                    tmpI = (stepcount - i) * 2;
+
+                if (actCurveRot != ROTATE_CLKWISE)
+                    tmpI = (stepcount - tmpI);
+
+                //x = -2200 + tmpI * 4400.0 / stepcount;
+                x = -2200 + tmpI * 4400.0 / stepcount;
+                y = 0;// -2200 + tmpI * 4400.0 / stepcount;
+                break;
+            default:
+                x = RES_X_POS;
+                y = RES_Y_POS;
+                z = RES_Z_POS;
+            }
+
+            x1 = x*cos(actCurveAngle*M_PI/4)-y*sin(actCurveAngle*M_PI/4);
+            y1 = x*sin(actCurveAngle*M_PI/4)+y*cos(actCurveAngle*M_PI/4);
+
+            if (actCurveType != CURVE_NONE)
+                z = 6500.0 - y1*0.9;
+
+            tmpdeg = 2 * M_PI * i / (double)stepcount;   //to same jako horni tmpdeg, jen s i
+            switch(pronSupVal) {
+            case PRON_SUP_1:
+                a = sin(tmpdeg) * 15 + 45;
+                break;
+            case PRON_SUP_2:
+                a = sin(tmpdeg) * 45 + 45;
+                break;
+            default:
+                a = 0.0;
+            }
+
+            if (i == stepcount/2)
+                calcCurvePoints[0] = QVector3D(x1,y1,z);
+            else if (i == stepcount)
+                calcCurvePoints[1] = QVector3D(x1,y1,z);
+
+            calculatedCurve.append(QVector4D(x1,y1,z,a*10));
+#ifdef FILE_TEST
+            if (file.isOpen()) {
+                store << (qint16)x1 << ";" << (qint16)y1 << ";" << (qint16)(7500.0+y/2.5) << ";" << (qint16)a << endl;
+            }
+#endif
+        }
+#ifdef FILE_TEST
+        if (file.isOpen())
+            file.close();
+#endif
+        ui->glwidget->setTubusColor(QVector4D(1, 0.737f, 0.231f, 0.7f));
+        if (actCurveType != CURVE_NONE)
+            ui->glwidget->setCurve(calculatedCurve);
+        currState = SEND_CURVE;
+    }
+}
+
+//! Učení křivky
+/*!
+ * V závislosti na vstupním parametru je zahájeno, nebo ukončeno učení křivky. Pokud je učení zahájeno, je nejprve zobrazen
+ *  dialog s informací o tom, že je třeba počkat, než bude aplikátor v základní pozici. Pak je možno začít manuálně
+ * projíždět křivku, která bude zaznamenána strojem.
+ * Pokud je učení ukončeno, je do stroje poslán příkaz o ukončení učení
+ * \param pressed Parametr, který obsahuje informaci o tom, jestli má být učení zahájeno, nebo ukončeno
+ */
+void MainWindow::curveTeachChanged(bool pressed)
+{
+    if (pressed) {
+        deviceResetClicked();
+        display3DScene();
+
+        waitDlg = new QProgressDialog("<font size=15>Počkejte, než bude stroj v základní pozici</font>", "Zrušit", 0, 50);
+        waitDlg->setModal(true);
+        waitDlg->setValue(0);
+        waitDlg->show();
+        ui->curveTeachBtn->setStyleSheet("background-color: rgb(0, 85, 255)");
+    } else {
+        if (waitDlg != nullptr) {
+            delete waitDlg;
+            waitDlg = nullptr;
+        }
+
+        writeValue(BIT_BTEACH, QModbusDataUnit::Coils,0);
+        writeValue(BIT_BXYZ, QModbusDataUnit::Coils,0);
+        ui->curveTeachBtn->setStyleSheet("background-color: rgb(0, 222, 222)");
+    }
+}
+
+//! Výběr uložené křivky
+/*!
+ * Po stisknutí tlačítka na načtení křivky z disku se objeví dialog pro výběr souboru. Pak
+ * je křivka vyčtena z daného souboru.
+ */
+void MainWindow::curveLoadClicked()
+{
+    QString fileName = QFileDialog::getOpenFileName(this,
+         tr("Načíst křivku"), "", tr("Souboru s křivkou (*.txt);;Vše (*.*)"));
+
+    getCurveDataFromFile(fileName);
+}
+
+void MainWindow::measurementLoadClicked()
+{
+    openMeasurementFile();
+    writeValue(BIT_MEASUREMENT_TO_PC, QModbusDataUnit::Coils, 1);
+    currState = GET_MEAS_START;
+}
+
+QVector4D MainWindow::getDeltaMovingAverage(QVector4D point)
+{
+    tmpCurveMA.push_back(point);
+    if (tmpCurveMA.size() > 10)
+        tmpCurveMA.pop_front();
+    qint32 sumx = 0, sumy = 0, sumz = 0;
+    for (auto val: tmpCurveMA) {   //std::list<float>::iterator p = listDeltaMA.begin(); p != listDeltaMA.end(); ++p)
+        sumx += val.x();
+        sumy += val.y();
+        sumz += val.z();
+    }
+    return QVector4D(sumx/tmpCurveMA.size(), sumy/tmpCurveMA.size(), sumz/tmpCurveMA.size(), point.w());
+}
+
+void MainWindow::openMeasurementFile()
+{
+    file.setFileName(QString("%1.csv").arg(QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss")));
+    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+         store.setDevice(&file);
+
+         store << "cas;x1;y1;z1;x2;y2;z2;x3;y3;z3" << endl;
+    }
+}
+
+//!  Načtení uložené křivky ze souboru
+int MainWindow::getCurveDataFromFile(QString fileName)
+{
+    int nRet = 0;
+    QFile file(fileName);
+
+    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        calculatedCurve.clear();
+
+        QTextStream storeFile(&file);
+        QVector4D point;
+        QVector3D pointPrev;
+        QStringList list;
+        QString line;
+
+        tmpCurveMA.clear();
+
+        while(!storeFile.atEnd()) {
+            line = storeFile.readLine();
+            list = line.split(';');
+            if (list.size() < 4)
+                continue;
+            point.setX(list.at(0).toShort());
+            point.setY(list.at(1).toShort());
+            point.setZ(list.at(2).toShort());
+            point.setW(list.at(3).toShort());
+            if (calculatedCurve.size() > 1) {
+                pointPrev = calculatedCurve.last().toVector3D();
+                if (pointPrev.distanceToPoint(point.toVector3D()) > 500.0)
+                    calculatedCurve.append(getDeltaMovingAverage(point));
+            } else
+                calculatedCurve.append(getDeltaMovingAverage(point));
+            /*pos++;
+            if ((pos % 4) == 0)
+                calculatedCurve.append(getDeltaMovingAverage(point));*/
+        }
+        if (calculatedCurve.size() > 2) {
+            for (int i = 0; i<10; i++)
+                calculatedCurve.append(getDeltaMovingAverage(calculatedCurve.first()));
+        }
+
+        file.close();
+        if (calculatedCurve.size() > 0) {
+            ui->glwidget->setTubusColor(QVector4D(1, 0.737f, 0.231f, 0.7f));
+            ui->glwidget->setCurve(calculatedCurve);
+        }
+        actCurveFileName = fileName;
+        actCurveType = CURVE_EXTERN;
+        currState = SEND_CURVE;
+        nRet = 1;
+    }
+    return nRet;
+}
+
+//! Uložení aktuální křivky
+/*!
+ * Po stisknutí tlačítka "Uložení křivky" se objeví dialog pro výběr souboru. Pak
+ * je aktuální křivka uložena do daného souboru.
+ */
+void MainWindow::curveStoreClicked()
+{
+    if (calculatedCurve.size() > 0) {
+        QString fileName = QFileDialog::getSaveFileName(this,
+            tr("Uložit křivku"), "", tr("Souboru s křivkou (*.txt)"));
+
+        QFile file(fileName);
+        if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+            QTextStream storeFile(&file);
+
+            for(auto &point: calculatedCurve) { //C++ 11 use
+                storeFile << static_cast<qint16>(point.x()) << ";" << static_cast<qint16>(point.y())
+                          << ";" << static_cast<qint16>(point.z()) << ";" << static_cast<qint16>(point.w()) << endl;
+            }
+            file.close();
+        }
+
+    } else {
+        QMessageBox::warning(this, tr("Cvičební stroj"),
+                             tr("<font size=15>V aplikaci není stažená žádná křivka\n</font>"),
+                             QMessageBox::Ok);
+    }
+}
+
+//! Přesun aktuatoru do defaultní pozice
+void MainWindow::deviceResetClicked()
+{
+    writeValue(BIT_RESET_POS, QModbusDataUnit::Coils, 1);
+}
+
+//! Výběr pacienta
+/*!
+ * Po stisknutí tlačítka "Výběr pacienta" se objeví dialog pro výběr pacienta, který bude provádět procedury.
+ * Konkrétní křivka a její provedení odpovídající proceduře je získána z databáze.
+ */
+void MainWindow::patientSelectClicked()
+{
+    if (!useDb) {
+        infoDialog dlg;
+        dlg.setInfoText(tr("Výběr pacienta/indikace"),tr("DB není použita, data nemohou být vybrána"));
+        dlg.exec();
+    } else {
+        if (dbConnected) {
+            selectPatientDlg dlg(db);
+            QString cName;
+            QStringList curveDataStr;
+            dlg.exec();
+            if (dlg.result() == QDialog::Accepted) {
+                QString name, surname;
+                dlg.getPatientInfo(&pId, &indId, &name, &surname, &actSeries, &procedureTimeRemaining, &cName);
+
+                if (!cName.isEmpty()) {
+                    curveDataStr = cName.split("_");
+                    if (curveDataStr.size() == 4) {
+                        actCurveType = curveDataStr.at(0).toInt();
+                        actCurveAngle = curveDataStr.at(1).toInt();
+                        actCurveRot = curveDataStr.at(2).toInt();
+                        pronSupVal = curveDataStr.at(3).toInt();
+                        ui->glwidget->setTubusColor(QVector4D(1, 0.737f, 0.231f, 0.7f));
+                        setCurveData();
+                    }
+                }
+
+                ui->patientNameLabel->setText(tr("Jméno: ") + name + " " + surname);
+                ui->indicationLabel->setText(tr("Série: ") + QString::number(actSeries));
+                ui->curveAssistPlayBtn->setText(tr("Spustit cvičení\n") + QString::number(procedureTimeRemaining/60)
+                                                + ":" + QString("%1").arg(procedureTimeRemaining%60,2,10,QChar('0')) + "min");
+                ui->procTimeDial->setValue(procedureTimeRemaining/60);
+            }
+        } else {
+            infoDialog dlg;
+            dlg.setInfoText(tr("Výběr pacienta/indikace"),tr("DB není připojena, data nemohou být vybrána"));
+            dlg.exec();
+        }
+    }
+}
+
+//! Předvedení křivky strojem
+/*!
+ * Po stisknutí tlačítka "Provedení křivky" stroj začne opisovat křivku (bez asistence pacienta), která byla naposledy
+ * do stroje poslána. Tento příkaz slouží k otestování, jak bude cvičení vypadat. Po dalším stisknutí tlačítka se
+ * provádění křivky ukončí.
+ * \param pressed Parametr, který obsahuje informaci o tom, jestli má být předvádění zahájeno, nebo ukončeno
+ */
+void MainWindow::curvePlayChanged(bool pressed)
+{
+    if (pressed)
+        writeValue(BIT_BPLAY, QModbusDataUnit::Coils,1);
+    else
+        writeValue(BIT_BPLAY, QModbusDataUnit::Coils,0);
+}
+
+//! Start/stop procedury
+/*!
+ * Po stisknutí tlačítka "Spustit cvičení" stroj začne provádět cvičení (s asistencí pacienta) procedury. Provádí se
+ * po křivce, která byla naposledy do stroje poslána. Procedura se zastaví buď po uplynutí nastaveného času a nebo po
+ * dalším stisknutí téhož tlačítka, které bude po startu cvičení přejmenováno na "Ukončit cvičení"
+ * \param pressed Parametr, který obsahuje informaci o tom, jestli má být procedura zahájena, nebo ukončena
+ */
+void MainWindow::curveAssistChanged(bool pressed)
+{
+#ifdef PROCEDURE_TEST
+    if (pressed) {
+        procedureTimer->start(1000);
+        ui->curveAssistPlayBtn->setStyleSheet("background-color: rgb(255, 170, 0);");
+    }
+    else {
+        procedureTimer->stop();
+
+        procedureTimeRemaining = ui->procTimeDial->value()*60;
+        ui->curveAssistPlayBtn->setText(tr("Spustit cvičení\n") + QString::number(procedureTimeRemaining/60)
+                                        + ":" + QString("%1").arg(procedureTimeRemaining%60,2,10,QChar('0')) + "min");
+
+        ui->curveAssistPlayBtn->setStyleSheet("background-color: rgb(0, 255, 0);");
+
+        infoDialog dlg;
+        dlg.setInfoText(tr("Cvičení"),tr("Cvičení je dokončeno"));
+        dlg.exec();
+    }
+#else
+    if (!bKeyState)
+        return;
+
+    if (pressed) {
+        writeValue(BIT_BPLAY_ASSIST, QModbusDataUnit::Coils,1);
+        ui->curveAssistPlayBtn->setStyleSheet("background-color: rgb(255, 170, 0);");
+    } else {
+        writeValue(BIT_BPLAY_ASSIST, QModbusDataUnit::Coils,0);
+        ui->curveAssistPlayBtn->setStyleSheet("background-color: rgb(0, 255, 0);");
+    }
+#endif
+}
+
+//! Posun aktuátoru nahoru/dolu
+/*!
+ * Když je posuvník potažen směrem nahoru, stroj jede s aktuátorem nahoru. Dtto pro směr dolu
+ * \param val Parametr, podle kterého se pozná, zda má stroj jet nahoru, nebo dolu
+ */
+void MainWindow::upDownSliderMoved(int val)
+{
+    QVector<quint16> vals;
+
+    if (val > 50) { //motor nahoru
+        vals.append(1);  //up
+        vals.append(0);  //down
+    } else if (val == 50) {  // motor zastavit
+        vals.append(0);  //up
+        vals.append(0);  //down
+    } else { //motor dolu
+        vals.append(0);  //up
+        vals.append(1);  //down
+    }
+    writeValues(BIT_MOTOR_UP, QModbusDataUnit::Coils, vals);
+}
+
+//! Posun aktuátoru zastavit
+/*!
+ * Když je posuvník uvolněn, stroj zastaví pohyb nahoru/dolu.
+ */
+void MainWindow::movementSliderReleased()
+{  //motor zastavit
+    ui->upDownSlider->setValue(50);
+    writeValue(BIT_MOTOR_UP, QModbusDataUnit::Coils,0);
+    writeValue(BIT_MOTOR_DOWN, QModbusDataUnit::Coils,0);
+}
+
+//! Hlavní cyklus
+/*!
+ * Funkce je volána periodicky každých 100ms, když je modbus/tcp aktivní. Je zde řešena periodická kontrola spojení se strojem.
+ * Pokud je modbus/tcp spojení ukončeno, zkusí se znovu připojit. V každém volání funkce se vytváří pořadavky na čtení dat ze stroje.
+ * Dále se mění parametry stavového stroje na základě přijatých dat
+ */
+void MainWindow::mainCycle()
+{
+    if (connectionEstablished) {
+        if (connectionGuard->elapsed() > 1000) {
+            QLOG_ERROR() << tr("Od stroje nepřišla odpověď více, než 1 sekundu");
+            connectionGuard->restart();
+        }
+    } else {
+        if (connectionGuard->elapsed() > 20000) {
+            QLOG_ERROR() << tr("Pokouším se znovu připojit");
+            if (mbConnected) {
+                mbClient->disconnectDevice();
+                mbConnected = false;
+            }
+            connectClicked();
+            connectionGuard->restart();
+        }
+    }
+
+    if (waitDlg != nullptr) {
+        int val = waitDlg->value();
+        waitDlg->setValue(val+1);
+#ifdef PROCEDURE_TEST
+        itemCount = 0;
+#endif
+        if ((val > 48)|| (waitDlg->wasCanceled())) {
+            delete waitDlg;
+            waitDlg = nullptr;
+            //stroj by mel byt v zakladni pozici
+
+            infoDialog dlg;
+            dlg.setInfoText("Učení", "Stroj je v základní pozici, stisknutím OK můžete začít učit pohyb\nPřipojte prosím pacienta ke stroji.");
+            dlg.exec();
+
+            writeValue(BIT_BTEACH, QModbusDataUnit::Coils,1);
+            writeValue(BIT_BXYZ, QModbusDataUnit::Coils,1);
+        }
+    }
+
+#if !defined(FILE_TEST) && !defined(PROCEDURE_TEST)
+    if (!mbConnected)
+        return;
+
+    switch(currState) {
+    case NO_STATE:
+        if (!pendingRead) {
+            //precteme vsechny vektory najednou - REG, REG_ACT,REG_DIR i REG_Q
+            readValues(REG_X, QModbusDataUnit::HoldingRegisters, 15);
+            //readValue(REG_SPEED, QModbusDataUnit::HoldingRegisters);
+            readValue(BIT_WRITE_ENABLE, QModbusDataUnit::Coils);
+            readValue(BIT_BTEACH, QModbusDataUnit::Coils);
+            readValue(BIT_BPLAY_ASSIST, QModbusDataUnit::Coils);
+            readValue(BIT_BPLAY, QModbusDataUnit::Coils);
+            readValue(BIT_BKEY, QModbusDataUnit::DiscreteInputs);
+            readValue(BIT_PART_FINISHED, QModbusDataUnit::Coils);
+            readValue(BIT_SAFETY_BTN, QModbusDataUnit::DiscreteInputs);
+            readValue(BIT_MEASUREMENT_TO_PC, QModbusDataUnit::Coils);
+            pendingRead = true;
+            if (!bProcedureRunning) {
+                ui->glwidget->setSphereData(spherePos, QVector3D(0,0,0), QVector3D(0,0,0));
+                ui->glwidget->setTestSphereData(spherePos);
+            } else {
+                ui->glwidget->setSphereData(spherePos,dirArrow*2,actualArrow*2); //pokusne prodlouzeni sipek - aby byly lepe videt
+                if ((actCurveType == CURVE_CIRCLE) || (actCurveType == CURVE_ELLIPSE)
+                        || (actCurveType == CURVE_KARD) || (actCurveType == CURVE_LEMN)
+                        || (actCurveType == CURVE_LINE)) {
+                    ui->glwidget->setTestSphereData(staticSpherePos);
+                    if (staticSpherePos.distanceToPoint(spherePos) < minDistanceFromTarget) {
+                        if (staticSpherePos == calcCurvePoints[0])
+                            staticSpherePos = calcCurvePoints[1];
+                        else
+                            staticSpherePos = calcCurvePoints[0];
+                    }
+                } else {
+                    ui->glwidget->setTestSphereData(spherePos);
+                }
+            }
+            if (bTeachStatus) {
+                ui->glwidget->addSphereData(spherePos, false, false);
+                ui->glwidget->setTestSphereData(spherePos);
+            }
+        }
+        break;
+    case SEND_CURVE:
+        curvePacket = 0;
+        lastPacket = false;
+        currState = SEND_PREP_CURVE;
+        writeValue(BIT_DATA_TO_PLC, QModbusDataUnit::Coils,1);
+        pd = new QProgressDialog("<font size=15>Křivka se odesílá do stroje</font>", "Zrušit", 0, calculatedCurve.size()/25+1);
+        pd->setModal(true);
+        pd->setValue(0);
+        pd->show();
+        break;
+    case SEND_PREP_CURVE:
+        int len;
+        len = prepareCurveData(curvePacket);
+        if (len < 25)
+            lastPacket = true;
+
+        currState = SEND_WAIT_CURVE;
+        writeValue(BIT_RDY, QModbusDataUnit::Coils, 1);  //rdy
+        QLOG_DEBUG() << "send packet";
+        curvePacket++;
+        break;
+    case SEND_WAIT_CURVE:
+        readValue(BIT_RDY, QModbusDataUnit::Coils);
+        break;
+    case SEND_LAST_CURVE:
+        writeValue(BIT_DATA_TO_PLC, QModbusDataUnit::Coils,0);
+        currState = NO_STATE;
+        if (pd != nullptr) {
+            delete pd;
+            pd = nullptr;
+        }
+        break;
+    case GET_CURVE:
+        writeValue(BIT_DATA_TO_PC, QModbusDataUnit::Coils, 1); //ziskat krivku z PC
+        curvePacket = 0;
+        currState = GET_WAIT_CURVE;
+        pd = new QProgressDialog("<font size=15>Křivka se čte ze stroje</font>", "Zrušit", 0, 100);
+        pd->setModal(true);
+        pd->setValue(0);
+        pd->show();
+        QLOG_DEBUG() << "Get new curve";
+        receivedDataSize = 0;
+        break;
+    case GET_WAIT_CURVE:
+        readValue(BIT_RDY, QModbusDataUnit::Coils);
+        break;
+    case GET_PART_CURVE:
+        if (initStep) {
+            readValues(REG_LEN, QModbusDataUnit::HoldingRegisters, 2);  //INDEX and LEN
+            initStep = false;
+        }
+        break;
+    case GET_NEXT_PART:
+        QLOG_DEBUG() << "Get next part";
+        currState = NO_STATE;
+        break;
+    case GET_MEAS_START:
+        curvePacket = 0;
+        receivedDataSize = 0;
+        currState = GET_MEAS_WAIT;
+        pd = new QProgressDialog("<font size=15>Měření se čte ze stroje</font>", "Zrušit", 0, 100);
+        pd->setModal(true);
+        pd->setValue(0);
+        pd->show();
+        QLOG_DEBUG() << "Get new measurement";
+        break;
+    case GET_MEAS_WAIT:
+        readValue(BIT_RDY, QModbusDataUnit::Coils);
+        break;
+    case GET_MEAS_LEN:
+        if (initStep) {
+            readValues(REG_LEN, QModbusDataUnit::HoldingRegisters, 2);  //INDEX and LEN
+            initStep = false;
+        }
+        break;
+    case GET_MEAS_NEXT:
+        QLOG_DEBUG() << "Get next part";
+        currState = NO_STATE;
+        break;
+    default:
+        ;
+    }
+#endif
+
+    if (pd != nullptr) {
+        if (pd->wasCanceled()) {
+            QLOG_DEBUG() << "cancel dlg pressed";
+            if (currState == SEND_WAIT_CURVE)
+                currState = SEND_LAST_CURVE;
+            else {
+                if (file.isOpen()) {
+                    file.close();
+                }
+                if (pd != nullptr) {
+                    delete pd;
+                    pd = nullptr;
+                }
+                writeValue(BIT_DATA_TO_PLC, QModbusDataUnit::Coils,0); //ukoncit krivku z PLC
+                writeValue(BIT_DATA_TO_PC, QModbusDataUnit::Coils, 0); //ukoncit krivku z PC
+                writeValue(BIT_MEASUREMENT_TO_PC, QModbusDataUnit::Coils, 0);
+                currState = NO_STATE;
+            }
+
+        }
+    }
+
+    if ((safetyBtnState == 0)||(bKeyState == 0)) {  //neni stisknuto bezp. tlacitko, nebo nein nahozen klicek auto
+        blinkCntr++;
+        if (blinkCntr > 10) {
+            if (safetyBtnState == 0) {
+                if (safetyBtnBlinkOn)
+                    ui->safetyBtnLabel->setStyleSheet("background-color: rgb(255,0,0)");
+                else
+                    ui->safetyBtnLabel->setStyleSheet("");
+                safetyBtnBlinkOn = !safetyBtnBlinkOn;
+            }
+            if (bKeyState == 0) {
+                if (keyAutoBtnBlinkOn)
+                    ui->autoKeyStatusLabel->setStyleSheet("background-color: #ffa500");  //oranzova
+                else
+                    ui->autoKeyStatusLabel->setStyleSheet("");
+                keyAutoBtnBlinkOn = !keyAutoBtnBlinkOn;
+            }
+            blinkCntr = 0;
+        }
+    }
+#ifdef GRAPH_TEST
+    cntr++;
+    if (cntr > 100) {
+        double r = ((double) rand() / (RAND_MAX))*100;
+        cntr = 0;
+        qualitySet->append(r);
+        chart->removeSeries(qualityData);
+        chart->addSeries(qualityData);
+        chart->setAxisY(axisy, qualityData);
+
+        QLOG_DEBUG() << QString("Data %1, %2").arg(itemCount).arg(r);
+        itemCount++;
+    }
+#endif
+
+#ifdef PROCEDURE_TEST
+    cntr++;
+    if (cntr > 1) {
+        QVector4D vec, vec1, vec2;
+        bool start = false, finish = false;
+        cntr = 0;
+        if (!calculatedCurve.isEmpty())
+            vec = calculatedCurve.at(itemCount);
+        else
+            vec = QVector4D(0,0,0,0);
+
+
+        //vec = sphere.at(itemCount);
+        cur.append(vec);
+        vec1 = dir.at(itemCount);
+        vec2 = act.at(itemCount);
+        vec1 = vec2 = QVector4D(0,0,0,0);
+
+        if (itemCount == 0) {
+            start = true;
+        }
+        //itemCount += 10;
+        itemCount ++;
+        //if (itemCount > sphere.size()-1) {
+        if (itemCount > calculatedCurve.size()-1) {
+            itemCount = 0;
+            cur.clear();
+            finish = true;
+        }
+
+        //ui->glwidget->setTubusColor(QVector4D(0, 0.87f, 0.87f, 1));
+        //ui->glwidget->addSphereData(vec, start, finish);
+
+        /*if (itemCount > calculatedCurve.size()-1)
+            itemCount = 0;*/
+        /*if (!cur.isEmpty() && (cur.size() > 5)) {
+            const QList<QVector3D> *data;
+            data = &cur;
+            ui->glwidget->setCurve(*data);
+        }*/
+        //ui->glwidget->setSphereData(vec.toVector3D(), vec1.toVector3D(), vec2.toVector3D());
+        vec1 = QVector4D((float)rand()/(RAND_MAX)*2-1.0,(float)rand()/(RAND_MAX)*2-1.0,(float)rand()/(RAND_MAX)*2-1.0,0);
+        ui->glwidget->setSphereData(vec.toVector3D(),
+                                    QVector3D::crossProduct(vec.toVector3D()/5, vec1.toVector3D()),
+                                    QVector3D::crossProduct(vec.toVector3D()/5, QVector3D(0,1,0)));
+                                    /*QVector3D::crossProduct(vec.toVector3D()/5, QVector3D(-1,0,0)),
+                                    QVector3D::crossProduct(vec.toVector3D()/5, QVector3D(0,1,0)));*/
+        //ui->glwidget->setSphereData(vec, QVector3D(1000,-1000,0), QVector3D(-1200,1200,500));
+        connectionGuard->restart();
+    }
+#endif
+}
+
+//! Příjem dat ze stroje
+/*!
+ * Funkce je volána, jakmile přijdou jakákoliv data ze stroje po modbus/tcp. Data se zpracují a jsou připravena
+ * pro provádění akce v hlavním cyklu
+ */
+void MainWindow::readyRead()
+{
+    QModbusReply *readRequest = qobject_cast<QModbusReply *>(sender());
+    if (!readRequest)
+        return;
+
+    if (readRequest->error() == QModbusDevice::NoError) {
+        const QModbusDataUnit unit = readRequest->result();
+        int value, address = unit.startAddress();
+        connectionGuard->restart();
+
+        switch(unit.registerType()) {
+        case QModbusDataUnit::Coils:
+            for (uint i = 0; i < unit.valueCount(); i++) {
+                value = unit.value(i);
+                int addr = address+i;
+                /*if ((address+i) == BIT_DATA_TO_PLC) {
+                    if (value != 0) {
+                        if (currState != SEND_LAST_CURVE)
+                            currState = SEND_CURVE;
+                    } else {
+                        currState = NO_STATE;
+                        lastPacket = false;
+                    }
+                } else*/
+                switch(addr) {
+                case BIT_RDY:
+                {
+                    if ((currState == SEND_WAIT_CURVE) && (value == 0)) {
+                        if (lastPacket) {
+                            QLOG_DEBUG() << "Last packet sent";
+                            currState = SEND_LAST_CURVE;
+                        } else {
+                            QLOG_DEBUG() << "Send new data";
+                            currState = SEND_PREP_CURVE;
+                        }
+                        if (pd != nullptr) {
+                            pd->setValue(curvePacket);
+                        }
+                    } else if ((currState == GET_WAIT_CURVE) && (value == 1)) {
+                        initStep = true;
+                        currState = GET_PART_CURVE;
+                    } else if ((currState == GET_MEAS_WAIT) && (value == 1)) {
+                        initStep = true;
+                        currState = GET_MEAS_LEN;
+                    }
+                    break;
+                }
+                case BIT_WRITE_ENABLE:
+                {
+                    if (bWriteEnable != value) {
+                        /*if (value == 0)
+                            ui->curveBtn->setEnabled(false);
+                        else
+                            ui->curveBtn->setEnabled(true);*/
+                        bWriteEnable = value;
+                        QLOG_DEBUG() << "bWriteEnableChanged";
+                    }
+                    break;
+                }
+                case BIT_BTEACH:
+                {
+                    if (bTeachStatus != value) {
+                        if (value == 0) {
+                            changeClicked();//stahnout krivku
+                            actCurveType = CURVE_NONE; //neni vybrana zadna predpocitana krivka
+                            if (ui->curveTeachBtn->isChecked())
+                                ui->curveTeachBtn->toggle();
+                            ui->glwidget->addSphereData(spherePos, false, true);
+                        } else {
+                            if (!ui->curveTeachBtn->isChecked())
+                                ui->curveTeachBtn->toggle();
+                            ui->glwidget->setTubusColor(QVector4D(0, 0.87f, 0.87f, 0.7f));
+                            ui->glwidget->addSphereData(spherePos, true, false);
+                        }
+                        QLOG_DEBUG() << "bTeach changed";
+                        bTeachStatus = value;
+                    }
+                    break;
+                }
+                case BIT_BPLAY:
+                {
+                    if (bPlay != value) {
+                        if (value == 0) {
+                            if (ui->curvePlayBtn->isChecked())
+                                ui->curvePlayBtn->toggle();
+                        } else {
+                            if (!ui->curvePlayBtn->isChecked())
+                                ui->curvePlayBtn->toggle();
+                        }
+                        QLOG_DEBUG() << "bPlay changed";
+                        bPlay = value;
+                    }
+                    break;
+                }
+                case BIT_BPLAY_ASSIST:
+                {
+                    if (bProcedureRunning != value) {
+                        QLOG_DEBUG() << QString("bPlayAssist changed, val %1").arg(value);
+                        bProcedureRunning = value;
+                        //ui->glwidget->procedureState(value);
+                        if (value != 0) {
+                            overallQ = oneCycleQ = tempQ = 0;
+                            itemCount = 0;
+                            qualitySet->remove(0,qualitySet->count());
+                            ui->overallQualityEdit->setText("0");
+                            ui->oneCycleQualityEdit->setText("0");
+                            ui->actQualityEdit->setText("0");
+                            if (!ui->curveAssistPlayBtn->isChecked())
+                                ui->curveAssistPlayBtn->toggle();
+                            procedureQuality.clear();
+                            procedureTimer->start(1000);
+                            if (actCurveType != CURVE_NONE) {
+                                staticSpherePos = calcCurvePoints[0];
+                            }
+                        } else {
+                            ui->overallQualityEdit->setText(QString("%1").arg(overallQ));  //konec cviceni, zobrazit celkovy vysledek
+                            if (ui->curveAssistPlayBtn->isChecked())
+                                ui->curveAssistPlayBtn->toggle();
+                            procedureTimer->stop();
+                            if (dbConnected)
+                                db->addResult(pId, indId, actSeries, procedureQuality);
+
+                            procedureTimeRemaining = ui->procTimeDial->value()*60;
+                            ui->curveAssistPlayBtn->setText(tr("Spustit cvičení\n") + QString::number(procedureTimeRemaining/60)
+                                                + ":" + QString("%1").arg(procedureTimeRemaining%60,2,10,QChar('0')) + "min");
+                        }
+                    }
+                    break;
+                }
+                case BIT_PART_FINISHED:
+                {
+                    if (bPartState != value) {
+                        if (value != 0) {
+                            QLOG_DEBUG() << "part finished";
+                            ui->oneCycleQualityEdit->setText(QString("%1").arg(oneCycleQ));
+                            writeValue(BIT_PART_FINISHED, QModbusDataUnit::Coils, 0); //vynulovat priznak konce jednoho cyklu
+                            if (oneCycleQ > 0)
+                                procedureQuality.append(oneCycleQ);
+                            qualitySet->append(oneCycleQ);
+                            chart->removeSeries(qualityData);
+                            chart->addSeries(qualityData);
+                            chart->setAxisY(axisy, qualityData);
+                            itemCount++;
+                        }
+                        bPartState = value;
+                    }
+                    break;
+                }
+                case BIT_MEASUREMENT_TO_PC:
+                {
+                    if (value && (currState < GET_MEAS_START)) {
+                        currState = GET_MEAS_START;
+                        openMeasurementFile();
+                    }
+                    if (!value && (currState > GET_MEAS_START )) {
+                        if (file.isOpen()) {
+                            file.close();
+                        }
+                        if (pd != nullptr) {
+                            delete pd;
+                            pd = nullptr;
+                        }
+                    }
+                    break;
+                }
+                default:
+                    ;
+                }
+            }
+            break;
+        case QModbusDataUnit::HoldingRegisters:
+            if ((unit.startAddress() == REG_X)&&(unit.valueCount() == 15)) {
+                spherePos = QVector3D((qint16)unit.value(0)/1.0,(qint16)unit.value(1)/1.0,(qint16)unit.value(2)/1.0);
+                //QLOG_DEBUG() << QString("sphere %1,%2,%3").arg((qint16)unit.value(0)/1.0).arg((qint16)unit.value(1)/1.0).arg((qint16)unit.value(2)/1.0);
+                //a = unit.value(3);
+                //REG_ACT_X
+                dirArrow = QVector3D((qint16)unit.value(4)/1.0,(qint16)unit.value(5)/1.0,(qint16)unit.value(6)/1.0);
+                //QLOG_DEBUG() << QString("dir %1,%2,%3").arg((qint16)unit.value(4)/1.0).arg((qint16)unit.value(5)/1.0).arg((qint16)unit.value(6)/1.0);
+                //REG_DIR_X
+                actualArrow = QVector3D((qint16)unit.value(8)*4.0,(qint16)unit.value(9)*4.0,(qint16)unit.value(10)*4.0);
+                //QLOG_DEBUG() << QString("act %1,%2,%3").arg((qint16)unit.value(8)/1.0).arg((qint16)unit.value(9)/1.0).arg((qint16)unit.value(10)/1.0);
+                //REG_Q
+                overallQ = unit.value(13);
+                value = unit.value(12);
+                /*if ((value != 0)&&(oneCycleQ != 0)) {
+                    QLOG_DEBUG() << "cycle finished - quality " << value;
+                    ui->oneCycleQualityEdit->setText(QString("%1").arg(value));
+                    procedureQuality.append(value);
+                    //end of cycle
+                }*/
+                oneCycleQ = value;
+                tempQ = unit.value(14);
+                ui->overallQualityEdit->setText(QString("%1").arg(overallQ));
+                ui->actQualityEdit->setText(QString("%1").arg(tempQ));
+            }
+
+            if (unit.startAddress() == REG_DATA) {
+                QLOG_DEBUG() << QString("Mam %1 dat a %2 uz jich je stazeno").arg(unit.valueCount()/4).arg(calculatedCurve.size());
+                getCurveData(currState, nIndex, unit.values());
+                writeValue(BIT_RDY, QModbusDataUnit::Coils, 0); //ziskat krivku z PC
+                if (pd != nullptr)
+                    pd->setValue(receivedDataSize);
+
+                /*if ((numPoints - nIndex) > 0) {
+                    if (currState == GET_PART_CURVE) {
+                        currState = GET_WAIT_CURVE;
+                        pd->setValue(calculatedCurve.size());
+                    }
+                    else {
+                        currState = GET_MEAS_WAIT;
+                        pd->setValue(numPoints - nIndex);
+                    }
+                    QLOG_DEBUG() << "Dalsi cast";
+                }*/
+
+                if (receivedDataSize < numPoints) {
+                    if (currState == GET_PART_CURVE)
+                        currState = GET_WAIT_CURVE;
+                    else
+                        currState = GET_MEAS_WAIT;
+                    QLOG_DEBUG() << "Dalsi cast";
+                }
+                else {
+                    QLOG_DEBUG() << "OK mam krivku";
+                    currState = NO_STATE;
+                    if (currState == GET_PART_CURVE) {
+                        writeValue(BIT_DATA_TO_PC, QModbusDataUnit::Coils, 0); //ziskat krivku z PC
+                        ui->glwidget->setTubusColor(QVector4D(1, 0.737f, 0.231f, 0.7f));
+                        if (calculatedCurve.size() > MAX_CURVE_SIZE) {
+                            infoDialog dlg;
+                            dlg.setInfoText(tr("Velikost křivky"), tr("Předcvičená křivka je příliš dlouhá.\nBude zkrácena."));
+                            dlg.exec();
+                        }
+                        if (calculatedCurve.size() > 0) {
+                            ui->glwidget->setCurve(calculatedCurve);
+                        } else {
+                            infoDialog dlg;
+                            dlg.setInfoText(tr("Velikost křivky"), tr("Naučená křivka nelze použít. Neplatná data."));
+                            dlg.exec();
+                            display3DScene();
+                        }
+                    } else {
+                        writeValue(BIT_MEASUREMENT_TO_PC, QModbusDataUnit::Coils, 0);
+                    }
+                    if (file.isOpen()) {
+                        file.close();
+                    }
+                    if (pd != nullptr) {
+                        delete pd;
+                        pd = nullptr;
+                    }
+                    //ui->changeDataBtn->setEnabled(false);   //ok mam vsechny data, cekam na dalsi nauceni stroje
+                }
+                initStep = true;
+            } else if (unit.startAddress() == REG_LEN) {
+                numPoints = unit.value(0);  //pocet bodu
+                nIndex  = unit.value(1);    //index
+                QLOG_DEBUG() << QString("Mam len  %1, index %2").arg(numPoints).arg(nIndex);
+                readValues(REG_DATA, QModbusDataUnit::HoldingRegisters, 100); //precti data
+                if (pd != nullptr)
+                    pd->setMaximum(numPoints);
+            } else if (unit.startAddress() == REG_SPEED) {
+            }
+
+            /*for (uint i = 0; i < unit.valueCount(); i++) {
+                const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress() + i)
+                        .arg(QString::number(unit.value(i)));
+                ui->textEdit->append(entry);
+            }*/
+            break;
+        case QModbusDataUnit::DiscreteInputs:
+            value = unit.value(0);
+            if  (address == BIT_BKEY) {
+                if (bKeyState != value) {
+                    QLOG_DEBUG() << "BKEY DI changed val = " << value;
+                    if (value == 0) {
+                        ui->curveAssistPlayBtn->setEnabled(false);
+                    }
+                    else {
+                        ui->curveAssistPlayBtn->setEnabled(true);
+                        ui->autoKeyStatusLabel->setStyleSheet("background-color: #00ff00");
+                    }
+                    bKeyState = value;
+                }
+            } else if  (address  == BIT_SAFETY_BTN) {
+                safetyBtnState = value;
+                if (value == 1)
+                    ui->safetyBtnLabel->setStyleSheet("background-color: rgb(0,255,0)");
+            }
+            break;
+        default:
+            break;
+
+        }
+    } else if (readRequest->error() == QModbusDevice::ProtocolError) {
+        QLOG_ERROR() << QString(tr("Read response error: %1 (Modbus exception: 0x%2)").
+                                 arg(readRequest->errorString()).
+                                 arg(readRequest->rawResult().exceptionCode(), -1, 16));
+    } else {
+        QLOG_ERROR() << QString(tr("Read response error: %1 (code: 0x%2)").
+                                 arg(readRequest->errorString()).
+                                 arg(readRequest->error(), -1, 16));
+    }
+
+    readRequest->deleteLater();
+
+    pendingRead = false;
+}
+
+//! Potvrzení zápisu dat na Modbus/TCP
+void MainWindow::writeFinished()
+{
+    QModbusReply *writeRequest = qobject_cast<QModbusReply *>(sender());
+    if (!writeRequest)
+        return;
+
+    if (writeRequest->error() == QModbusDevice::ProtocolError) {
+        QLOG_ERROR() << QString(tr("Write response error: %1 (Modbus exception: 0x%2)")
+                                 .arg(writeRequest->errorString()).arg(writeRequest->rawResult().exceptionCode(), -1, 16));
+    } else if (writeRequest->error() != QModbusDevice::NoError) {
+        QLOG_ERROR() << QString(tr("Write response error: %1 (code: 0x%2)").
+                                 arg(writeRequest->errorString()).arg(writeRequest->error(), -1, 16));
+    }
+    writeRequest->deleteLater();
+}
+
+//! Změna stavu spojení s modbus/tcp serverem
+/*!
+ * Funkce se volá, pokud se změní stav spojení modbus/tcp. Vzhled aplikace se upraví na základě stavu spojení.
+ * \param state Stav spojení - Connected, nebo Unconnected
+ */
+void MainWindow::onStateChanged(int state)
+{
+    bool connected = (state != QModbusDevice::UnconnectedState);
+
+    if (state == QModbusDevice::UnconnectedState) {
+        ui->connectionLabel->setText(tr("Odpojeno"));
+        ui->connectionLabel->setStyleSheet("background-color: rgb(255,0,0)");
+        ui->safetyBtnLabel->setStyleSheet("");
+        ui->autoKeyStatusLabel->setStyleSheet("");
+        mbConnected = false;
+        //checkTimer->stop();
+        checkTimer->setInterval(500);
+
+        ui->resetPosBtn->setEnabled(false);
+        ui->curvePlayBtn->setEnabled(false);
+        ui->curveAssistPlayBtn->setEnabled(false);
+        ui->curveGenerateBtn->setEnabled(false);
+        ui->curveTeachBtn->setEnabled(false);
+        ui->curveLoadBtn->setEnabled(false);
+        ui->curveStoreBtn->setEnabled(false);
+
+        connectClicked();
+    } else if (state == QModbusDevice::ConnectedState) {
+        mbConnected = true;
+        ui->connectionLabel->setText(tr("Připojeno"));
+        ui->connectionLabel->setStyleSheet("background-color: rgb(0,255,0)");
+        //checkTimer->start(100);
+        checkTimer->setInterval(100);
+
+        bTeachStatus = bWriteEnable = bProcedureRunning = bPartState = bKeyState = bPlay = safetyBtnState = 0;
+
+        ui->resetPosBtn->setEnabled(true);
+        ui->curvePlayBtn->setEnabled(true);
+        ui->curveGenerateBtn->setEnabled(true);
+        ui->curveTeachBtn->setEnabled(true);
+        ui->curveLoadBtn->setEnabled(true);
+        ui->curveStoreBtn->setEnabled(true);
+
+        connectionGuard->restart();
+        connectionEstablished = true;
+
+        //ziskat rovnou status tlacitek
+        readValue(BIT_BKEY, QModbusDataUnit::DiscreteInputs);
+        readValue(BIT_SAFETY_BTN, QModbusDataUnit::DiscreteInputs);
+
+        setCurveData();  //nahrat do stroje rovnou krivku
+    }
+}
+
+//! Ošetření chyby při komunikaci
+void MainWindow::handleDeviceError(QModbusDevice::Error newError)
+{
+    if (newError == QModbusDevice::NoError || !mbClient)
+        return;
+
+    QLOG_ERROR() <<  mbClient->errorString();
+}
+
+//! Vytvoření úvodní 3D "křivky", pokud není ještě křivka ze stroje k dispozici
+void MainWindow::display3DScene()
+{
+    calculatedCurve.clear();
+    calculatedCurve.append(QVector4D(0,0,-4900,0.0));
+    calculatedCurve.append(QVector4D(0,0,-4900,0.0));
+    calculatedCurve.append(QVector4D(0,0,-4900,0.0));
+    calculatedCurve.append(QVector4D(0,0,-4000,0.0));
+    ui->glwidget->setCurve(calculatedCurve);
+}
+
+//! Aktualizace času při asistovaném cvičení pacienta
+void MainWindow::updateAppTime()
+{
+    if (procedureTimeRemaining > 0) {
+        procedureTimeRemaining--;
+        ui->curveAssistPlayBtn->setText(tr("Ukončit cvičení\n") + QString::number(procedureTimeRemaining/60)
+                                                + ":" + QString("%1").arg(procedureTimeRemaining%60,2,10,QChar('0')) + "min");
+        if (procedureTimeRemaining == 0) {
+            procedureTimer->stop();
+            ui->curveAssistPlayBtn->toggle();
+        }
+    }
+}
+
+//! Úprava doby asistovaného cvičení
+void MainWindow::timeDialMoved(int time)
+{
+    QString txt = tr("Ukončit cvičení\n");
+    if (!bProcedureRunning) {
+        txt = tr("Spustit cvičení\n");
+    }
+    ui->curveAssistPlayBtn->setText(txt + QString::number(time) + ":00 min");
+}
+
+//! Úprava doby asistovaného cvičení
+void MainWindow::timeDialReleased()
+{
+    QString txt = tr("Ukončit cvičení\n");
+
+    if (!bProcedureRunning) {
+        txt = tr("Spustit cvičení\n");
+    }
+    procedureTimeRemaining = ui->procTimeDial->value()*60;
+    ui->curveAssistPlayBtn->setText(txt + QString::number(procedureTimeRemaining/60) + ":00 min");
+}
+
+#ifdef PROCEDURE_TEST
+QList<QVector4D> MainWindow::readPoints(QString fName)
+{
+    QList<QVector4D> results;
+    double a = 0.0;
+
+    QFile file(fName);
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+    {
+        return results;
+    }
+
+    while (!file.atEnd())
+    {
+        QByteArray line = file.readLine();
+        QList<QByteArray> splitted = line.split(';');
+        if (splitted.size() < 3)
+            continue;
+        if (splitted.size() == 4)
+            a = splitted.at(3).trimmed().toFloat();
+        QVector4D point(QString(splitted.at(0)).trimmed().toFloat(), QString(splitted.at(1)).trimmed().toFloat(), QString(splitted.at(2)).trimmed().toFloat(),a);
+        results.append(point);
+    }
+    return results;
+}
+#endif
+
+//! Vytvoření modbus/tcp požadavku na čtení jedné hodnoty
+/*!
+ * \param addr Modbus adresa
+ * \param table Typ registru
+ */
+void MainWindow::readValue(int addr, QModbusDataUnit::RegisterType table)
+{
+    QModbusDataUnit unit(table, addr, 1);
+    if (QModbusReply *readRequest = mbClient->sendReadRequest(unit, mbServerId)) {
+        if (!readRequest->isFinished())
+            connect(readRequest, SIGNAL(finished()), this, SLOT(readyRead()));
+        else
+            delete readRequest; // broadcast replies return immediately
+    } else {
+        QLOG_ERROR() << QString("Read error: %1").arg(mbClient->errorString());
+    }
+}
+
+//! Vytvoření modbus/tcp požadavku na čtení více hodnot
+/*!
+ * \param addr Modbus adresa
+ * \param table Typ registrů
+ * \param regCount Počet čtených registrů
+ */
+void MainWindow::readValues(int addr, QModbusDataUnit::RegisterType table, qint16 regCount)
+{
+    QModbusDataUnit unit(table, addr, regCount);
+    if (QModbusReply *readRequest = mbClient->sendReadRequest(unit, mbServerId)) {
+        if (!readRequest->isFinished())
+            connect(readRequest, SIGNAL(finished()), this, SLOT(readyRead()));
+        else
+            delete readRequest; // broadcast replies return immediately
+    } else {
+        QLOG_ERROR() << QString("Read error: %1").arg(mbClient->errorString());
+    }
+}
+
+//! Vytvoření modbus/tcp požadavku na zápis jedné hodnoty
+/*!
+ * \param addr Modbus adresa
+ * \param table Typ registru
+ * \param value Zapisovaná hodnota
+ */
+void MainWindow::writeValue(int addr, QModbusDataUnit::RegisterType table, qint16 value)
+{
+    QModbusDataUnit unit(table, addr, 1);
+    unit.setValue(0, value);
+
+    if (QModbusReply *reply = mbClient->sendWriteRequest(unit, mbServerId)) {
+        if (!reply->isFinished()) {
+            connect(reply, SIGNAL(finished()), this, SLOT(writeFinished()));
+        } else {
+            // broadcast replies return immediately
+            reply->deleteLater();
+        }
+    } else {
+        QLOG_ERROR() << QString("Write error: %1").arg(mbClient->errorString());
+    }
+}
+
+//! Vytvoření modbus/tcp požadavku na zápis více hodnot
+/*!
+ * \param addr Modbus adresa
+ * \param table Typ registru
+ * \param vals Zapisované hodnoty
+ */
+void MainWindow::writeValues(int addr, QModbusDataUnit::RegisterType table, QVector<quint16> vals)
+{
+    QModbusDataUnit unit(table, addr, vals);
+    if (QModbusReply *reply = mbClient->sendWriteRequest(unit, mbServerId)) {
+        if (!reply->isFinished()) {
+            connect(reply, SIGNAL(finished()), this, SLOT(writeFinished()));
+        } else {
+            // broadcast replies return immediately
+            reply->deleteLater();
+        }
+    } else {
+        QLOG_ERROR() << QString("Write error: %1").arg(mbClient->errorString());
+    }
+}
+
+//! Příprava bloku dat pro stroj
+/*!
+ * Připraví požadovaný blok dat s křivkou pro poslání do stroje
+ * \param packetNo Pořadové číslo bloku
+ * \return Počet poslaných dat
+ */
+int MainWindow::prepareCurveData(int packetNo)
+{
+    int nLen = 0;
+    QVector<quint16> vals;
+
+    QLOG_DEBUG() << "prepare data";
+    QLOG_DEBUG() << QString("data count %1, packetNo %2").arg(calculatedCurve.size()).arg(packetNo);
+
+    if (calculatedCurve.size() < packetNo*25)
+        return 0;
+
+    if (calculatedCurve.size() > 0) {
+        nLen = (calculatedCurve.size() - packetNo*25);
+        if (nLen > 25)
+            nLen = 25;
+        QLOG_DEBUG() << QString("Send data size %1, packetNo %2").arg(nLen).arg(packetNo);
+        for(int i = 0; i < nLen; i++) {
+            vals.append((qint16)(calculatedCurve.at(i+25*packetNo).x())); //x
+            vals.append((qint16)(calculatedCurve.at(i+25*packetNo).y())); //y
+            vals.append((qint16)(calculatedCurve.at(i+25*packetNo).z())); //z
+            vals.append((qint16)(calculatedCurve.at(i+25*packetNo).w())); //a
+        }
+        writeValues(REG_DATA, QModbusDataUnit::HoldingRegisters, vals);
+        writeValue(REG_INDEX, QModbusDataUnit::HoldingRegisters, packetNo*25); //index
+        writeValue(REG_LEN, QModbusDataUnit::HoldingRegisters, calculatedCurve.size()); //len
+    }
+
+    return nLen;
+}
+
+//! Získání bloku dat ze stroje
+/*!
+ * Přijme další blok dat s křivkou od stroje, přidá dané bodu do aktuální křivky, která se na konci vykreslí
+ * ve 3D okně
+ * \param packetNo Pořadové číslo bloku
+ * \param data Přijatá data
+ * \return Počet přijatých dat
+ */
+int MainWindow::getCurveData(int dataType, int packetNo, QVector<quint16> data)
+{
+    int nLen = 0, packetRemaining = numPoints - packetNo;
+
+    if (dataType == GET_PART_CURVE)
+    {
+        nLen = (packetRemaining < 25) ? packetRemaining : 25;
+
+        QLOG_DEBUG() <<  QString("nLen = %1, data size %2").arg(nLen).arg(data.size());
+        if ((nLen*4) > data.size()) {
+            QLOG_ERROR() << "Not enough data came - use only prersent data";
+            nLen = data.size()/4;
+        }
+
+        for(int i = 0; i < nLen; i++) {
+            calculatedCurve.append(QVector4D((qint16)data.at(i*4), (qint16)data.at(i*4 + 1),
+                                         (qint16)data.at(i*4 + 2), (qint16)data.at(i*4 + 3)));
+            if (file.isOpen()) {
+                store << (qint16)data.at(i*4) << ";" << (qint16)data.at(i*4 + 1)
+                      << ";" << (qint16)data.at(i*4 + 2) << ";" << (qint16)data.at(i*4 + 3) << endl;
+            }
+        }
+    } else {
+        nLen = (packetRemaining < 10) ? packetRemaining : 10;
+
+        QLOG_DEBUG() <<  QString("nLen = %1, data size %2").arg(nLen).arg(data.size());
+        if ((nLen*10) > data.size()) {
+            QLOG_ERROR() << "Not enough data came - use only present data";
+            nLen = data.size()/10;
+        }
+
+        for(int i = 0; i < nLen; i++) {
+            if (file.isOpen()) {
+                store << (qint16)data.at(i*10) << ";" << (qint16)data.at(i*10 + 1)
+                      << ";" << (qint16)data.at(i*10 + 2) << ";" << (qint16)data.at(i*10 + 3)
+                      << ";" << (qint16)data.at(i*10 + 4) << ";" << (qint16)data.at(i*10 + 5)
+                      << ";" << (qint16)data.at(i*10 + 6) << ";" << (qint16)data.at(i*10 + 7)
+                      << ";" << (qint16)data.at(i*10 + 8) << ";" << (qint16)data.at(i*10 + 9)
+                      << endl;
+            }
+        }
+    }
+    receivedDataSize += nLen;
+    QLOG_DEBUG() << QString("get data packet No %1, received data count %2, packetRem %3").arg(packetNo).arg(receivedDataSize).arg(packetRemaining);
+
+    return nLen;
+}
diff --git a/deltarobot/mainwindow.h b/deltarobot/mainwindow.h
new file mode 100644
index 0000000..62552e7
--- /dev/null
+++ b/deltarobot/mainwindow.h
@@ -0,0 +1,190 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QModbusClient>
+#include <QModbusReply>
+#include "QsLog.h"
+#include "../db_browser/dbaccess.h"
+
+#include <QFile>
+#include <QTextStream>
+
+#include <QProgressDialog>
+
+#include <QBarSet>
+#include <QBarSeries>
+#include <QChartView>
+#include <QValueAxis>
+#include <QVector3D>
+
+#undef FILE_TEST
+#undef PROCEDURE_TEST
+#undef GRAPH_TEST
+
+QT_CHARTS_USE_NAMESPACE
+
+namespace Ui {
+class MainWindow;
+}
+
+class QSqlQueryModel;
+
+//! Hlavní část celé aplikace - okno s ovládacími prvky
+/*!
+ * Hlavní část celé aplikace. Vytvoří okno s ovládacími prvky pro ovládání stroje, zobrazení předcvičované
+ * křivky i výběr pacienta a jemu odpovídající křivku.
+*/
+class MainWindow : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    //! Konstruktor.
+    /*!
+     * V kostruktoru se inicializuje UI, vyčtou se uložené konfigurační parametry z textového souboru a
+     * a připraví se spojení s databází (pokud má být použito)
+    */
+    explicit MainWindow(QWidget *parent = nullptr);
+    //! Destruktor.
+    /*!
+      Slouží pro správné ukončení aplikace - ukončení spojení s databází, uložení změněných konfiguračních hodnot
+    */
+    ~MainWindow();
+
+private Q_SLOTS:
+    void connectClicked(void);
+    void changeClicked(void);
+    void curveGenerateClicked(void);
+    void curvePlayChanged(bool pressed);
+    void curveAssistChanged(bool pressed);
+    void curveTeachChanged(bool pressed);
+    void curveLoadClicked(void);
+    void measurementLoadClicked();
+    void curveStoreClicked(void);
+    void deviceResetClicked(void);
+    void patientSelectClicked(void);
+    void mainCycle(void);
+    void readyRead(void);
+    void writeFinished(void);
+    void onStateChanged(int state);
+    void handleDeviceError(QModbusDevice::Error newError);
+    void display3DScene(void);
+    void updateAppTime(void);
+    void timeDialMoved(int time);
+    void timeDialReleased(void);
+    void upDownSliderMoved(int val);
+    void movementSliderReleased(void);
+
+private:
+    void readValue(int addr, QModbusDataUnit::RegisterType table);
+    void readValues(int addr, QModbusDataUnit::RegisterType table, qint16 regCount);
+    void writeValue(int addr, QModbusDataUnit::RegisterType table, qint16 value);
+    void writeValues(int addr, QModbusDataUnit::RegisterType table, QVector<quint16> vals);
+    int prepareCurveData(int packetNo);
+    int getCurveData(int dataType, int packetNo, QVector<quint16> data);
+    int getCurveDataFromFile(QString fileName);
+    void setCurveData(void);
+    QVector4D getDeltaMovingAverage(QVector4D point);
+    void openMeasurementFile(void);
+#ifdef PROCEDURE_TEST
+    QList<QVector4D> readPoints(QString fName);
+    QList<QVector4D> sphere, act, dir, cur;
+#endif
+
+    /** \brief Uživatelské rozhraní */
+    Ui::MainWindow *ui;
+    //! Modbus/TCP spojení
+    QModbusClient *mbClient;
+    //! Databázové spojení
+    dbAccess *db;
+    //! Status spojení s databází
+    bool dbConnected;
+    //! Proměnná obsahující info, má-li být databáze použita
+    int useDb;
+    //! Databázový model
+    QSqlQueryModel *model;
+    //! IP adresa Modbus/TCP serveru
+    QString serverIp;
+    //! ID Modbus/TCP serveru
+    int mbServerId;
+    //! Proměnné obsahující údaje o stavu Modbus/TCP spojení
+    /**@{*/
+    bool mbConnected, pendingRead, pendingWrite;
+    bool connectionEstablished;
+    /**@}*/
+    //! Proměnné obsahující údaje o stavu stroje a komunikace s ním
+    /**@{*/
+    bool lastPacket, initStep, bSpeedUpdated;
+    int safetyBtnState, blinkCntr, safetyBtnBlinkOn;
+    int keyAutoBtnBlinkOn;
+    int bTeachStatus, bWriteEnable, bProcedureRunning, bPartState, bKeyState, bPlay;
+    /**@}*/
+
+    //! Proměnné obsahující údaje o použité křivce a proceduře
+    /**@{*/
+    int currState, actCurveType, actCurveAngle, actCurveRot, actSeries;
+    int pronSupVal;
+    QString actCurveFileName;
+    QList<QVector4D> calculatedCurve;
+    QList<QVector4D> tmpCurveMA;
+    int curvePacket, numPoints, nIndex;
+    /**@}*/
+    //! Proměnné obsahující údaje o pacientovi a indikaci
+    /**@{*/
+    int pId, indId, procedureTimeRemaining;
+    /**@}*/
+
+    //! Proměnné obsahující údaje o kvalitě cvičení v dané proceduře
+    /**@{*/
+    qint16 overallQ, oneCycleQ, tempQ;
+    QList<int> procedureQuality;
+    /**@}*/
+
+    //! Timer používané pro periodické akce
+    /**@{*/
+    QTimer *checkTimer, *procedureTimer;
+    /**@}*/
+
+    //! Timer používaný na periodickou kontrolu spojení
+    QTime *connectionGuard;
+
+    //! aktuální pozice aktuátoru a vektory určující správný směr pohyby a aktuální směr pohybu a polohu "zarážky"
+    /**@{*/
+    QVector3D spherePos, dirArrow, actualArrow, staticSpherePos;
+    /**@}*/
+
+    //! minimální vzdálenost aktuátoru od "zarážky", aby bylo možné označit cíl za splněný
+    int minDistanceFromTarget;
+
+    //! Pole, které obsahuje údaje o zarážkách
+    QVector3D calcCurvePoints[2];
+
+    QFile file;
+    QTextStream store;
+
+    //! Proměnné pro graf
+    /*!
+     * Ukazatele na objekty, které jsou použité pro zobrazování údajů o kvalitě
+     * provedení předchozích procedur
+     */
+    /**@{*/
+    QBarSet *qualitySet;
+    QBarSeries *qualityData;
+    QChartView *graphView;
+    QChart *chart;
+    QValueAxis *axisy;
+    /**@}*/
+
+    QVector3D testSpherePos;
+
+    //! Dialog používaný pro informaci o čekání na akci
+    /**@{*/
+    QProgressDialog *pd, *waitDlg;
+    /**@}*/
+    int itemCount, cntr;
+
+    int receivedDataSize;
+};
+
+#endif // MAINWINDOW_H
diff --git a/deltarobot/mainwindow.ui b/deltarobot/mainwindow.ui
new file mode 100644
index 0000000..cdfd085
--- /dev/null
+++ b/deltarobot/mainwindow.ui
@@ -0,0 +1,532 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>941</width>
+    <height>726</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <widget class="QLabel" name="connectionLabel">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>40</height>
+       </size>
+      </property>
+      <property name="font">
+       <font>
+        <pointsize>15</pointsize>
+       </font>
+      </property>
+      <property name="text">
+       <string>Odpojeno</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignCenter</set>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="1">
+     <widget class="QLabel" name="safetyBtnLabel">
+      <property name="font">
+       <font>
+        <pointsize>15</pointsize>
+       </font>
+      </property>
+      <property name="text">
+       <string>Bezpečnostní ruční spínač</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignCenter</set>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="2">
+     <widget class="QLabel" name="autoKeyStatusLabel">
+      <property name="font">
+       <font>
+        <pointsize>15</pointsize>
+       </font>
+      </property>
+      <property name="text">
+       <string>Klíč automat</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignCenter</set>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="3">
+     <widget class="QLabel" name="dbConnectionStatusLabel">
+      <property name="font">
+       <font>
+        <pointsize>15</pointsize>
+       </font>
+      </property>
+      <property name="text">
+       <string>DB nepřipojena</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignCenter</set>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="0" colspan="4">
+     <widget class="QSplitter" name="splitter">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <widget class="QWidget" name="layoutWidget">
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QGroupBox" name="groupBox_2">
+          <property name="font">
+           <font>
+            <pointsize>15</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Ovládání stroje</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_3">
+           <item row="0" column="1">
+            <widget class="QPushButton" name="curveAssistPlayBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="font">
+              <font>
+               <pointsize>15</pointsize>
+              </font>
+             </property>
+             <property name="styleSheet">
+              <string notr="true">background-color: rgb(0, 255, 0);</string>
+             </property>
+             <property name="text">
+              <string>Spustit cvičení
+10:00min</string>
+             </property>
+             <property name="checkable">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="4">
+            <widget class="QPushButton" name="resetPosBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Reset pozice</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0">
+            <widget class="QPushButton" name="curvePlayBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Provedení křivky</string>
+             </property>
+             <property name="checkable">
+              <bool>true</bool>
+             </property>
+             <property name="flat">
+              <bool>false</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2">
+            <widget class="QDial" name="procTimeDial">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>110</height>
+              </size>
+             </property>
+             <property name="notchesVisible">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="5" rowspan="2">
+            <widget class="QSlider" name="upDownSlider">
+             <property name="minimumSize">
+              <size>
+               <width>90</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="maximumSize">
+              <size>
+               <width>16777215</width>
+               <height>16777215</height>
+              </size>
+             </property>
+             <property name="focusPolicy">
+              <enum>Qt::StrongFocus</enum>
+             </property>
+             <property name="styleSheet">
+              <string notr="true">/* QSlider:vertical {
+       min-height: 32px;
+    }
+     
+QSlider::groove:vertical {
+        margin: -2px 0; 
+    }
+
+
+QSlider::handle:vertical {
+    background: #22B14C;
+    border: 5px solid #B5E61D;
+    width: 100px;
+    height: 100px;
+    margin: -24px -12px;
+}*/
+
+/*.QSlider {
+    min-height: 68px;
+   max-height: 68px;
+    background: #5F4141;
+}*/
+
+.QSlider::groove:vertical {
+    width: 55px;
+	background-color: rgb(90, 90, 90);
+    margin: 0 12px;
+}
+
+.QSlider::handle:vertical {
+    background: #22B14C;
+    border: 5px solid #B5E61D;
+    width: 50px;
+    height: 50px;
+    margin: 0px -12px;
+	
+	image: url(:/img/up-down.png);
+}
+</string>
+             </property>
+             <property name="singleStep">
+              <number>0</number>
+             </property>
+             <property name="pageStep">
+              <number>0</number>
+             </property>
+             <property name="value">
+              <number>50</number>
+             </property>
+             <property name="sliderPosition">
+              <number>50</number>
+             </property>
+             <property name="tracking">
+              <bool>false</bool>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="5">
+            <widget class="QLabel" name="label_4">
+             <property name="text">
+              <string>Posun</string>
+             </property>
+             <property name="alignment">
+              <set>Qt::AlignHCenter|Qt::AlignTop</set>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="2">
+            <widget class="QLabel" name="label_5">
+             <property name="text">
+              <string>Čas</string>
+             </property>
+             <property name="alignment">
+              <set>Qt::AlignCenter</set>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item>
+         <widget class="QGroupBox" name="groupBox_3">
+          <property name="font">
+           <font>
+            <pointsize>15</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Práce s křivkou</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_4" columnstretch="2,2,1,1,1">
+           <item row="0" column="0">
+            <widget class="QPushButton" name="curveTeachBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="sizeIncrement">
+              <size>
+               <width>1</width>
+               <height>0</height>
+              </size>
+             </property>
+             <property name="font">
+              <font>
+               <pointsize>15</pointsize>
+              </font>
+             </property>
+             <property name="styleSheet">
+              <string notr="true">background-color: rgb(0, 222, 222);</string>
+             </property>
+             <property name="text">
+              <string>Učení křivky</string>
+             </property>
+             <property name="checkable">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QPushButton" name="curveGenerateBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="sizeIncrement">
+              <size>
+               <width>1</width>
+               <height>0</height>
+              </size>
+             </property>
+             <property name="font">
+              <font>
+               <pointsize>15</pointsize>
+              </font>
+             </property>
+             <property name="styleSheet">
+              <string notr="true">background-color: rgb(255, 188, 59);</string>
+             </property>
+             <property name="text">
+              <string>Předprogramované
+trajektorie</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2">
+            <widget class="QPushButton" name="curveStoreBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Uložení
+křivky</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="3">
+            <widget class="QPushButton" name="curveLoadBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Načtení
+křivky</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="4">
+            <widget class="QPushButton" name="measurementLoadBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>90</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Načtení
+měření</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item>
+         <widget class="QGroupBox" name="groupBox">
+          <property name="font">
+           <font>
+            <pointsize>15</pointsize>
+           </font>
+          </property>
+          <property name="title">
+           <string>Cvičení</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_2">
+           <item row="1" column="6" rowspan="2">
+            <widget class="QPushButton" name="patientSelectBtn">
+             <property name="minimumSize">
+              <size>
+               <width>0</width>
+               <height>80</height>
+              </size>
+             </property>
+             <property name="text">
+              <string>Výběr pacienta</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QLabel" name="label_2">
+             <property name="text">
+              <string>Po jednom cyklu</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0" rowspan="3">
+            <widget class="QLineEdit" name="actQualityEdit">
+             <property name="text">
+              <string>0</string>
+             </property>
+             <property name="readOnly">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="1" rowspan="3">
+            <widget class="QLineEdit" name="oneCycleQualityEdit">
+             <property name="text">
+              <string>0</string>
+             </property>
+             <property name="readOnly">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="2" rowspan="3" colspan="2">
+            <widget class="QLineEdit" name="overallQualityEdit">
+             <property name="text">
+              <string>0</string>
+             </property>
+             <property name="dragEnabled">
+              <bool>false</bool>
+             </property>
+             <property name="readOnly">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QLabel" name="label">
+             <property name="text">
+              <string>Aktuální</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="2">
+            <widget class="QLabel" name="label_3">
+             <property name="text">
+              <string>Celková</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0" colspan="2">
+            <widget class="QLabel" name="patientNameLabel">
+             <property name="text">
+              <string>Jméno:</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2" colspan="5">
+            <widget class="QLabel" name="indicationLabel">
+             <property name="text">
+              <string>Indikace:</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="Scene" name="glwidget">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>941</width>
+     <height>20</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QToolBar" name="mainToolBar">
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <customwidgets>
+  <customwidget>
+   <class>Scene</class>
+   <extends>QOpenGLWidget</extends>
+   <header>gl/scene.hpp</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/deltarobot/modbusSlave.pro b/deltarobot/modbusSlave.pro
new file mode 100644
index 0000000..bb97f84
--- /dev/null
+++ b/deltarobot/modbusSlave.pro
@@ -0,0 +1,73 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2017-12-13T18:45:44
+#
+#-------------------------------------------------
+
+QT       += core gui serialbus opengl charts sql
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+QMAKE_CXXFLAGS += -std=c++11
+
+TARGET = modbusSlave
+TEMPLATE = app
+
+# The following define makes your compiler emit warnings if you use
+# any feature of Qt which has been marked as deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if you use deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
+
+include(libQsLog/QsLog.pri)
+
+win32 {
+    LIBS  += -lopengl32
+}
+
+SOURCES += \
+        main.cpp \
+        mainwindow.cpp \
+    curvedialog.cpp \
+    element/arrow.cpp \
+    element/element.cpp \
+    element/sphere.cpp \
+    element/trajectory.cpp \
+    element/wall.cpp \
+    gl/camera.cpp \
+    gl/scene.cpp \
+    ../db_browser/dbaccess.cpp \
+    infodialog.cpp \
+    selectpatientdlg.cpp
+
+HEADERS += \
+        mainwindow.h \
+    curvedialog.h \
+    element/arrow.hpp \
+    element/element.hpp \
+    element/sphere.hpp \
+    element/trajectory.hpp \
+    element/wall.hpp \
+    gl/camera.hpp \
+    gl/scene.hpp \
+    ../db_browser/dbaccess.h \
+    infodialog.h \
+    selectpatientdlg.h
+
+FORMS += \
+        mainwindow.ui \
+    curvedialog.ui \
+    infodialog.ui \
+    selectpatientdlg.ui
+
+RESOURCES += \
+    resources.qrc
+
+DISTFILES += \
+    glsl/shader.frag \
+    glsl/shader.vert
diff --git a/deltarobot/pax_global_header b/deltarobot/pax_global_header
new file mode 100644
index 0000000..2b5e700
--- /dev/null
+++ b/deltarobot/pax_global_header
@@ -0,0 +1 @@
+52 comment=c7fb61125e7b7553cb92ef70c4bb48592e1ca0f1
diff --git a/deltarobot/resources.qrc b/deltarobot/resources.qrc
new file mode 100644
index 0000000..5eb4763
--- /dev/null
+++ b/deltarobot/resources.qrc
@@ -0,0 +1,15 @@
+<RCC>
+    <qresource prefix="/">
+        <file>glsl/shader.frag</file>
+        <file>glsl/shader.vert</file>
+        <file>img/floor.png</file>
+        <file>img/tile.png</file>
+        <file>img/ceiling.png</file>
+        <file>img/ceiling_1013.png</file>
+        <file>img/ceiling_1015.png</file>
+        <file>img/ceiling_7035.png</file>
+        <file>img/if_rotate-ccw.png</file>
+        <file>img/if_rotate-cw.png</file>
+        <file>img/up-down.png</file>
+    </qresource>
+</RCC>
diff --git a/deltarobot/selectpatientdlg.cpp b/deltarobot/selectpatientdlg.cpp
new file mode 100644
index 0000000..1c0fb94
--- /dev/null
+++ b/deltarobot/selectpatientdlg.cpp
@@ -0,0 +1,173 @@
+#include "selectpatientdlg.h"
+#include "ui_selectpatientdlg.h"
+#include "../db_browser/dbaccess.h"
+#include <QSqlQueryModel>
+#include <QModelIndex>
+#include <QModelIndexList>
+#include <QAbstractItemModel>
+#include <QDebug>
+#include <QPushButton>
+
+selectPatientDlg::selectPatientDlg(dbAccess *dbase, QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::selectPatientDlg)
+{
+    ui->setupUi(this);
+
+    db = dbase;
+
+    ui->usersTableView->setSelectionMode(QAbstractItemView::SingleSelection);
+    ui->usersTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+    connect(ui->usersTableView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(patientSelected(const QModelIndex&)));
+    connect(ui->nextSeriesBtn, SIGNAL(clicked()), this, SLOT(nextSeriesBtnClicked()));
+
+    connect(ui->okBtn, SIGNAL(clicked()), this, SLOT(okClicked()));
+    connect(ui->exitBtn, SIGNAL(clicked()), this, SLOT(reject()));
+
+    QSqlQueryModel *model1 = new QSqlQueryModel;
+    db->getPatientsQueryModel(model1);
+    ui->usersTableView->setModel(model1);
+    ui->usersTableView->horizontalHeader()->resizeSections(QHeaderView::Stretch);
+
+    p_id = series = procedure_time = 0;
+    p_name = p_surname = "";
+
+    qualitySet = new QBarSet("Kvalita");
+    qualityData = new QBarSeries();
+    qualityData->append(qualitySet);
+
+    QFont font;
+    font.setPixelSize(18);
+
+    chart = new QChart();
+    chart->addSeries(qualityData);
+
+    axisy = new QValueAxis();
+    axisy->setRange(0.0, 100.0);
+    axisy->setLabelsFont(font);
+
+    chart->setAxisY(axisy, qualityData);
+    chart->setTitle(tr("Graf kvality cvičení v poslední sérii procedur"));
+
+    chart->setTitleFont(font);
+    chart->setBackgroundVisible(false);
+    chart->setMargins(QMargins(0,0,0,0));
+    chart->legend()->hide();
+    chart->setPlotAreaBackgroundBrush(QBrush(Qt::black));
+    chart->setPlotAreaBackgroundVisible(true);
+    graphView = new QChartView(chart);
+    graphView->setMinimumSize(250,120);
+    ui->verticalLayout->addWidget(graphView);
+}
+
+selectPatientDlg::~selectPatientDlg()
+{
+    delete ui;
+}
+
+//! Získání údajů o vybraném pacientovi
+/*!
+ * Funkce je použita pro získání všech potřebných údajů o právě vybraném pacientovi
+ *
+ * \param[out] *pid Identifikační číslo pacienta
+ * \param[out] *indid Identifikační číslo příslušné indikace
+ * \param[out] *name Jméno pacienta
+ * \param[out] *surname Příjmení pacienta
+ * \param[out] *series_no Pořadové číslo poslední série procedur
+ * \param[out] *p_time Doba trvání jedné procedury
+ * \param[out] *cname Údaje o křivce, kterou má pacient provádět
+ */
+void selectPatientDlg::getPatientInfo(int *pid, int  *indid, QString *name, QString *surname, int *series_no, int *p_time, QString *cname)
+{
+    *name = p_name;
+    *surname = p_surname;
+    *series_no = series;
+    *p_time = procedure_time*60;
+    *pid = p_id;
+    *indid = ind_id;
+    *cname = c_name;
+}
+
+//! Změna jazyka dialogu
+/*!
+ * Pokud se změní jazyk aplikace, funkce změní text v dialogu, aby odpovídal
+ * nastavenému jazyku
+ * \param *e Ukazatel na objekt, který obsahuje posílanou událost
+*/
+void selectPatientDlg::changeEvent(QEvent *e)
+{
+    QDialog::changeEvent(e);
+    switch (e->type()) {
+    case QEvent::LanguageChange:
+        ui->retranslateUi(this);
+        break;
+    case QEvent::ActivationChange: {
+        ui->usersTableView->horizontalHeader()->resizeSections(QHeaderView::Stretch);
+        break;
+    }
+    default:
+        break;
+    }
+}
+
+//! Začátek nové série procedur
+/*!
+ * Pokud je v dialogovém okně stisknuto tlačítko "Nová série", volá se tato funkce. Funkce
+ * zvýší pořadové číslo aktuální serie o jednu, tj. od příštího cvičení se cvičí nová série
+ * procedur
+ */
+void selectPatientDlg::nextSeriesBtnClicked()
+{
+    series++;
+    ui->selectedPatientText->setText(QString("Pacient %1 %2, série procedur číslo %3.").arg(p_name)
+                                     .arg(p_surname)
+                                     .arg(series));
+
+}
+
+//! Je voláno, pokud je z dialogového okna vybrán pacient
+/*!
+ * Je voláno, pokud je z dialogového okna vybrán pacient. Pokud je vybráno platné identifikační
+ *  číslo pacienta, zobrazí se do grafu data o kvalitě cvičení porcedur z poslední série
+ *
+ * \param index Pořadové číslo vybrané řádky
+ */
+void selectPatientDlg::patientSelected(const QModelIndex &index)
+{
+    auto *select = ui->usersTableView->selectionModel();
+    auto id_no = select->selectedRows(3).value(0).data().toString();
+    ind_id = select->selectedRows(4).value(0).data().toInt();
+    p_name = select->selectedRows(0).value(0).data().toString();
+    p_surname = select->selectedRows(1).value(0).data().toString();
+    p_id = db->getPatientId(id_no);
+    series = db->getLastSeriesNo(p_id);
+    db->getIndicationInfo(ind_id, &procedure_time, &c_name);
+    ui->selectedPatientText->setText(QString("Pacient %1 %2, série procedur číslo %3.").arg(p_name)
+                                     .arg(p_surname)
+                                     .arg(series));
+    if (p_id != 0) {
+        QList<int> avg;
+        db->getSeriesResultAvg(p_id, series, &avg);
+        qualitySet->remove(0,qualitySet->count());
+        for(auto &val: avg)
+            qualitySet->append(val);
+        chart->removeSeries(qualityData);
+        chart->addSeries(qualityData);
+        chart->setAxisY(axisy, qualityData);
+    }
+}
+
+//! Je voláno, pokud je stisknuto tlačítko pro opuštění dialogu
+/*!
+ * Je voláno, pokud je stisknuto tlačítko pro opuštění dialogu, zkontroluje se, zda je
+ * vybraný nějaký pacient. Pokud ano, dialog se ukončí s návratvým kódem OK
+ */
+void selectPatientDlg::okClicked()
+{
+    if (p_id != 0) {
+        accept();
+    } else {
+        qDebug() << "Err - no patient, or indication selected";
+    }
+}
diff --git a/deltarobot/selectpatientdlg.h b/deltarobot/selectpatientdlg.h
new file mode 100644
index 0000000..6ac9434
--- /dev/null
+++ b/deltarobot/selectpatientdlg.h
@@ -0,0 +1,96 @@
+#ifndef SELECTPATIENTDLG_H
+#define SELECTPATIENTDLG_H
+
+#include <QDialog>
+#include <QBarSet>
+#include <QBarSeries>
+#include <QChartView>
+#include <QValueAxis>
+
+QT_CHARTS_USE_NAMESPACE
+
+namespace Ui {
+class selectPatientDlg;
+}
+
+class dbAccess;
+class QModelIndex;
+
+//!  Třída pro uživatelské rozhraní výběru pacienta z databáze
+/*!
+ * Třída slouží pro výběr pacienta z databáze, po výběru konkrétního pacienta se získá i jeho indikace, křivka, kterou bude
+ * cvičit a doba trvání procedury.
+ *
+ *
+ *  \image html select_patient.jpg "Dialog výběru pacienta"
+ *  \image latex select_patient.eps "Dialog výběru pacienta" width=10cm
+ *
+*/
+
+class selectPatientDlg : public QDialog
+{
+    Q_OBJECT
+
+public:
+    //! Konstruktor.
+    /*!
+     * V kostruktoru se inicializuje UI a vytvoří
+     *
+     * \param *dbase Databázový objekt, který bude sloužit pro výběr dat z databáze
+     */
+    explicit selectPatientDlg(dbAccess *dbase, QWidget *parent = nullptr);
+    //! Destruktor.
+    /*!
+      Slouží pro správné ukončení dialogu
+    */
+    ~selectPatientDlg();
+    void getPatientInfo(int *p_id, int  *ind_id, QString *name, QString *surname, int *series_no, int *p_time, QString *cname);
+
+protected:
+    void changeEvent(QEvent *e);
+
+private:
+    //! Ukazatel na UI
+    /*!
+      Ukazatel na vytvořené uživatelské rozhraní
+    */
+    Ui::selectPatientDlg *ui;
+    //! Databázový objekt
+    /*!
+      Ukazatel na objekt obsahující spojení s databází
+    */
+    dbAccess *db;
+    //! Parametry procedury
+    /*
+     * Proměné obsahující identifikační čísla pacienta, indikace a parametry procedury
+     */
+    /**@{*/
+    int p_id, ind_id, procedure_time, series;
+    /**@}*/
+    //! Další parametry procedury
+    /*
+     * Proměné obsahující jméno a příjmení a parametry předcvičované křivky
+     */
+    /**@{*/
+    QString p_name, p_surname, c_name;
+    /**@}*/
+
+    //! Proměnné pro graf
+    /*!
+     * Ukazatele na objekty, které jsou použité pro zobrazování údajů o kvalitě
+     * provedení předchozích procedur
+     */
+    /**@{*/
+    QBarSet *qualitySet;
+    QBarSeries *qualityData;
+    QChartView *graphView;
+    QChart *chart;
+    QValueAxis *axisy;
+    /**@}*/
+
+private slots:
+    void patientSelected(const QModelIndex &index);
+    void okClicked(void);
+    void nextSeriesBtnClicked(void);
+};
+#endif // SELECTPATIENTDLG_H
diff --git a/deltarobot/selectpatientdlg.ui b/deltarobot/selectpatientdlg.ui
new file mode 100644
index 0000000..b63c974
--- /dev/null
+++ b/deltarobot/selectpatientdlg.ui
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>selectPatientDlg</class>
+ <widget class="QDialog" name="selectPatientDlg">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>941</width>
+    <height>719</height>
+   </rect>
+  </property>
+  <property name="font">
+   <font>
+    <pointsize>14</pointsize>
+   </font>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0" colspan="2">
+    <layout class="QVBoxLayout" name="verticalLayout">
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QLabel" name="selectedPatientText">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="font">
+          <font>
+           <pointsize>14</pointsize>
+          </font>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignCenter</set>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="nextSeriesBtn">
+         <property name="minimumSize">
+          <size>
+           <width>0</width>
+           <height>80</height>
+          </size>
+         </property>
+         <property name="maximumSize">
+          <size>
+           <width>16777215</width>
+           <height>16777215</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>Další série</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox">
+       <property name="font">
+        <font>
+         <pointsize>14</pointsize>
+        </font>
+       </property>
+       <property name="title">
+        <string>Seznam uživatelů</string>
+       </property>
+       <layout class="QGridLayout" name="gridLayout">
+        <item row="0" column="0">
+         <widget class="QTableView" name="usersTableView">
+          <property name="styleSheet">
+           <string notr="true">QHeaderView { font-size: 14pt; }
+
+QTableView { font-size: 14pt; }
+</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item row="1" column="0">
+    <widget class="QPushButton" name="okBtn">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>80</height>
+      </size>
+     </property>
+     <property name="baseSize">
+      <size>
+       <width>0</width>
+       <height>80</height>
+      </size>
+     </property>
+     <property name="font">
+      <font>
+       <pointsize>14</pointsize>
+      </font>
+     </property>
+     <property name="text">
+      <string>OK</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QPushButton" name="exitBtn">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>80</height>
+      </size>
+     </property>
+     <property name="baseSize">
+      <size>
+       <width>0</width>
+       <height>80</height>
+      </size>
+     </property>
+     <property name="font">
+      <font>
+       <pointsize>14</pointsize>
+      </font>
+     </property>
+     <property name="text">
+      <string>Exit</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/deltarobot/test_server/mbServer.py b/deltarobot/test_server/mbServer.py
new file mode 100644
index 0000000..0003b58
--- /dev/null
+++ b/deltarobot/test_server/mbServer.py
@@ -0,0 +1,314 @@
+#!/usr/bin/env python
+"""
+Pymodbus Server With Updating Thread
+--------------------------------------------------------------------------
+
+This is an example of having a background thread updating the
+context while the server is operating. This can also be done with
+a python thread::
+
+    from threading import Thread
+
+    thread = Thread(target=updating_writer, args=(context,))
+    thread.start()
+"""
+# --------------------------------------------------------------------------- #
+# import the modbus libraries we need
+# --------------------------------------------------------------------------- #
+from pymodbus.server.async import StartTcpServer
+from pymodbus.device import ModbusDeviceIdentification
+from pymodbus.datastore import ModbusSequentialDataBlock
+from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
+
+# --------------------------------------------------------------------------- #
+# import the twisted libraries we need
+# --------------------------------------------------------------------------- #
+from twisted.internet.task import LoopingCall
+
+# --------------------------------------------------------------------------- #
+# configure the service logging
+# --------------------------------------------------------------------------- #
+import logging
+logging.basicConfig()
+log = logging.getLogger()
+log.setLevel(logging.ERROR)
+
+# random numbers
+import random
+
+# global constants
+
+# discrete input
+# poloha klicku
+BIT_BKEY = 32789
+# bezpecnostni tlacitko
+BIT_SAFETY_BTN = 32785
+
+# holding regs
+# aktualni poloha
+REG_X = 32768
+REG_Y = 32769
+REG_Z = 32770
+REG_A = 32771
+#pozice vektoru, kam se tlaci
+REG_ACT_X = 32772
+REG_ACT_Y = 32773
+REG_ACT_Z = 32774
+#pozice vektoru, kam se ma tlacit
+REG_DIR_X = 32776
+REG_DIR_Y = 32777
+REG_DIR_Z = 32778
+
+#data s krivkou
+REG_INDEX = 32867
+REG_LEN = 32866
+REG_DATA = 32868
+# data s kvalitou cviceni
+REG_Q_1 = 32780
+REG_Q_TOT = 32781
+REG_Q_PART = 32782
+
+#coils
+#info bity 
+BIT_RDY = 32871
+BIT_PC_TO_PLC = 32869
+BIT_PLC_TO_PC = 32870
+BIT_MEASUREMENT_TO_PC = 32874
+#posun motoru
+BIT_M_UP = 32788
+BIT_M_DOWN = 32789
+# uceni
+BIT_TEACH = 32780
+# reset pozice
+BIT_RESET_POS = 32769
+# prehravani naucene krivky
+BIT_BPLAY = 32772
+#cviceni naucene kriky
+BIT_BPLAY_ASSIST = 32773
+#priznak ukonceni jednoho cyklu
+BIT_PART_FINISHED = 32873
+#adresy pro testovaci zmenu DI
+BIT_BKEY_CHANGE = 32950
+BIT_SBTN_CHANGE = 32951
+
+# modbus reg
+MB_CO = 1
+MB_DI = 2
+MB_HR = 3
+MB_IR = 4
+
+# --------------------------------------------------------------------------- #
+# define your callback process
+# --------------------------------------------------------------------------- #
+def prepareMbRegVals(values):
+    vals = []
+    for val in values:
+        if val < 0:
+            val = val & 0xFFFF
+        vals.append(val)
+    return vals
+
+def updating_writer(a,):
+    """ A worker process that runs every so often and
+    updates live values of the context. It should be noted
+    that there is a race condition for the update.
+
+    :param arguments: The input arguments to the call
+    """
+    global bit_teach, bit_play, bit_rdy, bit_data_change, bit_motor, learned_curve, index_curve, meas_array
+    global cycles_no, quality, array_pos
+
+    reset_pos = [0,0,4000]
+    
+    log.debug("updating the context")
+    context = a[0]
+    
+    
+    brdy = context[0].getValues(MB_CO, BIT_RDY, 1)
+    data_change = context[0].getValues(MB_CO, BIT_PC_TO_PLC, 2)
+    measurement_get = context[0].getValues(MB_CO, BIT_MEASUREMENT_TO_PC, 1)
+    motor = context[0].getValues(MB_CO, BIT_M_UP, 2)
+    bteach = context[0].getValues(MB_CO, BIT_TEACH, 1)
+    bplay = context[0].getValues(MB_CO, BIT_BPLAY, 2)
+
+    if (context[0].getValues(MB_CO, BIT_RESET_POS, 1) == [1]):
+        print("Position reset")
+        context[0].setValues(MB_CO, BIT_RESET_POS, [0])
+        context[0].setValues(MB_HR, REG_X, reset_pos)
+    if (bteach != bit_teach):
+        if (bteach == [1]):
+            bplay = [0, 0]
+            context[0].setValues(MB_CO, BIT_BPLAY, bplay)
+            learned_curve = []
+            array_pos = 0
+            f = open("krivka.txt")
+            for line in f:
+                line.rstrip()
+                lineStr = line.split(";")
+                onePoint = [int(i) for i in lineStr]
+                learned_curve.extend(prepareMbRegVals(onePoint))
+                print(onePoint)
+            print(len(learned_curve)//4)
+        else:
+            index_curve = 0
+    if (motor != bit_motor):
+        if (motor[0] == 1):
+            print("Nahoru")
+        elif (motor[1] == 1):
+            print("Dolu")
+        else:
+            print("Zastaveno")
+    if (bit_data_change != data_change):
+        if (data_change == [0,0]):
+            brdy = [0]
+            context[0].setValues(MB_CO, BIT_RDY, brdy)
+    if (data_change[0] == 1):
+        if (bit_rdy != brdy) and (brdy == [1]):
+            val = context[0].getValues(MB_HR, REG_LEN, 2)
+            print("<- Len: " + str(val[0]) + ", Index: " + str(val[1]))
+            points = val[0]-val[1]
+            if (points > 25):
+                points = 25
+            learned_curve.extend(context[0].getValues(MB_HR, REG_DATA, points*4))
+            brdy = [0]
+            context[0].setValues(MB_CO, BIT_RDY, brdy)
+    if (data_change[0] != bit_data_change[0]):
+        if (data_change[0] == 0):
+            index_curve = 0
+            print("curve finish")
+        else:
+            bplay = [0, 0]
+            context[0].setValues(MB_CO, BIT_BPLAY, bplay)
+            learned_curve = []
+    if (data_change[1] == 1):
+        if (brdy == [0]):
+            index_to = index_curve + 25
+            if (len(learned_curve)-(index_curve*4) < 100):
+                index_to = len(learned_curve)//4
+            context[0].setValues(MB_HR, REG_DATA, learned_curve[index_curve*4:index_to*4])
+            brdy = [1]
+            context[0].setValues(MB_HR, REG_LEN, [len(learned_curve)//4])
+            context[0].setValues(MB_HR, REG_INDEX, [index_curve])
+            context[0].setValues(MB_CO, BIT_RDY, brdy)
+            print("-> Len: " + str(len(learned_curve)) + ", Index: " + str(index_curve) + ", to: " + str(index_to))
+            index_curve += 25
+            if (index_curve*4 > len(learned_curve)):
+                context[0].setValues(MB_CO, BIT_PLC_TO_PC, [0])
+                index_curve = 0
+    if (measurement_get == [1]):
+        if (brdy == [0]):
+            index_to = index_curve + 10
+            if (len(meas_array)-(index_curve*10) < 100):
+                index_to = len(meas_array)//10
+            context[0].setValues(MB_HR, REG_DATA, meas_array[index_curve*10:index_to*10])
+            brdy = [1]
+            context[0].setValues(MB_HR, REG_LEN, [len(meas_array)//10])
+            context[0].setValues(MB_HR, REG_INDEX, [index_curve])
+            context[0].setValues(MB_CO, BIT_RDY, brdy)
+            print("-> Len: " + str(len(meas_array)) + ", Index: " + str(index_curve) + ", to: " + str(index_to))
+            index_curve += 10
+            if (index_curve*10 > len(learned_curve)):
+                context[0].setValues(MB_CO, BIT_MEASUREMENT_TO_PC, [0])
+                index_curve = 0
+            print("measure")
+    if (bplay != bit_play):
+        cycles_no = 0
+        array_pos = 0
+        quality = [0,0,0]
+    if (bit_play[1] == 1):
+        onePoint = learned_curve[array_pos*4:array_pos*4+3]
+        context[0].setValues(MB_HR, REG_X, onePoint)
+        
+        values = [random.randint(-500,500),random.randint(-500,500),random.randint(-200,200),0]
+        onePoint = prepareMbRegVals(values)
+        context[0].setValues(MB_HR, REG_ACT_X, onePoint)
+        values = [random.randint(-200,200),random.randint(-200,200),random.randint(-70,70),0]
+        onePoint = prepareMbRegVals(values)
+        context[0].setValues(MB_HR, REG_DIR_X, onePoint)
+        cycles_no += 1
+        array_pos += 3
+        if (array_pos*4 > len(learned_curve)):
+            array_pos = 0
+        if (array_pos == 0):
+            quality[0] = (random.randint(45,100));
+            context[0].setValues(MB_CO, BIT_PART_FINISHED, [1])
+        if (cycles_no%25 == 0):
+            quality[1] = (random.randint(45,100));
+        quality[2] = (random.randint(45,100));
+        context[0].setValues(MB_HR, REG_Q_1, quality)
+    else:
+        if (bteach == [1]):
+            #learned_curve.extend(onePoint);
+            onePoint = learned_curve[array_pos*4:array_pos*4+4]
+            context[0].setValues(MB_HR, REG_X, onePoint)
+            array_pos += 8
+            if (array_pos > len(learned_curve)//4):
+                context[0].setValues(MB_CO, BIT_TEACH, [0])
+        else:
+            values = [random.randint(-1000,1000),random.randint(-1000,1000),random.randint(5000,8000),0]
+            onePoint = prepareMbRegVals(values)
+            context[0].setValues(MB_HR, REG_X, onePoint)
+            context[0].setValues(MB_HR, REG_X, reset_pos)
+    
+    #test: set input register using testing coils
+    #bkey_change = context[0].getValues(MB_CO, BIT_BKEY_CHANGE, 2)
+    bkey_change = [1,1]
+    context[0].setValues(MB_DI, BIT_BKEY, [bkey_change[0]])
+    context[0].setValues(MB_DI, BIT_SAFETY_BTN, [bkey_change[1]])
+        
+    bit_rdy = brdy
+    bit_data_change = data_change
+    bit_motor = motor
+    bit_teach = bteach
+    bit_play = bplay
+
+def run_updating_server():
+    # ----------------------------------------------------------------------- # 
+    # initialize your data store
+    # ----------------------------------------------------------------------- # 
+    
+    store = ModbusSlaveContext(
+        di=ModbusSequentialDataBlock(32768, [0]*200),
+        co=ModbusSequentialDataBlock(32768, [0]*200),
+        hr=ModbusSequentialDataBlock(32768, [0]*200),
+        ir=ModbusSequentialDataBlock(32768, [0]*200),zero_mode=True)
+    context = ModbusServerContext(slaves=store, single=True)
+
+    store.setValues(MB_DI, BIT_SAFETY_BTN, [1])
+    store.setValues(MB_DI, BIT_BKEY, [1])
+    # ----------------------------------------------------------------------- # 
+    # initialize the server information
+    # ----------------------------------------------------------------------- # 
+    identity = ModbusDeviceIdentification()
+    identity.VendorName = 'pymodbus'
+    identity.ProductCode = 'PM'
+    identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
+    identity.ProductName = 'pymodbus Server'
+    identity.ModelName = 'pymodbus Server'
+    identity.MajorMinorRevision = '1.0'
+
+    # ----------------------------------------------------------------------- # 
+    # run the server you want
+    # ----------------------------------------------------------------------- # 
+    time = 0.333  # 333 mseconds delay
+    loop = LoopingCall(f=updating_writer, a=(context,))
+    loop.start(time, now=False) # initially delay by time
+    StartTcpServer(context, identity=identity, address=("localhost", 1502))
+
+
+bit_teach = 0
+bit_rdy = [0]
+bit_data_change = [0,0]
+bit_motor = [0,0]
+bit_play = [0,0]
+learned_curve = []
+index_curve = 0
+cycles_no = 0
+array_pos = 0
+quality = [0,0,0]
+# vytvoreni pole s hodnotami mereni #
+meas_array = [(j) for j in range(270)]
+
+
+if __name__ == "__main__":
+    run_updating_server()
