diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f8f63f7b4e878b7db46271d5680e8175d3b766f9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,72 @@
+# Makefile for testing purposes, will build libadios.a, libadios_nompi.a 
+# Created on: Oct 4, 2016
+#     Author: wfg
+     
+#DEFAULT COMPILERS IN PATH, LIBS will be modified in Makefile.libs
+CC:=g++
+MPICC:=mpic++
+LIBS:=
+
+SHARED:=no
+CFLAGS:=-c -Wall -Wpedantic -std=c++11 -O0 -g
+LINKERMPI:=ar
+LINKERNoMPI:=ar
+LINKERFLAGS:= rcs
+LIBEXT:=a
+
+ifeq ($(SHARED),yes)
+	CFLAGS+= -fPIC
+	LINKERMPI=$(MPICC) 
+	LINKERNoMPI=$(CC)
+	LINKERFLAGS= -shared -o
+	LIBEXT=so
+endif
+
+
+#ADIOS 
+HFiles:=$(shell find ./include -type f -name "*.h")
+CPPFiles:=$(shell find ./src -type f -name "*.cpp")
+INC:=-I./include
+VPATH = ./src ./src/core ./src/functions \
+        ./src/engine/bp ./src/engine/dataman ./src/engine/adios1 \
+		./src/transport/file ./src/transport/wan \
+		./src/capsule/heap ./src/capsule/shmem \
+		./src/transform \
+		./src/format
+
+#SEPARATE EXTERNAL HEADERS AND LIBRARIES HANDLING in Makefile.libs, export variables 
+export $(HFiles) $(CPPFiles) $(CFLAGS) $(INC) $(LIBS)  
+include Makefile.libs
+
+OBJMPI:=$(patsubst %.cpp, ./bin/mpi/%.o, $(notdir $(CPPFiles)) )
+OBJMPI:=$(patsubst ./bin/mpi/mpidummy.o, ,$(OBJMPI) )  #remove mpidummy from compilation
+
+OBJNoMPI:=$(patsubst %.cpp, ./bin/nompi/%.o, $(notdir $(CPPFiles)) )
+OBJNoMPI:=$(patsubst ./bin/nompi/MPIFile.o, ,$(OBJNoMPI) )  #remove MPIFile from compilation (not supported in serial)
+
+.PHONY: all clean mpi nompi
+
+all: mpi nompi
+
+mpi: $(HFiles) $(OBJMPI)
+	@( mkdir -p ./lib );
+	$(LINKERMPI) $(LINKERFLAGS) ./lib/libadios.$(LIBEXT) $(OBJMPI)
+	@echo "Finished building MPI library ./lib/libadios.$(LIBEXT)";
+	@echo
+    
+./bin/mpi/%.o: %.cpp $(HFiles)
+	@( mkdir -p ./bin/mpi );
+	$(MPICC) $(CFLAGS) $(INC) -o $@ $<
+
+nompi: $(HFiles) $(OBJNoMPI)
+	@( mkdir -p ./lib );
+	$(LINKERNoMPI) $(LINKERFLAGS) ./lib/libadios_nompi.$(LIBEXT) $(OBJNoMPI)
+	@echo "Finished building noMPI library ./lib/libadios.$(LIBEXT)";
+	@echo
+
+./bin/nompi/%.o: %.cpp $(HFiles)
+	@( mkdir -p ./bin/nompi );
+	$(CC) $(CFLAGS) $(INC) -DADIOS_NOMPI -o $@ $<
+	
+clean:
+	rm ./bin/mpi/*.o ./bin/nompi/*.o ./lib/*	
diff --git a/Makefile.libs b/Makefile.libs
new file mode 100644
index 0000000000000000000000000000000000000000..2f736c1e97433c0b44026cd1dc859231c79a262e
--- /dev/null
+++ b/Makefile.libs
@@ -0,0 +1,87 @@
+#Language API
+LANGUAGE_INC:=./include
+LANGUAGE_SRC:=./src
+
+ifeq ($(C_API),yes)
+else
+    HFiles:=$(filter-out $(LANGUAGE_INC)/ADIOS_C.h,$(HFiles))
+    CPPFiles:=$(filter-out $(LANGUAGE_SRC)/ADIOS_C.cpp,$(CPPFiles))     
+endif
+
+#EXTERNAL DEPENDECIES
+ENGINE_INC:=./include/engine
+ENGINE_SRC:=./src/engine
+TRANSPORT_INC:=./include/transport
+TRANSPORT_SRC:=./src/transport
+
+ifeq ($(HAVE_DATAMAN),yes)
+    DATAMAN_LOC:=/Users/w4g/Dropbox/lib/DataMan# need to change this to your local dataman location
+    CFLAGS += -DHAVE_DATAMAN
+    INC += -I$(DATAMAN_LOC)/include
+    LIBS += -L$(DATAMAN_LOC)/lib -ldataman
+else
+    HFiles:=$(filter-out $(ENGINE_INC)/dataman/DataManWriter.h,$(HFiles))
+    HFiles:=$(filter-out $(ENGINE_INC)/dataman/DataManReader.h,$(HFiles))
+    HFiles:=$(filter-out $(TRANSPORT_INC)/wan/MdtmMan.h,$(HFiles))
+    
+    CPPFiles:=$(filter-out $(ENGINE_SRC)/dataman/DataManWriter.cpp,$(CPPFiles))
+    CPPFiles:=$(filter-out $(ENGINE_SRC)/dataman/DataManReader.cpp,$(CPPFiles))
+    CPPFiles:=$(filter-out $(TRANSPORT_SRC)/wan/MdtmMan.cpp,$(CPPFiles))
+endif
+
+
+ifeq ($(HAVE_ADIOS1),yes)
+    ADIOS1_DIR=/opt/adios/lean/1.11# need to change this to your local adios 1.x installation
+    CFLAGS += -DHAVE_ADIOS1
+    INC += -I$(ADIOS1_DIR)/include
+    LIBS += $(shell ${ADIOS1_DIR}/bin/adios_config -l)
+else
+    HFiles:=$(filter-out $(ENGINE_INC)/adios1/ADIOS1Writer.h,$(HFiles))
+    HFiles:=$(filter-out $(ENGINE_INC)/adios1/ADIOS1Reader.h,$(HFiles))
+    CPPFiles:=$(filter-out $(ENGINE_SRC)/adios1/ADIOS1Writer.cpp,$(CPPFiles))
+    CPPFiles:=$(filter-out $(ENGINE_SRC)/adios1/ADIOS1Reader.cpp,$(CPPFiles))
+endif
+
+
+
+#EXTERNAL DEPENDENCIES
+ifeq ($(HAVE_NETCDF),yes)
+    LIBS += -lnetcdf
+    CFLAGS += -DHAVE_NETCDF
+else
+    HFiles:=$(filter-out $(TRANSPORT_INC)/NetCDF4.h,$(HFiles))
+    CPPFiles:=$(filter-out $(TRANSPORT_SRC)/NetCDF4.cpp,$(CPPFiles))     
+endif
+
+ifeq ($(HAVE_PHDF5),yes)
+    LIBS += -lhdf5
+    CFLAGS += -DHAVE_PHDF5
+else
+    HFiles:=$(filter-out $(TRANSPORT_INC)/PHDF5.h,$(HFiles))
+    CPPFiles:=$(filter-out $(TRANSPORT_SRC)/PHDF5.cpp,$(CPPFiles))     
+endif
+
+
+ifeq ($(HAVE_BZIP2),yes)
+    LIBS += -lbz2
+    CFLAGS += -DHAVE_BZIP2
+else
+    HFiles:=$(filter-out $(TRANSFORM_INC)/BZIP2.h,$(HFiles))
+    CPPFiles:=$(filter-out $(TRANSFORM_SRC)/BZIP2.cpp,$(CPPFiles))     
+endif
+
+ifeq ($(HAVE_SZIP),yes)
+    LIBS += -lsz
+    CFLAGS += -DHAVE_SZIP
+else
+    HFiles:=$(filter-out $(TRANSFORM_INC)/SZIP.h,$(HFiles))
+    CPPFiles:=$(filter-out $(TRANSFORM_SRC)/SZIP.cpp,$(CPPFiles))     
+endif
+
+ifeq ($(HAVE_ZLIB),yes)
+    LIBS += -lz
+    CFLAGS += -DHAVE_ZLIB
+else
+    HFiles:=$(filter-out $(TRANSFORM_INC)/ZLIB.h,$(HFiles))
+    CPPFiles:=$(filter-out $(TRANSFORM_SRC)/ZLIB.cpp,$(CPPFiles))     
+endif
diff --git a/bindings/python/Makefile b/bindings/python/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..76ea1342a0a1ed82827ff96acb3a8da77a0c35d7
--- /dev/null
+++ b/bindings/python/Makefile
@@ -0,0 +1,53 @@
+#Makefile
+# Created on: Mar 13, 2017
+#     Author: wfg
+
+MPICC:=mpic++
+
+CPPFiles:=$(shell find ./src -type f -name "*.cpp")
+OBJS:=$(patsubst %.cpp, ./bin/%.o, $(notdir $(CPPFiles)) )
+
+# location of the Python header files
+PYTHON_VERSION:= 2.7
+PYTHON_INC:= /usr/include/python$(PYTHON_VERSION)
+PYTHON_LIBLOC:= /usr/lib/python$(PYTHON_VERSION)/config-x86_64-linux-gnu/
+ 
+
+ifeq ($(HAVE_PYBIND11),yes)  # USE PYBIND11 (headers only)
+    BIND_FLAG:= -DHAVE_PYBIND11
+    BIND_INC:= /home/wfg/workspace/pybind11/include
+    BIND_LIBS:=
+    OBJS:=$(patsubst ./bin/glueBoostPython.o, ,$(OBJS) ) #remove BoostPython
+else                             # USE BOOST PYTHON (default)
+	BIND_FLAG:= -DHAVE_BOOSTPYTHON
+	BIND_INC:= /opt/boost_1_63_0/
+	BIND_LIBS:= -L/opt/boost_1_63_0/stage/lib/ -lboost_python -lboost_numpy
+	OBJS:=$(patsubst ./bin/gluePyBind11.o, ,$(OBJS) ) #remove PyBind11
+endif
+
+
+# location of ADIOS include and lib
+ADIOS_INC:= /home/wfg/workspace/ADIOSPP/include
+ADIOS_LIB:= /home/wfg/workspace/ADIOSPP/lib
+ADIOSPy_INC:=./include
+
+
+CFLAGS:=-c -Wall -fPIC -O0 -g -std=c++11 -Wno-deprecated-declarations $(BIND_FLAG)
+INC:= -I$(PYTHON_INC) -I$(BIND_INC) -I$(ADIOS_INC) -I$(ADIOSPy_INC)
+LIBS:= -L$(ADIOS_LIB) -ladios $(BIND_LIBS) -L$(PYTHON_LIBLOC) -lpython$(PYTHON_VERSION)
+
+ 
+# compile mesh classes
+TARGET = ADIOSPy
+
+all: $(TARGET).so
+ 
+$(TARGET).so: $(OBJS)
+	$(MPICC) -shared -o $(TARGET).so -Wl,--export-dynamic $(OBJS) $(LIBS) 
+ 
+./bin/%.o: ./src/%.cpp
+	@( mkdir -p ./bin );
+	$(MPICC) $(INC) $(CFLAGS) -o $@ $<
+	
+clean:
+	rm ./bin/*.o *.so
\ No newline at end of file
diff --git a/bindings/python/README.md b/bindings/python/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b94db28b5b90ead79adfbc5433d17cf5023c1373
--- /dev/null
+++ b/bindings/python/README.md
@@ -0,0 +1,28 @@
+Python bindings for ADIOS 2.0
+
+Dependencies:
+	
+	Python 2.7.x
+	Numpy and MPI4PY
+	ADIOS shared library (libadios.so) built with : make SHARED=yes (see ADIOS README.md)  
+	Add boost python and libadios.so libraries path in LD_LIBRARY_PATH or DYLD_LIBRARY_PATH
+
+
+For Boost Python use: 
+	make -jn , where n is the number of cores
+	e.g.
+	make -j4 
+	make -j8
+
+	Additional Requirements:
+	Boost.Python version 1.63 (latest)
+	
+
+For PyBind11 use:
+	make -jn HAVE_PYBIND11=yes, where n is the number of cores
+	e.g.
+	make -j4 HAVE_PYBIND11=yes
+	make -j8 HAVE_PYBIND11=yes
+	
+	Requirements:
+	PyBind11 version 2.0.1 or master from github (header only library, no need to compile)
diff --git a/bindings/python/include/ADIOSPy.h b/bindings/python/include/ADIOSPy.h
new file mode 100644
index 0000000000000000000000000000000000000000..584526e80600748dda31dc9be51f0aebee9d5d09
--- /dev/null
+++ b/bindings/python/include/ADIOSPy.h
@@ -0,0 +1,79 @@
+/*
+ * ADIOSPy.h
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+
+#ifndef ADIOSPY_H_
+#define ADIOSPY_H_
+
+#include <string>
+#include <memory> //std::shared_ptr
+#include <map>
+
+#ifdef HAVE_BOOSTPYTHON
+  #include "boost/python.hpp"
+#endif
+
+#ifdef HAVE_PYBIND11
+  #include "pybind11/pybind11.h"
+#endif
+
+#include "ADIOS.h"
+#include "adiosPyFunctions.h" //ListToVector, VectorToList
+#include "VariablePy.h"
+#include "MethodPy.h"
+
+namespace adios
+{
+
+#ifdef HAVE_BOOSTPYTHON
+using pyList = boost::python::list;
+using pyObject = boost::python::object;
+using pyNone = pyObject();
+#endif
+
+#ifdef HAVE_PYBIND11
+using pyList = pybind11::list;
+using pyObject = pybind11::object;
+#endif
+
+
+class EnginePy;
+
+
+class ADIOSPy : public ADIOS
+{
+
+public:
+
+    ADIOSPy( MPI_Comm mpiComm, const bool debug );
+    ~ADIOSPy( );
+
+    void HelloMPI( ); ///< says hello from rank/size for testing
+
+    VariablePy DefineVariablePy( const std::string name, const pyList localDimensionsPy = pyList(),
+                                 const pyList globalDimensionsPy = pyList(), const pyList globalOffsetsPy = pyList() );
+
+    MethodPy& DeclareMethodPy( const std::string methodName );
+
+    EnginePy OpenPy( const std::string name, const std::string accessMode, const MethodPy&  method, pyObject py_comm = pyObject() );
+
+    void DefineVariableType( VariablePy& variablePy );
+
+
+private:
+
+    std::set<std::string> m_VariablesPyNames;
+
+};
+
+
+
+
+
+} //end namespace
+
+
+#endif /* ADIOSPY_H_ */
diff --git a/bindings/python/include/EnginePy.h b/bindings/python/include/EnginePy.h
new file mode 100644
index 0000000000000000000000000000000000000000..9955d7b64b4331c85e10f77a49c28fd90d35a885
--- /dev/null
+++ b/bindings/python/include/EnginePy.h
@@ -0,0 +1,86 @@
+/*
+ * EnginePy.h
+ *
+ *  Created on: Mar 15, 2017
+ *      Author: wgodoy
+ */
+
+#ifndef ENGINEPY_H_
+#define ENGINEPY_H_
+
+#ifdef HAVE_BOOSTPYTHON
+#include "boost/python.hpp"
+#include "boost/python/numpy.hpp"
+#endif
+
+#ifdef HAVE_PYBIND11
+#include "pybind11/pybind11.h"
+#include "pybind11/numpy.h"
+#endif
+
+#include "ADIOSPy.h"
+#include "core/Engine.h"
+#include "VariablePy.h"
+#include "adiosPyFunctions.h"
+
+namespace adios
+{
+
+#ifdef HAVE_BOOSTPYTHON
+using dtype = boost::python::numpy::dtype;
+#endif
+
+#ifdef HAVE_PYBIND11
+using pyArray = pybind11::array;
+using dtype = pybind11::dtype;
+#endif
+
+
+class EnginePy
+{
+
+public:
+
+	EnginePy( ADIOSPy& adiosPy );
+
+	~EnginePy( );
+
+    std::shared_ptr<Engine> m_Engine;
+
+	void WritePy( VariablePy& variable, const pyArray& array );
+
+	void Advance( );
+
+	void Close( );
+
+	void GetEngineType( ) const;
+
+private:
+
+	ADIOSPy& m_ADIOSPy;
+	bool m_IsVariableTypeDefined = false;
+
+	template< class T >
+    void DefineVariableInADIOS( VariablePy& variable )
+    {
+        auto& var = m_ADIOSPy.DefineVariable<T>( variable.m_Name, variable.m_LocalDimensions,
+                                                 variable.m_GlobalDimensions, variable.m_GlobalOffsets );
+        variable.m_VariablePtr = &var;
+        variable.m_IsVariableDefined = true;
+    }
+
+    template< class T >
+    void WriteVariableInADIOS( VariablePy& variable, const pyArray& array )
+    {
+        m_Engine->Write( *reinterpret_cast<Variable<T>*>( variable.m_VariablePtr ), PyArrayToPointer<T>( array ) );
+    }
+
+};
+
+
+} //end namespace
+
+
+
+
+#endif /* ENGINEPY_H_ */
diff --git a/bindings/python/include/MethodPy.h b/bindings/python/include/MethodPy.h
new file mode 100644
index 0000000000000000000000000000000000000000..77ca9471bb93263783a8c725b99f9b11657598d1
--- /dev/null
+++ b/bindings/python/include/MethodPy.h
@@ -0,0 +1,68 @@
+/*
+ * MethodPy.h
+ *
+ *  Created on: Mar 14, 2017
+ *      Author: wfg
+ */
+
+#ifndef METHODPY_H_
+#define METHODPY_H_
+
+#ifdef HAVE_BOOSTPYTHON
+  #include "boost/python.hpp"
+#endif
+
+#ifdef HAVE_PYBIND11
+  #include "pybind11/pybind11.h"
+  #include "pybind11/cast.h"
+#endif
+
+
+#include "core/Method.h"
+
+namespace adios
+{
+
+#ifdef HAVE_BOOSTPYTHON
+using pyObject = boost::python::object;
+using pyTuple = boost::python::tuple;
+using pyDict = boost::python::dict;
+#endif
+
+#ifdef HAVE_PYBIND11
+using pyObject = pybind11::object;
+using pyTuple = pybind11::tuple;
+using pyDict = pybind11::dict;
+#endif
+
+
+class MethodPy : public Method
+{
+
+public:
+
+    MethodPy( const std::string type, const bool debugMode );
+
+    ~MethodPy( );
+
+
+    #ifdef HAVE_BOOSTPYTHON
+    static pyObject SetParametersPy( pyTuple args, pyDict kwargs );
+    static pyObject AddTransportPy( pyTuple args, pyDict kwargs );
+    #endif
+
+
+    #ifdef HAVE_PYBIND11
+    void SetParametersPyBind11( pybind11::kwargs kwargs );
+    void AddTransportPyBind11( const std::string type, pybind11::kwargs kwargs );
+    #endif
+
+    void PrintAll( ) const;
+
+};
+
+
+}
+
+
+#endif /* METHODPY_H_ */
diff --git a/bindings/python/include/VariablePy.h b/bindings/python/include/VariablePy.h
new file mode 100644
index 0000000000000000000000000000000000000000..934b3b523d422aafb74eb31d28467b5ee2562a1f
--- /dev/null
+++ b/bindings/python/include/VariablePy.h
@@ -0,0 +1,57 @@
+/*
+ * VariablePy.h
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wgodoy
+ */
+
+#ifndef VARIABLEPY_H_
+#define VARIABLEPY_H_
+
+#include "core/Variable.h"
+#include "adiosPyFunctions.h"
+
+namespace adios
+{
+
+#ifdef HAVE_BOOSTPYTHON
+using pyList = boost::python::list;
+#endif
+
+#ifdef HAVE_PYBIND11
+using pyList = pybind11::list;
+#endif
+
+
+class VariablePy
+{
+
+public:
+
+    VariablePy( const std::string name, const pyList localDimensionsPy, const pyList globalDimensionsPy, const pyList globalOffsetsPy );
+
+    ~VariablePy( );
+
+	void SetLocalDimensions( const pyList list );
+
+	void SetGlobalDimensionsAndOffsets( const pyList globalDimensions, const pyList globalOffsets );
+
+	Dims GetLocalDimensions( );
+
+	void* m_VariablePtr = nullptr;
+	bool m_IsVariableDefined = false;
+
+	const std::string m_Name;
+	Dims m_LocalDimensions;
+	Dims m_GlobalDimensions;
+	Dims m_GlobalOffsets;
+};
+
+
+
+} //end namespace
+
+
+
+
+#endif /* BINDINGS_PYTHON_INCLUDE_VARIABLEPY_H_ */
diff --git a/bindings/python/include/adiosPyFunctions.h b/bindings/python/include/adiosPyFunctions.h
new file mode 100644
index 0000000000000000000000000000000000000000..1f3167929cf73e740293d9e746b5b3c1c1b2f520
--- /dev/null
+++ b/bindings/python/include/adiosPyFunctions.h
@@ -0,0 +1,112 @@
+/*
+ * adiosPyFunctions.h
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+
+#ifndef ADIOSPYFUNCTIONS_H_
+#define ADIOSPYFUNCTIONS_H_
+
+#include <vector>
+#include <map>
+#include <string>
+
+#ifdef HAVE_BOOSTPYTHON
+  #include "boost/python.hpp"
+  #include "boost/python/numpy.hpp"
+#endif
+
+#ifdef HAVE_PYBIND11
+  #include "pybind11/pybind11.h"
+  #include "pybind11/numpy.h"
+#endif
+
+
+namespace adios
+{
+
+using Dims = std::vector<std::size_t>;
+
+#ifdef HAVE_BOOSTPYTHON
+using pyList = boost::python::list;
+using pyDict = boost::python::dict;
+using pyArray = boost::python::numpy::ndarray;
+using dtype = boost::python::numpy::dtype;
+using pyKwargs = boost::python::dict;
+using pyObject = boost::python::object;
+#endif
+
+#ifdef HAVE_PYBIND11
+using pyList = pybind11::list;
+using pyDict = pybind11::dict;
+using pyArray = pybind11::array;
+using dtype = pybind11::dtype;
+using pyKwargs = pybind11::kwargs;
+using pyObject = pybind11::object;
+#endif
+
+/**
+ * Transforms a boost python list to a Dims (std::vector<std::size_t>) object
+ * @param list input boost python list from python program
+ * @return Dims (std::vector<std::size_t>) object than can be passed to python
+ */
+Dims ListToVector( const pyList& list );
+
+#ifdef HAVE_BOOSTPYTHON
+std::map<std::string, std::string> DictToMap( const pyDict& dictionary );
+#endif
+
+#ifdef HAVE_PYBIND11
+std::map<std::string, std::string> KwargsToMap( const pybind11::kwargs& dictionary );
+#endif
+
+
+template< class T >
+const T* PyArrayToPointer( const pyArray& array )
+{
+    #ifdef HAVE_BOOSTPYTHON
+    return reinterpret_cast<const T*>( array.get_data() );
+    #endif
+
+    #ifdef HAVE_PYBIND11
+    return reinterpret_cast<const T*>( array.data() );
+    #endif
+}
+
+template< class T >
+bool IsType( const pyArray& array )
+{
+    #ifdef HAVE_BOOSTPYTHON
+    if( array.get_dtype() == dtype::get_builtin<T>() ) return true;
+    #endif
+
+    #ifdef HAVE_PYBIND11
+    if( pybind11::isinstance<pybind11::array_t<T>>( array ) ) return true;
+    #endif
+
+    return false;
+}
+
+
+template< class T, class U>
+T PyCast( U object )
+{
+    #ifdef HAVE_BOOSTPYTHON
+    return boost::python::extract<T>( object );
+    #endif
+
+    #ifdef HAVE_PYBIND11
+    return pybind11::cast<T>( object );
+    #endif
+}
+
+
+bool IsEmpty( pyObject object );
+
+
+} //end namespace
+
+
+
+#endif /* ADIOSPYFUNCTIONS_H_ */
diff --git a/bindings/python/src/ADIOSPy.cpp b/bindings/python/src/ADIOSPy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f92bc8a6df8fc85de634c6913e0f0b2f187f108e
--- /dev/null
+++ b/bindings/python/src/ADIOSPy.cpp
@@ -0,0 +1,86 @@
+/*
+ * ADIOSPy.cpp
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+
+#include <iostream>
+
+#include <mpi4py/mpi4py.h>
+
+#include "ADIOSPy.h"
+#include "EnginePy.h"
+
+namespace adios
+{
+
+
+ADIOSPy::ADIOSPy( MPI_Comm mpiComm, const bool debug ):
+    ADIOS( mpiComm, adios::Verbose::ERROR, debug )
+{ }
+
+
+ADIOSPy::~ADIOSPy( )
+{ }
+
+
+void ADIOSPy::HelloMPI( )
+{
+    std::cout << "Hello ADIOSPy from rank " << m_RankMPI << "/" << m_SizeMPI << "\n";
+}
+
+
+MethodPy& ADIOSPy::DeclareMethodPy( const std::string methodName )
+{
+    Method& method = DeclareMethod( methodName );
+    return *reinterpret_cast<MethodPy*>( &method );
+}
+
+
+VariablePy ADIOSPy::DefineVariablePy( const std::string name, const pyList localDimensionsPy,
+                                      const pyList globalDimensionsPy, const pyList globalOffsetsPy )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_VariablesPyNames.count( name ) == 1 )
+            throw std::invalid_argument( "ERROR: Variable " + name + " is already defined\n" );
+    }
+
+    m_VariablesPyNames.insert( name );
+    return VariablePy( name, localDimensionsPy, globalDimensionsPy, globalOffsetsPy );
+}
+
+void ADIOSPy::DefineVariableType( VariablePy& variablePy )
+{
+
+}
+
+
+
+EnginePy ADIOSPy::OpenPy( const std::string name, const std::string accessMode,
+    		              const MethodPy& method, pyObject py_comm )
+{
+	EnginePy enginePy( *this );
+
+	bool isEmpty = IsEmpty( py_comm );
+
+	if( isEmpty == true   ) //None
+	{
+		enginePy.m_Engine = Open( name, accessMode, method );
+	}
+	else
+	{
+		if (import_mpi4py() < 0) throw std::logic_error( "ERROR: could not import mpi4py communicator in Open " + name + "\n" );
+		MPI_Comm* comm_p = PyMPIComm_Get( py_comm.ptr() );
+		if( comm_p == nullptr ) throw std::invalid_argument( "ERROR: MPI communicator is nullptr in Open " + name + "\n" );
+
+		enginePy.m_Engine = Open( name, accessMode, *comm_p, method );
+	}
+
+	return enginePy;
+}
+
+
+
+} //end namespace
diff --git a/bindings/python/src/EnginePy.cpp b/bindings/python/src/EnginePy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..790e997e3318ef00ea8ec30ea06617d040af0588
--- /dev/null
+++ b/bindings/python/src/EnginePy.cpp
@@ -0,0 +1,89 @@
+/*
+ * EnginePy.cpp
+ *
+ *  Created on: Mar 15, 2017
+ *      Author: wgodoy
+ */
+
+#include <string>
+
+
+#include "EnginePy.h"
+
+#include "adiosPyFunctions.h"
+
+namespace adios
+{
+
+EnginePy::EnginePy( ADIOSPy& adiosPy ):
+    m_ADIOSPy{ adiosPy }
+{ }
+
+
+EnginePy::~EnginePy( )
+{ }
+
+
+void EnginePy::WritePy( VariablePy& variable, const pyArray& array )
+{
+
+    if( variable.m_IsVariableDefined == false ) //here define variable
+    {
+             if( IsType<char>( array ) ) DefineVariableInADIOS<char>( variable );
+        else if( IsType<unsigned char>( array ) ) DefineVariableInADIOS<unsigned char>( variable );
+        else if( IsType<short>( array ) ) DefineVariableInADIOS<short>( variable );
+        else if( IsType<unsigned short>( array ) ) DefineVariableInADIOS<unsigned short>( variable );
+        else if( IsType<int>( array ) ) DefineVariableInADIOS<int>( variable );
+        else if( IsType<unsigned int>( array ) ) DefineVariableInADIOS<unsigned int>( variable );
+        else if( IsType<long int>( array ) ) DefineVariableInADIOS<long int>( variable );
+        else if( IsType<unsigned long int>( array ) ) DefineVariableInADIOS<unsigned long int>( variable );
+        else if( IsType<long long int>( array ) ) DefineVariableInADIOS<long long int>( variable );
+        else if( IsType<unsigned long long int>( array ) ) DefineVariableInADIOS<unsigned long long int>( variable );
+        else if( IsType<float>( array ) ) DefineVariableInADIOS<float>( variable );
+        else if( IsType<double>( array ) ) DefineVariableInADIOS<double>( variable );
+        else if( IsType<long double>( array ) ) DefineVariableInADIOS<long double>( variable );
+        else if( IsType<std::complex<float>>( array ) ) DefineVariableInADIOS<std::complex<float>>( variable );
+        else if( IsType<std::complex<double>>( array ) ) DefineVariableInADIOS<std::complex<double>>( variable );
+        else if( IsType<std::complex<long double>>( array ) ) DefineVariableInADIOS<std::complex<long double>>( variable );
+    }
+
+         if( IsType<char>( array ) ) WriteVariableInADIOS<char>( variable, array );
+    else if( IsType<unsigned char>( array ) ) WriteVariableInADIOS<unsigned char>( variable, array );
+    else if( IsType<short>( array ) ) WriteVariableInADIOS<short>( variable, array );
+    else if( IsType<unsigned short>( array ) ) WriteVariableInADIOS<unsigned short>( variable, array );
+    else if( IsType<int>( array ) ) WriteVariableInADIOS<int>( variable, array );
+    else if( IsType<unsigned int>( array ) ) WriteVariableInADIOS<unsigned int>( variable, array );
+    else if( IsType<long int>( array ) ) WriteVariableInADIOS<long int>( variable, array );
+    else if( IsType<unsigned long int>( array ) ) WriteVariableInADIOS<unsigned long int>( variable, array );
+    else if( IsType<long long int>( array ) ) WriteVariableInADIOS<long long int>( variable, array );
+    else if( IsType<unsigned long long int>( array ) ) WriteVariableInADIOS<unsigned long long int>( variable, array );
+    else if( IsType<float>( array ) ) WriteVariableInADIOS<float>( variable, array );
+    else if( IsType<double>( array ) ) WriteVariableInADIOS<double>( variable, array );
+    else if( IsType<long double>( array ) ) WriteVariableInADIOS<long double>( variable, array );
+    else if( IsType<std::complex<float>>( array ) ) WriteVariableInADIOS<std::complex<float>>( variable, array );
+    else if( IsType<std::complex<double>>( array ) ) WriteVariableInADIOS<std::complex<double>>( variable, array );
+    else if( IsType<std::complex<long double>>( array ) ) WriteVariableInADIOS<std::complex<long double>>( variable, array );
+
+}
+
+void EnginePy::Advance( )
+{
+    m_Engine->Advance( );
+}
+
+
+
+void EnginePy::Close( )
+{
+	m_Engine->Close( -1 );
+}
+
+
+void EnginePy::GetEngineType( ) const
+{
+    std::cout << "Engine type " << m_Engine->m_EngineType << "\n";
+}
+
+
+
+} //end namespace
diff --git a/bindings/python/src/MethodPy.cpp b/bindings/python/src/MethodPy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..88babe0b46711d540f3af4a3d1bd97b3b53d83c9
--- /dev/null
+++ b/bindings/python/src/MethodPy.cpp
@@ -0,0 +1,102 @@
+/*
+ * MethodPy.cpp
+ *
+ *  Created on: Mar 14, 2017
+ *      Author: wfg
+ */
+
+
+#include <iostream>
+
+#include "MethodPy.h"
+#include "adiosPyFunctions.h"
+
+namespace adios
+{
+
+#ifdef HAVE_BOOSTPYTHON
+namespace py = boost::python;
+#endif
+
+#ifdef HAVE_PYBIND11
+namespace py = pybind11;
+#endif
+
+
+MethodPy::MethodPy( const std::string type, const bool debugMode ):
+    Method( type, debugMode )
+{ }
+
+
+MethodPy::~MethodPy( )
+{ }
+
+#ifdef HAVE_BOOSTPYTHON
+pyObject MethodPy::SetParametersPy( pyTuple args, pyDict kwargs )
+{
+    if( py::len( args ) > 1  )
+        throw std::invalid_argument( "ERROR: syntax of Method SetParameters function is incorrect, only use dictionary\n" );
+
+    MethodPy& self = PyCast<MethodPy&>( args[0] );
+    self.m_Parameters = DictToMap( kwargs );
+    return args[0];
+}
+
+
+pyObject MethodPy::AddTransportPy( pyTuple args, pyDict kwargs )
+{
+    if( py::len( args ) != 2  )
+        throw std::invalid_argument( "ERROR: syntax of Method AddTransport function is incorrect, only use one string for transport followed by a dictionary for parameters\n" );
+
+    MethodPy& self = PyCast<MethodPy&>( args[0] );
+    const std::string type = PyCast<std::string>( args[1] );
+
+    auto parameters = DictToMap( kwargs );
+    parameters.insert( std::make_pair( "transport", type ) );
+    self.m_TransportParameters.push_back( parameters );
+    return args[0];
+}
+#endif
+
+
+#ifdef HAVE_PYBIND11
+void MethodPy::SetParametersPyBind11( pybind11::kwargs kwargs )
+{
+    this->m_Parameters = KwargsToMap( kwargs );
+}
+
+
+void MethodPy::AddTransportPyBind11( const std::string type, pybind11::kwargs kwargs )
+{
+    auto parameters = KwargsToMap( kwargs );
+    parameters.insert( std::make_pair( "transport", type ) );
+    this->m_TransportParameters.push_back( parameters );
+}
+#endif
+
+
+
+void MethodPy::PrintAll( ) const
+{
+    std::cout << "Method parameters\n";
+    for( const auto& param : m_Parameters )
+        std::cout << "Parameter: " << param.first << "\t Value: " << param.second << "\n";
+
+    std::cout << "\n";
+    std::cout << "Transport Parameters\n";
+
+    for( const auto& transportParameters : m_TransportParameters )
+    {
+        std::cout << "Transport:\n";
+    	for( const auto& param : transportParameters )
+            std::cout << "Parameter: " << param.first << "\t Value: " << param.second << "\n";
+
+        std::cout << "\n";
+    }
+}
+
+
+
+
+} //end namespace
+
diff --git a/bindings/python/src/VariablePy.cpp b/bindings/python/src/VariablePy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..562bbb8948d2cae96fe2df531f1004bea64f3bea
--- /dev/null
+++ b/bindings/python/src/VariablePy.cpp
@@ -0,0 +1,49 @@
+/*
+ * VariablePy.cpp
+ *
+ *  Created on: Mar 17, 2017
+ *      Author: wfg
+ */
+
+
+#include "VariablePy.h"
+
+
+namespace adios
+{
+
+VariablePy::VariablePy( const std::string name, const pyList localDimensionsPy,
+                        const pyList globalDimensionsPy, const pyList globalOffsetsPy ):
+    m_Name{ name },
+    m_LocalDimensions{ ListToVector( localDimensionsPy ) },
+    m_GlobalDimensions{ ListToVector( globalDimensionsPy ) },
+    m_GlobalOffsets{ ListToVector( globalOffsetsPy ) }
+{ }
+
+
+VariablePy::~VariablePy( )
+{ }
+
+
+void VariablePy::SetLocalDimensions( const pyList list )
+{
+//      this->m_Dimensions = ListToVector( list );
+
+}
+
+
+void VariablePy::SetGlobalDimensionsAndOffsets( const pyList globalDimensions, const pyList globalOffsets  )
+{
+//        this->m_GlobalDimensions = ListToVector( globalDimensions );
+//        this->m_GlobalOffsets = ListToVector( globalOffsets );
+}
+
+
+Dims VariablePy::GetLocalDimensions( )
+{
+    return this->m_LocalDimensions;
+}
+
+
+
+} //end namespace
diff --git a/bindings/python/src/adiosPyFunctions.cpp b/bindings/python/src/adiosPyFunctions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..80cef254d9af297846fa9f8fae7b779cdc9cb080
--- /dev/null
+++ b/bindings/python/src/adiosPyFunctions.cpp
@@ -0,0 +1,88 @@
+/*
+ * adiosPyFunctions.cpp
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+#include <iostream>
+
+#include "adiosPyFunctions.h"
+
+
+namespace adios
+{
+
+#ifdef HAVE_BOOSTPYTHON
+namespace py = boost::python;
+#endif
+
+#ifdef HAVE_PYBIND11
+namespace py = pybind11;
+#endif
+
+
+
+Dims ListToVector( const pyList& list )
+{
+    const unsigned int length = py::len( list );
+    Dims vec;
+    vec.reserve( length );
+
+    for( unsigned int i=0; i<length;i++ )
+        vec.push_back( PyCast<std::size_t>( list[i]) );
+
+    return vec;
+}
+
+#ifdef HAVE_BOOSTPYTHON
+std::map<std::string, std::string> DictToMap( const pyDict& dictionary )
+{
+    std::map<std::string, std::string> parameters;
+
+    pyList keys = dictionary.keys();
+    const unsigned int length = py::len( keys );
+
+    for( unsigned int k = 0; k < length; ++k )
+    {
+        const std::string key( PyCast<std::string>( keys[k] ) );
+        const std::string value( PyCast<std::string>( dictionary[ keys[k] ] ) );
+        parameters.insert( std::make_pair( key, value ) );
+    }
+
+    return parameters;
+}
+#endif
+
+#ifdef HAVE_PYBIND11
+std::map<std::string, std::string> KwargsToMap( const pybind11::kwargs& kwargs )
+{
+    std::map<std::string, std::string> parameters;
+
+    for( const auto& pair : kwargs )
+    {
+        const std::string key( PyCast<std::string>( pair.first ) );
+        const std::string value( PyCast<std::string>( pair.second ) );
+        parameters.insert( std::make_pair( key, value ) );
+    }
+    return parameters;
+}
+#endif
+
+
+bool IsEmpty( pyObject object )
+{
+    bool isEmpty = false;
+
+#ifdef HAVE_BOOSTPYTHON
+    if( object == boost::python::object() ) isEmpty = true;
+#endif
+
+#ifdef HAVE_PYBIND11
+    if( object == pybind11::none() ) isEmpty = true;
+#endif
+    return isEmpty;
+}
+
+
+} //end namespace
+
diff --git a/bindings/python/src/glueBoostPython.cpp b/bindings/python/src/glueBoostPython.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2adc5af2d7f83b27e4ee4e831966a9eac4f7fb11
--- /dev/null
+++ b/bindings/python/src/glueBoostPython.cpp
@@ -0,0 +1,75 @@
+/*
+ * glue.cpp
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+
+#include <mpi4py/mpi4py.h>
+
+#include "boost/python.hpp"
+#include "boost/python/suite/indexing/vector_indexing_suite.hpp"
+#include "boost/python/raw_function.hpp"
+#include "boost/python/numpy.hpp"
+
+
+#include "ADIOSPy.h"
+#include "EnginePy.h"
+#include "adiosPyFunctions.h"
+
+
+namespace py = boost::python;
+namespace np = boost::python::numpy;
+
+
+adios::ADIOSPy ADIOSPy( py::object py_comm, const bool debug )
+{
+    MPI_Comm* comm_p = PyMPIComm_Get( py_comm.ptr() );
+    if (comm_p == NULL) py::throw_error_already_set();
+    return adios::ADIOSPy( *comm_p, debug );
+}
+
+
+using ReturnInternalReference = py::return_internal_reference<>;
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( open_overloads, adios::ADIOSPy::OpenPy, 3, 4 )
+
+
+BOOST_PYTHON_MODULE( ADIOSPy )
+{
+    if (import_mpi4py() < 0) return; /* Python 2.X */
+
+    Py_Initialize();
+    np::initialize();
+
+    py::class_< adios::Dims >("Dims")
+        .def(boost::python::vector_indexing_suite< adios::Dims >() );
+    //functions
+    py::def("ADIOSPy", ADIOSPy );
+
+    //classes
+    py::class_<adios::ADIOSPy>("ADIOS", py::no_init )
+        .def("HelloMPI", &adios::ADIOSPy::HelloMPI )
+        .def("DefineVariable", &adios::ADIOSPy::DefineVariablePy )
+        .def("DeclareMethod", &adios::ADIOSPy::DeclareMethodPy, ReturnInternalReference() )
+		.def("Open", &adios::ADIOSPy::OpenPy, open_overloads() )
+    ;
+
+    py::class_<adios::VariablePy>("Variable", py::no_init )
+        .def("SetLocalDimensions", &adios::VariablePy::SetLocalDimensions )
+        .def("GetLocalDimensions", &adios::VariablePy::GetLocalDimensions )
+    ;
+
+    py::class_<adios::MethodPy>("Method", py::no_init )
+        .def("SetParameters", py::raw_function( &adios::MethodPy::SetParametersPy, 1 )  )
+        .def("AddTransport", py::raw_function( &adios::MethodPy::AddTransportPy, 1 ) )
+        .def("PrintAll", &adios::MethodPy::PrintAll )
+    ;
+
+    //Engine
+    py::class_<adios::EnginePy>("EnginePy", py::no_init )
+        .def("Write", &adios::EnginePy::WritePy )
+        .def("Advance", &adios::EnginePy::WritePy )
+		.def("Close", &adios::EnginePy::Close )
+    ;
+}
+
diff --git a/bindings/python/src/gluePyBind11.cpp b/bindings/python/src/gluePyBind11.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d7ee0456c69307d2ae3cff53255642209fa48e46
--- /dev/null
+++ b/bindings/python/src/gluePyBind11.cpp
@@ -0,0 +1,64 @@
+/*
+ * gluePyBind11.cpp
+ *
+ *  Created on: Mar 16, 2017
+ *      Author: wfg
+ */
+
+#include <stdexcept>
+
+#include <mpi4py/mpi4py.h>
+
+#include "pybind11/pybind11.h"
+
+#include "ADIOSPy.h"
+#include "EnginePy.h"
+
+
+namespace py = pybind11;
+
+
+adios::ADIOSPy ADIOSPy( py::object py_comm, const bool debug )
+{
+    MPI_Comm* comm_p = PyMPIComm_Get( py_comm.ptr() );
+    if( comm_p == NULL ) py::error_already_set();
+    return adios::ADIOSPy( *comm_p, debug );
+}
+
+
+PYBIND11_PLUGIN( ADIOSPy )
+{
+    if (import_mpi4py() < 0) throw std::runtime_error("ERROR: mpi4py not loaded correctly\n"); /* Python 2.X */
+
+    py::module m( "ADIOSPy", "ADIOS Python bindings using pybind11" );
+
+    m.def("ADIOSPy", &ADIOSPy, "Function that creates an ADIOS object" );
+
+    py::class_<adios::ADIOSPy>( m, "ADIOS" )
+        .def("HelloMPI", &adios::ADIOSPy::HelloMPI )
+        .def("DefineVariable", &adios::ADIOSPy::DefineVariablePy )
+        .def("DeclareMethod", &adios::ADIOSPy::DeclareMethodPy, py::return_value_policy::reference_internal )
+        .def("Open", &adios::ADIOSPy::OpenPy )
+    ;
+
+    py::class_<adios::VariablePy>( m, "Variable")
+        .def("SetLocalDimensions", &adios::VariablePy::SetLocalDimensions )
+        .def("GetLocalDimensions", &adios::VariablePy::GetLocalDimensions )
+    ;
+
+    py::class_<adios::MethodPy>( m, "Method")
+        .def("SetParameters", &adios::MethodPy::SetParametersPyBind11 )
+        .def("AddTransport", &adios::MethodPy::AddTransportPyBind11 )
+        .def("PrintAll", &adios::MethodPy::PrintAll )
+    ;
+
+    //Engine
+    py::class_<adios::EnginePy>( m, "Engine")
+        .def("Write", &adios::EnginePy::WritePy )
+        .def("Advance", &adios::EnginePy::WritePy )
+        .def("Close", &adios::EnginePy::Close )
+    ;
+
+
+    return m.ptr();
+}
diff --git a/bindings/python/test_hello.py b/bindings/python/test_hello.py
new file mode 100644
index 0000000000000000000000000000000000000000..a383b573f897d00157f5174c65e58c3f0a227197
--- /dev/null
+++ b/bindings/python/test_hello.py
@@ -0,0 +1,44 @@
+# test_hello.py
+#  Created on: Feb 2, 2017
+#      Author: wfg
+
+from mpi4py import MPI
+from ADIOSPy import *
+import numpy as np
+
+# Create ADIOS and verify MPI Comm is passed correctly
+adios = ADIOSPy( MPI.COMM_WORLD, True ) #Pass communicator and debug flag is True
+rank = MPI.COMM_WORLD.Get_rank()
+size = MPI.COMM_WORLD.Get_size() 
+
+# User data
+myArray = np.array( [1,2,3,4])
+
+if( rank % 2 == 1 ):  # odd ranks only
+    oddRankArray = np.array( [11.,12.,13.,14.] )
+    
+
+# ADIOS Define Variables    
+ioArray = adios.DefineVariable( "ioArray", [myArray.size], [], [] )
+
+if( rank % 2 == 1 ): # odd ranks only
+    ioOddRankArray = adios.DefineVariable( "ioMyFloats", [oddRankArray.size], [], [] )
+    
+
+#Setup method and print summary
+ioSettings = adios.DeclareMethod("adiosSettings")
+ioSettings.SetParameters( profile_units = 'mus' )
+ioSettings.AddTransport( 'File', have_metadata_file = 'no', profile_units = 'mus' )  # POSIX is default, just checking
+
+#Start Engine
+bpFileWriter = adios.Open( "file.bp", "w", ioSettings, None )  # Open files using N-to-N method, None means no new MPI communicator
+bpFileWriter.Write( ioArray, myArray )
+
+if( rank % 2 == 1 ): 
+    bpFileWriter.Write( ioOddRankArray, oddRankArray )
+    
+bpFileWriter.Close( ) 
+
+if( rank == 0 ):
+    print "Done writing " + str( size ) + " bp files"
+    ioSettings.PrintAll( ) # just prints a summary of Method/Transport parameters
diff --git a/buildADIOS1.sh b/buildADIOS1.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7549f24afbbe8281c38545eef997a384671484da
--- /dev/null
+++ b/buildADIOS1.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+
+# buildTest.sh for ADIOS1 Writer example
+# Created on: Mar 27, 2017
+#     Author: pnb
+# Recommended: do a "make clean" the first time 
+
+MPICOMPILER=mpic++
+ADIOS1_DIR=/opt/adios/1.11
+
+if [ "$(uname)" == "Darwin" ]; then
+	CCOMPILER=clang++
+elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
+	CCOMPILER=g++
+fi
+echo "######################################################################################"
+echo "Start building ADIOS ./lib/libadios.a ./libadios_nompi.a" 
+echo "######################################################################################"
+echo
+make -j4 HAVE_ADIOS1=yes ADIOS1_DIR=${ADIOS1_DIR} CC=$CCOMPILER MPICC=$MPICOMPILER       #build the ./lib/libadios.a and ./libadios_nompi.a
+echo
+echo "#################################################################"
+echo "Building ADIOS1Writer example"
+echo "#################################################################"
+make -j4 -C ./examples/hello/adios1Writer CC=$CCOMPILER MPICC=$MPICOMPILER mpi
+#make -j4 -C ./examples/hello/adios1Reader CC=$CCOMPILER MPICC=$MPICOMPILER mpi
+echo
+echo
+echo
+echo "#################################################################"
+echo "Running the MPI example"
+echo "#################################################################"
+echo
+echo
+echo "#################################################################"
+echo "ADIOS1 writer"
+echo "#################################################################"
+mpirun -np 4 ./examples/hello/adios1Writer/helloADIOS1Writer.exe
+echo "DONE...check for myDoubles.bp directory"
+
+echo "#################################################################"
+echo "ADIOS1 reader..not ready yet"
+echo "#################################################################"
+#./examples/hello/adios1Writer/helloADIOS1Reader.exe
+echo
+echo
+echo "#################################################################"
+echo "To run mpi version with 4 mpi processes: "
+echo "mpirun -n 4 ./examples/hello/bpWriter/helloBPWriter.exe"
+echo "mpirun -n 4 ./examples/hello/bpReader/helloBPReader.exe"
+echo "END"
+echo "################################################################"
diff --git a/buildBP.sh b/buildBP.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1da55d54d515cf4f8448e69297e89e79150ea609
--- /dev/null
+++ b/buildBP.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+
+# buildTest.sh for BP Writer example
+# Created on: Feb 9, 2017
+#     Author: wfg
+# Recommended: do a "make clean" the first time 
+
+MPICOMPILER=mpic++
+
+if [ "$(uname)" == "Darwin" ]; then
+	CCOMPILER=clang++
+elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
+	CCOMPILER=g++
+fi
+echo "######################################################################################"
+echo "Start building ADIOS ./lib/libadios.a ./libadios_nompi.a" 
+echo "######################################################################################"
+echo
+make -j4 CC=$CCOMPILER MPICC=$MPICOMPILER       #build the ./lib/libadios.a and ./libadios_nompi.a
+echo
+echo "#################################################################"
+echo "Building BPWriter example"
+echo "#################################################################"
+make -j4 -C ./examples/hello/bpWriter CC=$CCOMPILER MPICC=$MPICOMPILER
+#make -j4 -C ./examples/hello/bpReader CC=$CCOMPILER MPICC=$MPICOMPILER
+echo
+echo
+echo
+echo "#################################################################"
+echo "Running nompi.exe example"
+echo "#################################################################"
+echo
+echo
+echo "#################################################################"
+echo "BP writer"
+echo "#################################################################"
+./examples/hello/bpWriter/helloBPWriter_nompi.exe
+echo "DONE...check for myDoubles_nompi.bp directory"
+
+echo "#################################################################"
+echo "BP reader..not ready yet"
+echo "#################################################################"
+#./examples/hello/bpWriter/helloBPReader.exe
+echo
+echo
+echo "#################################################################"
+echo "To run mpi version with 4 mpi processes: "
+echo "mpirun -n 4 ./examples/hello/bpWriter/helloBPWriter.exe"
+echo "mpirun -n 4 ./examples/hello/bpReader/helloBPReader.exe"
+echo "END"
+echo "################################################################"
diff --git a/buildDataMan.sh b/buildDataMan.sh
new file mode 100755
index 0000000000000000000000000000000000000000..886d96447ab724f8f003605560cedac7b183a7cd
--- /dev/null
+++ b/buildDataMan.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+
+# buildTest.sh for Dataman example
+# Created on: Feb 9, 2017
+#     Author: wfg
+
+DATAMAN_LOCATION=/Users/w4g/Dropbox/lib/DataMan
+MPICOMPILER=mpic++
+
+if [ "$(uname)" == "Darwin" ]; then
+	CCOMPILER=g++
+	export DYLD_LIBRARY_PATH=$DATAMAN_LOCATION/lib:$DYLD_LIBRARY_PATH
+elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
+	CCOMPILER=g++
+	export LD_LIBRARY_PATH=$DATAMAN_LOCATION/lib:$LD_LIBRARY_PATH
+fi
+echo "######################################################################################"
+echo "Start building ADIOS ./lib/libadios.a ./libadios_nompi.a with DataMan library" 
+echo "######################################################################################"
+echo
+make -j4 HAVE_DATAMAN=yes DATAMAN_LOC=$DATAMAN_LOCATION CC=$CCOMPILER MPICC=$MPICOMPILER       #build the ./lib/libadios.a and ./libadios_nompi.a
+echo
+echo "#################################################################"
+echo "Building Dataman Reader and Writer examples"
+echo "#################################################################"
+make -j4 -C ./examples/hello/datamanWriter HAVE_DATAMAN=yes DATAMAN_LOC=$DATAMAN_LOCATION CC=$CCOMPILER MPICC=$MPICOMPILER
+echo
+make -j4 -C ./examples/hello/datamanReader HAVE_DATAMAN=yes DATAMAN_LOC=$DATAMAN_LOCATION CC=$CCOMPILER MPICC=$MPICOMPILER
+
+echo
+echo
+echo "#################################################################"
+echo "Running nompi.exe examples"
+echo "#################################################################"
+echo
+echo
+echo "#################################################################"
+echo "DataMan writer"
+echo "#################################################################"
+./examples/hello/datamanWriter/helloDataManWriter_nompi.exe
+
+echo "#################################################################"
+echo "DataMan reader"
+echo "#################################################################"
+#./examples/hello/datamanReader/helloDataManReader_nompi.exe
+
+echo
+echo
+echo "#################################################################"
+echo "To run mpi version with 4 mpi processes: "
+echo "mpirun -n 4 ./examples/hello/datamanWriter/helloDatamanWriter.exe"
+echo "mpirun -n 4 ./examples/hello/datamanReader/helloDatamanReader.exe"
+echo "END"
+echo "################################################################"
diff --git a/doc/API_design/API_example_use.cpp b/doc/API_design/API_example_use.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57333e03048a8bd6c9839a91e3f53b9c94f29bf7
--- /dev/null
+++ b/doc/API_design/API_example_use.cpp
@@ -0,0 +1,350 @@
+/* Fake example for Current API by design, incorrect as code but describes most of the ideas */
+#include <mpi.h>
+
+#include "ADIOS.h"
+
+
+void cb_AsyncWriteAdvanceCompleted( std::shared_ptr<adios::Engine> writer )
+{
+    std::cout << "AdvanceAsync() completed. We can modify our zero-copy variables\n";
+}
+
+void cb_AsyncReadAdvanceCompleted( std::shared_ptr<adios::Engine> writer )
+{
+    std::cout << "AdvanceAsync() completed. We have new data to read and we have the lock on it\n";
+}
+
+int main( int argc, char* argv[])
+{
+    //Application variables
+    MPI_Comm comm = MPI_COMM_WORLD;
+    const unsigned int NX = 10;
+    double Temperature[1][NX+2]; // We will want to write only Nx elements, skipping the first and last (think ghost cells)
+    std::vector<float> RaggedArray;
+
+    int Nparts, nproc;
+
+    // Global class/object that serves for init, finalize and provides ADIOS functions
+    adios::ADIOS adios( "config.xml", comm, /*verbose=*/adios::INFO, /*debugflag=*/false );
+
+    /*************
+     * WRITE API
+     *************/
+
+    /* Method
+     * We associate Engines and Transports and user settings into an object called Method.
+     * ADIOS checks if it is defined by the user in the config file, and fills it out if it is.
+     */
+
+    adios::Method& wmethod = adios.DeclareMethod( "WriteMethod" );
+    if( ! wmethod.isUserDefined() )
+    {
+        // if not defined by user, we can change the default settings
+        wmethod.SetEngine( "BP" ); // BP is the default engine
+        wmethod.AllowThreads( 1 ); // no threading for data processing (except for staging)
+        wmethod.AddTransport( "File", "lucky=yes" ); // ISO-POSIX file is the default transport
+        wmethod.AddTransport( "Staging" ); //"The" staging method developed in ECP
+        wmethod.SetParameters("have_metadata_file","yes" ); // Passing parameters to the engine
+        wmethod.SetParameters( "Aggregation", (nproc+1)/2 ); // number of aggregators
+        wmethod.SetParameters( "verbose", adios::Verbose::WARN ); // Verbosity level for this engine and what it calls
+    }
+
+
+    //Define variables with transformations.
+    adios::Variable<unsigned int>& varNX = adios.DefineVariable<unsigned int>( "NX" ); // global single-value across processes
+    auto& varNproc   = adios.DefineVariable<int>( "nproc", adios::Dims{adios::GLOBAL_VALUE} ); // same def for global value
+    adios::Variable<int>&    varNparts  = adios.DefineVariable<int>( "Nparts", adios::Dims{adios::LOCAL_VALUE} ); // a single-value different on every process
+    adios::Variable<double>& var2D      = adios.DefineVariable<double>( "Temperature", adios::Dims{nproc,NX} ); // 2D global array, 1D decomposition
+    adios::Variable<float>&  varRagged  = adios.DefineVariable<float>( "Ragged", adios::Dims{nproc,adios::VARYING_DIMENSION} ); // ragged array
+
+
+    //add transform to variable
+    adios::Transform zfp = adios::transform::ZFP();
+    var2D.AddTransform( zfp, "accuracy=0.001" );
+
+    // open...write.write.write...advance...write.write.write...advance... ...close  cycle
+    // "w" create/overwrite on open, "a" append at open, "u" open for update (does not increase step), "r" open for read.
+    std::shared_ptr<adios::Engine> writer = adios.Open( "myNumbers.bp", "w", comm, wmethod, adios::IOMode::INDEPENDENT);
+
+    if( writer == nullptr )
+        throw std::ios_base::failure( "ERROR: failed to open ADIOS writer\n" );
+
+    // Zero-Copy API: Define a variable with local dimensions now, and make ADIOS allocate it inside its buffers
+    // This requires an engine created. The variable will be deallocated in writer->Close()
+    // Calling varZeroCopy.SetSelection() later should throw an exception, i.e. modification is not allowed
+    // 2D global array, 1D decomposition
+    adios::Variable<double>& varZeroCopy = adios.DefineVariable<double>( "ZC", adios::Dims{nproc,NX}, adios::Dims{1,NX}, adios::Dims{rank,0} );
+    double fillValue = -1.0;
+    double * const myVarZC = writer->AllocateVariable<double>( varZeroCopy, fillValue );
+
+
+    for (int step = 0; step < 10; ++step) {
+        // write scalar value
+        writer->Write<int>( varNparts, Nparts );
+
+        // Make a selection to describe the local dimensions of the variable we write and
+        // its offsets in the global spaces. This could have been done in adios.DefineVariable()
+        adios::Selection sel = adios.SelectionBoundingBox( {1,NX}, {rank,NX} ); // local dims and offsets; both as list
+        var2D.SetSelection( sel );   // Shall we call it SetSpaceSelection, SetOutputSelection?
+
+        // Select the area that we want to write from the data pointer we pass to the writer
+        // Think HDF5 memspace, just not hyperslabs yet, only a bounding box selection
+        // Engine will copy this bounding box from the data pointer into the buffer. Size of the bounding box should match the
+        // "space" selection which was given above. Default memspace is the full selection.
+        adios::Selection memspace = adios.SelectionBoundingBox( {1,NX}, {0,1} ); // local dims and offsets; both as list
+        var2D.SetMemorySelection( memspace );
+
+        writer->Write<double>( var2D, *Temperature );
+
+        // Indicate we are done for this step.
+        // N-to-M Aggregation, disk I/O will be performed during this call, unless
+        // time aggregation postpones all of that to some later step.
+        // When Advance() returns, user can overwrite its Zero Copy variables.
+        // Internal buffer is freed only if there are no Zero Copy variables and there is no time aggregation going on
+        writer->Advance(); // same as AppendMode
+        writer->Advance( adios::APPEND, 0.0 ); // append new step at next write
+        writer->Advance( adios::UPDATE ); // do not increase step;
+
+        // When AdvanceAsync returns, user need to wait for notification that he can overwrite the Zero Copy variables.
+        writer->AdvanceAsync( adios::APPEND, cb_AsyncWriteAdvanceCompleted );
+
+    }
+
+    // Called once: indicate that we are done with this output for the run
+    // Zero Copy variables will be deallocated
+    writer->Close();
+
+
+
+    /*************
+     * READ API
+     *************/
+    adios::Method& rmethod = adios.DeclareMethod( "ReadMethod" );
+    if( ! rmethod.isUserDefined() )
+    {
+        // if not defined by user, we can change the default settings
+        rmethod.SetEngine( "BP" ); // BP is the default engine
+        rmethod.AddTransport( "Staging" ); //"The" staging method developed in ECP
+        rmethod.SetParameters( "Aggregation", (nproc+1)/2 ); // number of aggregators
+        rmethod.SetParameters( "verbose", adios::Verbose::WARN ); // Verbosity level for this engine and what it calls
+    }
+
+    // 1. Open a stream, where every reader can see everything in a stream (so that they can read a global array)
+    // Blocking read of a variable
+    try
+    {
+        // These method settings are developer-only, not available to the user
+        rmethod.SetReadMultiplexPattern( adios::GLOBAL_READERS );  // Each reader process sees everything from the stream
+        rmethod.SetStreamOpenMode( adios::WAITFORSTREAM );  // In Open(), wait for the first step appear (default)
+
+        // Open a stream
+        std::shared_ptr<adios::Engine> reader =
+                adios.Open( "filename.bp", "r", comm, rmethod, adios::IOMode::COLLECTIVE,
+                            /*timeout_sec=*/ 300.0); // wait this long for the stream, return error afterwards
+
+        /* Variable names are available as a vector of strings */
+        std::cout << "List of variables in file: " << reader->VariableNames() << "\n";
+        /* read a Global scalar which has a single value in a step */
+        reader->Read<unsigned int>( "NX", NX );
+
+        // inquiry about a variable, whose name we know
+        adios::Variable<double> var2D = reader->InquireVariableDouble( "Temperature" );
+        std::vector<std::size_t> gdims = var2D.GetGlobalDimensions();
+        int nsteps = var2D.GetSteps();
+
+        struct adios::BlockInfo blocks = reader.InquiryVariableBlockInfo( reader, var2D ); // get per-writer size info
+        // this is adios1 ADIOS_VARBLOCK
+        struct adios::Statistics stats = reader.InquiryVariableStat( reader, var2D, perstepstat, perblockstat ); // get min/max statistics
+        // this is adios1 ADIOS_VARSTAT
+
+        while( true )
+        {
+            // Make a selection to describe the local dimensions of the variable we READ and
+            // its offsets in the global spaces
+            adios::Selection bbsel = adios.SelectionBoundingBox( {1,NX}, {0,0} ); // local dims and offsets; both as list
+            var2D.SetSelection( bbsel );
+            adios::Selection memspace = adios.SelectionBoundingBox( {1,NX}, {0,1} ); // local dims and offsets; both as list
+            var2D.SetMemorySelection( memspace );
+            reader->Read<double>(var2D, *Temperature);
+            //var2D, Temperature );
+
+            // Better for staging to schedule several reads at once
+            reader->ScheduleRead<double>( var2D, *Temperature );
+            reader->PerformReads( adios::BLOCKINGREAD );
+
+            // promise to not read more from this step/item
+            reader->Release();
+
+            // want to move on to the next available step/item
+            reader->Advance(adios::NEXT_AVAILABLE);   // default
+            reader->Advance(adios::LATEST_AVAILABLE); // interested only in the latest data
+        }
+        // Close file/stream
+        reader->Close();
+    }
+    catch( adios::end_of_stream& e )
+    {
+        //  Reached end of stream, end processing loop
+        // Close file/stream
+        reader->Close();
+    }
+    catch( adios::file_not_found& e )
+    {
+        // File/stream does not exist, quit
+    }
+
+
+
+    // 2. Open a stream, where each item from the writers will get to a single reader only
+    // If the writers are collective, that means a whole steps go to different readers
+    // If the writers are independent, that means each writer's output goes to different readers
+    // Also show here ScheduleRead/PerformRead
+    //try
+    {
+        rmethod.SetReadMultiplexPattern( adios::FIFO_READERS );  // Each reader process sees everything from the stream
+        rmethod.SetStreamOpenMode( adios::WAITFORSTREAM );  // In Open(), wait for the first step appear (default)
+
+        // Open a stream
+        std::shared_ptr<adios::Engine> reader =
+                adios.Open( "filename.bp", "r", comm, rmethod, adios::IOMode::INDEPENDENT,
+                           /*timeout_sec=*/ 300.0 ); // wait this long for the stream, return error afterwards
+
+        while( true )
+        {
+            // Make a selection to describe the local dimensions of the variable we READ and
+            // its offsets in the global spaces if we know this somehow
+            adios::Selection bbsel = adios.SelectionBoundingBox( {1,NX}, {0,0} ); // local dims and offsets; both as list
+            var2D->SetSelection( bbsel );
+            reader->Read<double>( var2D, *Temperature );
+
+            // Let ADIOS allocate space for the incoming (per-writer) item
+            double * data = reader->Read<double>( var2D );
+
+            // promise to not read more from this step/item
+            reader->Release();
+
+            // want to move on to the next available step/item
+            reader->Advance();   // default
+            reader->Advance(adios::LATEST_AVAILABLE); // This should be an error, or could it make sense?
+        }
+        reader->Close();
+    }
+
+
+    // 3. Open a stream and return immediately, not waiting for data to appear
+    // In this mode we cannot inquiry variables, but can schedule reads
+    //try
+    {
+        rmethod.SetReadMultiplexPattern( adios::GLOBAL_READERS );  // Each reader process sees everything from the stream
+        rmethod.SetStreamOpenMode( adios::NOWAITFORSTREAM );  // In Open(), wait for the first step appear (default)
+
+        // Open a stream
+        std::shared_ptr<adios::Engine> reader =
+                adios.Open( "filename.bp", "r", comm, rmethod, adios::IOMode::INDEPENDENT );
+
+        while( true )
+        {
+
+            // Let ADIOS allocate space for the incoming (per-writer) item
+            reader->ScheduleRead();  // read whatever comes
+
+            // One way is to handle the incoming data through a callback (which will be called in a thread)
+            // void cb( const void *data, std::string doid, std::string var, std::string dtype, std::vector<std::size_t> varshape );
+            // void cb( adios::VARCHUNK * chunk ); // see adios1 for VARCHUNK
+            reader->SetReadCallback( cb );
+            reader->PerformReads( adios::NONBLOCKINGREAD );
+
+            // Another way is checking back manually like in adios1 and processing chunks
+            reader->PerformReads( adios::NONBLOCKINGREAD );
+            int ck;
+            adios::VARCHUNK * chunk;
+            try
+            {
+                while ( (ck = reader->CheckReads( &chunk )) > 0) {
+                    if (chunk) {
+                        // process the chunk first
+                        // ...
+                        // free memory of chunk (not the data!)
+                        adios::FreeChunk(chunk);
+                    } else {
+                        // no chunk was returned, slow down a little
+                        sleep(1);
+                    }
+                }
+            }
+            catch( std::exception& e )
+            {
+                // some error happened while getting a chunk
+            }
+
+            reader->Release();
+
+            // When AdvanceAsync returns new data is not yet available.
+            // A callback will tell us when we have the new data (and we have the lock on it to read)
+            writer->AdvanceAsync( adios::NEXT_AVAILABLE, cb_AsyncReadAdvanceCompleted );
+            // Do we need more fine grained control? Like this function does not get the lock and so
+            // do we need to call Advance() to get the lock?
+        }
+        reader->Close();
+    }
+    // Note: chunk reading also works if scheduling reads for specific variables
+
+
+    // 4. Open it as file and see all steps at once.
+    // Allow for reading multiple steps of a variable into a contiguous array
+    try
+    {
+        rmethod.AddTransport( "BP" ); // Set a file engine here. Shall we have RemoveTransport() too?
+
+        // Open a file with all steps immediately available
+        std::shared_ptr<adios::Engine> reader =
+                adios.OpenFileReader( "filename.bp", comm, rmethod, adios::COLLECTIVE_IO );
+
+        /* NX */
+        /* There is a single value for each step. We can read all into a 1D array with a step selection.
+         * Steps are not automatically presented as an array dimension and read does not read it as array.
+         */
+        // We can also just conveniently get the first step with a simple read statement.
+        reader->Read<unsigned int>( "NX", &NX );  // read a Global scalar which has a single value in a step
+        reader->Read<unsigned int>( varNX, &NX );  // read a Global scalar which has a single value in a step
+
+
+        adios::Variable<void> varNXread = reader->InquireVariable("NX");
+        adios::Variable<unsigned int> varNXreadint = reader->InquireVariableInt("NX");
+        std::vector<unsigned int> Nxs( varNXread.GetSteps() );  // number of steps available
+        // make a StepSelection to select multiple steps. Args: From, #of consecutive steps
+        adios::StepSelection stepsNx( 0, varNXread.GetSteps() );
+        // ? How do we make a selection for an arbitrary list of steps ?
+        varNXread.SetStepSelection( stepsNx );
+        reader->Read<unsigned int>( varNXreadint, Nxs.data());
+        reader->Read<void>( varNXread, Nxs.data());
+
+        auto itmax = std::max_element(std::begin(Nxs), std::end(Nxs));
+        auto itmin = std::min_element(std::begin(Nxs), std::end(Nxs));
+        if (*itmin != *itmax)
+        {
+            throw std::ios_base::failure( "ERROR: NX is not the same at all steps!\n" );
+        }
+
+
+        /* Nparts */
+        // Nparts local scalar is presented as a 1D array of nproc elements.
+        // We can read all steps into a 2D array of nproc * nsteps
+        adios::Variable<void> varNpartsread = reader->InquireVariable("Nparts");
+        std::vector<int> partsV( Nproc * varNpartsread->GetSteps() );
+        varNpartsread->SetStepSelection(
+                                            adios.StepSelection( 0, varNpartsread.GetSteps() )
+                                       );
+        reader->Read<int>( "Nparts", partsV.data() );
+        reader->Read<void>( varNpartsread, partsV.data() ); // missing spatial selection = whole array at each step
+
+        // Close file/stream
+        reader->Close();
+    }
+    catch( adios::file_not_found& e )
+    {
+        // File/stream does not exist, quit
+    }
+
+    return 0;
+}
diff --git a/doc/API_design/Doxyfile b/doc/API_design/Doxyfile
new file mode 100644
index 0000000000000000000000000000000000000000..b5afa02b7cd578da21192d43a7c6fee9c46886de
--- /dev/null
+++ b/doc/API_design/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 = "ADIOS2 API Design"
+
+# 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 = 
+
+# 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 = 
+
+# 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 = English
+
+# 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 = NO
+
+# 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 = NO
+
+# 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 = ../../include ../../include/core
+
+# 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 = ADIOS.h Variable.h Method.h Engine.h 
+
+# 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 = 
+
+# 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 = NO
+
+# 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 = NO
+
+# 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 = NO
+
+# 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 = NO
+
+# 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/doc/CodingGuidelines b/doc/CodingGuidelines
new file mode 100644
index 0000000000000000000000000000000000000000..270bee0db8b57cad89202f2a7ee308ed25b23ddf
--- /dev/null
+++ b/doc/CodingGuidelines
@@ -0,0 +1,167 @@
+CodingGuidelines
+ Created on: Sep 30, 2016 
+     Rev:    0.1
+     Author: William F Godoy, godoywf@ornl.gov
+
+This document introduces coding guidelines that all developers must follow as standard practice.
+This list is open as corrections and new ideas/suggestions come in place. 
+Take them as mandatory to improve ADIOS development and collaboration.
+Many items from this list are taken from Stroustrup, Sutter, and Meyers books.
+       
+
+Objectives:
+
+1) Improve collaboration:
+    1.a. Reduce new code development and integration times for developers and users, by making code easy to understand
+    1.b. Allocate more time for discussion and pathfinding rather than understanding developers' coding
+    1.c. Expand developers and users base
+
+2) Execute new ideas faster
+
+3) Allocate more time to research and publication from new ideas
+
+4) Improve quality of final software product: reduce potential security risks (segmentation faults, core dumps, overflows)
+   and ease the integration of customers' products with ADIOS
+
+
+
+C++ coding guidelines, all mandatory in no particular order:
+
+Text style for readability (Coding format setup in Eclipse with Window > Preferences > C/C++ > CodeStyle > Formatters )
+1) Use meaningful English words (time not t, rank not r or rk), well-known acronyms (MPI, XML, CFD, GMRES, etc.) 
+   or well-known short names (Config, Comm, 2D, 3D).
+   Examples: timeInitial instead of tIni, or work instead of wrk
+   One Exception: when redefining long types with the keyword "using" some mnemonics and short names is allowed, document scope of using
+2) Avoid "_" in names, adds unnecessary length (specially when mixed with STL containers) to the variable name and could conflict with name mangling. 
+   Reserve it for prefix of special cases (see class members and lambda functions).
+   Use upper case letter instead:
+   Don't: std::vector< std::vector<double> > this_is_my_very_very_long_two_dimensional_vector_name
+      Do: std::vector< std::vector<double> > thisIsMyVeryVeryLongTwoDimensionalVectorName
+
+3) Use 4 spaces instead of tab. Tab behaves different in other editors (vi, emacs, gedit, slickedit, code blocks, etc.)
+4) Use 4 spaces for nested logic structure indentation (like in Python), Eclipse has a CTRL+I option to set it automatically.
+   if( number1 < 1 )
+   {
+       if( number2 < 2 )
+       {
+           ....
+       }
+   }
+
+    
+5) Brackets: use an extra space for brackets. Only one line conditionals can skip having brackets.
+    Do: 
+    if( number < 1 )
+    {
+        number = 4;
+        ...
+    } 
+    
+    Don't:
+    if( number < 1 ){
+    number = 4;    .....
+                     .....}
+
+   It's ok to omit brackets in one line conditionals:
+   if( itMap == map.end() ) throw std::invalid_argument( "ERROR: not found in map\n" );
+    
+6) Prefer the keyword "using" over "typedef". Only rename very long complex or custom types, 
+   do not rename standard types (int, double, std::vector) 
+   Don't: typedef std::vector<std::vector< std::map<std::string,double> >> MapIn2DVector;
+   Do:    using std::vector<std::vector< std::map<std::string,double> >> = MapIn2DVector;
+   
+   See 1) for Exception: when redefining long types with the keyword "using" 
+   some mnemonics and short names are allowed, document scope of using (local, class, file, etc.), though
+    
+
+Documentation/Comments
+1) Use Doxygen as the official API documentation tool. 
+   Eclipse has a template autocomplete option for function declarations.
+2) Only use Doxygen function documentation in header declaration (.h) files, 
+   never in source definition (.cpp). Use informative // comments in the latter, see next.
+3) Use meaningful comments that are not redundant in the definition. Add context instead.
+   Example: Don't: int size; // define the size of the MPI processes
+               Do: int size; // global size for tracking purposes at close() 
+
+
+Variable scope and Namespaces
+1) Local scope variables and function arguments passed by value: first letter must be lower case ( int rank, int size ).
+2) Functions: start with an upper case letter ( e.g. void Transform ( ), double Fourier( ), etc.  )
+3) Lambda functions: use hungarian notation with prefix lf_ in the function name. ( e.g. auto lf_Fourier = []( const double argument ) )   
+4) Avoid the "using namespace foo" clause, instead use the namespace explicitly. 
+   (e.g. std::cout not cout, adios::CHDF5 not CHDF5 ) 
+   This prevents name conflict and allows identifying the function/variable source.   
+5) Declare variables right before they are needed, not at the beginning (Fortran style). 
+   e.g. Don't ---> int rank; ...Many Lines of code...  ; rank = SomeFunction( );
+        Do---> ...Many Lines of code...  ; int rank = SomeFunction( );
+6) Always pass by value primitives ( const int, double, const std::string ) if only a copy if needed.
+   The latter allows compiler optimization hints.
+   For bigger objects and STL containers pass by reference always 
+   ( CNETCDF& netcdf, std::vector<std::string>& names ) 
+7) Use auto keyword only when it doesn't interfere with understanding the logic of the code (don't abuse its use). 
+   Don't use it to replace primitives (int, unsigned int, double) or well-known types (std::vector). 
+   Use it for iterators, when the container is well-known and comes from a STL member function.
+   e.g. auto itMap = myMap.find("William");   (we know it is an iterator from find in map)  
+    
+    
+Classes / Structs
+1) Classes will be initialized with an upper case letter, example: ( ADIOS, NETCDF, PHDF5, Transform, Group, etc. )
+2) Class member variables will use hungarian notation "m_" prefix followed an upper case letter: m_XMLConfig, m_GlobalSize. While member functions will have the same rules as regular functions (e.g. start with an upper case letter).
+3) Reserve structs for public member variables only, Structs should not have member functions, inheritance or private members. Structs will be initialized with an upper case letter and member variables won't use hungarian notation as classes.
+   
+   
+4) Only allow one header and one source file per class ( e.g. class Transport in Transport.h and Transport.cpp), do not define several classes in the same file. 
+   Structs are always define in one header file, ( e.g. Attribute in Attribute.h )
+   One EXCEPTION: structs with static member variables, which must be defined in a source (*.cpp) file   
+ 
+ 
+Memory Management: Pointers, Smart Pointers, References and STL Containers
+1) Avoid bare pointers (*p) at all cost for memory management (new/delete). Prefer smart pointers 
+   unique_ptr, shared_ptr. Also, use smart pointers for polymorphism as objects are a dynamic (runtime) concept.
+   ONE Exception: MPI Data_TYPE that require pointers 
+2) Prefer references (&) over pointers in passing by reference or for members of a class. 
+   ONE Exception: Use a bare pointer only if a reference to an object can be nullptr 
+   (NEVER use it for memory management).
+3) Prefer the STL for memory management to minimize new structs/object (new/delete) creation 
+   (e.g. std::vector<double> instead of double* )
+4) Avoid storing bare pointers in STL containers, they must be deallocated manually if so. 
+   The STL is already taking care of object memory management.
+      Do: std::vector<double>
+   Don't: std::vector<double*>   
+5) Use reference and pointer identifiers attached to the type not the variable name, 
+   Do: double* numbers , Don't: double * numbers 
+   Do: std::vector<double>& vector, Don't: std::vector<double> &vector
+6) Use RAII: resource allocation is initialization. 
+   A good design should allocate memory resources at the constructor stage, 
+   or as soon as the required information is available.
+   Fine tuning memory should be used only if it causes a big impact.    
+ 
+ 
+const / constexpr  correctness, macro, and include statements
+1) Always use const or constexpr when it is due as they are optimized and caught at compilation time
+2) Do not use pre-processor macros (#define) unless it's a must (e.g. #ifdef __cplusplus or #pragma )
+3) Use const in functions that don't change the state of an Object or its members
+4) Use const in function arguments (value or references) if the state of the argument is not changed.
+5) Always use include guards in headers (*.h), Eclipse does it automatically at file creation 
+   using the file name. 
+   (e.g. in CADIOS.h start with #ifndef CADIOS_H_ 
+                                #define CADIOS_H_ )
+6) Only include header files at the beginning of the file (#include <cmath>). Make each *.h file self-contained.
+   Don't include the same header file in *.cpp already defined in an included *.h file. 
+   Example: if cmath is included in CADIOS.h, which is included by CADIOS.cpp,
+   then don't include cmath in CADIOS.cpp     
+
+
+Avoid mixing C-like equivalents
+1) Use exclusive C++ header versions of their C-counterpart ( cmath over math.h, cstdlib over stdlib.h ). 
+   Only use C-headers in these cases: 
+   a. If there is no C++ equivalent (e.g. unistd.h )
+   b. When C++ libraries are deprecated or not fully supported ( MPI, CUDA_C, PETSc )
+   c. When interoperability is required with another language, C++ --> C ---> Fortran, or C++ --> C ---> JNI ---> Java  
+2) Do not use C functions if there is a C++ equivalent ( use std::cout instead of printf, new instead of malloc )
+
+
+C++ Exceptions
+1) Throw C++ standard exceptions for error handling, do not throw integers. This is helpful as it allows handling of different exception types in different ways. In rare cases a custom exceptions must be defined/declared.
+2) All error exceptions must be caught at main (program stops) and must start with "ERROR: ". Use informative messages for exception handling to complement the nature of the exception. Help the user fix the error/warning.
+3) Exceptions thrown by the code (no by STL functions) must be inside a debug mode condition set in the ADIOS class constructor.
\ No newline at end of file
diff --git a/doc/Doxyfile b/doc/Doxyfile
new file mode 100644
index 0000000000000000000000000000000000000000..105df52c3bc595de3a2fc89428fa7b1ac4f9ca04
--- /dev/null
+++ b/doc/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 = ADIOS
+
+# 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 = 2.00
+
+# 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 = 
+
+# 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 = 
+
+# 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 = English
+
+# 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 = YES
+
+# 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 = NO
+
+# 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 = NO
+
+# 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 = ../src ../include 
+
+# 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 = 
+
+# 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 = 
+
+# 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 = YES
+
+# 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 = NO
+
+# 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 = NO
+
+# 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 = YES
+
+# 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 = YES
+
+# 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 = YES
+
+# 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 = YES
+
+# 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/examples/globalArray/Makefile b/examples/globalArray/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5548dd15f99182368b8ec594681bbcb237100394
--- /dev/null
+++ b/examples/globalArray/Makefile
@@ -0,0 +1,36 @@
+# Makefile for testing purposes, will build libadios.a 
+# Created on: Oct 31, 2016
+#     Author: pnorbert
+
+
+BASE_NAME=globalArrayXML
+     
+TOOL_DIR=/usr/bin
+
+CC=$(TOOL_DIR)/g++ # Compiling with mpicc for now
+MPICC:=/usr/local/bin/mpic++
+AR=$(TOOL_DIR)/ar
+
+#ADIOS LOCATION
+ADIOS_DIR=../..
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+
+
+#FLAGS
+CFLAGS=-Wall -O0 -g -Wpedantic -std=c++11
+
+all: mpi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $(BASE_NAME).cpp -o $(BASE_NAME)_mpi $(ADIOS_LIB)
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME).cpp -o $(BASE_NAME)_nompi $(ADIOS_NOMPI_LIB)
+
+clean:
+	rm -f *_mpi *_nompi *.o 
+	rm -rf *.dSYM
+     
diff --git a/examples/globalArray/globalArrayNoXML.cpp b/examples/globalArray/globalArrayNoXML.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b90054b0c8dd701fa957c17a35773814bb135342
--- /dev/null
+++ b/examples/globalArray/globalArrayNoXML.cpp
@@ -0,0 +1,113 @@
+/*
+ * globalArrayNoXML.cpp
+ *
+ *  Created on: Oct 31, 2016
+ *      Author: pnorbert
+ */
+
+#include <stdexcept>
+#include <mpi.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "../../include/ADIOS.h"
+
+int main( int argc, char* argv [] )
+{
+    int         rank, size;
+    const int   NX = 10;
+    double      t[NX];
+    std::vector<double> p(NX);
+    MPI_Comm    comm=MPI_COMM_WORLD;
+
+    MPI_Init (&argc, &argv);
+    MPI_Comm_rank (comm, &rank);
+    MPI_Comm_size (comm, &size);
+
+    try
+    {
+        // ADIOS manager object creation. MPI must be initialized
+        adios::ADIOS adios( "globalArrayNoXML.xml", comm, true );
+
+        // set a maximum buffersize that ADIOS can use (for one group).
+        // multiple groups may use each such buffersize if they are overlapped or
+        // use time-aggregation or use zero-copy staging
+
+        // Define Group and its variables
+        // The group's transport can be defined at runtime in the input XML file
+        adios.CreateGroup ("arrays");
+
+        // Set the maximum buffersize for this group. This must happen before
+        // defining a zero copy variable, which will cause the group's internal buffer
+        // allocated (during the variable definition call)
+        //adios.SetMaxBuffersize ("arrays", 10000000);
+
+        adios.CreateVariable ("arrays", "NX", "int"); // scalar variable
+        adios.CreateVariable ("arrays", "size", "int");
+        adios.CreateVariable ("arrays", "size", "rank");
+
+        // define a 2D array with 1D decomposition
+        adios.CreateVariable ("arrays", "temperature", "double", "1,NX", "NONE", "size,NX", "rank,0");
+
+//        // set a variable-level transformation for this variable
+//        adios.SetVariableTransform ("arrays", "temperature", "none");
+
+        adios.CreateVariable ("arrays", "pressure", "std::vector<double>", "1,NX", "size,NX", "rank,0" );
+
+        // set a group-level transport
+        adios.SetTransport ( "arrays", "time-aggregate" ); // no options passed here
+
+        //Get Monitor info
+        std::ofstream logStream( "info_" + std::to_string(rank) + ".log" );
+        adios.MonitorGroups( logStream );
+
+        adios.Open("arrays", "globalArray.bp", "w", 100000000 );
+
+        for (int it = 1; it <= 13; it++)
+        {
+
+            for (int i = 0; i < NX; i++)
+            {
+                t[i] = it*100.0 + rank*NX + i;
+                p[i] = it*1000.0 + rank*NX + i;
+            }
+
+//            if (it==1)
+//
+//            else
+//                adios.Open("arrays", "globalArray.bp", "a", 100000000 );
+
+            //uint64_t    adios_groupsize, adios_totalsize;
+            // adios_groupsize = 4 + 4 + 4 + 2*NX*sizeof(double);
+            // adios_totalsize = adios.GroupSize("arrays", adios_groupsize);
+
+            adios.Write ("arrays", "NX", &NX);
+            adios.Write ("arrays", "size", &size);
+            adios.Write ("arrays", "rank", &rank);
+            adios.Write ("arrays", "temperature", t);
+            adios.Write ("arrays", "pressure", &p);
+
+            MPI_Barrier (comm);
+            if (rank==0) printf("Timestep %d written\n", it);
+        }
+
+        adios.Close ("arrays");
+
+        MPI_Barrier (comm);
+        // need barrier before we destroy the ADIOS object here automatically
+        if (rank==0) printf("Finalize adios\n");
+    }
+    catch( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        if( rank == 0 )
+        {
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    if (rank==0) printf("Finalize MPI\n");
+    MPI_Finalize ();
+    return 0;
+}
diff --git a/examples/globalArray/globalArrayNoXML.xml b/examples/globalArray/globalArrayNoXML.xml
new file mode 100644
index 0000000000000000000000000000000000000000..87cceeab1b8f3e06b107059797a506182f52fe91
--- /dev/null
+++ b/examples/globalArray/globalArrayNoXML.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<adios-config>
+
+  <method group="arrays" method="MPI">ts_buffersize=32000;verbose=4</method>
+  <!--
+  <method group="arrays" method="MPI_AGGREGATE">num_aggregators=1;num_ost=1</method>
+  -->
+
+  <buffer max-size-MB="1"/>
+
+</adios-config>
+
diff --git a/examples/globalArray/globalArrayXML.cpp b/examples/globalArray/globalArrayXML.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..82b9e9e0a666fbf4623c49191eea89924baa9a81
--- /dev/null
+++ b/examples/globalArray/globalArrayXML.cpp
@@ -0,0 +1,90 @@
+/*
+ * globalArrayXML.cpp
+ *
+ *  Created on: Oct 31, 2016
+ *      Author: pnorbert
+ */
+
+#include <stdexcept>
+#include <mpi.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "../../include/ADIOS.h"
+
+int main( int argc, char* argv [] )
+{
+    int         rank, size;
+    const int   NX = 10;
+    double      t[NX];
+    std::vector<double> p(NX);
+    MPI_Comm    comm=MPI_COMM_WORLD;
+
+    MPI_Init (&argc, &argv);
+    MPI_Comm_rank (comm, &rank);
+    MPI_Comm_size (comm, &size);
+
+    try
+    {
+        // ADIOS manager object creation. MPI must be initialized
+        adios::ADIOS adios( "globalArrayXML.xml", comm, true );
+
+        adios::ADIOS_OUTPUT &ckptfile = adios.Open( "globalArray.bp", comm, "a", "POSIX");
+
+        adios::ADIOS_OUTPUT ckptfile( "globalArray.bp", subcomm, "a", "POSIX");
+        //adios::ADIOS_OUTPUT *ckptfile = adios.Open( "globalArray.bp", "POSIX");
+
+        //Get Monitor info
+        std::ofstream logStream( "info_" + std::to_string(rank) + ".log" );
+        adios.MonitorGroups( logStream );
+
+        for (int it = 1; it <= 13; it++)
+        {
+
+            for (int i = 0; i < NX; i++)
+            {
+                t[i] = it*100.0 + rank*NX + i;
+                p[i] = it*1000.0 + rank*NX + i;
+            }
+
+//            if (it==1)
+//                adios.Open("arrays", "globalArray.bp", "w");
+//            else
+//                adios.Open("arrays", "globalArray.bp", "a");
+
+            //uint64_t    adios_groupsize, adios_totalsize;
+            // adios_groupsize = 4 + 4 + 4 + 2*NX*sizeof(double);
+            // adios_totalsize = adios.GroupSize("arrays", adios_groupsize);
+
+            ckptfile.Write ("NX", &NX);
+            ckptfile.Write ("pressure", &p);
+            //adios.Write ("arrays", "NX", &NX);
+            //adios.Write ("arrays", "size", &size);
+            //adios.Write ("arrays", "rank", &rank);
+            //adios.Write ("arrays", "temperature", t);
+            //adios.Write ("arrays", "pressure", &p);
+
+            //adios.Close ("arrays");
+            ckptfile.PerformIO();
+            MPI_Barrier (comm);
+            if (rank==0) printf("Timestep %d written\n", it);
+        }
+        MPI_Barrier (comm);
+        ckptfile.Close();
+        // need barrier before we destroy the ADIOS object here automatically
+        if (rank==0) printf("Finalize adios\n");
+    }
+    catch( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        if( rank == 0 )
+        {
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    if (rank==0) printf("Finalize MPI\n");
+    MPI_Finalize ();
+    return 0;
+}
diff --git a/examples/globalArray/globalArrayXML.xml b/examples/globalArray/globalArrayXML.xml
new file mode 100644
index 0000000000000000000000000000000000000000..315ba12963a9d6bbc4574c85bb769f668d1255ef
--- /dev/null
+++ b/examples/globalArray/globalArrayXML.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<adios-config>
+  <adios-group name="arrays">
+    <var name="NX" type="integer"/>
+    <var name="size" type="integer"/>
+    <var name="rank" type="integer"/>
+
+    <global-bounds dimensions="size,NX" offsets="rank,0">
+       <var name="temperature" gwrite="t" type="double"              dimensions="1,NX"/>
+       <var name="pressure"    gwrite="p" type="std::vector<double>" dimensions="1,NX"/>
+    </global-bounds>
+
+    <attribute name="temperature/description" 
+        value="Global array written from 'size' processes over several timesteps" 
+        type="string"/>
+  </adios-group>
+
+  <method group="arrays" method="MPI">ts_buffersize=32000;verbose=4</method>
+  <!--
+  <method group="arrays" method="MPI_AGGREGATE">num_aggregators=1;num_ost=1</method>
+  -->
+
+  <buffer max-size-MB="1"/>
+
+</adios-config>
+
diff --git a/examples/globalArray/globalArrayZeroCopy.cpp b/examples/globalArray/globalArrayZeroCopy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9a5716591f9508a71e8df1923da3cc8a050f4bb0
--- /dev/null
+++ b/examples/globalArray/globalArrayZeroCopy.cpp
@@ -0,0 +1,121 @@
+/*
+ * globalArrayZeroCopy.cpp
+ *
+ *  Created on: Oct 31, 2016
+ *      Author: pnorbert
+ */
+
+#include <stdexcept>
+#include <mpi.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "../../include/ADIOS.h"
+
+int main( int argc, char* argv [] )
+{
+    int         rank, size;
+    const int   NX = 10;
+    MPI_Comm    comm=MPI_COMM_WORLD;
+
+    MPI_Init (&argc, &argv);
+    MPI_Comm_rank (comm, &rank);
+    MPI_Comm_size (comm, &size);
+
+    try
+    {
+        // ADIOS manager object creation. MPI must be initialized
+        adios::ADIOS adios( "globalArrayNoXML.xml", comm, true );
+
+        // set a maximum buffersize that ADIOS can use (for one group).
+        // multiple groups may use each such buffersize if they are overlapped or
+        // use time-aggregation or use zero-copy staging
+        adios.SetMaxBuffersize (100000000);
+
+        // Define Group and its variables
+        // The group's transport can be defined at runtime in the input XML file
+        adios.CreateGroup ("arrays", adios_stat_default);
+
+        // Set the maximum buffersize for this group. This must happen before
+        // defining a zero copy variable, which will cause the group's internal buffer
+        // allocated (during the variable definition call)
+        adios.SetMaxBuffersize ("arrays", 10000000);
+
+        adios.DefineVariable ("arrays", "NX", "int"); // scalar variable
+        adios.DefineVariable ("arrays", "size", "int");
+        adios.DefineVariable ("arrays", "size", "rank");
+
+        // Define and allocate a 2D array with 1D decomposition and get back a
+        // pre-allocated typed pointer.
+        // The size of the array must be known at this point, so no scalar variables can
+        // be used for its dimensions.
+        std::string ldim = "1," + std::to_string(NX); // == "1,10" if NX==10
+        std::string gdim = std::to_string(size) + "," + std::to_string(NX);
+        std::string offs = std::to_string(rank) + ",0";
+
+        double *t = adios.DefineZeroCopyVariable(
+                "arrays", "temperature", "double",
+                ldim, gdim, offs);
+
+        // set a variable-level transformation for this variable
+        adios.SetVariableTransform ("arrays", "temperature", "none");
+
+        std::vector<double> p = adios.DefineZeroCopyVariable(
+                "arrays", "pressure",    "std::vector<double>",
+                ldim, gdim, offs);
+
+        // set a group-level transformation
+        adios.SetGroupTransform ("arrays", "time-aggregate", ""); // no options passed here
+
+
+
+        //Get Monitor info
+        std::ofstream logStream( "info_" + std::to_string(rank) + ".log" );
+        adios.MonitorGroups( logStream );
+
+        for (int it = 1; it <= 13; it++)
+        {
+
+            for (int i = 0; i < NX; i++)
+            {
+                t[i] = it*100.0 + rank*NX + i;
+                p[i] = it*1000.0 + rank*NX + i;
+            }
+
+            if (it==1)
+                adios.Open("arrays", "globalArray.bp", "w");
+            else
+                adios.Open("arrays", "globalArray.bp", "a");
+
+            //uint64_t    adios_groupsize, adios_totalsize;
+            // adios_groupsize = 4 + 4 + 4 + 2*NX*sizeof(double);
+            // adios_totalsize = adios.GroupSize("arrays", adios_groupsize);
+
+            adios.Write ("arrays", "NX", &NX);
+            adios.Write ("arrays", "size", &size);
+            adios.Write ("arrays", "rank", &rank);
+            adios.Write ("arrays", "temperature", t);
+            adios.Write ("arrays", "pressure", &p);
+
+            adios.Close ("arrays");
+            MPI_Barrier (comm);
+            if (rank==0) printf("Timestep %d written\n", it);
+        }
+        MPI_Barrier (comm);
+        // need barrier before we destroy the ADIOS object here automatically
+        if (rank==0) printf("Finalize adios\n");
+    }
+    catch( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        if( rank == 0 )
+        {
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    if (rank==0) printf("Finalize MPI\n");
+    MPI_Finalize ();
+    return 0;
+}
diff --git a/examples/groupless/basic/Makefile b/examples/groupless/basic/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1fc69407c352f75f74bee1bcdc588ea00463cb4e
--- /dev/null
+++ b/examples/groupless/basic/Makefile
@@ -0,0 +1,26 @@
+# Makefile for testing purposes, will build writer_mpi (make or make mpi) or writer_nompi (make nompi) 
+# Created on: Feb 13, 2017
+#     Author: pnorbert
+
+#COMPILERS
+CC=g++ 
+MPICC=mpic++
+
+#ADIOS LOCATION
+ADIOS_DIR=../../..
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -Woverloaded-virtual -std=c++11 -O0 -g
+LDFLAGS=
+
+all: writer reader 
+
+writer reader: $(ADIOS_LIB) $(ADIOS_HFiles)
+	    $(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $@.cpp -o $@ $(ADIOS_LIB) $(LDFLAGS) -lpthread  \
+	
+clean:
+	rm -f writer reader
+     
diff --git a/examples/groupless/basic/reader.cpp b/examples/groupless/basic/reader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ccbde89114b6344c6fad9a17809e347834ca501e
--- /dev/null
+++ b/examples/groupless/basic/reader.cpp
@@ -0,0 +1,180 @@
+/*
+ * reader.cpp
+ *
+ *  Created on: Feb 13, 2017
+ *      Author: pnorbert
+ */
+
+#include <vector>
+#include <iostream>
+
+#include <mpi.h>
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    int rank, nproc;
+    MPI_Init( &argc, &argv );
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    MPI_Comm_size( MPI_COMM_WORLD, &nproc);
+    const bool adiosDebug = true;
+
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    //Application variable
+    std::vector<double> NiceArray;
+    std::vector<float> RaggedArray;
+    unsigned int Nx;
+    int Nparts;
+    int Nwriters;
+
+    try
+    {
+        //Define method for engine creation
+        // 1. Get method def from config file or define new one
+        adios::Method& bpReaderSettings = adios.GetMethod( "input" );
+        if( bpReaderSettings.undeclared() )
+        {
+            // if not defined by user, we can change the default settings
+            bpReaderSettings.SetEngine( "BP" ); // BP is the default engine
+        }
+
+        //Create engine smart pointer due to polymorphism,
+        // Default behavior
+        // auto bpReader = adios.Open( "myNumbers.bp", "r" );
+        // this would just open with a default transport, which is "BP"
+        auto bpReader = adios.Open( "myNumbers.bp", "r", bpReaderSettings );
+
+        // All the above is same as default use:
+        //auto bpReader = adios.Open( "myNumbers.bp", "r");
+
+        if( bpReader == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to open ADIOS bpReader\n" );
+
+
+        /* Variable names are available as a vector of strings */
+        std::cout << "List of variables in file: " << bpReader->VariableNames << "\n";
+
+        /* NX */
+        bpReader->Read<unsigned int>( "NX", Nx );  // read a Global scalar which has a single value in a step
+
+        /* nproc */
+        bpReader->Read<int>( "nproc", Nwriters );  // also a global scalar
+
+
+        /* Nparts */
+        // Nparts local scalar is presented as a 1D array of Nwriters elements.
+        // We need to read a specific value the same way as reading from any 1D array.
+        // Make a single-value selection to describe our rank's position in the
+        // 1D array of Nwriters values.
+        if( rank < Nwriters )
+        {
+            std::shared_ptr<adios::Variable> varNparts = bpReader.InquiryVariable("Nparts");
+            std::unique_ptr<adios::Selection> selNparts = adios.SelectionBoundingBox( {1}, {rank} );
+            varNparts->SetSelection( selNparts );
+            bpReader->Read<int>( varNparts, Nparts );
+        }
+        // or we could just read the whole array by every process
+        std::vector<int> partsV( Nwriters );
+        bpReader->Read<int>( "Nparts", partsV.data() ); // read with string name, no selection => read whole array
+
+        std::vector<int> partsV;
+        bpReader->Read<int>( "Nparts", partsV); // read with string name, no selection => read whole array
+        (Nwriters == partsV.size())
+
+        /* Nice */
+        // inquiry about a variable, whose name we know
+        std::shared_ptr<adios::Variable> varNice = bpReader.InquiryVariable("Nice");
+
+        if( varNice == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to find variable 'myDoubles' in input file\n" );
+
+        // ? how do we know about the type? std::string varNice->m_Type
+        uint64_t gdim = varNice->m_GlobalDimensions[0];  // ?member var or member func?
+        uint64_t ldim = gdim / nproc;
+        uint64_t offs = rank * ldim;
+        if( rank == nproc-1 )
+        {
+            ldim = gdim - (ldim * gdim);
+        }
+
+        NiceArray.reserve(ldim);
+
+        // Make a 1D selection to describe the local dimensions of the variable we READ and
+        // its offsets in the global spaces
+        std::unique_ptr<adios::Selection> bbsel = adios.SelectionBoundingBox( {ldim}, {offs} ); // local dims and offsets; both as list
+        varNice->SetSelection( bbsel );
+        bpReader->Read<double>( varNice, NiceArray.data() );
+
+
+
+        /* Ragged */
+        // inquiry about a variable, whose name we know
+        std::shared_ptr<adios::Variable<void> > varRagged = bpReader.InquiryVariable("Ragged");
+        if( varRagged->m_GlobalDimensions[1] != adios::VARYING_DIMENSION)
+        {
+            throw std::ios_base::failure( "Unexpected condition: Ragged array's fast dimension "
+                    "is supposed to be VARYING_DIMENSION\n" );
+        }
+        // We have here varRagged->sum_nblocks, nsteps, nblocks[], global
+        if( rank < varRagged->nblocks[0] ) // same as rank < Nwriters in this example
+        {
+            // get per-writer size information
+            varRagged->InquiryBlocks();
+            // now we have the dimensions per block
+
+            unsigned long long int ldim = varRagged->blockinfo[rank].m_Dimensions[1];
+            RaggedArray.resize( ldim );
+
+            std::unique_ptr<adios::Selection> wbsel = adios.SelectionWriteblock( rank );
+            varRagged->SetSelection( wbsel );
+            bpReader->Read<float>( varRagged, RaggedArray.data() );
+
+            // We can use bounding box selection as well
+            std::unique_ptr<adios::Selection> rbbsel = adios.SelectionBoundingBox( {1,ldim}, {rank,0} );
+            varRagged->SetSelection( rbbsel );
+            bpReader->Read<float>( varRagged, RaggedArray.data() );
+        }
+
+        /* Extra help to process Ragged */
+        int maxRaggedDim = varRagged->GetMaxGlobalDimensions(1); // contains the largest
+        std::vector<int> raggedDims = varRagged->GetVaryingGlobalDimensions(1); // contains all individual sizes in that dimension
+
+
+        // Close file/stream
+        bpReader->Close();
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
+
+
+
diff --git a/examples/groupless/basic/writer.cpp b/examples/groupless/basic/writer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc36069850ce7b47997b3f3873edd2057d3db33e
--- /dev/null
+++ b/examples/groupless/basic/writer.cpp
@@ -0,0 +1,145 @@
+/*
+ * writer.cpp
+ *
+ *  Created on: Feb 13, 2017
+ *      Author: pnorbert
+ */
+
+#include <vector>
+#include <iostream>
+
+#include <mpi.h>
+#include "ADIOS_CPP.h"
+
+namespace adios {
+    typedef enum {
+        VARYING_DIMENSION = -1,
+        LOCAL_VALUE = 0,
+        GLOBAL_VALUE = 1
+    };
+}
+
+int main( int argc, char* argv [] )
+{
+    int rank, nproc;
+    MPI_Init( &argc, &argv );
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank);
+    MPI_Comm_size( MPI_COMM_WORLD, &nproc);
+    const bool adiosDebug = true;
+
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    //Application variable
+    const unsigned int Nx = 10;
+    const int Nparts = rand()%6 + 5; // random size per process, 5..10 each
+
+    std::vector<double> NiceArray( Nx );
+    for( int i=0; i < Nx; i++ )
+    {
+        NiceArray[i] = rank*Nx + (double)i;
+    }
+
+    std::vector<float> RaggedArray( Nparts );
+    for( int i=0; i < Nparts; i++ )
+    {
+        RaggedArray[i] = rank*Nx + (float)i;
+    }
+
+
+    try
+    {
+        //Define group and variables with transforms, variables don't have functions, only group can access variables
+        adios::Variable<unsigned int>& varNX = adios.DefineVariable<unsigned int>( "NX" ); // global single-value across processes
+        adios::Variable<int>&    varNproc   = adios.DefineVariable<int>( "nproc", adios::GLOBAL_VALUE ); // same def for global value
+        adios::Variable<int>&    varNparts  = adios.DefineVariable<int>( "Nparts", adios::LOCAL_VALUE ); // a single-value different on every process
+        adios::Variable<double>& varNice    = adios.DefineVariable<double>( "Nice", {nproc*Nx} ); // 1D global array
+        adios::Variable<float>&  varRagged  = adios.DefineVariable<float>( "Ragged", {nproc,adios::VARYING_DIMENSION} ); // ragged array
+
+        //add transform to variable in group...not executed (just testing API)
+        adios::Transform bzip2 = adios::transform::BZIP2( );
+        varNice->AddTransform( bzip2, 1 );
+
+        //Define method for engine creation
+        // 1. Get method def from config file or define new one
+        adios::Method& bpWriterSettings = adios.GetMethod( "output" );
+        if( bpWriterSettings.undeclared() )
+        {
+            // if not defined by user, we can change the default settings
+            bpWriterSettings.SetEngine( "BP" ); // BP is the default engine
+            bpWriterSettings.AddTransport( "File", "lucky=yes" ); // ISO-POSIX file is the default transport
+                                                                  // Passing parameters to the transport
+            bpWriterSettings.SetParameters("have_metadata_file","yes" ); // Passing parameters to the engine
+            bpWriterSettings.SetParameters( "Aggregation", (nproc+1)/2 ); // number of aggregators
+        }
+
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        // "w" means we overwrite any existing file on disk, but AdvanceStep will append steps later.
+        auto bpWriter = adios.Open( "myNumbers.bp", "w", bpWriterSettings );
+
+        if( bpWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to open ADIOS bpWriter\n" );
+
+        if( rank == 0 )
+        {
+            // Writing a global scalar from only one process
+            bpWriter->Write<unsigned int>( varNX, Nx );
+        }
+        // Writing a local scalar on every process. Will be shown at reading as a 1D array
+        bpWriter->Write<int>( varNparts, Nparts );
+
+        // Writing a global scalar on every process is useless. Information will be thrown away
+        // and only rank 0's data will be in the output
+        bpWriter->Write<int>( varNproc, nproc );
+
+        // Make a 1D selection to describe the local dimensions of the variable we write and
+        // its offsets in the global spaces
+        adios::Selection& sel = adios.SelectionBoundingBox( {Nx}, {rank*Nx} ); // local dims and offsets; both as list
+        varNice.SetSelection( sel );
+        bpWriter->Write<double>( varNice, NiceArray.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+
+        adios::Selection& lsel = adios.SelectionBoundingBox( {1,Nparts}, {rank,0} );
+        varRagged.SetSelection( sel );
+        bpWriter->Write<float>( varRagged, RaggedArray.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+
+        // Indicate we are done for this step
+        // N-to-M Aggregation, disk I/O will be performed during this call, unless
+        // time aggregation postpones all of that to some later step
+        bpWriter->Advance( );
+        bpWriter->AdvanceAsync( callback_func_to_notify_me );
+
+        // Called once: indicate that we are done with this output for the run
+        bpWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
+
+
+
diff --git a/examples/groupless/compound/.#writer.cpp b/examples/groupless/compound/.#writer.cpp
new file mode 120000
index 0000000000000000000000000000000000000000..1482a7f96e96d1614f9286b076547b90a97ea279
--- /dev/null
+++ b/examples/groupless/compound/.#writer.cpp
@@ -0,0 +1 @@
+eisen@inferno.cc.gatech.edu.274
\ No newline at end of file
diff --git a/examples/groupless/compound/Makefile b/examples/groupless/compound/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1fc69407c352f75f74bee1bcdc588ea00463cb4e
--- /dev/null
+++ b/examples/groupless/compound/Makefile
@@ -0,0 +1,26 @@
+# Makefile for testing purposes, will build writer_mpi (make or make mpi) or writer_nompi (make nompi) 
+# Created on: Feb 13, 2017
+#     Author: pnorbert
+
+#COMPILERS
+CC=g++ 
+MPICC=mpic++
+
+#ADIOS LOCATION
+ADIOS_DIR=../../..
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -Woverloaded-virtual -std=c++11 -O0 -g
+LDFLAGS=
+
+all: writer reader 
+
+writer reader: $(ADIOS_LIB) $(ADIOS_HFiles)
+	    $(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $@.cpp -o $@ $(ADIOS_LIB) $(LDFLAGS) -lpthread  \
+	
+clean:
+	rm -f writer reader
+     
diff --git a/examples/groupless/compound/reader.cpp b/examples/groupless/compound/reader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..16c78cd7a1238fc23f219b608b4159c9e93cf41e
--- /dev/null
+++ b/examples/groupless/compound/reader.cpp
@@ -0,0 +1,202 @@
+/*
+ * reader.cpp
+ *
+ *  Created on: Feb 21, 2017
+ *      Author: eisen, modified from basic by pnorbert
+ */
+
+#include <vector>
+#include <iostream>
+
+#include <mpi.h>
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    int rank, nproc;
+    MPI_Init( &argc, &argv );
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    MPI_Comm_size( MPI_COMM_WORLD, &nproc);
+    const bool adiosDebug = true;
+
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    //  Application variable
+    //  GSE === user-defined structure
+    //  
+    //  Like HDF5 example, read with a subset of the structure that was written.
+    //  Easily handled by FFS and HDF5, but ambitious for ADIOS
+    typedef struct s2_t {
+	double c;
+	int    a;
+    };
+    unsigned int Nx;
+    int Nparts;
+    int Nwriters;
+
+    try
+    {
+        //Define method for engine creation
+        // 1. Get method def from config file or define new one
+        adios::Method& bpReaderSettings = adios.GetMethod( "input" );
+        if( bpReaderSettings.undeclared() )
+        {
+            // if not defined by user, we can change the default settings
+            bpReaderSettings.SetEngine( "BP" ); // BP is the default engine
+        }
+
+        //Create engine smart pointer due to polymorphism,
+        // Default behavior
+        // auto bpReader = adios.Open( "myNumbers.bp", "r" );
+        // this would just open with a default transport, which is "BP"
+        auto bpReader = adios.Open( "myNumbers.bp", "r", bpReaderSettings );
+
+        // All the above is same as default use:
+        //auto bpReader = adios.Open( "myNumbers.bp", "r");
+
+        if( bpReader == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to open ADIOS bpReader\n" );
+
+
+        /* Variable names are available as a vector of strings */
+        std::cout << "List of variables in file: " << bpReader->VariableNames << "\n";
+
+        /* NX */
+        bpReader->Read<unsigned int>( "NX", Nx );  // read a Global scalar which has a single value in a step
+
+        /* nproc */
+        bpReader->Read<int>( "nproc", Nwriters );  // also a global scalar
+
+
+        /* Nparts */
+        // Nparts local scalar is presented as a 1D array of Nwriters elements.
+        // We need to read a specific value the same way as reading from any 1D array.
+        // Make a single-value selection to describe our rank's position in the
+        // 1D array of Nwriters values.
+        if( rank < Nwriters )
+        {
+            std::shared_ptr<adios::Variable> varNparts = bpReader.InquiryVariable("Nparts");
+            std::unique_ptr<adios::Selection> selNparts = adios.SelectionBoundingBox( {1}, {rank} );
+            varNparts->SetSelection( selNparts );
+            bpReader->Read<int>( varNparts, Nparts );
+        }
+        // or we could just read the whole array by every process
+        std::vector<int> partsV( Nwriters );
+        bpReader->Read<int>( "Nparts", partsV.data() ); // read with string name, no selection => read whole array
+
+        std::vector<int> partsV;
+        bpReader->Read<int>( "Nparts", partsV); // read with string name, no selection => read whole array
+        (Nwriters == partsV.size())
+
+        /* Nice */
+        // inquiry about a variable, whose name we know
+	/* GSE === compound type declaration borrowed heavily from HDF5 style */
+	adios::CompType mtype( sizeof(s2_t) );
+	mtype.insertMember( "c_name", OFFSET(s2_t, c), PredType::NATIVE_DOUBLE);
+	mtype.insertMember( "a_name", OFFSET(s2_t, a), PredType::NATIVE_INT);
+
+	/*  
+	 *   GSE === this is a bit conceptually different.  There was no real
+	 *   check in the prior API that the variable in the file was in any way
+	 *   "compatible" with how we planned to read it.  This could be done
+	 *   here, by providing the details of the structure that we are
+	 *   prepared to read in the inquiryVariable, or if we had an API that
+	 *   allowed more introspection, we could perhaps support a query on the
+	 *   adios::Variable and a later operation that informed it of the data
+	 *   type that we were prepared to extract from it.
+	 */
+        std::shared_ptr<adios::Variable> varNice = bpReader.InquiryVariable("Nice", mtype);
+
+        if( varNice == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to find variable 'myDoubles' in input file\n" );
+
+        // ? how do we know about the type? std::string varNice->m_Type
+        uint64_t gdim = varNice->m_GlobalDimensions[0];  // ?member var or member func?
+        uint64_t ldim = gdim / nproc;
+        uint64_t offs = rank * ldim;
+        if( rank == nproc-1 )
+        {
+            ldim = gdim - (ldim * gdim);
+        }
+
+        NiceArray.reserve(ldim);
+
+        // Make a 1D selection to describe the local dimensions of the variable we READ and
+        // its offsets in the global spaces
+        std::unique_ptr<adios::Selection> bbsel = adios.SelectionBoundingBox( {ldim}, {offs} ); // local dims and offsets; both as list
+        varNice->SetSelection( bbsel );
+	// GSE ===   Again, templated here?
+        bpReader->Read<s2_t>( varNice, NiceArray.data() );
+
+
+
+        /* Ragged */
+        // inquiry about a variable, whose name we know
+        std::shared_ptr<adios::Variable<void> > varRagged = bpReader.InquiryVariable("Ragged");
+        if( varRagged->m_GlobalDimensions[1] != adios::VARYING_DIMENSION)
+        {
+            throw std::ios_base::failure( "Unexpected condition: Ragged array's fast dimension "
+                    "is supposed to be VARYING_DIMENSION\n" );
+        }
+        // We have here varRagged->sum_nblocks, nsteps, nblocks[], global
+        if( rank < varRagged->nblocks[0] ) // same as rank < Nwriters in this example
+        {
+            // get per-writer size information
+            varRagged->InquiryBlocks();
+            // now we have the dimensions per block
+
+            unsigned long long int ldim = varRagged->blockinfo[rank].m_Dimensions[1];
+            RaggedArray.resize( ldim );
+
+            std::unique_ptr<adios::Selection> wbsel = adios.SelectionWriteblock( rank );
+            varRagged->SetSelection( wbsel );
+            bpReader->Read<float>( varRagged, RaggedArray.data() );
+
+            // We can use bounding box selection as well
+            std::unique_ptr<adios::Selection> rbbsel = adios.SelectionBoundingBox( {1,ldim}, {rank,0} );
+            varRagged->SetSelection( rbbsel );
+            bpReader->Read<float>( varRagged, RaggedArray.data() );
+        }
+
+        /* Extra help to process Ragged */
+        int maxRaggedDim = varRagged->GetMaxGlobalDimensions(1); // contains the largest
+        std::vector<int> raggedDims = varRagged->GetVaryingGlobalDimensions(1); // contains all individual sizes in that dimension
+
+
+        // Close file/stream
+        bpReader->Close();
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
+
+
+
diff --git a/examples/groupless/compound/writer.cpp b/examples/groupless/compound/writer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e5d7e7307855fd0cacde452bfadc03a28aefd32a
--- /dev/null
+++ b/examples/groupless/compound/writer.cpp
@@ -0,0 +1,153 @@
+/*
+ * writer.cpp
+ *
+ *  Created on: Feb 13, 2017
+ *      Author: pnorbert
+ */
+
+#include <vector>
+#include <iostream>
+
+#include <mpi.h>
+#include "ADIOS_CPP.h"
+
+namespace adios {
+    typedef enum {
+        VARYING_DIMENSION = -1,
+        LOCAL_VALUE = 0,
+        GLOBAL_VALUE = 1
+    };
+}
+
+int main( int argc, char* argv [] )
+{
+    int rank, nproc;
+    MPI_Init( &argc, &argv );
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank);
+    MPI_Comm_size( MPI_COMM_WORLD, &nproc);
+    const bool adiosDebug = true;
+
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    //Application variable
+    const unsigned int Nx = 10;
+    //  GSE === user-defined structure
+    typedef struct s1_t {
+	int    a;
+	float  b;
+	double c;
+    };
+    const int Nparts = rand()%6 + 5; // random size per process, 5..10 each
+
+    std::vector<s1_t> NiceArray( Nx );
+    for( int i=0; i < Nx; i++ )
+    {
+	NiceArray.push_back(ss1_t());
+        NiceArray[i].a = rank*Nx + (double)i;
+        NiceArray[i].b = 100.0*rank*Nx + 100.0*(double)i;
+        NiceArray[i].c = 10000.0*rank*Nx + 10000.0*(double)i;
+    }
+
+
+    try
+    {
+	/* GSE === compound type declaration borrowed heavily from HDF5 style */
+	adios::CompType mtype( sizeof(s1_t) );
+	mtype.insertMember( "a_name", OFFSET(s1_t, a), PredType::NATIVE_INT);
+	mtype.insertMember( "c_name", OFFSET(s1_t, c), PredType::NATIVE_DOUBLE);
+	mtype.insertMember( "b_name", OFFSET(s1_t, b), PredType::NATIVE_FLOAT);
+
+        //Define group and variables with transforms, variables don't have functions, only group can access variables
+        adios::Variable<unsigned int>& varNX = adios.DefineVariable<unsigned int>( "NX" ); // global single-value across processes
+        adios::Variable<int>&    varNproc   = adios.DefineVariable<int>( "nproc", adios::GLOBAL_VALUE ); // same def for global value
+        adios::Variable<int>&    varNparts  = adios.DefineVariable<int>( "Nparts", adios::LOCAL_VALUE ); // a single-value different on every process
+
+	// GSE === template necessary or useful here? Extra argument for previously-built compound type information */
+        adios::Variable<s1_t>& varNice    = adios.DefineVariable<s1_t>( "Nice", {nproc*Nx}, mtype ); // 1D global array
+
+        //add transform to variable in group...not executed (just testing API)
+        adios::Transform bzip2 = adios::transform::BZIP2( );
+        varNice->AddTransform( bzip2, 1 );
+
+        //Define method for engine creation
+        // 1. Get method def from config file or define new one
+        adios::Method& bpWriterSettings = adios.GetMethod( "output" );
+        if( bpWriterSettings.undeclared() )
+        {
+            // if not defined by user, we can change the default settings
+            bpWriterSettings.SetEngine( "BP" ); // BP is the default engine
+            bpWriterSettings.AddTransport( "File", "lucky=yes" ); // ISO-POSIX file is the default transport
+                                                                  // Passing parameters to the transport
+            bpWriterSettings.SetParameters("have_metadata_file","yes" ); // Passing parameters to the engine
+            bpWriterSettings.SetParameters( "Aggregation", (nproc+1)/2 ); // number of aggregators
+        }
+
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        // "w" means we overwrite any existing file on disk, but AdvanceStep will append steps later.
+        auto bpWriter = adios.Open( "myNumbers.bp", "w", bpWriterSettings );
+
+        if( bpWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to open ADIOS bpWriter\n" );
+
+        if( rank == 0 )
+        {
+            // Writing a global scalar from only one process
+            bpWriter->Write<unsigned int>( varNX, Nx );
+        }
+        // Writing a local scalar on every process. Will be shown at reading as a 1D array
+        bpWriter->Write<int>( varNparts, Nparts );
+
+        // Writing a global scalar on every process is useless. Information will be thrown away
+        // and only rank 0's data will be in the output
+        bpWriter->Write<int>( varNproc, nproc );
+
+        // Make a 1D selection to describe the local dimensions of the variable we write and
+        // its offsets in the global spaces
+        adios::Selection& sel = adios.SelectionBoundingBox( {Nx}, {rank*Nx} ); // local dims and offsets; both as list
+        varNice.SetSelection( sel );
+
+	// GSE === Template useful or necessary here?   We have to treat this as a void* inside ADIOS...
+        bpWriter->Write<sl_t>( varNice, NiceArray.data() ); 
+
+        // Indicate we are done for this step
+        // N-to-M Aggregation, disk I/O will be performed during this call, unless
+        // time aggregation postpones all of that to some later step
+        bpWriter->Advance( );
+        bpWriter->AdvanceAsync( callback_func_to_notify_me );
+
+        // Called once: indicate that we are done with this output for the run
+        bpWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
+
+
+
diff --git a/examples/groupless/multistep/Makefile b/examples/groupless/multistep/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1498091ae7097fdb382fd07a35bcd46d996700ef
--- /dev/null
+++ b/examples/groupless/multistep/Makefile
@@ -0,0 +1,26 @@
+# Makefile for testing purposes, will build writer_mpi (make or make mpi) or writer_nompi (make nompi) 
+# Created on: Feb 13, 2017
+#     Author: pnorbert
+
+#COMPILERS
+CC=g++ 
+MPICC=mpic++
+
+#ADIOS LOCATION
+ADIOS_DIR=../../..
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -Woverloaded-virtual -std=c++11 -O0 -g
+LDFLAGS=
+
+all: writer_multistep reader_allsteps reader_stepping
+
+writer_multistep reader_allsteps reader_stepping: $(ADIOS_LIB) $(ADIOS_HFiles)
+	    $(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $@.cpp -o $@ $(ADIOS_LIB) $(LDFLAGS) -lpthread  \
+	
+clean:
+	rm -f writer_multistep reader_allsteps reader_stepping
+     
diff --git a/examples/groupless/multistep/reader_allsteps.cpp b/examples/groupless/multistep/reader_allsteps.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..46415c1bba62028d7773b0a54f8c28a3d7d562c2
--- /dev/null
+++ b/examples/groupless/multistep/reader_allsteps.cpp
@@ -0,0 +1,198 @@
+/*
+ * reader.cpp
+ *
+ *  Created on: Feb 13, 2017
+ *      Author: pnorbert
+ */
+
+#include <vector>
+#include <iostream>
+
+#include <mpi.h>
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    int rank, nproc;
+    MPI_Init( &argc, &argv );
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    MPI_Comm_size( MPI_COMM_WORLD, &nproc);
+    const bool adiosDebug = true;
+
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    //Application variable
+    std::vector<double> NiceArray;
+    std::vector<float> RaggedArray;
+
+    int Nparts;
+    int Nwriters;
+    int Nsteps;
+
+    try
+    {
+        //Define method for engine creation
+        // 1. Get method def from config file or define new one
+        adios::Method& bpReaderSettings = adios.GetMethod( "input" );
+        if( bpReaderSettings.undeclared() )
+        {
+            // if not defined by user, we can change the default settings
+            bpReaderSettings.SetEngine( "BP" ); // BP is the default engine
+            // By default we see all steps available in a file, so the next line is not needed
+            bpReaderSettings.SetParameters ("Stepping", false);
+        }
+
+        //Create engine smart pointer due to polymorphism,
+        // Default behavior
+        // auto bpReader = adios.Open( "myNumbers.bp", "r" );
+        // this would just open with a default transport, which is "BP"
+        auto bpReader = adios.Open( "myNumbers.bp", "r", bpReaderSettings );
+
+        // All the above is same as default use:
+        //auto bpReader = adios.Open( "myNumbers.bp", "r");
+
+        if( bpReader == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to open ADIOS bpReader\n" );
+
+
+        /* Note: there is no global number of steps. Each variable has its own number of steps */
+
+        /* NX */
+        /* There is a single value for each step. We can read all into a 1D array with a step selection.
+         * We can also just conveniently get the first with a simple read statement.
+         * Steps are not automatically presented as an array dimension and read does not read it as array.
+         */
+        unsigned int Nx;
+        bpReader->Read<unsigned int>( "NX", &Nx );  // read a Global scalar which has a single value in a step
+
+        std::shared_ptr<adios::Variable<void> > varNx = bpReader.InquiryVariable("Nx");
+        std::vector<int> Nxs( varNx->nsteps() );  // number of steps available
+        // make a StepSelection to select multiple steps. Args: From, #of consecutive steps
+        std::unique_ptr<adios::StepSelection> stepsNx = adios.StepSelection( 0, varNx->nsteps() );
+        // ? How do we make a selection for an arbitrary list of steps ?
+        varNX.SetStepSelection( stepsNx );
+        bpReader->Read<unsigned int>( varNx, Nxs.data() );
+
+        auto itmax = std::max_element(std::begin(Nxs), std::end(Nxs));
+        auto itmin = std::min_element(std::begin(Nxs), std::end(Nxs));
+        if (*itmin != *itmax)
+        {
+            throw std::ios_base::failure( "ERROR: NX is not the same at all steps!\n" );
+        }
+
+
+        /* nproc */
+        bpReader->Read<int>( "nproc", &Nwriters );  // also a global scalar
+
+
+
+        /* Nparts */
+        // Nparts local scalar is presented as a 1D array of Nwriters elements.
+        // We can read all steps into a 2D array of nproc * Nwriters
+        std::shared_ptr<adios::Variable<void> > varNparts = bpReader.InquiryVariable("Nparts");
+        std::vector<int> partsV( Nproc*Nwriters );
+        varNparts->SetStepSelection(
+                                    adios.StepSelection( 0, varNparts->nsteps() )
+                                   );
+        bpReader->Read<int>( varNparts, partsV.data() ); // missing spatial selection = whole array at each step
+
+
+
+
+        /* Nice */
+        // inquiry about a variable, whose name we know
+        std::shared_ptr<adios::Variable<void> > varNice = bpReader.InquiryVariable("Nice");
+
+        if( varNice == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to find variable 'myDoubles' in input file\n" );
+
+        // ? how do we know about the type? std::string varNice->m_Type
+        unsigned long long int gdim = varMyDoubles->m_GlobalDimensions[0];  // ?member var or member func?
+        unsigned long long int ldim = gdim / nproc;
+        unsigned long long int offs = rank * ldim;
+        if( rank == nproc-1 )
+        {
+            ldim = gdim - (ldim * gdim);
+        }
+
+        NiceArray.reserve(ldim);
+
+        // Make a 1D selection to describe the local dimensions of the variable we READ and
+        // its offsets in the global spaces
+        std::unique_ptr<adios::Selection> bbsel = adios.SelectionBoundingBox( {ldim}, {offs} ); // local dims and offsets; both as list
+        bpReader->Read<double>( "Nice", bbsel, NiceArray.data() ); // Base class Engine own the Read<T> that will call overloaded Read from Derived
+
+
+
+        /* Ragged */
+        // inquiry about a variable, whose name we know
+        std::shared_ptr<adios::Variable<void> > varRagged = bpReader.InquiryVariable("Ragged");
+        if( varRagged->m_GlobalDimensions[1] != adios::VARYING_DIMENSION)
+        {
+            throw std::ios_base::failure( "Unexpected condition: Ragged array's fast dimension "
+                    "is supposed to be VARYING_DIMENSION\n" );
+        }
+        // We have here varRagged->sum_nblocks, nsteps, nblocks[], global
+        if( rank < varRagged->nblocks[0] ) // same as rank < Nwriters in this example
+        {
+            // get per-writer size information
+            varRagged->InquiryBlocks();
+            // now we have the dimensions per block
+
+            unsigned long long int ldim = varRagged->blockinfo[rank].m_Dimensions[0];
+            RaggedArray.resize( ldim );
+
+            std::unique_ptr<adios::Selection> wbsel = adios.SelectionWriteblock( rank );
+            bpReader->Read<float>( "Ragged", wbsel, RaggedArray.data() );
+
+            // We can use bounding box selection as well
+            std::unique_ptr<adios::Selection> rbbsel = adios.SelectionBoundingBox( {1,ldim}, {rank,0} );
+            bpReader->Read<float>( "Ragged", rbbsel, RaggedArray.data() );
+        }
+
+        /* Extra help to process Ragged */
+        int maxRaggedDim = varRagged->GetMaxGlobalDimensions(1); // contains the largest
+        std::vector<int> raggedDims = varRagged->GetVaryingGlobalDimensions(1); // contains all individual sizes in that dimension
+
+
+
+
+
+        // Close file/stream
+        bpReader->Close();
+
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
+
+
+
diff --git a/examples/groupless/multistep/reader_stepping.cpp b/examples/groupless/multistep/reader_stepping.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3bf7022e9e0c3b2ea136a6c7280ce956d57595e2
--- /dev/null
+++ b/examples/groupless/multistep/reader_stepping.cpp
@@ -0,0 +1,191 @@
+/*
+ * reader.cpp
+ *
+ *  Created on: Feb 13, 2017
+ *      Author: pnorbert
+ */
+
+#include <vector>
+#include <iostream>
+
+#include <mpi.h>
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    int rank, nproc;
+    MPI_Init( &argc, &argv );
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    MPI_Comm_size( MPI_COMM_WORLD, &nproc);
+    const bool adiosDebug = true;
+
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    //Application variable
+    std::vector<double> NiceArray;
+    std::vector<float> RaggedArray;
+    unsigned int Nx;
+    int Nparts;
+    int Nwriters;
+    int Nsteps;
+
+    try
+    {
+        //Define method for engine creation
+        // 1. Get method def from config file or define new one
+        adios::Method& bpReaderSettings = adios.GetMethod( "input" );
+        if( bpReaderSettings.undeclared() )
+        {
+            // if not defined by user, we can change the default settings
+            bpReaderSettings.SetEngine( "BP" ); // BP is the default engine
+            bpReaderSettings.SetParameters ("Stepping", true); // see only one step at a time
+        }
+
+        //Create engine smart pointer due to polymorphism,
+        // Default behavior
+        // auto bpReader = adios.Open( "myNumbers.bp", "r" );
+        // this would just open with a default transport, which is "BP"
+        try
+        {
+            auto bpReader = adios.Open( "myNumbers.bp", "r", bpReaderSettings );
+
+            while (true)
+            {
+                /* NX */
+                bpReader->Read<unsigned int>( "NX", &Nx );  // read a Global scalar which has a single value in a step
+
+                /* nproc */
+                bpReader->Read<int>( "nproc", &Nwriters );  // also a global scalar
+
+
+                /* Nparts */
+                // Nparts local scalar is presented as a 1D array of Nwriters elements.
+                // We can read all as a 1D array
+                std::vector<int> partsV( Nwriters );
+                bpReader->Read<int>( "Nparts", &partsV ); // read with string name, no selection => read whole array
+
+
+                /* Nice */
+                // inquiry about a variable, whose name we know
+                std::shared_ptr<adios::Variable<void> > varNice = bpReader.InquiryVariable("Nice");
+
+                if( varNice == nullptr )
+                    throw std::ios_base::failure( "ERROR: failed to find variable 'myDoubles' in input file\n" );
+
+                // ? how do we know about the type? std::string varNice->m_Type
+                unsigned long long int gdim = varMyDoubles->m_GlobalDimensions[0];  // ?member var or member func?
+                unsigned long long int ldim = gdim / nproc;
+                unsigned long long int offs = rank * ldim;
+                if( rank == nproc-1 )
+                {
+                    ldim = gdim - (ldim * gdim);
+                }
+
+                NiceArray.reserve(ldim);
+
+                // Make a 1D selection to describe the local dimensions of the variable we READ and
+                // its offsets in the global spaces
+                std::unique_ptr<adios::Selection> bbsel = adios.SelectionBoundingBox( {ldim}, {offs} ); // local dims and offsets; both as list
+                varNice->SetSelection( bbsel );
+                bpReader->Read<double>( varNice, NiceArray.data() );
+
+
+                /* Ragged */
+                // inquiry about a variable, whose name we know
+                std::shared_ptr<adios::Variable<void> > varRagged = bpReader.InquiryVariable("Ragged");
+                if( varRagged->m_GlobalDimensions[1] != adios::VARYING_DIMENSION)
+                {
+                    throw std::ios_base::failure( "Unexpected condition: Ragged array's fast dimension "
+                            "is supposed to be VARYING_DIMENSION\n" );
+                }
+                // We have here varRagged->sum_nblocks, nsteps, nblocks[], global
+                if( rank < varRagged->nblocks[0] ) // same as rank < Nwriters in this example
+                {
+                    // get per-writer size information
+                    varRagged->InquiryBlocks();
+                    // now we have the dimensions per block
+
+                    unsigned long long int ldim = varRagged->blockinfo[rank].m_Dimensions[0];
+                    RaggedArray.resize( ldim );
+
+                    std::unique_ptr<adios::Selection> wbsel = adios.SelectionWriteblock( rank );
+                    varRagged->SetSelection( wbsel );
+                    bpReader->Read<float>( varRagged, RaggedArray.data() );
+
+                    // We can use bounding box selection as well
+                    std::unique_ptr<adios::Selection> rbbsel = adios.SelectionBoundingBox( {1,ldim}, {rank,0} );
+                    varRagged->SetSelection( rbbsel );
+                    bpReader->Read<float>( varRagged, RaggedArray.data() );
+                }
+
+                /* Extra help to process Ragged */
+                int maxRaggedDim = varRagged->GetMaxGlobalDimensions(1); // contains the largest
+                std::vector<int> raggedDims = varRagged->GetVaryingGlobalDimensions(1); // contains all individual sizes in that dimension
+
+
+
+                // promise to not read more from this step
+                bpReader->Release();
+
+                // want to move on to the next available step
+                //bpReader->Advance(adios::NextStep);
+                //bpReader->Advance(adios::LatestStep);
+                bpReader->Advance(); // default is adios::NextStep
+
+            }
+
+            // Close file/stream
+            bpReader->Close();
+
+        }
+        catch( adios::end_of_stream& e )
+        {
+            if( rank == 0 )
+            {
+                std::cout << "Reached end of stream, end processing loop.\n";
+            }
+            // Close file/stream
+            bpReader->Close();
+        }
+        catch( adios::file_not_found& e )
+        {
+            if( rank == 0 )
+            {
+                std::cout << "File/stream does not exist, quit.\n";
+            }
+        }
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
+
+
+
diff --git a/examples/groupless/multistep/writer_multistep.cpp b/examples/groupless/multistep/writer_multistep.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..89eba61d40152d2f3cd088373fcab5472792506e
--- /dev/null
+++ b/examples/groupless/multistep/writer_multistep.cpp
@@ -0,0 +1,150 @@
+/*
+ * writer.cpp
+ *
+ *  Created on: Feb 13, 2017
+ *      Author: pnorbert
+ */
+
+#include <vector>
+#include <iostream>
+
+#include <mpi.h>
+#include "ADIOS_CPP.h"
+
+namespace adios {
+    typedef enum {
+        VARYING_DIMENSION = -1,
+        LOCAL_VALUE = 0,
+        GLOBAL_VALUE = 1
+    };
+}
+
+int main( int argc, char* argv [] )
+{
+    int rank, nproc;
+    MPI_Init( &argc, &argv );
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank);
+    MPI_Comm_size( MPI_COMM_WORLD, &nproc);
+    const bool adiosDebug = true;
+    const int NSTEPS = 5;
+
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    //Application variable
+    const unsigned int Nx = 10;
+    int Nparts; // random size per process, 5..10 each
+
+    std::vector<double> NiceArray( Nx );
+    for( int i=0; i < Nx; i++ )
+    {
+        NiceArray[i] = rank*Nx + (double)i;
+    }
+
+    std::vector<float> RaggedArray;
+
+    try
+    {
+        //Define group and variables with transforms, variables don't have functions, only group can access variables
+        adios::Variable<unsigned int>& varNX = adios.DefineVariable<unsigned int>( "NX" ); // global single-value across processes
+        adios::Variable<int>&    varNproc   = adios.DefineVariable<int>( "nproc", adios::GLOBAL_VALUE ); // same def for global value
+        adios::Variable<int>&    varNparts  = adios.DefineVariable<int>( "Nparts", adios::LOCAL_VALUE ); // a single-value different on every process
+        adios::Variable<double>& varNice    = adios.DefineVariable<double>( "Nice", {nproc*Nx} ); // 1D global array
+        adios::Variable<float>&  varRagged  = adios.DefineVariable<float>( "Ragged", {nproc,adios::VARYING_DIMENSION} ); // ragged array
+
+        //add transform to variable in group...not executed (just testing API)
+        adios::Transform bzip2 = adios::transform::BZIP2( );
+        varNice->AddTransform( bzip2, 1 );
+
+        //Define method for engine creation
+        // 1. Get method def from config file or define new one
+        adios::Method& bpWriterSettings = adios.GetMethod( "output" );
+        if( bpWriterSettings.undeclared() )
+        {
+            // if not defined by user, we can change the default settings
+            bpWriterSettings.SetEngine( "BP" ); // BP is the default engine
+            bpWriterSettings.AddTransport( "File", "lucky=yes" ); // ISO-POSIX file is the default transport
+                                                                  // Passing parameters to the transport
+            bpWriterSettings.SetParameters("have_metadata_file","yes" ); // Passing parameters to the engine
+            bpWriterSettings.SetParameters( "Aggregation", (nproc+1)/2 ); // number of aggregators
+        }
+
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        // "w" means we overwrite any existing file on disk, but AdvanceStep will append steps later.
+        auto bpWriter = adios.Open( "myNumbers.bp", "w", bpWriterSettings );
+
+        if( bpWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to open ADIOS bpWriter\n" );
+
+        for ( int step; step < NSTEPS; step++ )
+        {
+            int Nparts = rand()%6 + 5; // random size per process, 5..10 each
+            RaggedArray.reserve(Nparts);
+            for( int i=0; i < Nparts; i++ )
+            {
+                RaggedArray[i] = rank*Nx + (float)i;
+            }
+
+            if( rank == 0 )
+            {
+                // Writing a global scalar from only one process
+                bpWriter->Write<unsigned int>( varNX, &Nx );
+            }
+            // Writing a local scalar on every process. Will be shown at reading as a 1D array
+            bpWriter->Write<int>( varNparts, &Nparts );
+
+            // Writing a global scalar on every process is useless. Information will be thrown away
+            // and only rank 0's data will be in the output
+            bpWriter->Write<int>( varNproc, &nproc );
+
+            // Make a 1D selection to describe the local dimensions of the variable we write and
+            // its offsets in the global spaces
+            adios::Selection& sel = adios.SelectionBoundingBox( {Nx}, {rank*Nx} ); // local dims and offsets; both as list
+            NiceArray.SetSelection( sel );
+            bpWriter->Write<double>( varNice, NiceArray.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+
+            adios::Selection& lsel = adios.SelectionBoundingBox( {1,Nparts}, {rank,0} );
+            RaggedArray.SetSelection( sel );
+            bpWriter->Write<float>( varRagged, RaggedArray.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+
+            // Indicate we are done for this step
+            // N-to-M Aggregation, disk I/O will be performed during this call, unless
+            // time aggregation postpones all of that to some later step
+            bpWriter->Advance( );
+        }
+
+        // Called once: indicate that we are done with this output for the run
+        bpWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
+
+
+
diff --git a/examples/heatTransfer/HeatTransfer.cpp b/examples/heatTransfer/HeatTransfer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd6d84f6c0a4b77449f34587238a19859dd3d960
--- /dev/null
+++ b/examples/heatTransfer/HeatTransfer.cpp
@@ -0,0 +1,238 @@
+/*
+ * heatTransfer.cpp
+ *
+ * Recreates heat_transfer.f90 (Fortran) in C++
+ *
+ * Created on: Feb 2017
+ *     Author: Norbert Podhorszki
+ *
+ */
+#include <mpi.h>
+
+#include <stdexcept>
+#include <memory>
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <math.h>
+
+
+#include "HeatTransfer.h"
+
+
+HeatTransfer::HeatTransfer( const Settings& settings )
+: m_s{settings}
+{
+    m_T1 = new double*[ m_s.ndx+2 ];
+    m_T1[0] = new double[ (m_s.ndx+2) * (m_s.ndy+2) ];
+    m_T2 = new double*[ m_s.ndx+2 ];
+    m_T2[0] = new double[ (m_s.ndx+2) * (m_s.ndy+2) ];
+    for (unsigned int i = 1; i < m_s.ndx+2; i++)
+    {
+        m_T1[i] = m_T1[i-1] + m_s.ndy+2;
+        m_T2[i] = m_T2[i-1] + m_s.ndy+2;
+    }
+    m_TCurrent = m_T1;
+    m_TNext = m_T2;
+}
+
+HeatTransfer::~HeatTransfer()
+{
+    delete[] m_T1[0];
+    delete[] m_T1;
+    delete[] m_T2[0];
+    delete[] m_T2;
+}
+
+
+void HeatTransfer::init(bool init_with_rank)
+{
+    if (init_with_rank)
+    {
+        for (unsigned int i = 0; i < m_s.ndx+2; i++)
+            for (unsigned int j = 0; j < m_s.ndy+2; j++)
+                m_T1[i][j] = m_s.rank;
+    }
+    else
+    {
+        const double hx = 2.0 * 4.0*atan(1.0)/m_s.ndx;
+        const double hy = 2.0 * 4.0*atan(1.0)/m_s.ndy;
+
+        double x, y;
+        for (unsigned int i = 0; i < m_s.ndx+2; i++)
+        {
+            x = 0.0 + hx*(i-1);
+            for (unsigned int j = 0; j < m_s.ndy+2; j++)
+            {
+                y = 0.0 + hy*(j-1);
+                m_T1[i][j] = cos(8*x) + cos(6*x) - cos(4*x) + cos(2*x) - cos(x) +
+                        sin(8*y) - sin(6*y) + sin(4*y) - sin(2*y) + sin(y);
+            }
+        }
+    }
+    m_TCurrent = m_T1;
+    m_TNext = m_T2;
+}
+
+void HeatTransfer::printT(std::string message, MPI_Comm comm) const
+{
+    int rank, size;
+    int tag = 1;
+    int token;
+    MPI_Status status;
+    MPI_Comm_rank( comm, &rank );
+    MPI_Comm_size( comm, &size );
+    if( rank > 0)
+    {
+        MPI_Recv(&token, 1, MPI_INT, rank-1, tag, comm, &status);
+    }
+
+    std::cout << "Rank " << rank << " " << message << std::endl;
+    for (unsigned int i = 0; i < m_s.ndx+2; i++)
+    {
+        std::cout << "  T[" << i << "][] = ";
+        for (unsigned int j = 0; j < m_s.ndy+2; j++)
+        {
+            std::cout << std::setw(6) << m_TCurrent[i][j];
+        }
+        std::cout << std::endl;
+    }
+    std::cout << std::flush << std::endl;
+
+    if( rank < size-1)
+    {
+        MPI_Send(&token, 1, MPI_INT, rank+1, tag, comm);
+    }
+}
+
+
+void HeatTransfer::switchCurrentNext()
+{
+    double **tmp = m_TCurrent;
+    m_TCurrent = m_TNext;
+    m_TNext = tmp;
+}
+
+void HeatTransfer::iterate()
+{
+    for( unsigned int i = 1; i <= m_s.ndx; ++i)
+    {
+        for( unsigned int j = 1; j <= m_s.ndy; ++j)
+        {
+            m_TNext[i][j] =
+                    omega/4*(m_TCurrent[i-1][j] +
+                             m_TCurrent[i+1][j] +
+                             m_TCurrent[i][j-1] +
+                             m_TCurrent[i][j+1]) +
+                    (1.0-omega)*m_TCurrent[i][j];
+        }
+    }
+    switchCurrentNext();
+}
+
+void HeatTransfer::heatEdges()
+{
+    // Heat the whole global edges
+    if( m_s.posx==0 )
+        for( unsigned int j = 0; j < m_s.ndy+2; ++j)
+            m_TCurrent[0][j]= edgetemp;
+
+    if( m_s.posx==m_s.npx-1 )
+        for( unsigned int j = 0; j < m_s.ndy+2; ++j)
+            m_TCurrent[m_s.ndx+1][j]= edgetemp;
+
+    if (m_s.posy==0)
+        for( unsigned int i = 0; i < m_s.ndx+2; ++i)
+            m_TCurrent[i][0]= edgetemp;
+
+    if (m_s.posy==m_s.npy-1)
+        for( unsigned int i = 0; i < m_s.ndx+2; ++i)
+            m_TCurrent[i][m_s.ndy+1]= edgetemp;
+}
+
+void HeatTransfer::exchange( MPI_Comm comm )
+{
+    // Exchange ghost cells, in the order left-right-up-down
+
+    double * send_x = new double[m_s.ndx+2];
+    double * recv_x = new double[m_s.ndx+2];
+
+    // send to left + receive from right
+    int tag = 1;
+    MPI_Status status;
+    if( m_s.rank_left >= 0 )
+    {
+        std::cout << "Rank " << m_s.rank << " send left to rank " <<  m_s.rank_left << std::endl;
+        for( unsigned int i = 0; i < m_s.ndx+2; ++i)
+            send_x[i] = m_TCurrent[i][1];
+         MPI_Send(send_x, m_s.ndx+2, MPI_REAL8, m_s.rank_left, tag, comm);
+    }
+    if( m_s.rank_right >= 0 )
+    {
+        std::cout << "Rank " << m_s.rank << " receive from right from rank " <<  m_s.rank_right << std::endl;
+        MPI_Recv(recv_x, m_s.ndx+2, MPI_REAL8, m_s.rank_right, tag, comm, &status);
+        for( unsigned int i = 0; i < m_s.ndx+2; ++i)
+            m_TCurrent[i][m_s.ndy+1] = recv_x[i];
+    }
+
+    // send to right + receive from left
+    tag = 2;
+    if( m_s.rank_right >= 0 )
+    {
+        std::cout << "Rank " << m_s.rank << " send right to rank " <<  m_s.rank_right << std::endl;
+        for( unsigned int i = 0; i < m_s.ndx+2; ++i)
+            send_x[i] = m_TCurrent[i][m_s.ndy];
+        MPI_Send(send_x, m_s.ndx+2, MPI_REAL8, m_s.rank_right, tag, comm);
+    }
+    if( m_s.rank_left >= 0 )
+    {
+        std::cout << "Rank " << m_s.rank << " receive from left from rank " <<  m_s.rank_left << std::endl;
+        MPI_Recv(recv_x, m_s.ndx+2, MPI_REAL8, m_s.rank_left, tag, comm, &status);
+        for( unsigned int i = 0; i < m_s.ndx+2; ++i)
+            m_TCurrent[i][0] = recv_x[i];
+    }
+
+    // send down + receive from above
+    tag = 3;
+    if( m_s.rank_down >= 0 )
+    {
+        std::cout << "Rank " << m_s.rank << " send down to rank " <<  m_s.rank_down << std::endl;
+        MPI_Send(m_TCurrent[m_s.ndx], m_s.ndy+2, MPI_REAL8, m_s.rank_down, tag, comm);
+    }
+    if ( m_s.rank_up >= 0 )
+    {
+        std::cout << "Rank " << m_s.rank << " receive from above from rank " <<  m_s.rank_up << std::endl;
+        MPI_Recv(m_TCurrent[0], m_s.ndy+2, MPI_REAL8, m_s.rank_up, tag, comm, &status);
+    }
+
+    // send up + receive from below
+    tag = 4;
+    if( m_s.rank_up >= 0 )
+    {
+        std::cout << "Rank " << m_s.rank << " send up to rank " <<  m_s.rank_up << std::endl;
+        MPI_Send(m_TCurrent[1], m_s.ndy+2, MPI_REAL8, m_s.rank_up, tag, comm);
+    }
+    if ( m_s.rank_down >= 0 )
+    {
+        std::cout << "Rank " << m_s.rank << " receive from below from rank " <<  m_s.rank_down << std::endl;
+        MPI_Recv(m_TCurrent[m_s.ndx+1], m_s.ndy+2, MPI_REAL8, m_s.rank_down, tag, comm, &status);
+    }
+
+    delete[] send_x;
+    delete[] recv_x;
+}
+
+#include <cstring>
+/* Copies the internal ndx*ndy section of the ndx+2 * ndy+2 local array
+ * into a separate contiguous vector and returns it.
+ * @return A vector with ndx*ndy elements
+ */
+std::vector<double> HeatTransfer::data_noghost() const
+{
+    std::vector<double>d( m_s.ndx * m_s.ndy );
+    for( unsigned int i = 1; i <= m_s.ndx; ++i )
+    {
+        std::memcpy( &d[(i-1)*m_s.ndy], m_TCurrent[i]+1, m_s.ndy*sizeof(double));
+    }
+    return d;
+}
diff --git a/examples/heatTransfer/HeatTransfer.h b/examples/heatTransfer/HeatTransfer.h
new file mode 100644
index 0000000000000000000000000000000000000000..09589e8ae158492ff2af2f6335d2edbb6a9b3cb4
--- /dev/null
+++ b/examples/heatTransfer/HeatTransfer.h
@@ -0,0 +1,46 @@
+/*
+ * HeatTransfer.h
+ *
+ *  Created on: Feb 2017
+ *      Author: Norbert Podhorszki
+ */
+
+#ifndef HEATTRANSFER_H_
+#define HEATTRANSFER_H_
+
+#include <mpi.h>
+#include <vector>
+
+#include "Settings.h"
+
+class HeatTransfer
+{
+public:
+    HeatTransfer( const Settings& settings ); // Create two 2D arrays with ghost cells to compute
+    ~HeatTransfer();
+    void init(bool init_with_rank); // set up array values with either rank or real demo values
+    void iterate();  // one local calculation step
+    void heatEdges(); // reset the heat values at the global edge
+    void exchange( MPI_Comm comm ); // send updates to neighbors
+
+    // return a single value at index i,j. 0 <= i <= ndx+2, 0 <= j <= ndy+2
+    double T( int i, int j) const {return m_TCurrent[i][j];};
+    // return (1D) pointer to current T data, ndx+2 * ndy+2 elements
+    double *data() const {return m_TCurrent[0];};
+    // return (1D) pointer to current T data without ghost cells, ndx*ndy elements
+    std::vector<double> data_noghost() const;
+
+    void printT(std::string message, MPI_Comm comm) const; // debug: print local TCurrent on stdout
+
+private:
+    const double edgetemp = 3.0; // temperature at the edges of the global plate
+    const double omega = 0.8;    // weight for current temp is (1-omega) in iteration
+    double **m_T1;       // 2D array (ndx+2) * (ndy+2) size, including ghost cells
+    double **m_T2;       // another 2D array
+    double **m_TCurrent; // pointer to T1 or T2
+    double **m_TNext;    // pointer to T2 or T1
+    const Settings& m_s;
+    void switchCurrentNext(); // switch the current array with the next array
+};
+
+#endif /* HEATTRANSFER_H_ */
diff --git a/examples/heatTransfer/IO.h b/examples/heatTransfer/IO.h
new file mode 100644
index 0000000000000000000000000000000000000000..789a4482b158c9f2feb0dcede693bbf8e58b8e91
--- /dev/null
+++ b/examples/heatTransfer/IO.h
@@ -0,0 +1,27 @@
+/*
+ * IO.h
+ *
+ *  Created on: Feb 2017
+ *      Author: Norbert Podhorszki
+ */
+
+#ifndef IO_H_
+#define IO_H_
+
+#include <mpi.h>
+#include "Settings.h"
+#include "HeatTransfer.h"
+
+class IO
+{
+
+public:
+    IO( const Settings& s, MPI_Comm comm );
+    ~IO();
+    void write( int step, const HeatTransfer& ht, const Settings& s, MPI_Comm comm );
+    
+private:
+    std::string m_outputfilename;
+};
+
+#endif /* IO_H_ */
diff --git a/examples/heatTransfer/IO_adios1.cpp b/examples/heatTransfer/IO_adios1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8d3a4a9e4e9ff636a70dde450c678e2b6e8fbab3
--- /dev/null
+++ b/examples/heatTransfer/IO_adios1.cpp
@@ -0,0 +1,73 @@
+/*
+ * IO_ADIOS1.cpp
+ *
+ *  Created on: Feb 2017
+ *      Author: Norbert Podhorszki
+ */
+
+#include <string>
+#include <iostream>
+#include <iomanip>
+
+#include "IO.h"
+#include "adios.h"
+
+static int64_t group;
+static int rank_saved;
+
+IO::IO( const Settings& s, MPI_Comm comm )
+{
+    rank_saved = s.rank;
+    m_outputfilename = s.outputfile + ".bp";
+    adios_init_noxml( comm );
+    adios_declare_group( &group, "heat", "", adios_stat_default );
+    adios_select_method( group, "MPI", "", "" );
+
+    adios_define_var( group, "gndx", "", adios_integer, "", "", "");
+    adios_define_var( group, "gndy", "", adios_integer, "", "", "");
+
+    std::string ldims( std::to_string( s.ndx ) + "," + std::to_string( s.ndy ));
+    std::string gdims( std::to_string( s.gndx ) + "," + std::to_string( s.gndy ));
+    std::string offs( std::to_string( s.offsx ) + "," + std::to_string( s.offsy ));
+    uint64_t T_id;
+    T_id = adios_define_var( group, "T", "", adios_double,
+                             ldims.c_str(), gdims.c_str(), offs.c_str() );
+
+    adios_set_transform( T_id, "none");
+    //adios_set_transform( T_id, "zfp:accuracy=0.001");
+}
+
+IO::~IO()
+{
+   adios_finalize(rank_saved);
+}
+
+void IO::write( int step, const HeatTransfer& ht, const Settings& s, MPI_Comm comm )
+{
+    char mode[2] = "w";
+    if (step > 0)
+    {
+        mode[0] = 'a';
+    }
+
+    // for time measurements, let's synchronize the processes
+    MPI_Barrier( comm );
+    double time_start = MPI_Wtime();
+
+    int64_t f;
+    adios_open( &f, "heat", m_outputfilename.c_str(), mode, comm);
+    adios_write( f, "gndx", &s.gndx);
+    adios_write( f, "gndy", &s.gndy);
+    adios_write( f, "T", ht.data_noghost().data() );
+    adios_close( f );
+
+    MPI_Barrier( comm );
+    double total_time = MPI_Wtime() - time_start;
+    uint64_t adios_totalsize = 2*sizeof(int) + 2*s.ndx*s.ndy*sizeof(double);
+    uint64_t sizeMB = adios_totalsize * s.nproc/1024/1024/1024; // size in MB
+    uint64_t mbs = sizeMB/total_time;
+    if (s.rank==0)
+        std::cout << "Step " << step << ": " << m_outputfilename
+                  << " " << sizeMB << " " << total_time << "" << mbs << std::endl;
+}
+
diff --git a/examples/heatTransfer/IO_adios2.cpp b/examples/heatTransfer/IO_adios2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9d27e7c3935622d55a95b4c9354f61b3266942e1
--- /dev/null
+++ b/examples/heatTransfer/IO_adios2.cpp
@@ -0,0 +1,96 @@
+/*
+ * IO_ADIOS2.cpp
+ *
+ *  Created on: Feb 2017
+ *      Author: Norbert Podhorszki
+ */
+
+#include "IO.h"
+#include "ADIOS_CPP.h"
+
+#include <string>
+
+static int rank_saved;
+adios::ADIOS * ad = nullptr;
+std::shared_ptr<adios::Engine> bpWriter;
+adios::Variable<double> * varT = nullptr;
+
+IO::IO( const Settings& s, MPI_Comm comm )
+{
+    rank_saved = s.rank;
+    m_outputfilename = s.outputfile + ".bp";
+    ad = new adios::ADIOS( "adios2.xml", comm, adios::Verbose::INFO );
+
+    //Define method for engine creation
+    // 1. Get method def from config file or define new one
+
+    adios::Method& bpWriterSettings = ad->DeclareMethod( "output" );
+    if( ! bpWriterSettings.isUserDefined())
+    {
+        // if not defined by user, we can change the default settings
+        bpWriterSettings.SetEngine( "BP" ); // BP is the default engine
+        bpWriterSettings.AllowThreads( 1 ); // allow 1 extra thread for data processing
+        bpWriterSettings.AddTransport( "File", "lucky=yes" ); // ISO-POSIX file is the default transport
+                                                              // Passing parameters to the transport
+        bpWriterSettings.SetParameters("have_metadata_file","yes" ); // Passing parameters to the engine
+        bpWriterSettings.SetParameters( "Aggregation", std::to_string((s.nproc+1)/2) ); // number of aggregators
+    }
+
+
+    // define T as 2D global array
+    varT = &ad->DefineVariable<double>(
+            "T",
+            {s.gndx,s.gndy},  // Global dimensions
+            {s.ndx,s.ndy},    // local size, could be defined later using SetSelection()
+            {s.offsx,s.offsy} // offset of the local array in the global space
+    );
+
+
+    //add transform to variable
+    //adios::Transform tr = adios::transform::BZIP2( );
+    //varT.AddTransform( tr, "" );
+    // varT.AddTransform( tr,"accuracy=0.001" );  // for ZFP
+
+    bpWriter = ad->Open( m_outputfilename, "w", comm, bpWriterSettings, adios::IOMode::COLLECTIVE);
+
+    if( bpWriter == nullptr )
+        throw std::ios_base::failure( "ERROR: failed to open ADIOS bpWriter\n" );
+
+
+}
+
+IO::~IO()
+{
+    bpWriter->Close();
+    delete ad;
+}
+
+void /*IO::*/old_style_write(int step, const HeatTransfer& ht, const Settings& s, MPI_Comm comm )
+{
+    bpWriter->Write<double>( *varT, ht.data_noghost().data());
+    bpWriter->Advance( );
+}
+
+void IO::write(int step, const HeatTransfer& ht, const Settings& s, MPI_Comm comm )
+{
+    /* This selection is redundant and not required, since we defined
+     * the selection already in DefineVariable(). It is here just as an example.
+     */
+    // Make a selection to describe the local dimensions of the variable we write and
+    // its offsets in the global spaces. This could have been done in adios.DefineVariable()
+    adios::Selection sel = adios.SelectionBoundingBox( {s.ndx,s.ndy}, {s.offsx,s.offsy} ); // local dims and offsets; both as list
+    var2D.SetSelection( sel );
+
+    /* Select the area that we want to write from the data pointer we pass to the writer.
+       Think HDF5 memspace, just not hyperslabs, only a bounding box selection.
+       Engine will copy this bounding box from the data pointer into the output buffer.
+       Size of the bounding box should match the "space" selection which was given above.
+       Default memspace is always the full selection.
+    */
+    adios::Selection memspace = adios.SelectionBoundingBox( {s.ndx,s.ndy}, {1,1} );
+    var2D.SetMemorySelection( memspace );
+
+    bpWriter->Write<double>( *varT, ht.data());
+    bpWriter->Advance( );
+}
+
diff --git a/examples/heatTransfer/IO_ascii.cpp b/examples/heatTransfer/IO_ascii.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..01bd6d2edf8538a2bd773283e57b27c928054d21
--- /dev/null
+++ b/examples/heatTransfer/IO_ascii.cpp
@@ -0,0 +1,75 @@
+/*
+ * IO_ascii.cpp
+ *
+ *  Created on: Feb 2017
+ *      Author: Norbert Podhorszki
+ */
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+
+#include "IO.h"
+
+static std::ofstream of;
+static std::streambuf *buf;
+
+IO::IO( const Settings& s, MPI_Comm comm )
+{
+    m_outputfilename = s.outputfile;
+
+    if (m_outputfilename == "cout")
+    {
+        buf = std::cout.rdbuf();
+    }
+    else
+    {
+        int rank;
+        MPI_Comm_rank( comm, &rank );
+        std::string rs = std::to_string(rank);
+        of.open(m_outputfilename + rs + ".txt");
+        buf = of.rdbuf();
+    }
+}
+
+IO::~IO()
+{
+    if (m_outputfilename != "cout")
+    {
+        of.close();
+    }
+}
+
+void IO::write( int step, const HeatTransfer& ht, const Settings& s, MPI_Comm comm)
+{
+    std::ostream out(buf);
+    if( step == 0)
+    {
+        out << "rank=" << s.rank
+                  << " size=" << s.ndx << "x" << s.ndy
+                  << " offsets=" << s.offsx << ":" << s.offsy
+                  << " step=" << step << std::endl;
+        out << " time   row   columns " << s.offsy << "..." << s.offsy+s.ndy-1 << std::endl;
+        out << "        ";
+        for (int j = 1; j <= s.ndy; ++j) {
+            out <<  std::setw(9) << s.offsy+j-1;
+        }
+        out << "\n--------------------------------------------------------------\n";
+    }
+    else
+    {
+        out << std::endl;
+    }
+
+    for (int i = 1; i <= s.ndx; ++i)
+    {
+        out <<  std::setw(5) << step << std::setw(5) << s.offsx+i-1;
+        for (int j = 1; j <= s.ndy; ++j)
+        {
+            out <<  std::setw(9) << ht.T(i,j);
+        }
+        out << std::endl;
+    }
+
+}
+
diff --git a/examples/heatTransfer/IO_hdf5_a.cpp b/examples/heatTransfer/IO_hdf5_a.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3872606283b61b103767dd4e317b683fd3fcfeb1
--- /dev/null
+++ b/examples/heatTransfer/IO_hdf5_a.cpp
@@ -0,0 +1,59 @@
+/*
+ * IO_hdf5_a.cpp
+ *
+ * Write output with sequential HDF5, one file per process, one separate set per timestep
+ *
+ *  Created on: Feb 2017
+ *      Author: Norbert Podhorszki
+ */
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <string>
+
+#include "IO.h"
+#include "hdf5.h"
+
+
+IO::IO( const Settings& s, MPI_Comm comm )
+:m_outputfilename{s.outputfile}
+{
+}
+
+IO::~IO()
+{
+}
+
+void IO::write( int step, const HeatTransfer& ht, const Settings& s, MPI_Comm comm)
+{
+    std::string rs = std::to_string(s.rank);
+    std::string ts = std::to_string(step);
+    std::string fname = s.outputfile + "." + rs + "." + ts + ".h5";
+
+    // for time measurements, let's synchronize the processes
+    MPI_Barrier( comm );
+    double time_start = MPI_Wtime();
+
+    hsize_t dims[2] = {static_cast<hsize_t>(s.ndx), static_cast<hsize_t>(s.ndy)};
+
+    hid_t space = H5Screate_simple( 2, dims, NULL );
+    hid_t file = H5Fcreate( fname.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT );
+    hid_t dset = H5Dcreate( file, "T", H5T_NATIVE_DOUBLE, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
+
+    H5Dwrite( dset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, ht.data_noghost().data());
+
+    H5Dclose( dset );
+    H5Sclose( space );
+    H5Fclose( file );
+
+    MPI_Barrier( comm );
+    double total_time = MPI_Wtime() - time_start;
+    uint64_t adios_totalsize = 2*sizeof(int) + 2*s.ndx*s.ndy*sizeof(double);
+    uint64_t sizeMB = adios_totalsize * s.nproc/1024/1024/1024; // size in MB
+    uint64_t mbs = sizeMB/total_time;
+    if (s.rank==0)
+        std::cout << "Step " << step << ": " << m_outputfilename
+                  << " " << sizeMB << " " << total_time << "" << mbs << std::endl;
+}
+
diff --git a/examples/heatTransfer/Makefile b/examples/heatTransfer/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ca8361a4178b1af21950f763bf8db2008301b0e8
--- /dev/null
+++ b/examples/heatTransfer/Makefile
@@ -0,0 +1,66 @@
+# Makefile
+# Created on: Feb 13, 2017
+#     Author: pnorbert
+
+#
+#   SYSTEM SPECIFIC SETTINGS
+#
+#COMPILERS
+CC=g++ 
+MPICC=mpic++
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -Woverloaded-virtual -std=c++11 -O0 -g
+LDFLAGS=-lpthread
+
+#ADIOS1 LOCATION
+ADIOS1_DIR=/opt/adios/1.11
+
+#ADIOS2 LOCATION
+ADIOS2_DIR=../..
+
+# SEQUENTIAL HDF5 LOCATION
+HDF5_DIR=/opt/hdf5-1.8.17
+HDF5_INCLUDE=-I$(HDF5_DIR)/include 
+HDF5_LIB=$(HDF5_DIR)/lib/libhdf5.la
+
+#
+#   SHOULD NOT NEED TO CHANGE ANYTHING BELOW
+#
+
+ADIOS1_INCLUDE=-I$(ADIOS1_DIR)/include
+ADIOS1_LIB=`${ADIOS1_DIR}/bin/adios_config -l`
+
+
+ADIOS2_INCLUDE= -DHAVE_MPI -I$(ADIOS2_DIR)/include
+ADIOS2_LIB=$(ADIOS2_DIR)/lib/libadios.a
+
+default: 
+	@echo "Make targets: ascii hdf5_a hdf5_b phdf5 adios1 adios2"
+	@echo "  ascii:    build example with text output(IO_ascii.cpp)"
+	@echo "  hdf5_a:   build example with HDF5, separate timesteps (IO_hdf5_a.cpp)"
+	@echo "  hdf5_b:   build example with HDF5, combined timesteps (IO_hdf5_b.cpp)"
+	@echo "  phdf5:    build example with Parallel HDF5  (IO_phdf5.cpp)"
+	@echo "  adios1:   build example with ADIOS 1.x  (IO_adios1.cpp)"
+	@echo "  adios2:   build example with ADIOS2  (IO_adios2.cpp)"
+
+
+all: default
+help: default
+
+
+ascii: main.cpp HeatTransfer.cpp Settings.cpp IO_ascii.cpp 
+	    $(MPICC) $(CFLAGS) -o heatTransfer_ascii $^ $(LDFLAGS)   
+
+hdf5_a: main.cpp HeatTransfer.cpp Settings.cpp IO_hdf5_a.cpp 
+	    libtool --mode=link --tag=CC $(MPICC) $(CFLAGS) $(HDF5_INCLUDE) -o heatTransfer_hdf5_a $^ $(HDF5_LIB) $(LDFLAGS)
+	    
+adios1: main.cpp HeatTransfer.cpp Settings.cpp IO_adios1.cpp 
+	    $(MPICC) $(CFLAGS) $(ADIOS1_INCLUDE) -o heatTransfer_adios1 $^ $(ADIOS1_LIB) $(LDFLAGS)  
+
+adios2: main.cpp HeatTransfer.cpp Settings.cpp IO_adios2.cpp 
+	    $(MPICC) $(CFLAGS) $(ADIOS2_INCLUDE) -o heatTransfer_adios2 $^ $(ADIOS2_LIB) $(LDFLAGS)  
+	
+clean:
+	rm -f heatTransfer_ascii heatTransfer_hdf5_a heatTransfer_adios1 heatTransfer_adios2
+     
diff --git a/examples/heatTransfer/Settings.cpp b/examples/heatTransfer/Settings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8910cbc838a084511d8142eaaffd3a3480f2419d
--- /dev/null
+++ b/examples/heatTransfer/Settings.cpp
@@ -0,0 +1,89 @@
+/*
+ * Settings.cpp
+ *
+ *  Created on: Feb 2017
+ *      Author: Norbert Podhorszki
+ */
+
+
+
+#include <errno.h>
+#include <cstdlib>
+
+#include "Settings.h"
+
+
+static unsigned int convertToUint( std::string varName, char *arg )
+{
+    char *end;
+    int retval = std::strtoll( arg, &end, 10);
+    if( end[0] || errno == ERANGE )
+    {
+        throw std::invalid_argument( "Invalid value given for " + varName + ": "
+                + std::string(arg) );
+    }
+    if( retval < 0 )
+    {
+        throw std::invalid_argument( "Negative value given for " + varName + ": "
+                + std::string(arg) );
+    }
+    return (unsigned int) retval;
+}
+
+Settings::Settings( int argc, char* argv [], int rank, int nproc )
+: rank{rank}
+{
+    if (argc < 8)
+    {
+        throw std::invalid_argument( "Not enough arguments" );
+    }
+    this->nproc = (unsigned int) nproc;
+
+    outputfile = argv[1];
+    npx = convertToUint("N", argv[2]);
+    npy = convertToUint("M", argv[3]);
+    ndx = convertToUint("nx", argv[4]);
+    ndy = convertToUint("ny", argv[5]);
+    steps = convertToUint("steps", argv[6]);
+    iterations = convertToUint("iterations", argv[7]);
+
+    if( npx * npy != this->nproc )
+    {
+        throw std::invalid_argument( "N*M must equal the number of processes" );
+    }
+
+    // calculate global array size and the local offsets in that global space
+    gndx  = npx * ndx;
+    gndy  = npy * ndy;
+    posx  = rank % npx;
+    posy  = rank / npx;
+    offsx = posx * ndx;
+    offsy = posy * ndy;
+
+    // determine neighbors
+    if( posx == 0 )
+        rank_left = -1;
+    else
+        rank_left = rank-1;
+
+    if( posx == npx-1 )
+        rank_right = -1;
+    else
+        rank_right = rank+1;
+
+    if( posy == 0 )
+        rank_up = -1;
+    else
+        rank_up = rank - npx;
+
+    if( posy == npy-1 )
+        rank_down = -1;
+    else
+        rank_down = rank + npx;
+
+}
+
+Settings::~Settings()
+{
+}
+
diff --git a/examples/heatTransfer/Settings.h b/examples/heatTransfer/Settings.h
new file mode 100644
index 0000000000000000000000000000000000000000..26ec50e18b270dc8945fd6df242116de89536931
--- /dev/null
+++ b/examples/heatTransfer/Settings.h
@@ -0,0 +1,51 @@
+/*
+ * Settings.h
+ *
+ *  Created on: Feb 2017
+ *      Author: Norbert Podhorszki
+ */
+
+#ifndef SETTINGS_H_
+#define SETTINGS_H_
+
+#include <memory>
+
+class Settings
+{
+
+public:
+    // user arguments
+    std::string outputfile;
+    unsigned int npx; // Number of processes in X (slow) dimension
+    unsigned int npy; // Number of processes in Y (fast) dimension
+    unsigned int ndx; // Local array size in X dimension per process
+    unsigned int ndy; // Local array size in y dimension per process
+    unsigned int steps; // Number of output steps
+    unsigned int iterations; // Number of computing iterations between steps
+
+    // calculated values from those arguments and number of processes
+    unsigned int gndx; // Global array size in slow dimension
+    unsigned int gndy; // Global array size in fast dimension
+    // X dim positions: rank 0, npx, 2npx... are in the same X position
+    // Y dim positions: npx number of consecutive processes belong to one row (npx columns)
+    unsigned int posx; // Position of this process in X dimension
+    unsigned int posy; // Position of this process in Y dimension
+    unsigned int offsx; // Offset of local array in X dimension on this process
+    unsigned int offsy; // Offset of local array in Y dimension on this process
+
+    int rank;  // MPI rank
+    unsigned int nproc; // number of processors
+
+    // neighbors by their MPI ranks, -1 if there is no such neighbor
+    int rank_left;
+    int rank_right;
+    int rank_up;
+    int rank_down;
+
+    Settings( int argc, char* argv [], int rank, int nproc );
+    ~Settings();
+
+};
+
+
+#endif /* SETTINGS_H_ */
diff --git a/examples/heatTransfer/main.cpp b/examples/heatTransfer/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..22fd919cefd2338b3bd79d8df3ef8ec81d7cd8a6
--- /dev/null
+++ b/examples/heatTransfer/main.cpp
@@ -0,0 +1,109 @@
+/*
+ * main.cpp
+ *
+ * Recreates heat_transfer.f90 (Fortran) ADIOS tutorial example in C++
+ *
+ * Created on: Feb 2017
+ *     Author: Norbert Podhorszki
+ *
+ */
+#include <mpi.h>
+
+#include <stdexcept>
+#include <memory>
+#include <iostream>
+#include <string>
+
+
+#include "Settings.h"
+#include "IO.h"
+#include "HeatTransfer.h"
+
+void printUsage()
+{
+    std::cout << "Usage: heatTransfer  output  N  M   nx  ny   steps iterations\n"
+              << "  output: name of output file\n"
+              << "  N:      number of processes in X dimension\n"
+              << "  M:      number of processes in Y dimension\n"
+              << "  nx:     local array size in X dimension per processor\n"
+              << "  ny:     local array size in Y dimension per processor\n"
+              << "  steps:  the total number of steps to output\n"
+              << "  iterations: one step consist of this many iterations\n\n";
+}
+
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    /* World comm spans all applications started with the same aprun command
+       on a Cray XK6. So we have to split and create the local
+       'world' communicator for heat_transfer only.
+       In normal start-up, the communicator will just equal the MPI_COMM_WORLD.
+    */
+
+    int wrank, wnproc;
+    MPI_Comm_rank( MPI_COMM_WORLD, &wrank );
+    MPI_Comm_size( MPI_COMM_WORLD, &wnproc );
+    MPI_Barrier( MPI_COMM_WORLD );
+
+    const unsigned int color = 1;
+    MPI_Comm mpiHeatTransferComm;
+    MPI_Comm_split( MPI_COMM_WORLD, color, wrank, &mpiHeatTransferComm );
+
+    int rank, nproc;
+    MPI_Comm_rank( mpiHeatTransferComm, &rank );
+    MPI_Comm_size( mpiHeatTransferComm, &nproc );
+
+    try
+    {
+        double timeStart = MPI_Wtime();
+        Settings settings( argc, argv, rank, nproc );
+        HeatTransfer ht( settings );
+        IO io( settings, mpiHeatTransferComm );
+
+        ht.init(true);
+        ht.printT("Initialized T:", mpiHeatTransferComm);
+        ht.heatEdges();
+        //ht.exchange( mpiHeatTransferComm );
+        ht.printT("Heated T:", mpiHeatTransferComm);
+        io.write( 0, ht, settings, mpiHeatTransferComm );
+
+        for( unsigned int t = 1; t <= settings.steps; ++t )
+        {
+            if( rank == 0 )
+                std::cout << "Step " << t << ":\n";
+            for( unsigned int iter = 1; iter <= settings.iterations; ++iter )
+            {
+                ht.iterate();
+                ht.exchange( mpiHeatTransferComm );
+                ht.heatEdges();
+            }
+            io.write( t, ht, settings, mpiHeatTransferComm );
+        }
+        MPI_Barrier( mpiHeatTransferComm );
+
+        double timeEnd = MPI_Wtime();
+        if( rank == 0 )
+            std::cout << "Total runtime = " << timeEnd-timeStart << "s\n";
+
+    }
+    catch( std::invalid_argument& e ) // command-line argument errors
+    {
+        std::cout << e.what() << std::endl;
+        printUsage();
+    }
+    catch( std::ios_base::failure& e ) //I/O failure (e.g. file not found)
+    {
+    	std::cout << "I/O base exception caught\n";
+		std::cout << e.what() << std::endl;
+    }
+	catch( std::exception& e ) //All other exceptions
+	{
+		std::cout << "Exception caught\n";
+		std::cout << e.what() << std::endl;
+	}
+
+	MPI_Finalize();
+	return 0;
+}
+
diff --git a/examples/hello/C/fstream.xml b/examples/hello/C/fstream.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f43942fb1e13329c05a43c714ee3f8e2c6807ac5
--- /dev/null
+++ b/examples/hello/C/fstream.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<adios-config host-language="C">
+  <adios-group name="Types">
+    <var name="NumbersSize" type="int"/> 
+    <var name="Numbers" type="double"/>
+    <attribute name="description" value="1 to 10"/>
+
+  </adios-group>
+  
+  <transport group="Types" method="FStream">verbose=3</transport>
+
+  <!--  <buffer size-MB="40" allocate-time="now"/> -->
+
+</adios-config>
diff --git a/examples/hello/C/helloFStream.c b/examples/hello/C/helloFStream.c
new file mode 100644
index 0000000000000000000000000000000000000000..70f890db1e0b13d243ebb58734e6621477f69bfb
--- /dev/null
+++ b/examples/hello/C/helloFStream.c
@@ -0,0 +1,46 @@
+/*
+ * helloFStream.c  Test for C API version of helloFStream
+ *  Created on: Nov 2, 2016
+ *      Author: wfg
+ */
+
+
+
+#include "../../../include/ADIOS_C.h"
+
+
+void main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+
+    //populate values
+    double* myNumbers;
+    myNumbers = (double*) malloc( 10 * sizeof(double) );
+
+    int i;
+    for( i = 0; i < 10; ++i )
+        myNumbers[i] = i+1;
+
+    //start ADIOS
+    ADIOS* adiosC, adiosC2;
+    const char group [] = "Types";
+    const char group2 [] = "Types2";
+
+
+    adiosC2 = adios_init_debug( "fstream.xml", MPI_COMM_WORLD ); //debug  mode
+
+    adios_create_group( adiosC, "groupCFD");
+    adios_create_variable( adiosC, "groupCFD", "temperature" );
+    adios_create_group( adiosC2, "groupFEM", "temperature" );
+    ///
+    adios_open( adiosC, group, "helloVector.txt", "w" ); //open group Types associated with file "helloVector.txt" for writing
+    adios_open( adiosC, group2, "Vector.txt", "w" ); //open group Types associated with file "helloVector.txt" for writing
+    adios_write( adiosC, group, "Types", myNumbers );
+    adios_close( adiosC, group );
+
+
+    free( myNumbers );
+
+}
diff --git a/examples/hello/Makefile b/examples/hello/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..62588a0625f53b246288677483bffb55033535fc
--- /dev/null
+++ b/examples/hello/Makefile
@@ -0,0 +1,35 @@
+# Makefile for testing purposes, will build libadios.a 
+# Created on: Oct 4, 2016
+#     Author: wfg
+
+
+BASE_NAME=helloADIOSNoXML_OOP
+     
+TOOL_DIR=/usr/bin
+
+CC=$(TOOL_DIR)/g++ # Compiling with mpicc for now
+MPICC=$(TOOL_DIR)/mpic++
+AR=$(TOOL_DIR)/ar
+
+#ADIOS LOCATION
+ADIOS_DIR=../..
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+
+
+#FLAGS
+CFLAGS=-Wall -O0 -g -Wpedantic -std=c++11
+
+all: mpi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $(BASE_NAME).cpp -o $(BASE_NAME)_mpi $(ADIOS_LIB)
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME).cpp -o $(BASE_NAME)_nompi $(ADIOS_NOMPI_LIB)
+
+clean:
+	rm *_mpi; rm *_nompi
+     
diff --git a/examples/hello/README b/examples/hello/README
new file mode 100644
index 0000000000000000000000000000000000000000..5966d87b721fe4e925ca70c1d3e959c382b7a6d2
--- /dev/null
+++ b/examples/hello/README
@@ -0,0 +1,10 @@
+Test if ADIOS MPI and noMPI code can be separated at compilation stage
+Single Makefile handles different binaries
+
+make mpi -> for MPI code, links ../../lib/libadios.a
+make nompi -> for noMPI code links ../../lib/libadios_nompi.a
+
+Choose different BASE_NAMES
+
+make nompi BASE_NAME=helloFStream
+make nompi BASE_NAME=helloADIOS
\ No newline at end of file
diff --git a/examples/hello/adios1Writer/Makefile b/examples/hello/adios1Writer/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..43e25223583e8a39ea3e563d732d189b71a67454
--- /dev/null
+++ b/examples/hello/adios1Writer/Makefile
@@ -0,0 +1,36 @@
+# Makefile for testing purposes, will build helloADIOS1Writer (make or make mpi) or helloADIOS1Writer_nompi (make nompi) 
+# Created on: Mar 27, 2017
+#     Author: pnb
+
+BASE_NAME=helloADIOS1Writer
+
+#COMPILERS
+CC=g++
+MPICC=mpic++
+
+#ADIOS 1.x  LOCATION
+ADIOS1_DIR=/opt/adios/1.11
+ADIOS1_LIB=$(shell ${ADIOS1_DIR}/bin/adios_config -l)
+ADIOS1_NOMPI_LIB=$(shell ${ADIOS1_DIR}/bin/adios_config -ls)
+
+#ADIOS 2.x LOCATION
+ADIOS_DIR=../../..
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -std=c++11 -O0 -g
+LDFLAGS=
+
+all: mpi nompi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME).cpp -o $(BASE_NAME).exe $(ADIOS_LIB) $(ADIOS1_LIB) $(LDFLAGS) -lpthread
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) -DADIOS_NOMPI $(BASE_NAME)_nompi.cpp -o $(BASE_NAME)_nompi.exe $(ADIOS_NOMPI_LIB) $(ADIOS1_NOMPI_LIB) $(LDFLAGS) -lpthread
+
+clean:
+	rm *.exe
+     
diff --git a/examples/hello/adios1Writer/helloADIOS1Writer.cpp b/examples/hello/adios1Writer/helloADIOS1Writer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..18d26d34d0f092da530a5734c2b5f72a215383cb
--- /dev/null
+++ b/examples/hello/adios1Writer/helloADIOS1Writer.cpp
@@ -0,0 +1,105 @@
+/*
+ * helloWriter.cpp
+ *
+ *  Created on: Feb 16, 2017
+ *      Author: wfg
+ */
+
+
+
+#include <vector>
+#include <iostream>
+
+
+#include <mpi.h>
+
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank, nproc;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    MPI_Comm_size( MPI_COMM_WORLD, &nproc );
+    const bool adiosDebug = true;
+    adios::ADIOS adios( MPI_COMM_WORLD, adios::Verbose::INFO, adiosDebug );
+
+    //Application variable
+    float frank = (float)rank;
+    std::vector<double> myDoubles = { frank, frank+0.1f, frank+0.2f, frank+0.3f, frank+0.4f, frank+0.5f,
+                                      frank+0.6f, frank+0.7f, frank+0.8f, frank+0.9f };
+    const std::size_t Nx = myDoubles.size();
+
+    const std::size_t rows = 3;
+    const std::size_t columns = 3;
+
+    std::vector<float> myMatrix;
+    myMatrix.reserve( rows * columns );
+    myMatrix.push_back( frank+0.0 ); myMatrix.push_back( frank+0.1 ), myMatrix.push_back( frank+0.2 );
+    myMatrix.push_back( frank+0.3 ); myMatrix.push_back( frank+0.4 ), myMatrix.push_back( frank+0.5 );
+    myMatrix.push_back( frank+0.6 ); myMatrix.push_back( frank+0.7 ), myMatrix.push_back( frank+0.8 );
+
+    frank = -(float)rank;
+    std::vector<float> myMatrix2 = {frank-0.1f, frank-0.2f, frank-0.3f,
+                                    frank-0.4f, frank-0.5f, frank-0.6f,
+                                    frank-0.7f, frank-0.8f, frank-0.9f };
+
+    try
+    {
+        //Define variable and local size
+        adios::Variable<double>& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", {1,Nx}, {nproc,Nx}, {rank,0} );
+        adios::Variable<float>& ioMyMatrix = adios.DefineVariable<float>( "myMatrix", {rows,columns}, {nproc*rows,columns}, {rank*rows,0} );
+        adios::Variable<float>& ioMyMatrix2 = adios.DefineVariable<float>( "myMatrix2", {rows,columns}, {rows,nproc*columns}, {0,rank*columns} );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpWriterSettings = adios.DeclareMethod( "SingleFile" ); //default method type is BPWriter
+        bpWriterSettings.SetEngine( "ADIOS1Writer" );
+        bpWriterSettings.SetParameters( "profile_units=mus" );
+        bpWriterSettings.AddTransport( "File", "profile_units=mus", "have_metadata_file=no" ); //uses default POSIX library
+
+        //Create engine smart pointer due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        auto bpWriter = adios.Open( "myDoubles.bp", "w", bpWriterSettings, adios::IOMode::COLLECTIVE );
+
+        if( bpWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: couldn't create bpWriter at Open\n" );
+
+        bpWriter->Write<double>( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+
+        bpWriter->Write<float>( ioMyMatrix, myMatrix.data() );
+        bpWriter->Write<float>( ioMyMatrix2, myMatrix2.data() );
+
+        bpWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
diff --git a/examples/hello/adios1Writer/helloADIOS1Writer_nompi.cpp b/examples/hello/adios1Writer/helloADIOS1Writer_nompi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c78fd08785a2ccfdcd6b0c97615c31de80a7739f
--- /dev/null
+++ b/examples/hello/adios1Writer/helloADIOS1Writer_nompi.cpp
@@ -0,0 +1,80 @@
+/*
+ * helloADIOSNoXML_OOP.cpp
+ *
+ *  Created on: Jan 9, 2017
+ *      Author: wfg
+ */
+
+#include <vector>
+#include <iostream>
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+ {
+    const bool adiosDebug = true;
+    adios::ADIOS adios( adiosDebug );
+
+    //Application variable
+    std::vector<double> myDoubles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    const std::size_t rows = 3;
+    const std::size_t columns = 3;
+    std::vector<float> myMatrix = { 1, 2, 3,
+                                    4, 5, 6,
+                                    7, 8, 9 };
+
+    std::vector<float> myMatrix2 = { -1, -2, -3,
+                                     -4, -5, -6,
+                                     -7, -8, -9 };
+
+    try
+    {
+        //Define variable and local size
+        adios::Variable<double>& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", adios::Dims{Nx} );
+        adios::Variable<float>& ioMyMatrix = adios.DefineVariable<float>( "myMatrix", adios::Dims{rows,columns} );
+        adios::Variable<float>& ioMyMatrix2 = adios.DefineVariable<float>( "myMatrix2", adios::Dims{rows,columns} );
+        adios::Variable<float>& ioMyMatrix3 = adios.DefineVariable<float>( "myMatrix3", adios::Dims{rows,columns} );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpWriterSettings = adios.DeclareMethod( "SinglePOSIXFile" ); //default method type is Writer
+        bpWriterSettings.SetParameters( "profile_units=mus" );
+        bpWriterSettings.AddTransport( "File", "have_metadata_file=yes", "profile_units=mus" );
+
+        //Create engine smart pointer due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        auto bpFileWriter = adios.Open( "myDoubles_nompi.bp", "w", bpWriterSettings, adios::IOMode::COLLECTIVE );
+
+        if( bpFileWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: couldn't create bpWriter at Open\n" );
+
+        bpFileWriter->Write<double>( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+        bpFileWriter->Write<float>( ioMyMatrix, myMatrix.data() ); //2d Example
+        bpFileWriter->Write<float>( ioMyMatrix2, myMatrix2.data() ); //2d Example
+        bpFileWriter->Write<float>( ioMyMatrix3, myMatrix2.data() ); //2d Example
+        bpFileWriter->Close( );
+        //
+    }
+    catch( std::invalid_argument& e )
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::ios_base::failure& e )
+    {
+        std::cout << "System exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        std::cout << "Exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+
+    return 0;
+}
+
+
+
diff --git a/examples/hello/bpReader/Makefile b/examples/hello/bpReader/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..b5705da1c7f7e406623c9aafd9380d3dc94ead07
--- /dev/null
+++ b/examples/hello/bpReader/Makefile
@@ -0,0 +1,31 @@
+# Makefile for testing purposes, will build helloWriter_OOP_mpi (make or make mpi) or helloWriter_OOP_nompi (make nompi) 
+# Created on: Oct 4, 2016
+#     Author: wfg
+
+BASE_NAME=helloBPReader
+
+#COMPILERS
+CC=g++
+MPICC=mpic++
+
+#ADIOS LOCATION
+ADIOS_DIR=../../..
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -std=c++11 -O0 -g
+LDFLAGS=
+
+all: mpi nompi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $(BASE_NAME).cpp -o $(BASE_NAME).exe $(ADIOS_LIB) $(LDFLAGS) -lpthread
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME)_nompi.cpp -o $(BASE_NAME)_nompi.exe $(ADIOS_NOMPI_LIB) $(LDFLAGS) -lpthread
+
+clean:
+	rm *.exe
+     
\ No newline at end of file
diff --git a/examples/hello/bpReader/helloBPReader.cpp b/examples/hello/bpReader/helloBPReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bb1bc35d9134b8fbe4bf5131aea99ff820e7a31c
--- /dev/null
+++ b/examples/hello/bpReader/helloBPReader.cpp
@@ -0,0 +1,71 @@
+/*
+ * helloWriter.cpp
+ *
+ *  Created on: Feb 16, 2017
+ *      Author: wfg
+ */
+
+
+
+#include <vector>
+#include <iostream>
+
+
+#include <mpi.h>
+
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    const bool adiosDebug = true;
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    try
+    {
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpReaderSettings = adios.DeclareMethod( "SingleFile" ); //default method type is BPWriter
+        bpReaderSettings.AddTransport( "File" ); //uses default POSIX library
+
+        //Create engine smart pointer due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        auto bpReader = adios.Open( "myDoubles_nompi.bp", "r", bpReaderSettings );
+
+        if( bpReader == nullptr )
+            throw std::ios_base::failure( "ERROR: couldn't create bpReader at Open\n" );
+
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
diff --git a/examples/hello/bpReader/helloBPReader_nompi.cpp b/examples/hello/bpReader/helloBPReader_nompi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b5e437deabafc50c5e8ec80c7d0010fb10bb6f27
--- /dev/null
+++ b/examples/hello/bpReader/helloBPReader_nompi.cpp
@@ -0,0 +1,52 @@
+/*
+ * helloADIOSNoXML_OOP.cpp
+ *
+ *  Created on: Jan 9, 2017
+ *      Author: wfg
+ */
+
+#include <vector>
+#include <iostream>
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    const bool adiosDebug = true;
+    adios::ADIOS adios( adiosDebug );
+
+    try
+    {
+    	//Define method for engine creation, it is basically straight-forward parameters
+    	adios::Method& bpReaderSettings = adios.DeclareMethod( "SingleFile" ); //default method type is BPWriter/BPReader
+    	bpReaderSettings.AddTransport( "File" ); //uses default POSIX library
+
+    	//Create engine smart pointer due to polymorphism,
+    	//Open returns a smart pointer to Engine containing the Derived class Writer
+    	auto bpReader = adios.Open( "myDoubles.bp", "r", bpReaderSettings );
+
+    	if( bpReader == nullptr )
+    		throw std::ios_base::failure( "ERROR: couldn't create bpReader at Open\n" );
+    }
+    catch( std::invalid_argument& e )
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::ios_base::failure& e )
+    {
+        std::cout << "System exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        std::cout << "Exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+
+    return 0;
+}
+
+
+
diff --git a/examples/hello/bpWriter/Makefile b/examples/hello/bpWriter/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..215bdf5e6d89f8efe944762a7afcd28e74a3029b
--- /dev/null
+++ b/examples/hello/bpWriter/Makefile
@@ -0,0 +1,31 @@
+# Makefile for testing purposes, will build helloWriter_OOP_mpi (make or make mpi) or helloWriter_OOP_nompi (make nompi) 
+# Created on: Oct 4, 2016
+#     Author: wfg
+
+BASE_NAME=helloBPWriter
+
+#COMPILERS
+CC=g++
+MPICC=mpic++
+
+#ADIOS LOCATION
+ADIOS_DIR=../../..
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -std=c++11 -O0 -g
+LDFLAGS=
+
+all: mpi nompi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME).cpp -o $(BASE_NAME).exe $(ADIOS_LIB) $(LDFLAGS) -lpthread
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) -DADIOS_NOMPI $(BASE_NAME)_nompi.cpp -o $(BASE_NAME)_nompi.exe $(ADIOS_NOMPI_LIB) $(LDFLAGS) -lpthread
+
+clean:
+	rm *.exe
+     
\ No newline at end of file
diff --git a/examples/hello/bpWriter/helloBPWriter.cpp b/examples/hello/bpWriter/helloBPWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..063dae3e1651558c9eb0f77e2272637faf2afe96
--- /dev/null
+++ b/examples/hello/bpWriter/helloBPWriter.cpp
@@ -0,0 +1,106 @@
+/*
+ * helloWriter.cpp
+ *
+ *  Created on: Feb 16, 2017
+ *      Author: wfg
+ */
+
+
+
+#include <vector>
+#include <iostream>
+
+
+#include <mpi.h>
+
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    const bool adiosDebug = true;
+    adios::ADIOS adios( MPI_COMM_WORLD, adios::Verbose::INFO, adiosDebug );
+
+    //Application variable
+    std::vector<double> myDoubles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    const std::size_t rows = 3;
+    const std::size_t columns = 3;
+
+    std::vector<float> myMatrix;
+    if( rank % 2 == 0 ) //even rank
+    {
+        myMatrix.reserve( rows * columns );
+        myMatrix.push_back( 1 ); myMatrix.push_back( 2 ), myMatrix.push_back( 3 );
+        myMatrix.push_back( 4 ); myMatrix.push_back( 5 ), myMatrix.push_back( 6 );
+        myMatrix.push_back( 7 ); myMatrix.push_back( 8 ), myMatrix.push_back( 8 );
+    }
+
+    std::vector<float> myMatrix2 = { -1, -2, -3,
+                                     -4, -5, -6,
+                                     -7, -8, -9 };
+
+    try
+    {
+        //Define variable and local size
+        adios::Variable<double>& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", {Nx} );
+        adios::Variable<float>& ioMyMatrix = adios.DefineVariable<float>( "myMatrix", {rows,columns} );
+        adios::Variable<float>& ioMyMatrix2 = adios.DefineVariable<float>( "myMatrix2", {rows,columns} );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpWriterSettings = adios.DeclareMethod( "SingleFile" ); //default method type is BPWriter
+        bpWriterSettings.SetParameters( "profile_units=mus" );
+        bpWriterSettings.AddTransport( "File", "profile_units=mus", "have_metadata_file=no" ); //uses default POSIX library
+
+        //Create engine smart pointer due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        auto bpWriter = adios.Open( "myDoubles.bp", "w", bpWriterSettings, adios::IOMode::COLLECTIVE );
+
+        if( bpWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: couldn't create bpWriter at Open\n" );
+
+        bpWriter->Write<double>( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+
+        if( rank % 2 == 0 ) //even rank
+        {
+            bpWriter->Write<float>( ioMyMatrix, myMatrix.data() );
+            bpWriter->Write<float>( ioMyMatrix2, myMatrix2.data() );
+        }
+
+        bpWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
diff --git a/examples/hello/bpWriter/helloBPWriter_nompi.cpp b/examples/hello/bpWriter/helloBPWriter_nompi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c78fd08785a2ccfdcd6b0c97615c31de80a7739f
--- /dev/null
+++ b/examples/hello/bpWriter/helloBPWriter_nompi.cpp
@@ -0,0 +1,80 @@
+/*
+ * helloADIOSNoXML_OOP.cpp
+ *
+ *  Created on: Jan 9, 2017
+ *      Author: wfg
+ */
+
+#include <vector>
+#include <iostream>
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+ {
+    const bool adiosDebug = true;
+    adios::ADIOS adios( adiosDebug );
+
+    //Application variable
+    std::vector<double> myDoubles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    const std::size_t rows = 3;
+    const std::size_t columns = 3;
+    std::vector<float> myMatrix = { 1, 2, 3,
+                                    4, 5, 6,
+                                    7, 8, 9 };
+
+    std::vector<float> myMatrix2 = { -1, -2, -3,
+                                     -4, -5, -6,
+                                     -7, -8, -9 };
+
+    try
+    {
+        //Define variable and local size
+        adios::Variable<double>& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", adios::Dims{Nx} );
+        adios::Variable<float>& ioMyMatrix = adios.DefineVariable<float>( "myMatrix", adios::Dims{rows,columns} );
+        adios::Variable<float>& ioMyMatrix2 = adios.DefineVariable<float>( "myMatrix2", adios::Dims{rows,columns} );
+        adios::Variable<float>& ioMyMatrix3 = adios.DefineVariable<float>( "myMatrix3", adios::Dims{rows,columns} );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpWriterSettings = adios.DeclareMethod( "SinglePOSIXFile" ); //default method type is Writer
+        bpWriterSettings.SetParameters( "profile_units=mus" );
+        bpWriterSettings.AddTransport( "File", "have_metadata_file=yes", "profile_units=mus" );
+
+        //Create engine smart pointer due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        auto bpFileWriter = adios.Open( "myDoubles_nompi.bp", "w", bpWriterSettings, adios::IOMode::COLLECTIVE );
+
+        if( bpFileWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: couldn't create bpWriter at Open\n" );
+
+        bpFileWriter->Write<double>( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+        bpFileWriter->Write<float>( ioMyMatrix, myMatrix.data() ); //2d Example
+        bpFileWriter->Write<float>( ioMyMatrix2, myMatrix2.data() ); //2d Example
+        bpFileWriter->Write<float>( ioMyMatrix3, myMatrix2.data() ); //2d Example
+        bpFileWriter->Close( );
+        //
+    }
+    catch( std::invalid_argument& e )
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::ios_base::failure& e )
+    {
+        std::cout << "System exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        std::cout << "Exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+
+    return 0;
+}
+
+
+
diff --git a/examples/hello/compound/Makefile b/examples/hello/compound/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..60eac201256d193410cbf9e4bf74fff50ebad6ac
--- /dev/null
+++ b/examples/hello/compound/Makefile
@@ -0,0 +1,31 @@
+# Makefile for testing purposes, will build helloWriter_OOP_mpi (make or make mpi) or helloWriter_OOP_nompi (make nompi) 
+# Created on: Oct 4, 2016
+#     Author: wfg
+
+BASE_NAME=helloCompound
+
+#COMPILERS
+CC=g++
+MPICC=mpic++
+
+#ADIOS LOCATION
+ADIOS_DIR=../../..
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -std=c++11 -O0 -g
+LDFLAGS=
+
+all: mpi nompi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $(BASE_NAME).cpp -o $(BASE_NAME).exe $(ADIOS_LIB) $(LDFLAGS) -lpthread
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME)_nompi.cpp -o $(BASE_NAME)_nompi.exe $(ADIOS_NOMPI_LIB) $(LDFLAGS) -lpthread
+
+clean:
+	rm *.exe
+     
\ No newline at end of file
diff --git a/examples/hello/compound/helloCompound.cpp b/examples/hello/compound/helloCompound.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c34e3f5b43961b5f2102b7095827b9c2ca906b4b
--- /dev/null
+++ b/examples/hello/compound/helloCompound.cpp
@@ -0,0 +1,104 @@
+/*
+ * helloCompound.cpp
+ *
+ *  Created on: Feb 20, 2017
+ *      Author: wfg
+ */
+
+#include <vector>
+#include <iostream>
+#include <cstddef>  // offsetof
+
+
+#include <mpi.h>
+
+
+#include "ADIOS_CPP.h"
+
+
+struct Particle
+{
+    char Type[10];  ///< alpha, beta, gamma, etc.
+    double Position[3];  ///< x, y, z
+    double Velocity[3];  ///< Vx, Vy, Vz
+};
+
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    const bool adiosDebug = true;
+    adios::ADIOS adios( MPI_COMM_WORLD, adiosDebug );
+
+    //Application variable
+    std::vector<double> myDoubles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    Particle myParticle;
+    sprintf( myParticle.Type, "%s", "photon" );
+    myParticle.Position[0] = 0;
+    myParticle.Position[1] = 1;
+    myParticle.Position[2] = 2;
+
+    myParticle.Velocity[0] = 10;
+    myParticle.Velocity[1] = 11;
+    myParticle.Velocity[2] = 12;
+
+    try
+    {
+        //Define variable and local size
+        adios::Variable<double>& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", adios::Dims{Nx} );
+
+        adios::VariableCompound& ioMyParticle = adios.DefineVariableCompound<Particle>( "myParticle", adios::Dims{1} );
+        ioMyParticle.InsertMember<std::string>( "Type", offsetof(Particle,Type) );
+        ioMyParticle.InsertMember<std::vector<double>>( "Position", offsetof(Particle,Position) );
+        ioMyParticle.InsertMember<std::vector<double>>( "Velocity", offsetof(Particle,Velocity) );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpWriterSettings = adios.DeclareMethod( "SingleFile" ); //default method type is BPWriter
+        bpWriterSettings.AddTransport( "File", "have_metadata_file=yes" ); //uses default POSIX library
+
+        //Create engine smart pointer due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        auto bpWriter = adios.Open( "myDoubles.bp", "w", bpWriterSettings );
+
+        if( bpWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: couldn't create bpWriter at Open\n" );
+
+        bpWriter->Write( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+        bpWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
+
+
diff --git a/examples/hello/compound/helloCompound_nompi.cpp b/examples/hello/compound/helloCompound_nompi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1bb0cb1a959677c05a47b37addf18a350522169d
--- /dev/null
+++ b/examples/hello/compound/helloCompound_nompi.cpp
@@ -0,0 +1,87 @@
+/*
+ * helloCompound.cpp
+ *
+ *  Created on: Feb 20, 2017
+ *      Author: wfg
+ */
+
+#include <vector>
+#include <iostream>
+#include <cstddef>  // offsetof
+#include <cstdio>
+
+#include "ADIOS_CPP.h"
+
+
+struct Particle
+{
+    char Type[10];  ///< alpha, beta, gamma, etc.
+    double Position[3];  ///< x, y, z
+    double Velocity[3];  ///< Vx, Vy, Vz
+};
+
+
+int main( int argc, char* argv [] )
+{
+    const bool adiosDebug = true;
+    adios::ADIOS adios( adiosDebug );
+
+    //Application variable
+    std::vector<double> myDoubles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    Particle myParticle;
+    sprintf( myParticle.Type, "%s", "photon" );
+    myParticle.Position[0] = 0;
+    myParticle.Position[1] = 1;
+    myParticle.Position[2] = 2;
+
+    myParticle.Velocity[0] = 10;
+    myParticle.Velocity[1] = 11;
+    myParticle.Velocity[2] = 12;
+
+    try
+    {
+        //Define variable and local size
+        adios::Variable<double>& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", adios::Dims{Nx} );
+
+        adios::VariableCompound& ioMyParticle = adios.DefineVariableCompound<Particle>( "myParticle" );
+        ioMyParticle.InsertMember<char>( "Type", offsetof(Particle,Type) );
+        ioMyParticle.InsertMember<double>( "Position", offsetof(Particle,Position) );
+        ioMyParticle.InsertMember<double>( "Velocity", offsetof(Particle,Velocity) );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpWriterSettings = adios.DeclareMethod( "SingleFile" ); //default method type is BPWriter
+        bpWriterSettings.AddTransport( "File", "have_metadata_file=yes" ); //uses default POSIX library
+
+        //Create engine smart pointer due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        auto bpWriter = adios.Open( "myDoubles.bp", "w", bpWriterSettings );
+
+        if( bpWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: couldn't create bpWriter at Open\n" );
+
+        bpWriter->Write( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+        bpWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::ios_base::failure& e )
+    {
+        std::cout << "System exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        std::cout << "Exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+
+    return 0;
+
+}
+
+
diff --git a/examples/hello/datamanReader/Makefile b/examples/hello/datamanReader/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..3a5d6007d5ea33aaaf29ab8e23949110dce3c984
--- /dev/null
+++ b/examples/hello/datamanReader/Makefile
@@ -0,0 +1,44 @@
+# Makefile for testing purposes, will build libadios.a 
+# Created on: Oct 4, 2016
+#     Author: wfg
+
+
+BASE_NAME=helloDataManReader
+
+CC=g++ # Compiling with defaults
+MPICC=mpic++
+INC=
+LIB=
+LIB_NOMPI=
+
+#ADIOS
+ADIOS_DIR=../../..
+LIB+= $(ADIOS_DIR)/lib/libadios.a
+LIB_NOMPI+= $(ADIOS_DIR)/lib/libadios_nompi.a
+INC+= -I$(ADIOS_DIR)/include
+
+#DATAMAN
+DATAMAN_LOC=/Users/w4g/Dropbox/lib/DataMan
+INC+= -I$(DATAMAN_LOC)/include
+LIB+= -L$(DATAMAN_LOC)/lib -ldataman # -lcacheman -lstreamman -lzmqman
+LIB_NOMPI+= -L$(DATAMAN_LOC)/lib -ldataman
+
+#COMPILER FLAGS
+CFLAGS=-Wall -O0 -g -Wpedantic -std=c++11
+
+#SYSTEM LIBS
+LIB+= -lpthread
+LIB_NOMPI+= -ldl -lpthread
+
+
+all: mpi nompi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(INC) $(BASE_NAME).cpp -o $(BASE_NAME).exe $(LIB)
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(INC) -DADIOS_NOMPI $(BASE_NAME)_nompi.cpp -o $(BASE_NAME)_nompi.exe $(LIB_NOMPI)
+
+clean:
+	rm *.exe;
+     
diff --git a/examples/hello/datamanReader/helloDataManReader.cpp b/examples/hello/datamanReader/helloDataManReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..44c597fac60393711b9add221229dfbc42bcc41c
--- /dev/null
+++ b/examples/hello/datamanReader/helloDataManReader.cpp
@@ -0,0 +1,101 @@
+/*
+ * helloDataManReader.cpp
+ *
+ *  Created on: Feb 16, 2017
+ *      Author: wfg
+ */
+
+
+
+#include <vector>
+#include <iostream> //std::cout, std::endl
+#include <string>
+#include <numeric> //std::accumulate
+#include <functional> //std::multiplies
+
+
+#include <mpi.h>
+
+
+#include "ADIOS_CPP.h"
+
+void getcb( const void *data, std::string doid, std::string var, std::string dtype, std::vector<std::size_t> varshape )
+{
+    std::cout << "data object ID = " << doid << "\n"; //do you need to flush?
+    std::cout << "variable name = " << var << "\n";
+    std::cout << "data type = " << dtype << "\n";
+
+    std::size_t varsize = std::accumulate(varshape.begin(), varshape.end(), 1, std::multiplies<std::size_t>());
+
+    for( unsigned int i=0; i < varsize; ++i )
+        std::cout << ((float*)data)[i] << " ";
+    std::cout << std::endl;
+}
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    const bool adiosDebug = true;
+    adios::ADIOS adios( MPI_COMM_WORLD, adios::Verbose::WARN, adiosDebug );
+
+    try
+    {
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& datamanSettings = adios.DeclareMethod( "WAN" );
+        if( ! datamanSettings.isUserDefined())
+        {
+            // if not defined by user, we can change the default settings
+            datamanSettings.SetEngine( "DataManReader" );
+            datamanSettings.SetParameters( "peer-to-peer=yes" );
+            datamanSettings.AddTransport( "Mdtm", "localIP=128.0.0.0.1", "remoteIP=128.0.0.0.2", "tolerances=1,2,3" );
+            //datamanSettings.AddTransport( "ZeroMQ", "localIP=128.0.0.0.1.1", "remoteIP=128.0.0.0.2.1", "tolerances=1,2,3" ); not yet supported , will throw an exception
+        }
+
+        //Create engine smart pointer to DataManReader Engine due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class DataManReader
+        auto datamanReader = adios.Open( "myDoubles.bp", "r", datamanSettings, adios::IOMode::INDEPENDENT );
+
+        if( datamanReader == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to create DataMan I/O engine at Open\n" );
+
+        datamanReader->SetCallBack( getcb );
+
+        adios::Variable<double>* ioMyDoubles = datamanReader->InquireVariableDouble( "ioMyDoubles" );
+        if( ioMyDoubles == nullptr )
+            std::cout << "Variable ioMyDoubles not read...yet\n";
+
+        datamanReader->Close( );
+
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
diff --git a/examples/hello/datamanReader/helloDataManReader_nompi.cpp b/examples/hello/datamanReader/helloDataManReader_nompi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..56e3ba1ae9465651f25990a6909bc3495a5e7fa0
--- /dev/null
+++ b/examples/hello/datamanReader/helloDataManReader_nompi.cpp
@@ -0,0 +1,82 @@
+/*
+ * helloADIOSNoXML_OOP.cpp
+ *
+ *  Created on: Jan 9, 2017
+ *      Author: wfg
+ */
+
+#include <vector>
+#include <iostream>
+#include <numeric>
+
+#include "ADIOS_CPP.h"
+
+void getcb( const void *data, std::string doid, std::string var, std::string dtype, std::vector<std::size_t> varshape )
+{
+    std::cout << "data object ID = " << doid << "\n"; //do you need to flush?
+    std::cout << "variable name = " << var << "\n";
+    std::cout << "data type = " << dtype << "\n";
+
+    std::size_t varsize = std::accumulate(varshape.begin(), varshape.end(), 1, std::multiplies<std::size_t>());
+
+    for( unsigned int i=0; i < varsize; ++i )
+        std::cout << ((float*)data)[i] << " ";
+    std::cout << std::endl;
+}
+
+int main( int argc, char* argv [] )
+{
+    const bool adiosDebug = true;
+    adios::ADIOS adios( adios::Verbose::WARN, adiosDebug );
+
+    try
+    {
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& datamanSettings = adios.DeclareMethod( "WAN" );
+        if( ! datamanSettings.isUserDefined())
+        {
+            // if not defined by user, we can change the default settings
+            datamanSettings.SetEngine( "DataManReader" );
+            datamanSettings.SetParameters( "real_time=yes", "method_type=stream", "method=zmq", "local_ip=127.0.0.1", "remote_ip=127.0.0.1", "local_port=12307", "remote_port=12306" );
+            //datamanSettings.AddTransport( "Mdtm", "localIP=128.0.0.0.1", "remoteIP=128.0.0.0.2", "tolerances=1,2,3" );
+            //datamanSettings.AddTransport( "ZeroMQ", "localIP=128.0.0.0.1.1", "remoteIP=128.0.0.0.2.1", "tolerances=1,2,3" ); not yet supported , will throw an exception
+        }
+
+        //Create engine smart pointer to DataManReader Engine due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class DataManReader
+        auto datamanReader = adios.Open( "myDoubles.bp", "r", datamanSettings, adios::IOMode::INDEPENDENT );
+
+        if( datamanReader == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to create DataMan I/O engine at Open\n" );
+
+        datamanReader->SetCallBack( getcb );
+
+        while(1){}
+
+        adios::Variable<double>* ioMyDoubles = datamanReader->InquireVariableDouble( "ioMyDoubles" );
+        if( ioMyDoubles == nullptr )
+            std::cout << "Variable ioMyDoubles not read...yet\n";
+
+        datamanReader->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::ios_base::failure& e )
+    {
+        std::cout << "System exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        std::cout << "Exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+
+    return 0;
+}
+
+
+
diff --git a/examples/hello/datamanWriter/Makefile b/examples/hello/datamanWriter/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..45f28cd17eed3abf2e4ee643f5de303f74210cd5
--- /dev/null
+++ b/examples/hello/datamanWriter/Makefile
@@ -0,0 +1,44 @@
+# Makefile for testing purposes, will build libadios.a 
+# Created on: Oct 4, 2016
+#     Author: wfg
+
+
+BASE_NAME=helloDataManWriter
+
+CC=g++ # Compiling with defaults
+MPICC=mpic++
+INC=
+LIB=
+LIB_NOMPI=
+
+#ADIOS
+ADIOS_DIR=../../..
+LIB+= $(ADIOS_DIR)/lib/libadios.a
+LIB_NOMPI+= $(ADIOS_DIR)/lib/libadios_nompi.a
+INC+= -I$(ADIOS_DIR)/include
+
+#DATAMAN
+DATAMAN_LOC=/Users/w4g/Dropbox/lib/DataMan
+INC+= -I$(DATAMAN_LOC)/include
+LIB+= -L$(DATAMAN_LOC)/lib -ldataman # -lcacheman -lstreamman -lzmqman
+LIB_NOMPI+= -L$(DATAMAN_LOC)/lib -ldataman # -lcacheman -lstreamman -lzmqman
+
+#COMPILER FLAGS
+CFLAGS=-Wall -O0 -g -Wpedantic -std=c++11
+
+#SYSTEM LIBS
+LIB+= -lpthread
+LIB_NOMPI+= -ldl -lpthread 
+
+
+all: mpi nompi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(INC) $(BASE_NAME).cpp -o $(BASE_NAME).exe $(LIB)
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(INC) -DADIOS_NOMPI $(BASE_NAME)_nompi.cpp -o $(BASE_NAME)_nompi.exe $(LIB_NOMPI)
+
+clean:
+	rm *.exe;
+     
diff --git a/examples/hello/datamanWriter/helloDataManWriter.cpp b/examples/hello/datamanWriter/helloDataManWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..942fdf11e3f1ff3f26c0e48c59ce4b11c6e55d3a
--- /dev/null
+++ b/examples/hello/datamanWriter/helloDataManWriter.cpp
@@ -0,0 +1,103 @@
+/*
+ * helloWriter.cpp
+ *
+ *  Created on: Feb 16, 2017
+ *      Author: wfg
+ */
+
+
+
+#include <vector>
+#include <iostream>
+
+
+#include <mpi.h>
+
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    const bool adiosDebug = true;
+    adios::ADIOS adios( MPI_COMM_WORLD, adios::Verbose::WARN, adiosDebug );
+
+    //Application variable
+    std::vector<double> myDoubles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    std::vector<std::complex<float>> myCFloats;
+    myCFloats.reserve( 3 );
+    myCFloats.emplace_back( 1, 3 );
+    myCFloats.emplace_back( 2, 2 );
+    myCFloats.emplace_back( 3, 1 );
+
+    try
+    {
+        //Define variable and local size
+        auto ioMyDoubles = adios.DefineVariable<double>( "myDoubles", {Nx} );
+        auto ioMyCFloats = adios.DefineVariable<std::complex<float>>( "myCFloats", {3} );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& datamanSettings = adios.DeclareMethod( "WAN" );
+        if( ! datamanSettings.isUserDefined())
+        {
+            // if not defined by user, we can change the default settings
+            datamanSettings.SetEngine("DatamanWriter");
+            datamanSettings.SetParameters( "peer-to-peer=yes", "real_time=yes", "compress=no" );
+            datamanSettings.AddTransport( "Mdtm", "localIP=128.0.0.0.1", "remoteIP=128.0.0.0.2", "tolerances=1,2,3" );
+            //datamanSettings.AddTransport( "file", "name=myfile.bp", "remoteIP=128.0.0.0.2", "tolerances=1,2,3" );
+            //datamanSettings.AddTransport( "file", "name=myfile.bp", "remoteIP=128.0.0.0.2", "tolerances=1,2,3" );
+            //datamanSettings.AddTransport( "Mdtm", "localIP=128.0.0.0.1", "remoteIP=128.0.0.0.2", "tolerances=1,2,3" );
+            //datamanSettings.AddTransport( "ZeroMQ", "localIP=128.0.0.0.1", "remoteIP=128.0.0.0.2", "tolerances=1,2,3" );
+            //datamanSettings.AddTransport( "ZeroMQ", "localIP=128.0.0.0.1.1", "remoteIP=128.0.0.0.2.1", "tolerances=1,2,3" ); not yet supported, will throw an exception
+        }
+
+        //Create engine smart pointer to DataMan Engine due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class DataMan
+
+        //adios::DataManWriter datamanWriter;
+
+        auto datamanWriter = adios.Open( "myDoubles.bp", "w", datamanSettings, adios::IOMode::INDEPENDENT );
+
+        if( datamanWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to create DataMan I/O engine at Open\n" );
+
+        datamanWriter->Write<double>( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+        datamanWriter->Write<std::complex<float>>( ioMyCFloats, myCFloats.data() );
+        datamanWriter->Close( );
+
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
diff --git a/examples/hello/datamanWriter/helloDataManWriter_nompi.cpp b/examples/hello/datamanWriter/helloDataManWriter_nompi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e9bec44d83101ddadc3ce50085925f8d17a304bb
--- /dev/null
+++ b/examples/hello/datamanWriter/helloDataManWriter_nompi.cpp
@@ -0,0 +1,83 @@
+/*
+ * helloADIOSNoXML_OOP.cpp
+ *
+ *  Created on: Jan 9, 2017
+ *      Author: wfg
+ */
+
+#include <vector>
+#include <iostream>
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    const bool adiosDebug = true;
+    adios::ADIOS adios( adios::Verbose::WARN, adiosDebug );
+
+    //Application variable
+    std::vector<float> myFloats = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    std::vector<double> myDoubles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    std::vector<std::complex<float>> myCFloats;
+    myCFloats.reserve( 3 );
+    myCFloats.emplace_back( 1, 3 );
+    myCFloats.emplace_back( 2, 2 );
+    myCFloats.emplace_back( 3, 1 );
+
+    try
+    {
+        //Define variable and local size
+        //Define variable and local size
+        auto ioMyFloats = adios.DefineVariable<float>( "myfloats", adios::Dims{Nx} );
+        auto ioMyFloat = adios.DefineVariable<float>( "myfloat", adios::Dims{1} );
+//        auto& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", adios::Dims{Nx} );
+//        auto& ioMyCFloats = adios.DefineVariable<std::complex<float>>( "myCFloats", {3} );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& datamanSettings = adios.DeclareMethod( "WAN" );
+        if( ! datamanSettings.isUserDefined())
+        {
+            // if not defined by user, we can change the default settings
+            datamanSettings.SetEngine( "DataManWriter" );
+            datamanSettings.SetParameters( "real_time=yes", "method_type=stream", "method=dump", "monitoring=yes", "local_ip=127.0.0.1", "remote_ip=127.0.0.1", "local_port=12306", "remote_port=12307" );
+            //datamanSettings.AddTransport( "Mdtm", "localIP=128.0.0.0.1", "remoteIP=128.0.0.0.2", "tolerances=1,2,3" );
+            //datamanSettings.AddTransport( "ZeroMQ", "localIP=128.0.0.0.1.1", "remoteIP=128.0.0.0.2.1", "tolerances=1,2,3" ); not yet supported , will throw an exception
+        }
+
+        //Create engine smart pointer to DataMan Engine due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class DataMan
+        auto datamanWriter = adios.Open( "myDoubles.bp", "w", datamanSettings, adios::IOMode::INDEPENDENT );
+
+        if( datamanWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: failed to create DataMan I/O engine at Open\n" );
+
+        datamanWriter->Write<float>( ioMyFloats, myFloats.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+        const float num = 1.12;
+        datamanWriter->Write<float>( ioMyFloat, &num ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+//        datamanWriter->Write( ioMyCFloats, myCFloats.data() );
+        datamanWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::ios_base::failure& e )
+    {
+        std::cout << "System exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        std::cout << "Exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+
+    return 0;
+}
+
+
+
diff --git a/examples/hello/fstream.xml b/examples/hello/fstream.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e46437445a1af49d4a8ee0465ea5a8762cfd430e
--- /dev/null
+++ b/examples/hello/fstream.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<adios-config host-language="C++">
+  <adios-group name="Vector">
+    <var name="size" type="unsigned int"/>
+    <var name="numbers" type="int" dimension="size"/>
+    <attribute name="description" value="1 to 10"/>
+  </adios-group>
+  
+  
+  <transform type="bzip2" >
+  </transform> 
+  
+  <!--  transport group="Types" method="FStream">verbose=3</transport> -->
+  
+  <method name="SingleFile" profile_units="mus" max_buffer_size="10000">
+  	<transport type="File" have_metadata_file="no" aggregators="10" profile_units="mus"/>
+  </method>
+  
+  <!--  <buffer size-MB="40" allocate-time="now"/> -->
+
+</adios-config>
diff --git a/examples/hello/timeBP/Makefile b/examples/hello/timeBP/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..2c80ba83ad6861ddd6ea9c6b37a57ddac58f0bb6
--- /dev/null
+++ b/examples/hello/timeBP/Makefile
@@ -0,0 +1,31 @@
+# Makefile for testing purposes, will build helloWriter_OOP_mpi (make or make mpi) or helloWriter_OOP_nompi (make nompi) 
+# Created on: Oct 4, 2016
+#     Author: wfg
+
+BASE_NAME=timeBPWriter
+
+#COMPILERS
+CC=g++
+MPICC=mpic++
+
+#ADIOS LOCATION
+ADIOS_DIR=../../..
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+#FLAGS
+CFLAGS=-Wall -Wpedantic -std=c++11 -O0 -g
+LDFLAGS=
+
+all: mpi nompi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME).cpp -o $(BASE_NAME).exe $(ADIOS_LIB) $(LDFLAGS) -lpthread
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) -DADIOS_NOMPI $(BASE_NAME)_nompi.cpp -o $(BASE_NAME)_nompi.exe $(ADIOS_NOMPI_LIB) $(LDFLAGS) -lpthread
+
+clean:
+	rm *.exe
+     
\ No newline at end of file
diff --git a/examples/hello/timeBP/test.sh b/examples/hello/timeBP/test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ef262a74c54cf2bdd7895fb273ce3516e9279667
--- /dev/null
+++ b/examples/hello/timeBP/test.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+rm -fr *.bp
+make clean
+make -j4
diff --git a/examples/hello/timeBP/timeBPWriter.cpp b/examples/hello/timeBP/timeBPWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..771a9ebecbafbed34f18aba212eb17f3192d7bb1
--- /dev/null
+++ b/examples/hello/timeBP/timeBPWriter.cpp
@@ -0,0 +1,113 @@
+/*
+ * timeBPWriter.cpp  example for time aggregation
+ *
+ *  Created on: Feb 16, 2017
+ *      Author: wfg
+ */
+
+
+#include <vector>
+#include <iostream>
+
+#include <mpi.h>
+
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+    const bool adiosDebug = true;
+    adios::ADIOS adios( MPI_COMM_WORLD, adios::Verbose::ERROR, adiosDebug );
+
+    //Application variable
+    std::vector<double> myDoubles = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    const std::size_t rows = 3;
+    const std::size_t columns = 3;
+
+    std::vector<float> myMatrix;
+    if( rank % 2 == 0 ) //even rank
+    {
+        myMatrix.reserve( rows * columns );
+        myMatrix.push_back( 1 ); myMatrix.push_back( 2 ), myMatrix.push_back( 3 );
+        myMatrix.push_back( 4 ); myMatrix.push_back( 5 ), myMatrix.push_back( 6 );
+        myMatrix.push_back( 7 ); myMatrix.push_back( 8 ), myMatrix.push_back( 8 );
+    }
+
+    std::vector<float> myMatrix2 = { -1, -2, -3,
+                                     -4, -5, -6,
+                                     -7, -8, -9 };
+
+    try
+    {
+        //Define variable and local size
+        adios::Variable<double>& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", {Nx} );
+        adios::Variable<float>& ioMyMatrix = adios.DefineVariable<float>( "myMatrix", {rows,columns} );
+        adios::Variable<float>& ioMyMatrix2 = adios.DefineVariable<float>( "myMatrix2", {rows,columns} );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpWriterSettings = adios.DeclareMethod( "MyMethod" ); //default method type is BPWriter
+        bpWriterSettings.SetParameters( "profile_units=mus" );
+        bpWriterSettings.AddTransport( "File", "profile_units=mus", "have_metadata_file=no" ); //uses default POSIX library
+
+        //Create engine smart pointer due to polymorphism,
+        //Open returns a smart pointer to Engine containing the Derived class Writer
+        auto bpWriter = adios.Open( "time.bp", "w", bpWriterSettings );
+
+        if( bpWriter == nullptr )
+            throw std::ios_base::failure( "ERROR: couldn't create bpWriter at Open\n" );
+
+
+        for( unsigned int t = 0; t < 10; ++t )
+        {
+            myDoubles[0] = t;
+            bpWriter->Write<double>( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+
+            if( rank % 2 == 0 ) //even rank
+            {
+                myMatrix[0] = t;
+                myMatrix2[0] = t;
+
+                bpWriter->Write<float>( ioMyMatrix, myMatrix.data() );
+                bpWriter->Write<float>( ioMyMatrix2, myMatrix2.data() );
+            }
+            bpWriter->Advance();
+        }
+
+        bpWriter->Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::ios_base::failure& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "System exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "Exception, STOPPING PROGRAM\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+
+    return 0;
+
+}
diff --git a/examples/hello/timeBP/timeBPWriter_nompi.cpp b/examples/hello/timeBP/timeBPWriter_nompi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d85a1b523be4b929242df7c102aa9dd647d38327
--- /dev/null
+++ b/examples/hello/timeBP/timeBPWriter_nompi.cpp
@@ -0,0 +1,86 @@
+/*
+ * timeBPWriter.cpp  example for time aggregation
+ *
+ *  Created on: Feb 16, 2017
+ *      Author: wfg
+ */
+
+
+#include <vector>
+#include <iostream>
+
+#include "ADIOS_CPP.h"
+
+
+int main( int argc, char* argv [] )
+{
+    const bool adiosDebug = true;
+    adios::ADIOS adios( adios::Verbose::ERROR, adiosDebug );
+
+    //Application variable
+    std::vector<double> myDoubles = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    const std::size_t Nx = myDoubles.size();
+
+    const std::size_t rows = 3;
+    const std::size_t columns = 3;
+
+    std::vector<float> myMatrix;
+    myMatrix.reserve( rows * columns );
+    myMatrix.push_back( 1 ); myMatrix.push_back( 2 ), myMatrix.push_back( 3 );
+    myMatrix.push_back( 4 ); myMatrix.push_back( 5 ), myMatrix.push_back( 6 );
+    myMatrix.push_back( 7 ); myMatrix.push_back( 8 ), myMatrix.push_back( 8 );
+
+
+    std::vector<float> myMatrix2 = { -1, -2, -3,
+                                     -4, -5, -6,
+                                     -7, -8, -9 };
+
+    try
+    {
+        //Define variable and local size
+        adios::Variable<double>& ioMyDoubles = adios.DefineVariable<double>( "myDoubles", {Nx} );
+        adios::Variable<float>& ioMyMatrix = adios.DefineVariable<float>( "myMatrix", {rows,columns} );
+        adios::Variable<float>& ioMyMatrix2 = adios.DefineVariable<float>( "myMatrix2", {rows,columns} );
+
+        //Define method for engine creation, it is basically straight-forward parameters
+        adios::Method& bpWriterSettings = adios.DeclareMethod( "SingleFile" ); //default method type is BPWriter
+        bpWriterSettings.SetParameters( "profile_units=mus" );
+        bpWriterSettings.AddTransport( "File", "profile_units=mus", "have_metadata_file=no" ); //uses default POSIX library
+
+        //Create object directly rather than using polymorphism with ADIOS.Open
+        adios::BPFileWriter bpWriter( adios, "time_nompi.bp", "w", adios.m_MPIComm, bpWriterSettings );
+
+        for( unsigned int t = 0; t < 3; ++t )
+        {
+            myDoubles[0] = t; // t * -1;
+            myMatrix[0] = t;
+            myMatrix2[0] = t;
+
+            bpWriter.Write( ioMyDoubles, myDoubles.data() ); // Base class Engine own the Write<T> that will call overloaded Write from Derived
+            bpWriter.Write( ioMyMatrix, myMatrix.data() );
+            bpWriter.Write( ioMyMatrix2, myMatrix2.data() );
+            bpWriter.Advance();
+        }
+
+        bpWriter.Close( );
+    }
+    catch( std::invalid_argument& e )
+    {
+        std::cout << "Invalid argument exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+
+    }
+    catch( std::ios_base::failure& e )
+    {
+        std::cout << "System exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        std::cout << "Exception, STOPPING PROGRAM\n";
+        std::cout << e.what() << "\n";
+    }
+
+    return 0;
+
+}
diff --git a/examples/hello/writer.xml b/examples/hello/writer.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3a467ddc39c54a042e4e8e18e037d7dbb0ca43dc
--- /dev/null
+++ b/examples/hello/writer.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<adios-config host-language="Fortran">
+  <adios-group name="writer2D">
+
+    <var name="nproc" path="/info" type="integer"/>
+    <attribute name="description" path="/info/nproc" value="Number of writers"/>
+    <var name="npx"   path="/info" type="integer"/>
+    <attribute name="description" path="/info/npx" value="Number of processors in x dimension"/>
+    <var name="npy"   path="/info" type="integer"/>
+    <attribute name="description" path="/info/npy" value="Number of processors in y dimension"/>
+
+    <var name="gdx"  type="integer"/>
+    <attribute name="description" path="/gdx" value="Global array size in x dimension"/>
+    <var name="gdy"  type="integer"/>
+    <attribute name="description" path="/gdy" value="Global array size in y dimension"/>
+
+    <!-- Auxiliary variables for global array indexing written (overwritten) by each process -->
+    <var name="ox"   type="integer"/>
+    <var name="oy"   type="integer"/>
+    <var name="ldx"  type="integer"/>
+    <var name="ldy"  type="integer"/>
+
+    <!-- 2D array to write with block,block decomposition -->
+    <global-bounds dimensions="gdx,gdy" offsets="ox,oy">
+        <var name="xy" type="double" dimensions="ldx,ldy"/>
+    </global-bounds>
+    <attribute name="description" path="/xy" 
+               value="2D array with 2D decomposition"/>
+
+  </adios-group>
+
+  <!-- Use transport method 
+       DATASPACES for staging data in memory coupling or
+       FLEXPATH   for socket based staging between applications
+       MPI        for file-based coupling
+  -->
+  <!--transport group="writer2D" method="MPI">verbose=2</transport-->
+  <!--transport group="writer2D" method="DATASPACES">verbose=3</transport-->
+  <transport group="writer2D" method="DIMES">verbose=3</transport>
+  <!--transport group="writer2D" method="FLEXPATH">QUEUE_SIZE=10;verbose=3</transport-->
+
+  <buffer size-MB="40" allocate-time="now"/>
+
+</adios-config>
diff --git a/examples/hello/writer2Groups.xml b/examples/hello/writer2Groups.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d019bdfdc3699c4f91e5c2c3963127e671b5d582
--- /dev/null
+++ b/examples/hello/writer2Groups.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<adios-config host-language="Fortran">
+  <adios-group name="writer2D">
+
+    <var name="nproc" path="/info" type="integer"/>
+    <attribute name="description" path="/info/nproc" value="Number of writers"/>
+    <var name="npx"   path="/info" type="integer"/>
+    <attribute name="description" path="/info/npx" value="Number of processors in x dimension"/>
+    <var name="npy"   path="/info" type="integer"/>
+    <attribute name="description" path="/info/npy" value="Number of processors in y dimension"/>
+
+    <var name="gdx"  type="integer"/>
+    <attribute name="description" path="/gdx" value="Global array size in x dimension"/>
+    <var name="gdy"  type="integer"/>
+    <attribute name="description" path="/gdy" value="Global array size in y dimension"/>
+
+    <!-- Auxiliary variables for global array indexing written (overwritten) by each process -->
+    <var name="ox"   type="integer"/>
+    <var name="oy"   type="integer"/>
+    <var name="ldx"  type="integer"/>
+    <var name="ldy"  type="integer"/>
+
+    <!-- 2D array to write with block,block decomposition -->
+    <global-bounds dimensions="gdx,gdy" offsets="ox,oy">
+        <var name="xy" type="double" dimensions="ldx,ldy"/>
+    </global-bounds>
+    <attribute name="description" path="/xy" 
+               value="2D array with 2D decomposition"/>
+
+  </adios-group>
+
+  <!-- Use transport method 
+       DATASPACES for staging data in memory coupling or
+       FLEXPATH   for socket based staging between applications
+       MPI        for file-based coupling
+  -->
+  <!--transport group="writer2D" method="MPI">verbose=2</transport-->
+  <!--transport group="writer2D" method="DATASPACES">verbose=3</transport-->
+  <transport group="writer2D" method="DIMES">verbose=3</transport>
+  <!--transport group="writer2D" method="FLEXPATH">QUEUE_SIZE=10;verbose=3</transport-->
+  <adios-group name="writer3D">
+
+    <var name="nproc" path="/info" type="integer"/>
+    <attribute name="description" path="/info/nproc" value="Number of writers"/>
+    <var name="npx"   path="/info" type="integer"/>
+    <attribute name="description" path="/info/npx" value="Number of processors in x dimension"/>
+    <var name="npy"   path="/info" type="integer"/>
+    <attribute name="description" path="/info/npy" value="Number of processors in y dimension"/>
+
+    <var name="gdx"  type="integer"/>
+    <attribute name="description" path="/gdx" value="Global array size in x dimension"/>
+    <var name="gdy"  type="integer"/>
+    <attribute name="description" path="/gdy" value="Global array size in y dimension"/>
+
+    <!-- Auxiliary variables for global array indexing written (overwritten) by each process -->
+    <var name="ox"   type="integer"/>
+    <var name="oy"   type="integer"/>
+    <var name="ldx"  type="integer"/>
+    <var name="ldy"  type="integer"/>
+
+    <!-- 2D array to write with block,block decomposition -->
+    <global-bounds dimensions="gdx,gdy" offsets="ox,oy">
+        <var name="xy" type="double" dimensions="ldx,ldy"/>
+    </global-bounds>
+    <attribute name="description" path="/xy" 
+               value="2D array with 2D decomposition"/>
+
+  </adios-group>
+
+  <buffer size-MB="40" allocate-time="now"/>
+
+</adios-config>
diff --git a/examples/solidfluid/Makefile b/examples/solidfluid/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f4acbc65533602d220cafeae1af7c57ef486e3b3
--- /dev/null
+++ b/examples/solidfluid/Makefile
@@ -0,0 +1,33 @@
+# Makefile for testing purposes, will build libadios.a 
+# Created on: Oct 31, 2016
+#     Author: pnorbert
+
+
+BASE_NAME=solidfluid_write
+
+CC=g++ # Compiling with mpicc for now
+MPICC:=mpic++
+
+#ADIOS LOCATION
+ADIOS_DIR=../..
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+
+
+#FLAGS
+CFLAGS=-Wall -O0 -g -Wpedantic -std=c++11
+
+all: mpi nompi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $(BASE_NAME).cpp -o $(BASE_NAME).exe $(ADIOS_LIB) -lpthread
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME)_nompi.cpp -o $(BASE_NAME)_nompi.exe $(ADIOS_NOMPI_LIB) -lpthread
+
+clean:
+	rm -f *.exe 
+	rm -rf *.dSYM
+     
diff --git a/examples/solidfluid/solidfluid.xml b/examples/solidfluid/solidfluid.xml
new file mode 100644
index 0000000000000000000000000000000000000000..84cb101326dffce082b2a2870e23e48a9657d7ad
--- /dev/null
+++ b/examples/solidfluid/solidfluid.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0"?>
+<adios-config host-language="C">
+
+  <!--  Changes to ADIOS-1 XML
+        Accommodate for the following extensions and flexiblity:
+        - Multiple engines e.g. SIRIUS can have it's own
+        - Do not bind one transport to a group, i.e. we can reuse a group in multiple I/O 
+          with different transports 
+        - Do not bind one group to each output file, i.e., we can write variables from
+          different groups into a single file at the same step
+   -->
+
+  <!--  Execution Engines: default-engine, sirius, dataman, hdf5
+   -->
+
+
+  <adios-group name="solid">
+    <var name="NX" type="integer"/>
+    <var name="size" type="integer"/>
+    <var name="rank" type="integer"/>
+
+    <global-bounds dimensions="size,NX" offsets="rank,0">
+       <var name="temperature" gwrite="solid.t" type="double"              dimensions="1,NX"/>
+       <var name="pressure"    gwrite="solid.p" type="std::vector<double>" dimensions="1,NX"/>
+    </global-bounds>
+
+    <attribute name="temperature/description" 
+        value="Global array written from 'size' processes over several timesteps" 
+        type="string"/>
+  </adios-group>
+
+
+  <adios-group name="fluid">
+    <var name="NX" type="integer"/>
+    <var name="size" type="integer"/>
+    <var name="rank" type="integer"/>
+
+    <global-bounds dimensions="size,NX" offsets="rank,0">
+       <var name="temperature" gwrite="fluid.t" type="double"              dimensions="1,NX"/>
+       <var name="pressure"    gwrite="fluid.p" type="std::vector<double>" dimensions="1,NX"/>
+    </global-bounds>
+
+    <attribute name="temperature/description" 
+        value="Global array written from 'size' processes over several timesteps" 
+        type="string"/>
+  </adios-group>
+
+  
+  <adios-group name="checkpoint">
+    <!-- Add all variables from group 'solid' with a path-prefix 'solid/...'
+         In adios write then one must refer to NX as "solid/NX", "solid/temperature", etc 
+         If prefix is not defined, the variables are simply merged in with their path, but
+         then there should be no name collisions  
+    -->
+    <add-group name="solid" prefix="solid"   />
+    <add-group name="fluid" prefix="fluid/"  />
+  </adios-group>
+
+
+  <!--  Method is with what we create an Output. It specifies either 
+        1. a group + a transport
+        2. a group + a data manager
+        3. a transport only 
+        4. a data manager only
+        
+        1 & 3. default manager is used
+        2 & 4. manager must have transports defined
+        3 & 4. each write needs explicit group + variable as argument
+   -->
+
+  <!--  Associate a single transport with a group. 
+        The manager will be the default manager when opening an output with this group
+        The name of the method will be the same as the group ("checkpoint") 
+        This ensures full backward-compatibility for ADIOS-1 XML files
+  -->
+  <method group="solid" transport="POSIX">options to POSIX transport</method>
+ 
+  <!--  the statement below is equivalent to the one above plus -->
+  <method group="solid" >
+      <transport="POSIX">options to POSIX transport</transport>
+  </method>
+
+  <method group="solid" <!-- engine="default-engine" --> >
+      <transport="POSIX" fname="out_p.bp">options to POSIX transport</transport>
+      <transport="MPI" fname="outsingle.bp">options to MPI transport</transport>
+      <!--  filenames overwrite the value provided in Open() call -->
+  </method>
+
+  <!--  Same as above but we can name the method separately from group name.
+        Hence multiple methods can be declared for one group 
+  -->
+  <method name="viz1" group="viz" transport="STAGING"></method>
+  <method name="viz2" group="viz" transport="MPI"></method>
+  
+  <!--  Associate an engine with a group and parameterize it here
+        The manager will define the transport(s) used in an output 
+  -->  
+  <method name="fluid" group="fluid" engine="sirius" fname="x.bp">
+      <level transport="SHMEM">options to SHMEM transport</level>
+      <level target="ssd" target-path="/ssd/pnorbert/" transport="POSIX"/>
+      <level target="wan" transport="ICEE" />
+  </method>
+
+  <method group="checkpoint" transport="MPI_AGGREGATE">
+        num_aggregators=1;num_ost=1
+  </method>
+  
+  <!--  We can set a transport to a group which is not defined yet.
+        The group can/should be defined in the source code before use.
+  -->
+  <method group="grouptobe" transport="POSIX">options to transport</method>
+
+  <!--  We can set a transport/engine without any group
+        All variables at writing should come from some existing group.
+        Each write call needs to add an extra argument to identify the variable's group 
+  -->
+  <method name="groupless" transport="POSIX">options to transport</method>
+  <method name="groupless" >
+      <transport="POSIX">options to POSIX transport</transport>
+  </method>
+
+  <!--  Global options for ADIOS that are not tied to a specific method -->
+  <options>verbose=2</options>
+
+  <buffer max-size-MB="1"/>
+
+</adios-config>
+
diff --git a/examples/solidfluid/solidfluid_read.cpp b/examples/solidfluid/solidfluid_read.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9d1a514911167429c0e150dca438a0d85d0b1140
--- /dev/null
+++ b/examples/solidfluid/solidfluid_read.cpp
@@ -0,0 +1,288 @@
+/*
+ * globalArrayXML.cpp
+ *
+ *  Created on: Oct 31, 2016
+ *      Author: pnorbert
+ */
+
+#include <stdexcept>
+#include <mpi.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "ADIOS_OOP.h"
+
+
+struct MYDATA {
+    int NX;
+    double *t;
+    std::vector<double> p;
+};
+
+const int N = 10;
+struct MYDATA solid, fluid;
+MPI_Comm    comm=MPI_COMM_WORLD;
+int         rank, size;
+
+void read_ckpt (adios::ADIOS adios, struct MYDATA &solid, struct MYDATA &fluid)
+{
+    try {
+        // Open an input which was written with an expected Method
+        // The write transport is associated with the group in the XML
+        // ADIOS pairs that with the corresponding read transport
+        // "r" is required to indicate we are reading
+        auto ckptfile = adios.Open("checkpoint.bp", "r", comm, "checkpoint");
+        // We can also manually set the read transport
+        //auto ckptfile = adios.Open("checkpoint.bp", adios::READ_METHOD_BP, "r", comm);
+
+        // Note: we only see a single step in the input but the checkpoint has
+        // only one step anyway. This makes this code simple
+
+        // simple immediate read of a scalar
+        ckptfile->ReadScalar("solid/NX", &solid.NX);
+        // solid.NX is filled at this point
+
+        // scheduled version of read of another scalar
+        // //ckptfile->ScheduleRead ("fluid/NX", &fluid.NX);
+        // //ckptfile->Read(); // perform reading now
+        ckptfile->Read("fluid/NX", &fluid.NX);
+        // fluid.NX is filled at this point
+
+        solid.t = new double(solid.NX);
+        solid.p = std::vector<double>(solid.NX);
+
+        fluid.t = new double(fluid.NX);
+        fluid.p = std::vector<double>(fluid.NX);
+
+        adios::ADIOS_SELECTION_WRITEBLOCK sel(rank);
+        adios.Read (ckptfile, sel, "solid/temperature", solid.t);
+        adios.Read (ckptfile, sel, "solid/pressure",    solid.p);
+        adios.Read (ckptfile, sel, "fluid/temperature", fluid.t);
+        // force checking if the allocated space equals to the size of the selection:
+        adios.Read (ckptfile, sel, "fluid/pressure",    fluid.p, fluid.NX*sizeof(double));
+        adios.Read(ckptfile, true); // true: blocking read, which is also default
+        adios.Close(ckptfile); // Should this do Read() if user misses or should we complain?
+    }
+    catch ( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        if( rank == 0 )
+        {
+            std::cout << e.what() << "\n";
+        }
+    }
+}
+
+void read_solid (adios::ADIOS adios, struct MYDATA &solid)
+{
+    float timeout_sec = 1.0;
+    int retval = 0;
+
+
+    try {
+        // Open a file for input, no group defined
+        // A reading transport should be defined if not file based
+        // "r" is required to indicate we are reading
+    	int solidfile = adios.Open("solid.bp", "r", comm); //, ADIOS_LOCKMODE_NONE, timeout_sec);
+        //int solidfile = adios.Open("solid.bp", adios::READ_METHOD_BP, "r", comm);
+        /* process file here... */
+        const adios::ADIOS_VARINFO &v = adios.InqVar (solidfile, "temperature");
+        v.GetBlockInfo();
+
+        printf ("ndim = %d\n",  v.ndim);
+        //printf ("nsteps = %d\n",  v.nsteps);
+        printf ("dims[%" PRIu64 "][%" PRIu64 "]\n",  v.dims[0], v.dims[1]);
+
+        uint64_t slice_size = v.dims[0]/size;
+
+        if (rank == size-1)
+            slice_size = slice_size + v.dims[0]%size;
+
+        start[0] = rank * slice_size;
+        count[0] = slice_size;
+        start[1] = 0;
+        count[1] = v.dims[1];
+
+        auto data = std::make_unique<double[]>(slice_size * v.dims[1] * 8);
+
+        adios::ADIOS_SELECTION_BOUNDINGBOX sel(v.ndim, start, count);
+
+        /* Processing loop over the steps (we are already in the first one) */
+        while (adios_errno != err_end_of_stream) {
+            steps++; // steps start counting from 1
+
+            solidfile.ScheduleRead (sel, "temperature", solid.t);
+            solidfile.Read(true);
+
+            if (rank == 0)
+                printf ("--------- Step: %d --------------------------------\n",
+                        solidfile.getCurrentStep());
+
+            printf("rank=%d: [0:%" PRIu64 ",0:%" PRIu64 "] = [", rank, v.dims[0], v.dims[1]);
+            for (i = 0; i < slice_size; i++) {
+                printf (" [");
+                for (j = 0; j < v.dims[1]; j++) {
+                    printf ("%g ", *((double *)data + i * v.dims[1] + j));
+                }
+                printf ("]");
+            }
+            printf (" ]\n\n");
+
+            // advance to 1) next available step with 2) blocking wait
+            solidfile.AdvanceStep (false, timeout_sec);
+            if (adios_errno == err_step_notready)
+            {
+                printf ("rank %d: No new step arrived within the timeout. Quit. %s\n",
+                        rank, adios_errmsg());
+                break; // quit while loop
+            }
+
+        }
+        solidfile.Close();
+
+    }
+    catch  ( std::exception& e )
+    {
+        if (adios_errno == err_file_not_found)
+        {
+            printf ("rank %d: Stream not found after waiting %f seconds: %s\n",
+                    rank, timeout_sec, adios_errmsg());
+            retval = adios_errno;
+        }
+        else if (adios_errno == err_end_of_stream)
+        {
+            printf ("rank %d: Stream terminated before open. %s\n", rank, adios_errmsg());
+            retval = adios_errno;
+        }
+        else if (f == NULL) {
+            printf ("rank %d: Error at opening stream: %s\n", rank, adios_errmsg());
+            retval = adios_errno;
+        }
+    }
+}
+
+void read_fluid (adios::ADIOS adios, struct MYDATA &fluid)
+{
+    float timeout_sec = 1.0;
+    int retval = 0;
+
+    // Open a file for input, no group defined
+    // A reading transport should be defined if not file based
+    // "r" is required to indicate we are reading
+    adios::ADIOS_INPUT fluidfile( comm, "r");
+
+    try {
+        fluidfile.Open("fluid.bp"); //, ADIOS_LOCKMODE_NONE, timeout_sec);
+
+        /* process file here... */
+        const adios::ADIOS_VARINFO &v = fluidfile.InqVar ("temperature");
+        v.GetBlockInfo();
+
+        printf ("ndim = %d\n",  v.ndim);
+        //printf ("nsteps = %d\n",  v.nsteps);
+        printf ("dims[%" PRIu64 "][%" PRIu64 "]\n",  v.dims[0], v.dims[1]);
+
+        uint64_t slice_size = v.dims[0]/size;
+
+        if (rank == size-1)
+            slice_size = slice_size + v.dims[0]%size;
+
+        start[0] = rank * slice_size;
+        count[0] = slice_size;
+        start[1] = 0;
+        count[1] = v.dims[1];
+
+        data = malloc (slice_size * v.dims[1] * 8);
+
+        adios::ADIOS_SELECTION_BOUNDINGBOX sel(v.ndim, start, count);
+
+        /* Processing loop over the steps (we are already in the first one) */
+        while (adios_errno != err_end_of_stream) {
+            steps++; // steps start counting from 1
+
+            fluidfile.ScheduleRead (sel, "temperature", fluid.t);
+            fluidfile.Read(true);
+
+            if (rank == 0)
+                printf ("--------- Step: %d --------------------------------\n",
+                        fluidfile.getCurrentStep());
+
+            printf("rank=%d: [0:%" PRIu64 ",0:%" PRIu64 "] = [", rank, v.dims[0], v.dims[1]);
+            for (i = 0; i < slice_size; i++) {
+                printf (" [");
+                for (j = 0; j < v.dims[1]; j++) {
+                    printf ("%g ", *((double *)data + i * v.dims[1] + j));
+                }
+                printf ("]");
+            }
+            printf (" ]\n\n");
+
+            // advance to 1) next available step with 2) blocking wait
+            fluidfile.AdvanceStep (false, timeout_sec);
+            if (adios_errno == err_step_notready)
+            {
+                printf ("rank %d: No new step arrived within the timeout. Quit. %s\n",
+                        rank, adios_errmsg());
+                break; // quit while loop
+            }
+
+        }
+        fluidfile.Close();
+
+    }
+    catch  ( std::exception& e )
+    {
+        if (adios_errno == err_file_not_found)
+        {
+            printf ("rank %d: Stream not found after waiting %f seconds: %s\n",
+                    rank, timeout_sec, adios_errmsg());
+            retval = adios_errno;
+        }
+        else if (adios_errno == err_end_of_stream)
+        {
+            printf ("rank %d: Stream terminated before open. %s\n", rank, adios_errmsg());
+            retval = adios_errno;
+        }
+        else if (f == NULL) {
+            printf ("rank %d: Error at opening stream: %s\n", rank, adios_errmsg());
+            retval = adios_errno;
+        }
+    }
+}
+
+
+int main (int argc, char ** argv)
+{
+
+    MPI_Init (&argc, &argv);
+    MPI_Comm_rank (comm, &rank);
+    MPI_Comm_size (comm, &size);
+
+    try
+    {
+        // ADIOS manager object creation. MPI must be initialized
+        adios::ADIOS adios( "globalArrayXML.xml", comm, true );
+
+        read_ckpt(adios, solid, fluid);
+
+        read_solid(adios, solid);
+
+        read_fluid(adios, fluid);
+    }
+    catch( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        if( rank == 0 )
+        {
+            std::cout << e.what() << "\n";
+        }
+    }
+    if (rank==0)
+        printf ("We have processed %d steps\n", steps);
+
+    free (data);
+    MPI_Finalize ();
+
+    return retval;
+
+}
diff --git a/examples/solidfluid/solidfluid_write.cpp b/examples/solidfluid/solidfluid_write.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a5a2d260c62f4365005e4263b41edfc7d03f0da0
--- /dev/null
+++ b/examples/solidfluid/solidfluid_write.cpp
@@ -0,0 +1,218 @@
+/*
+ * solid fluid example
+ *
+ *  Created on: Oct 31, 2016
+ *      Author: pnorbert
+ */
+
+#include <stdexcept>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "ADIOS_CPP.h"
+
+using adiosFile = std::shared_ptr<adios::Engine>;
+
+
+struct MYDATA {
+    int NX;
+    double *t;
+    std::vector<double> p;
+};
+
+const int N = 10;
+struct MYDATA solid, fluid;
+MPI_Comm    comm=MPI_COMM_WORLD;
+int         rank, size;
+
+
+void write_data( adiosFile writer, struct MYDATA &data )
+{
+    writer->Write("NX", &data.NX);
+    writer->Write("rank", &rank);
+    writer->Write("size", &size);
+    writer->Write("temperature", data.t);
+    writer->Write("pressure", data.p.data());
+    //writer->Flush();  AdvanceStep()???
+}
+
+void write_checkpoint( adiosFile ckptfile, const struct MYDATA &solid, const struct MYDATA &fluid )
+{
+    try
+    {
+        ckptfile->Write ("solid/NX", &solid.NX);
+        ckptfile->Write ("solid/rank", &rank);
+        ckptfile->Write ("solid/size", &size);
+        ckptfile->Write ("solid/temperature", solid.t);
+        ckptfile->Write ("solid/pressure", &solid.p[0]);
+
+        ckptfile->Write ("fluid/NX", &fluid.NX);
+        ckptfile->Write ("fluid/rank", &rank);
+        ckptfile->Write ("fluid/size", &size);
+        ckptfile->Write ("fluid/temperature", fluid.t);
+        ckptfile->Write ("fluid/pressure", fluid.p.data());
+        //ckptfile->AdvanceStep(); ??
+
+    }
+    catch ( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        if( rank == 0 )
+        {
+            std::cout << "ERROR: caught an exception from write_checkpoint\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+}
+
+void write_viz (std::shared_ptr<adios::Engine> vizstream, struct MYDATA &solid, struct MYDATA &fluid)
+{
+    // This stream is not associated with a group, so we must say for each write which group to use
+    // The output variable is re-defined inside as <groupname>/<varname>, unless given as third string argument
+    // An array variable's dimension definitions are also re-defined with dimensions <groupname>/<dimensionvar>
+
+    //vizstream->Write ("solid", "NX", &solid.NX);
+    //vizstream->Write ("solid", "rank", &rank);
+    //vizstream->Write ("solid", "size", &size);
+
+    // write solid group's temperature simply as temperature, risking overloading the 'temperature' variable when
+    // reading from a file
+
+    //vizstream->Write ("solid", "temperature", "my/tempvarinfile", solid.t);
+
+    //vizstream->Write ("fluid", "NX", &fluid.NX);
+    //vizstream->Write ("fluid", "rank", &rank);
+    //vizstream->Write ("fluid", "size", &size);
+
+    //vizstream->Write ("fluid", "temperature", "temperature", fluid.t);
+
+    //vizstream->Flush(); // flushes all data to disk; required operation
+    //vizstream.AdvanceStep();
+}
+
+void compute (int it,  struct MYDATA &solid, struct MYDATA &fluid)
+{
+    for (int i = 0; i < solid.NX; i++)
+    {
+        solid.t[i] = it*100.0 + rank*solid.NX + i;
+        solid.p[i] = it*1000.0 + rank*solid.NX + i;
+    }
+    for (int i = 0; i < fluid.NX; i++)
+    {
+        fluid.t[i] = it*200.0 + rank*fluid.NX + i;
+        fluid.p[i] = it*2000.0 + rank*fluid.NX + i;
+    }
+}
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init (&argc, &argv);
+    MPI_Comm_rank (comm, &rank);
+    MPI_Comm_size (comm, &size);
+
+    solid.NX = N;
+    solid.t = new double[N];
+    solid.p = std::vector<double>(N);
+
+    fluid.NX = N;
+    fluid.t = new double[N];
+    fluid.p = std::vector<double>(N);
+
+    try
+    {
+        // ADIOS manager object creation. MPI must be initialized
+        adios::ADIOS adios( comm, true );
+
+        adios::Method& fileSettings = adios.DeclareMethod( "Reusable" ); //default engine is BP writer
+        fileSettings.AddTransport( "POSIX", "have_metadata_file=no" );
+
+        // Open a file with a Method which has selected a group and a transport in the XML.
+        // "a" will append to an already existing file, "w" would create a new file
+        // Multiple writes to the same file work as append in this application run
+        // FIXME: how do we support Update to same step?
+
+        auto solidfile = adios.Open( "solid.bp", "w", comm, fileSettings );
+
+
+        // "solid" is a method but incidentally also a group
+        // Constructor only creates an object and what is needed there but does not open a stream/file
+        // It can be used to initialize a staging connection if not declared before
+        // FIXME: which argument can be post-poned into Open() instead of constructor?
+        //solidfile.Open("solid.bp");
+
+
+        // Open a file with a Method that has selected a group and an engine in the XML
+        // The transport method(s) are (must be) associated with the engines
+        // "a" will append to an already existing file, "w" would create a new file
+        // Multiple writes to the same file work as append in this application run
+        // FIXME: how do we support Update to same step?
+        auto fluidfile = adios.Open("fluid.bp", "w", comm, fileSettings );
+
+        auto checkpointFile = adios.Open("checkpoint.bp", "w", comm, fileSettings );
+
+        //int ckptfile = adios.Open("checkpoint.bp", "checkpoint", "w", comm);
+        // we do not open this here, but every time when needed in a function
+
+        // Another output not associated with a single group, so that we can mix variables to it
+        //adios:handle vizstream = adios.Open( "stream.bp", comm, "w", "STAGING", "options to staging method");
+        auto vizstream = adios.Open("stream.bp", "w", comm, fileSettings );
+
+        // This creates an empty group inside, and we can write all kinds of variables to it
+
+        //Get Monitor info
+        std::ofstream logStream( "info_" + std::to_string(rank) + ".log" );
+        adios.MonitorVariables( logStream );
+
+        int checkPointSteps = 10;
+
+
+        for (int it = 1; it <= 100; it++)
+        {
+            compute (it, solid, fluid);
+
+            write_data( solidfile, solid );
+            write_data( fluidfile, fluid );
+
+            if (it%checkPointSteps == 0) {
+                write_checkpoint( checkpointFile, solid, fluid );
+
+                MPI_Barrier( comm );
+                if( rank == 0 )
+                {
+                    std::cout << "New checkpoint step, current = " << checkPointSteps << "\n";
+                    std::cin >> checkPointSteps;
+                    MPI_Bcast( &checkPointSteps, 1, MPI_INT, 0, comm );
+                }
+                MPI_Barrier( comm );
+            }
+
+            write_viz(vizstream, solid, fluid);
+
+            MPI_Barrier (comm);
+            if (rank==0) printf("Timestep %d written\n", it);
+        }
+
+        solidfile->Close();
+        fluidfile->Close();
+        vizstream->Close();
+
+        // need barrier before we destroy the ADIOS object here automatically
+        MPI_Barrier (comm);
+        if (rank==0) printf("Finalize adios\n");
+    }
+    catch( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        if( rank == 0 )
+        {
+            std::cout << "ERROR: " << e.what() << "\n";
+        }
+    }
+
+    delete[] solid.t;
+    delete[] fluid.t;
+
+    if (rank==0) printf("Finalize MPI\n");
+    MPI_Finalize ();
+    return 0;
+}
diff --git a/examples/solidfluid/solidfluid_write_nompi.cpp b/examples/solidfluid/solidfluid_write_nompi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec450fd9a13337582f2c9e5f87c5394e0ec55b58
--- /dev/null
+++ b/examples/solidfluid/solidfluid_write_nompi.cpp
@@ -0,0 +1,217 @@
+/*
+ * solid fluid example
+ *
+ *  Created on: Oct 31, 2016
+ *      Author: pnorbert
+ */
+
+#include <stdexcept>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "ADIOS_CPP.h"
+
+using adiosFile = std::shared_ptr<adios::Engine>;
+
+
+struct MYDATA {
+    int NX;
+    double *t;
+    std::vector<double> p;
+};
+
+const int N = 10;
+struct MYDATA solid, fluid;
+int         rank = 0, size = 1;
+
+
+void set_io_variables( adios::ADIOS& adios, const std::string process )
+{
+    adios.DefineVariable<int>( process + "/NX" );
+    adios.DefineVariable<int>( process + "/rank" );
+    adios.DefineVariable<int>( process + "/size" );
+    adios.DefineVariable<double>( process + "/temperature", adios::Dims{N} );
+    adios.DefineVariable<double>( process + "/pressure", adios::Dims{N} );
+}
+
+
+void write_data( adiosFile writer, const std::string process, struct MYDATA &data)
+{
+    writer->Write( process + "/NX", &data.NX);
+    writer->Write( process + "/rank", &rank);
+    writer->Write( process + "/size", &size);
+    writer->Write( process + "/temperature", data.t );
+    writer->Write( process + "/pressure", data.p.data());
+    //writer->Flush();  AdvanceStep()???
+}
+
+
+void write_checkpoint( adiosFile ckptfile, const struct MYDATA &solid, const struct MYDATA &fluid )
+{
+    try
+    {
+        ckptfile->Write ("solid/NX", &solid.NX);
+        ckptfile->Write ("solid/rank", &rank);
+        ckptfile->Write ("solid/size", &size);
+        ckptfile->Write ("solid/temperature", solid.t);
+        ckptfile->Write ("solid/pressure", &solid.p[0]);
+
+        ckptfile->Write ("fluid/NX", &fluid.NX);
+        ckptfile->Write ("fluid/rank", &rank);
+        ckptfile->Write ("fluid/size", &size);
+        ckptfile->Write ("fluid/temperature", fluid.t);
+        ckptfile->Write ("fluid/pressure", fluid.p.data());
+        //ckptfile->AdvanceStep(); ??
+
+    }
+    catch ( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        if( rank == 0 )
+        {
+            std::cout << "ERROR: caught an exception from write_checkpoint\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+}
+
+void write_viz( adiosFile vizstream, struct MYDATA &solid, struct MYDATA &fluid )
+{
+    // This stream is not associated with a group, so we must say for each write which group to use
+    // The output variable is re-defined inside as <groupname>/<varname>, unless given as third string argument
+    // An array variable's dimension definitions are also re-defined with dimensions <groupname>/<dimensionvar>
+
+    //vizstream->Write ("solid", "NX", &solid.NX);
+    //vizstream->Write ("solid", "rank", &rank);
+    //vizstream->Write ("solid", "size", &size);
+
+    // write solid group's temperature simply as temperature, risking overloading the 'temperature' variable when
+    // reading from a file
+
+    //vizstream->Write ("solid", "temperature", "my/tempvarinfile", solid.t);
+
+    //vizstream->Write ("fluid", "NX", &fluid.NX);
+    //vizstream->Write ("fluid", "rank", &rank);
+    //vizstream->Write ("fluid", "size", &size);
+
+    //vizstream->Write ("fluid", "temperature", "temperature", fluid.t);
+
+    //vizstream->Flush(); // flushes all data to disk; required operation
+    //vizstream.AdvanceStep();
+}
+
+void compute (int it,  struct MYDATA &solid, struct MYDATA &fluid)
+{
+    for (int i = 0; i < solid.NX; i++)
+    {
+        solid.t[i] = it*100.0 + rank*solid.NX + i;
+        solid.p[i] = it*1000.0 + rank*solid.NX + i;
+    }
+    for (int i = 0; i < fluid.NX; i++)
+    {
+        fluid.t[i] = it*200.0 + rank*fluid.NX + i;
+        fluid.p[i] = it*2000.0 + rank*fluid.NX + i;
+    }
+}
+
+int main( int argc, char* argv [] )
+{
+    solid.NX = N;
+    solid.t = new double[N];
+    solid.p = std::vector<double>(N);
+
+    fluid.NX = N;
+    fluid.t = new double[N];
+    fluid.p = std::vector<double>(N);
+
+    try
+    {
+        // ADIOS manager object creation. MPI must be initialized
+        adios::ADIOS adios( true );
+        set_io_variables( adios, "solid" );
+        set_io_variables( adios, "fluid" );
+
+        adios::Method& fileSettings = adios.DeclareMethod( "Reusable" ); //default engine is BP writer
+        fileSettings.AddTransport( "POSIX", "have_metadata_file=no" );
+
+        // Open a file with a Method which has selected a group and a transport in the XML.
+        // "a" will append to an already existing file, "w" would create a new file
+        // Multiple writes to the same file work as append in this application run
+        // FIXME: how do we support Update to same step?
+
+        auto solidfile = adios.Open( "solid.bp", "w", fileSettings );
+
+
+        // "solid" is a method but incidentally also a group
+        // Constructor only creates an object and what is needed there but does not open a stream/file
+        // It can be used to initialize a staging connection if not declared before
+        // FIXME: which argument can be post-poned into Open() instead of constructor?
+        //solidfile.Open("solid.bp");
+
+
+        // Open a file with a Method that has selected a group and an engine in the XML
+        // The transport method(s) are (must be) associated with the engines
+        // "a" will append to an already existing file, "w" would create a new file
+        // Multiple writes to the same file work as append in this application run
+        // FIXME: how do we support Update to same step?
+        auto fluidfile = adios.Open("fluid.bp", "w", fileSettings );
+
+        auto checkpointFile = adios.Open("checkpoint.bp", "w", fileSettings );
+
+        //int ckptfile = adios.Open("checkpoint.bp", "checkpoint", "w", comm);
+        // we do not open this here, but every time when needed in a function
+
+        // Another output not associated with a single group, so that we can mix variables to it
+        //adios:handle vizstream = adios.Open( "stream.bp", comm, "w", "STAGING", "options to staging method");
+        auto vizstream = adios.Open("stream.bp", "w", fileSettings );
+
+        // This creates an empty group inside, and we can write all kinds of variables to it
+
+        //Get Monitor info
+        std::ofstream logStream( "info_nompi.log" );
+        adios.MonitorVariables( logStream );
+
+        int checkPointSteps = 10;
+
+
+        for (int it = 1; it <= 100; it++)
+        {
+            compute (it, solid, fluid);
+
+            write_data( solidfile, "solid", solid );
+            write_data( fluidfile, "fluid", fluid );
+
+            if (it%checkPointSteps == 0) {
+                write_checkpoint( checkpointFile, solid, fluid );
+
+                {
+                    std::cout << "New checkpoint step, current = " << checkPointSteps << "\n";
+                    std::cin >> checkPointSteps;
+                }
+
+            }
+
+            write_viz(vizstream, solid, fluid);
+
+            std::cout << "Timestep " << it << " written\n";
+        }
+
+        solidfile->Close();
+        fluidfile->Close();
+        vizstream->Close();
+        checkpointFile->Close();
+
+        // need barrier before we destroy the ADIOS object here automatically ...no!
+        std::cout << "Finalize adios\n";
+    }
+    catch( std::exception& e ) //need to think carefully how to handle C++ exceptions with MPI to avoid deadlocking
+    {
+        std::cout << e.what() << "\n";
+    }
+
+    delete[] solid.t;
+    delete[] fluid.t;
+
+    return 0;
+}
diff --git a/examples/xmlParser/Makefile b/examples/xmlParser/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..12d521a344cadbceb9fdfc458dfd7d53b6501f69
--- /dev/null
+++ b/examples/xmlParser/Makefile
@@ -0,0 +1,35 @@
+# Makefile for testing purposes, will build libadios.a 
+# Created on: Oct 4, 2016
+#     Author: wfg
+
+
+BASE_NAME=xmlParser
+     
+TOOL_DIR=/usr/bin
+
+CC=$(TOOL_DIR)/g++ 
+MPICC=$(TOOL_DIR)/mpic++
+AR=$(TOOL_DIR)/ar
+
+#ADIOS LOCATION
+ADIOS_DIR=../../
+ADIOS_LIB=$(ADIOS_DIR)/lib/libadios.a
+ADIOS_NOMPI_LIB=$(ADIOS_DIR)/lib/libadios_nompi.a
+
+ADIOS_INCLUDE=-I$(ADIOS_DIR)/include
+
+
+#FLAGS
+CFLAGS=-Wall -O0 -g -Wpedantic -std=c++11
+
+all: mpi
+
+mpi: $(ADIOS_LIB) $(ADIOS_HFiles)
+	$(MPICC) $(CFLAGS) $(ADIOS_INCLUDE) -DHAVE_MPI $(BASE_NAME).cpp -o $(BASE_NAME)_mpi $(ADIOS_LIB)
+	
+nompi: $(ADIOS_NOMPI_LIB) $(NoMPI_HFiles)
+	$(CC) $(CFLAGS) $(ADIOS_INCLUDE) $(BASE_NAME).cpp -o $(BASE_NAME)_nompi $(ADIOS_NOMPI_LIB)
+
+clean:
+	rm *_mpi; rm *_nompi
+     
diff --git a/examples/xmlParser/xmlParser.cpp b/examples/xmlParser/xmlParser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa1ef10834e0175dcc2b4c995c2bb32561a53370
--- /dev/null
+++ b/examples/xmlParser/xmlParser.cpp
@@ -0,0 +1,65 @@
+/*
+ * xmlParser.cpp
+ *
+ *  Created on: Nov 2, 2016
+ *      Author: wfg
+ */
+
+#include <stdexcept>
+#include <iostream>
+#include <string>
+
+#include "../../include/ADIOS.h"
+
+#ifdef HAVE_MPI
+    #include <mpi.h>
+#else
+    #include "../../include/mpidummy.h"
+    using namespace adios;
+#endif
+
+
+static void Usage( );
+
+
+int main( int argc, char* argv [] )
+{
+    MPI_Init( &argc, &argv );
+    int rank;
+    MPI_Comm_rank( MPI_COMM_WORLD, &rank );
+
+    try
+    {
+        if( argc != 2 )
+        {
+            Usage( );
+        }
+        else
+        {
+            const std::string xmlConfigFile( argv[1] );
+            adios::ADIOS adios( xmlConfigFile, MPI_COMM_WORLD, true );
+            adios.MonitorGroups( std::cout );
+        }
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+        {
+            std::cout << "ERROR: exception caught\n";
+            std::cout << e.what() << "\n";
+        }
+    }
+
+    MPI_Finalize( );
+    return 0;
+}
+
+
+static void Usage( )
+{
+    std::cout << "Program to test XML Config file parsing\n";
+    std::cout << "Usage: \n";
+    std::cout << "\t MPI version: ./xmlParser_mpi xmlConfigFile\n";
+    std::cout << "\t Non-MPI version: ./xmlParser_nompi xmlConfigFile\n";
+}
+
diff --git a/include/ADIOS.h b/include/ADIOS.h
new file mode 100644
index 0000000000000000000000000000000000000000..3009c3eb4688c0f663fc7c06d6620eaa654502cc
--- /dev/null
+++ b/include/ADIOS.h
@@ -0,0 +1,565 @@
+/*
+ * ADIOS.h
+ *
+ *  Created on: Oct 3, 2016
+ *      Author: wfg
+ */
+
+#ifndef ADIOS_H_
+#define ADIOS_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+#include <vector>
+#include <memory> //std::shared_ptr
+#include <ostream>
+#include <set>
+#include <map>
+#include <complex>
+/// \endcond
+
+#ifdef ADIOS_NOMPI
+  #include "mpidummy.h"
+#else
+  #include <mpi.h>
+#endif
+
+#include "ADIOSTypes.h"
+#include "core/Transform.h"
+#include "core/Variable.h"
+#include "core/VariableCompound.h"
+#include "core/Method.h"
+#include "core/Support.h"
+#include "functions/adiosTemplates.h"
+
+
+namespace adios
+{
+
+class Engine;
+
+/**
+ * @brief Unique class interface between user application and ADIOS library
+ */
+class ADIOS
+{
+
+public: // PUBLIC Constructors and Functions define the User Interface with ADIOS
+
+    MPI_Comm m_MPIComm = MPI_COMM_SELF; ///< only used as reference to MPI communicator passed from parallel constructor, MPI_Comm is a pointer itself. Public as called from C
+
+    int m_RankMPI = 0; ///< current MPI rank process
+    int m_SizeMPI = 1; ///< current MPI processes size
+
+    std::string m_HostLanguage = "C++";
+
+    /**
+     * @brief ADIOS empty constructor. Used for non XML config file API calls.
+     */
+    ADIOS( const Verbose verbose = Verbose::WARN, const bool debugMode = false );
+
+
+    /**
+     * @brief Serial constructor for config file, only allowed and compiled in libadios_nompi.a
+     * @param configFileName passed to m_ConfigFile
+     * @param debugMode true: on throws exceptions and do additional checks, false: off (faster, but unsafe)
+     */
+    ADIOS( const std::string configFileName, const Verbose verbose = Verbose::WARN, const bool debugMode = false );
+
+    /**
+     * @brief Parallel constructor for XML config file and MPI
+     * @param configFileName passed to m_XMLConfigFile
+     * @param mpiComm MPI communicator ...const to be discussed
+     * @param debugMode true: on, false: off (faster, but unsafe)
+     */
+
+    ADIOS( const std::string configFileName, MPI_Comm mpiComm, const Verbose verbose = Verbose::WARN, const bool debugMode = false );
+
+
+    /**
+     * @brief Parallel MPI communicator without XML config file
+     * @param mpiComm MPI communicator passed to m_MPIComm*
+     * @param debugMode true: on, false: off (faster)
+     */
+    ADIOS(  MPI_Comm mpiComm, const Verbose verbose = Verbose::WARN, const bool debugMode = false );
+
+
+
+    ~ADIOS( ); ///< empty, using STL containers for memory management
+
+    void InitMPI( ); ///< sets rank and size in m_rank and m_Size, respectively.
+
+    /**
+     * Look for template specialization
+     * @param name
+     * @param dimensions
+     * @param globalDimensions
+     * @param globalOffsets
+     * @return
+     */
+    template<class T> inline
+    Variable<T>& DefineVariable( const std::string name, const Dims dimensions = Dims{1},
+                                 const Dims globalDimensions = Dims( ),
+                                 const Dims globalOffsets = Dims() )
+    {
+        throw std::invalid_argument( "ERROR: type not supported for variable " + name + " in call to DefineVariable\n" );
+    }
+
+    template<class T> inline
+    Variable<T>& GetVariable( const std::string name )
+    {
+        throw std::invalid_argument( "ERROR: type not supported for variable " + name + " in call to GetVariable\n" );
+    }
+
+
+    template<class T>
+    VariableCompound& DefineVariableCompound( const std::string name, const Dims dimensions = Dims{1},
+                                              const Dims globalDimensions = Dims(),
+                                              const Dims globalOffsets = Dims() )
+    {
+        CheckVariableInput( name, dimensions );
+        const unsigned int size = m_Compound.size();
+        m_Compound.emplace( size, VariableCompound( name, sizeof(T), dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+        m_Variables.emplace( name, std::make_pair( GetType<T>(), size ) );
+        return m_Compound.at( size );
+    }
+
+    VariableCompound& GetVariableCompound( const std::string name );
+
+
+    /**
+     * Declares a new method. If the method is defined in the user config file,
+     * it will be already created during processing the config file,
+     * the method is set up with the user settings and this function just returns that method.
+     * Otherwise it will create and return a new Method with default settings.
+     * Use method.isUserDefined() to distinguish between the two cases.
+     * @param methodName must be unique
+     */
+    Method& DeclareMethod( const std::string methodName );
+
+
+    /**
+     * @brief Open to Write, Read. Creates a new engine from previously defined method
+     * @param streamName unique stream or file name
+     * @param accessMode "w" or "write", "r" or "read", "a" or "append", "u" or "update"
+     * @param mpiComm option to modify communicator from ADIOS class constructor
+     * @param method looks for corresponding Method object in ADIOS to initialize the engine
+     * @param iomode Independent or collective open/advance by writers/readers? Write() operations are always independent.
+     * @param timeout_sec Wait some time before reporting on missing stream (i.e. wait for it for a while)
+      * @return Derived class of base Engine depending on Method parameters, shared_ptr for potential flexibility
+     */
+    std::shared_ptr<Engine> Open( const std::string streamName, const std::string accessMode, MPI_Comm mpiComm,
+                                  const Method& method, const IOMode iomode = IOMode::INDEPENDENT, const float timeout_sec = 0.0 );
+
+    /**
+     * @brief Open to Write, Read. Creates a new engine from previously defined method.
+     * Reuses MPI communicator from ADIOS constructor.
+     * @param streamName unique stream or file name
+     * @param accessMode "w" or "write", "r" or "read", "a" or "append", "u" or "update"
+     * @param method contains engine parameters
+     * @param iomode Independent or collective open/advance by writers/readers? Write() operations are always independent.
+     * @param timeout_sec Wait some time before reporting on missing stream (i.e. wait for it for a while)
+      * @return Derived class of base Engine depending on Method parameters, shared_ptr for potential flexibility
+     */
+    std::shared_ptr<Engine> Open( const std::string streamName, const std::string accessMode, 
+    							  const Method& method, const IOMode iomode = IOMode::INDEPENDENT, const float timeout_sec = 0.0 );
+
+
+    /**
+     * Version required by the XML config file implementation, searches method inside ADIOS through a unique name
+     * @param streamName unique stream or file name
+     * @param accessMode "w" or "write", "r" or "read", "a" or "append"
+     * @param mpiComm mpi Communicator
+     * @param methodName used to search method object inside ADIOS object
+     * @param iomode Independent or collective open/advance by writers/readers? Write() operations are always independent.
+     * @param timeout_sec Wait some time before reporting on missing stream (i.e. wait for it for a while)
+     * @return Derived class of base Engine depending on Method parameters, shared_ptr for potential flexibility
+     */
+    std::shared_ptr<Engine> Open( const std::string streamName, const std::string accessMode, MPI_Comm mpiComm,
+                                  const std::string methodName, const IOMode iomode = IOMode::INDEPENDENT, const float timeout_sec = 0.0 );
+
+    /**
+     * Version required by the XML config file implementation, searches method inside ADIOS through a unique name.
+     * Reuses ADIOS MPI Communicator from constructor.
+     * @param streamName unique stream or file name
+     * @param accessMode "w" or "write", "r" or "read", "a" or "append"
+     * @param methodName used to search method object inside ADIOS object
+     * @param iomode Independent or collective open/advance by writers/readers? Write() operations are always independent.
+     * @param timeout_sec Wait some time before reporting on missing stream (i.e. wait for it for a while)
+     * @return Derived class of base Engine depending on Method parameters, shared_ptr for potential flexibility
+     */
+    std::shared_ptr<Engine> Open( const std::string streamName, const std::string accessMode,
+                                  const std::string methodName, const IOMode iomode = IOMode::INDEPENDENT,
+                                  const float timeout_sec = 0.0 );
+
+    /**
+     * @brief Open to Read all steps from a file. No streaming, advancing is possible here. All steps in the file
+     * are immediately available for reading. Creates a new engine from previously defined method.
+     * @param fileName file name
+     * @param mpiComm option to modify communicator from ADIOS class constructor
+     * @param method looks for corresponding Method object in ADIOS to initialize the engine
+     * @param iomode Independent or collective open/advance by writers/readers? Write() operations are always independent.
+     * @return Derived class of base Engine depending on Method parameters, shared_ptr for potential flexibility
+     */
+    std::shared_ptr<Engine> OpenFileReader( const std::string fileName, MPI_Comm mpiComm,
+                                            const Method& method, const IOMode iomode = IOMode::INDEPENDENT );
+
+    /**
+     * @brief Open to Read all steps from a file. No streaming, advancing is possible here. All steps in the file
+     * are immediately available for reading. Creates a new engine from previously defined method.
+     * Version required by the XML config file implementation, searches method inside ADIOS through a unique name.
+     * @param fileName file name
+     * @param mpiComm option to modify communicator from ADIOS class constructor
+     * @param methodName used to search method object inside ADIOS object
+      * @param iomode Independent or collective open/advance by writers/readers? Write() operations are always independent.
+     * @return Derived class of base Engine depending on Method parameters, shared_ptr for potential flexibility
+     */
+    std::shared_ptr<Engine> OpenFileReader( const std::string fileName, MPI_Comm mpiComm,
+                                            const std::string methodName, const IOMode iomode = IOMode::INDEPENDENT );
+
+    /**
+     * @brief Dumps groups information to a file stream or standard output.
+     * Note that either the user closes this fileStream or it's closed at the end.
+     * @param logStream either std::cout standard output, or a std::ofstream file
+     */
+    void MonitorVariables( std::ostream& logStream );
+
+
+
+protected: //no const to allow default empty and copy constructors
+
+    std::map<unsigned int, Variable<char> > m_Char;
+    std::map<unsigned int, Variable<unsigned char> > m_UChar;
+    std::map<unsigned int, Variable<short> > m_Short;
+    std::map<unsigned int, Variable<unsigned short> > m_UShort;
+    std::map<unsigned int, Variable<int> > m_Int;
+    std::map<unsigned int, Variable<unsigned int> > m_UInt;
+    std::map<unsigned int, Variable<long int> > m_LInt;
+    std::map<unsigned int, Variable<unsigned long int> > m_ULInt;
+    std::map<unsigned int, Variable<long long int> > m_LLInt;
+    std::map<unsigned int, Variable<unsigned long long int> > m_ULLInt;
+    std::map<unsigned int, Variable<float> > m_Float;
+    std::map<unsigned int, Variable<double> > m_Double;
+    std::map<unsigned int, Variable<long double> > m_LDouble;
+    std::map<unsigned int, Variable<std::complex<float>> > m_CFloat;
+    std::map<unsigned int, Variable<std::complex<double>> > m_CDouble;
+    std::map<unsigned int, Variable<std::complex<long double>> > m_CLDouble;
+    std::map<unsigned int, VariableCompound > m_Compound;
+
+    std::string m_ConfigFile; ///< XML File to be read containing configuration information
+    bool m_DebugMode = false; ///< if true will do more checks, exceptions, warnings, expect slower code
+
+    //Variables
+    std::map< std::string, std::pair< std::string, unsigned int > > m_Variables; ///< Makes variable name unique, key: variable name, value: pair.first = type, pair.second = index in corresponding vector of Variable
+
+    std::vector< std::shared_ptr<Transform> > m_Transforms; ///< transforms associated with ADIOS run
+
+
+    /**
+     * @brief List of Methods (engine metadata) defined from either ADIOS XML configuration file or the DeclareMethod function.
+     * <pre>
+     *     Key: std::string unique method name
+     *     Value: Method class
+     * </pre>
+     */
+    std::map< std::string, Method > m_Methods;
+    std::set< std::string > m_EngineNames; ///< set used to check Engine name uniqueness in debug mode
+
+    /**
+     * @brief Checks for group existence in m_Groups, if failed throws std::invalid_argument exception
+     * @param itGroup m_Groups iterator, usually from find function
+     * @param groupName unique name, passed for thrown exception only
+     * @param hint adds information to thrown exception
+     */
+    void CheckVariableInput( const std::string name, const Dims& dimensions ) const;
+
+    /**
+     * Checks for variable name, if not found throws an invalid exception
+     * @param itVariable iterator pointing to the variable name in m_Variables
+     * @param name variable name
+     * @param hint message to be thrown for debugging purporses
+     */
+    void CheckVariableName( std::map< std::string, std::pair< std::string, unsigned int > >::const_iterator itVariable,
+                            const std::string name, const std::string hint ) const;
+
+    /**
+     * @brief Checks for method existence in m_Methods, if failed throws std::invalid_argument exception
+     * @param itMethod m_Methods iterator, usually from find function
+     * @param methodName unique name, passed for thrown exception only
+     * @param hint adds information to thrown exception
+     */
+    void CheckMethod( std::map< std::string, Method >::const_iterator itMethod,
+                      const std::string methodName, const std::string hint ) const;
+
+    template< class T >
+    unsigned int GetVariableIndex( const std::string name )
+    {
+        auto itVariable = m_Variables.find( name );
+        CheckVariableName( itVariable, name, "in call to GetVariable<" + GetType<T>() + ">, or call to GetVariableCompound if <T> = <compound>\n" );
+        return itVariable->second.second;
+    }
+
+};
+
+//template specializations of DefineVariable:
+template<> inline
+Variable<char>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                       const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_Char.size();
+    m_Char.emplace( size, Variable<char>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<char>(), size ) );
+    return m_Char.at( size );
+}
+
+
+template<> inline
+Variable<unsigned char>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                                const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_UChar.size();
+    m_UChar.emplace( size, Variable<unsigned char>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<unsigned char>(), size ) );
+    return m_UChar.at( size );
+}
+
+
+template<> inline
+Variable<short>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                        const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_Short.size();
+    m_Short.emplace( size, Variable<short>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<unsigned char>(), size ) );
+    return m_Short.at( size );
+}
+
+
+template<> inline
+Variable<unsigned short>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                                 const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_UShort.size();
+    m_UShort.emplace( size, Variable<unsigned short>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<unsigned short>(), size ) );
+    return m_UShort.at( size );
+}
+
+
+template<> inline
+Variable<int>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                      const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_Int.size();
+    m_Int.emplace( size, Variable<int>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<int>(), size ) );
+    return m_Int.at( size );
+}
+
+
+template<> inline
+Variable<unsigned int>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                               const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_UInt.size();
+    m_UInt.emplace( size, Variable<unsigned int>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<unsigned int>(), size ) );
+    return m_UInt.at( size );
+}
+
+
+template<> inline
+Variable<long int>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                           const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_LInt.size();
+    m_LInt.emplace( size, Variable<long int>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<long int>(), size ) );
+    return m_LInt.at( size );
+}
+
+
+template<> inline
+Variable<unsigned long int>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                                    const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_LInt.size();
+    m_ULInt.emplace( size, Variable<unsigned long int>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<unsigned long int>(), size ) );
+    return m_ULInt.at( size );
+}
+
+
+template<> inline
+Variable<long long int>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                                const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_LLInt.size();
+    m_LLInt.emplace( size, Variable<long long int>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<long long int>(), size ) );
+    return m_LLInt.at( size );
+}
+
+
+template<> inline
+Variable<unsigned long long int>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                                         const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_ULLInt.size();
+    m_ULLInt.emplace( size, Variable<unsigned long long int>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<unsigned long long int>(), size ) );
+    return m_ULLInt.at( size );
+}
+
+template<> inline
+Variable<float>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                        const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_Float.size();
+    m_Float.emplace( size, Variable<float>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<float>(), size ) );
+    return m_Float.at( size );
+}
+
+
+template<> inline
+Variable<double>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                         const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_Double.size();
+    m_Double.emplace( size, Variable<double>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<double>(), size ) );
+    return m_Double.at( size );
+}
+
+
+template<> inline
+Variable<long double>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                              const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_LDouble.size();
+    m_LDouble.emplace( size, Variable<long double>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<long double>(), size ) );
+    return m_LDouble.at( size );
+}
+
+
+template<> inline
+Variable<std::complex<float>>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                                      const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_CFloat.size();
+    m_CFloat.emplace( size, Variable<std::complex<float>>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<std::complex<float>>(), size ) );
+    return m_CFloat.at( size );
+}
+
+
+template<> inline
+Variable<std::complex<double>>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                                       const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_CDouble.size();
+    m_CDouble.emplace( size, Variable<std::complex<double>>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<std::complex<double>>(), size ) );
+    return m_CDouble.at( size );
+}
+
+
+template<> inline
+Variable<std::complex<long double>>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
+                                                            const Dims globalDimensions, const Dims globalOffsets )
+{
+    CheckVariableInput( name, dimensions );
+    const unsigned int size = m_CLDouble.size();
+    m_CLDouble.emplace( size, Variable<std::complex<long double>>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
+    m_Variables.emplace( name, std::make_pair( GetType<std::complex<long double>>(), size ) );
+    return m_CLDouble.at( size );
+}
+
+
+//Get template specialization
+template<> inline
+Variable<char>& ADIOS::GetVariable( const std::string name )
+{ return m_Char.at( GetVariableIndex<char>(name) ); }
+
+template<> inline
+Variable<unsigned char>& ADIOS::GetVariable( const std::string name )
+{ return m_UChar.at( GetVariableIndex<unsigned char>(name) ); }
+
+template<> inline
+Variable<short>& ADIOS::GetVariable( const std::string name )
+{ return m_Short.at( GetVariableIndex<short>(name) ); }
+
+template<> inline
+Variable<unsigned short>& ADIOS::GetVariable( const std::string name )
+{ return m_UShort.at( GetVariableIndex<unsigned short>(name) ); }
+
+template<> inline
+Variable<int>& ADIOS::GetVariable( const std::string name )
+{ return m_Int.at( GetVariableIndex<int>(name) ); }
+
+template<> inline
+Variable<unsigned int>& ADIOS::GetVariable( const std::string name )
+{ return m_UInt.at( GetVariableIndex<unsigned int>(name) ); }
+
+template<> inline
+Variable<long int>& ADIOS::GetVariable( const std::string name )
+{ return m_LInt.at( GetVariableIndex<unsigned int>(name) ); }
+
+template<> inline
+Variable<unsigned long int>& ADIOS::GetVariable( const std::string name )
+{ return m_ULInt.at( GetVariableIndex<unsigned long int>(name) ); }
+
+template<> inline
+Variable<long long int>& ADIOS::GetVariable( const std::string name )
+{ return m_LLInt.at( GetVariableIndex<long long int>(name) ); }
+
+template<> inline
+Variable<unsigned long long int>& ADIOS::GetVariable( const std::string name )
+{ return m_ULLInt.at( GetVariableIndex<unsigned long long int>(name) ); }
+
+template<> inline
+Variable<float>& ADIOS::GetVariable( const std::string name )
+{ return m_Float.at( GetVariableIndex<float>(name) ); }
+
+template<> inline
+Variable<double>& ADIOS::GetVariable( const std::string name )
+{ return m_Double.at( GetVariableIndex<double>(name) ); }
+
+template<> inline
+Variable<long double>& ADIOS::GetVariable( const std::string name )
+{ return m_LDouble.at( GetVariableIndex<long double>(name) ); }
+
+template<> inline
+Variable<std::complex<float>>& ADIOS::GetVariable( const std::string name )
+{ return m_CFloat.at( GetVariableIndex<std::complex<float>>(name) ); }
+
+template<> inline
+Variable<std::complex<double>>& ADIOS::GetVariable( const std::string name )
+{ return m_CDouble.at( GetVariableIndex<std::complex<double>>(name) ); }
+
+template<> inline
+Variable<std::complex<long double>>& ADIOS::GetVariable( const std::string name )
+{ return m_CLDouble.at( GetVariableIndex<std::complex<long double>>(name) ); }
+
+
+} //end namespace
+
+
+#endif /* ADIOS_H_ */
diff --git a/include/ADIOSTypes.h b/include/ADIOSTypes.h
new file mode 100644
index 0000000000000000000000000000000000000000..28761e003f2e367e2f5c8ae24f806e52ac1a7b8a
--- /dev/null
+++ b/include/ADIOSTypes.h
@@ -0,0 +1,29 @@
+/*
+ * ADIOS_Types.h
+ *
+ *  Created on: Mar 23, 2017
+ *      Author: pnb
+ */
+
+#ifndef ADIOS_TYPES_H_
+#define ADIOS_TYPES_H_
+
+namespace adios
+{
+
+/** Use these values in Dims() when defining variables
+ */
+enum {
+    VARYING_DIMENSION = -1,//!< VARYING_DIMENSION
+    LOCAL_VALUE = 0,       //!< LOCAL_VALUE
+    GLOBAL_VALUE = 1       //!< GLOBAL_VALUE
+};
+
+enum class Verbose { ERROR = 0, WARN = 1, INFO = 2, DEBUG = 3 };
+
+enum class IOMode { INDEPENDENT = 0, COLLECTIVE = 1 };
+
+} //end namespace
+
+
+#endif /* ADIOS_TYPES_H_ */
diff --git a/include/ADIOS_C.h b/include/ADIOS_C.h
new file mode 100644
index 0000000000000000000000000000000000000000..93bf82d3f7cbd907d817cea3deaf218c85a1e7cc
--- /dev/null
+++ b/include/ADIOS_C.h
@@ -0,0 +1,84 @@
+/*
+ * ADIOS_C.h  "C" interface to ADIOS C++ class. This header defines the C API
+ *
+ *  Created on: Oct 31, 2016
+ *      Author: wfg
+ */
+
+#ifndef ADIOS_C_H_
+#define ADIOS_C_H_
+
+#ifdef ADIOS_NOMPI
+  #include "mpidummy.h"
+  using adios::MPI_Comm_rank;
+  using adios::MPI_Comm;
+#else
+  #include <mpi.h>
+#endif
+
+
+
+typedef void ADIOS;
+typedef void Method;
+typedef void Engine;
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * ADIOS Init
+ * @param mpicomm MPI communicator from user app
+ */
+void adios_init( MPI_Comm mpiComm );
+
+/**
+ * ADIOS Init in debug mode: extra checks
+ * @param mpicomm MPI communicator from user app
+ */
+void adios_init_debug( MPI_Comm mpiComm );
+
+/**
+ * Sequential version (nompi)
+ */
+void adios_init_nompi( );
+
+
+/**
+ *
+ * @param fileName
+ * @param accessMode
+ * @param mpiComm
+ * @return engine handler
+ */
+int adios_open( const char* fileName, const char* accessMode, MPI_Comm mpiComm );
+
+/**
+ *
+ * @param variableName
+ * @param values
+ */
+void adios_write( const char* variableName, const void* values  );
+
+/**
+ *
+ * @param handler
+ */
+void adios_close( const int handler );
+
+void adios_finalize( const ADIOS* adiosC ); // deallocate ADIOS pointer
+
+void adios_monitor_groups( const ADIOS* adiosC );
+
+void adios_monitor_groups_file( const ADIOS* adiosC, const char* fileName, const char* mode );
+
+
+
+#ifdef __cplusplus
+} //end extern C
+#endif
+
+#endif /* ADIOS_C_H_ */
diff --git a/include/ADIOS_CPP.h b/include/ADIOS_CPP.h
new file mode 100644
index 0000000000000000000000000000000000000000..7032eed67155880f18c6098ec02665f78512b781
--- /dev/null
+++ b/include/ADIOS_CPP.h
@@ -0,0 +1,28 @@
+/*
+ * ADIOS_CPP.h
+ *
+ *  Created on: Jan 9, 2017
+ *      Author: wfg
+ */
+
+#ifndef ADIOS_CPP_H_
+#define ADIOS_CPP_H_
+
+#include "ADIOSTypes.h"
+#include "ADIOS.h"
+#include "core/Method.h"
+
+#include "core/Engine.h"
+#include "core/Transform.h"
+#include "engine/bp/BPFileWriter.h"
+
+//Will allow to create engines directly (no polymorphism)
+#ifdef HAVE_DATAMAN
+#include "engine/dataman/DataManWriter.h"
+#include "engine/dataman/DataManReader.h"
+#endif
+
+#include "transform/BZip2.h"
+
+
+#endif /* ADIOS_CPP_H_ */
diff --git a/include/capsule/heap/STLVector.h b/include/capsule/heap/STLVector.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ae8ce9f5c65f0f4304d6f349677d00b2c2517cc
--- /dev/null
+++ b/include/capsule/heap/STLVector.h
@@ -0,0 +1,62 @@
+/*
+ * Heap.h
+ *
+ *  Created on: Dec 19, 2016
+ *      Author: wfg
+ */
+
+#ifndef STLVECTOR_H_
+#define STLVECTOR_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <vector>
+/// \endcond
+
+
+#include "core/Capsule.h"
+
+
+namespace adios
+{
+namespace capsule
+{
+
+/**
+ * Data and Metadata buffers are allocated in the Heap
+ */
+class STLVector : public Capsule
+{
+
+public:
+
+    std::vector<char> m_Data; ///< data buffer allocated using the STL in heap memory, default size = 16 Mb
+    std::vector<char> m_Metadata; ///< metadata buffer allocated using the STL in heap memory, default size = 100 Kb
+
+    /**
+     * Unique constructor
+     * @param accessMode read, write or append
+     * @param rankMPI MPI rank
+     * @param debugMode true: extra checks, slower
+     */
+    STLVector( const std::string accessMode, const int rankMPI, const bool debugMode = false );
+
+    ~STLVector( );
+
+    char* GetData( );
+    char* GetMetadata( );
+
+    std::size_t GetDataSize( ) const;
+    std::size_t GetMetadataSize( ) const;
+
+    void ResizeData( const std::size_t size );
+    void ResizeMetadata( const std::size_t size );
+
+};
+
+
+} //end namespace capsule
+} //end namespace
+
+
+
+#endif /* STLVECTOR_H_ */
diff --git a/include/capsule/shmem/ShmSystemV.h b/include/capsule/shmem/ShmSystemV.h
new file mode 100644
index 0000000000000000000000000000000000000000..d13621c17b36d0dd3bb83793a0fb4ac35766c5ec
--- /dev/null
+++ b/include/capsule/shmem/ShmSystemV.h
@@ -0,0 +1,61 @@
+
+#ifndef SHMSYSTEMV_H_
+#define SHMSYSTEMV_H_
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+
+
+#include "core/Capsule.h"
+
+
+namespace adios
+{
+
+/**
+ * Buffer and Metadata are allocated in virtual memory using interprocess communication (IPC) of Unix's System V
+ */
+class ShmSystemV : public Capsule
+{
+
+public:
+
+    /**
+     * Create a Capsule in shared memory using System V shm API
+     * @param accessMode
+     * @param pathName used to create the key as a unique identifier
+     * @param dataSize size of allocated memory segment for data
+     * @param metadataSize size of allocated memory segment for metadata
+     * @param debugMode true: extra checks, slower
+     */
+    ShmSystemV( const std::string accessMode, const int rankMPI, const std::string pathName,
+                const size_t dataSize, const size_t metadataSize, const bool debugMode = false );
+
+    ~ShmSystemV( );
+
+    char* GetData( ); ///< return the pointer to the raw data buffer
+    char* GetMetadata( ); ///< return the pointer to the raw metadata buffer
+
+    std::size_t GetDataSize( ) const; ///< get current data buffer size
+    std::size_t GetMetadataSize( ) const; ///< get current metadata buffer size
+
+
+private:
+
+    char* m_Data = nullptr; ///< reference to a shared memory data buffer created with shmget
+    const std::size_t m_DataSize; ///< size of the allocated shared memory segment
+    key_t m_DataKey; ///< key associated with the data buffer, created with ftok
+    int m_DataShmID; ///< data shared memory buffer id
+
+    char* m_Metadata = nullptr; ///< reference to a shared memory metadata buffer created with shmget
+    const std::size_t m_MetadataSize; ///< size of the allocated shared memory segment
+    key_t m_MetadataKey; ///< key associated with the metadata buffer, created with ftok
+    int m_MetadataShmID; ///< metadata shared memory buffer id
+
+    void CheckShm( ) const; ///< checks if all shared memory allocations are correct, throws std::bad_alloc, called from constructor if debug mode is true
+};
+
+} //end namespace
+
+
+#endif /* SHMSYSTEMV_H_ */
diff --git a/include/core/Attribute.h b/include/core/Attribute.h
new file mode 100644
index 0000000000000000000000000000000000000000..a35e81bdd90b26fd1f7ef57c117ccd0cacbbec33
--- /dev/null
+++ b/include/core/Attribute.h
@@ -0,0 +1,32 @@
+/*
+ * Attribute.h
+ *
+ *  Created on: Oct 5, 2016
+ *      Author: wfg
+ */
+
+#ifndef ATTRIBUTE_H_
+#define ATTRIBUTE_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+/// \endcond
+
+namespace adios
+{
+
+/**
+ * Plain-old data struct that defines an attribute in an ADIOS group in Group.h
+ */
+struct Attribute
+{
+    const char TypeID; ///< '0': string, '1': numeric
+    const std::string Value; ///< information about the attribute
+};
+
+
+} //end namespace
+
+
+
+#endif /* ATTRIBUTE_H_ */
diff --git a/include/core/Capsule.h b/include/core/Capsule.h
new file mode 100644
index 0000000000000000000000000000000000000000..c04680b028f0ce2789f478495f0a09f4ffbd90da
--- /dev/null
+++ b/include/core/Capsule.h
@@ -0,0 +1,69 @@
+/*
+ * Capsule.h
+ *
+ *  Created on: Dec 7, 2016
+ *      Author: wfgtemplates and pointers
+ */
+
+#ifndef CAPSULE_H_
+#define CAPSULE_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+/// \endcond
+
+
+namespace adios
+{
+
+/**
+ * Base class that raw data and metadata buffers, used by Engine.
+ * Derived classes will allocate their own buffer in different memory spaces.
+ * e.g. locally (heap) or in shared memory (virtual memory)
+ */
+class Capsule
+{
+
+public:
+
+    const std::string m_Type; ///< buffer type
+    const std::string m_AccessMode; ///< 'w': write, 'r': read, 'a': append
+
+    std::size_t m_DataPosition = 0; ///< position in current data buffer (not included data flushed to transports)
+    std::size_t m_DataAbsolutePosition = 0; ///< includes the data flushed to transports
+
+    std::size_t m_MetadataPosition = 0; ///< position in metadata buffer
+
+    /**
+     * Base class constructor providing type from derived class and accessMode
+     * @param type derived class type
+     * @param accessMode 'w':write, 'r':read, 'a':append
+     * @param rankMPI current MPI rank
+     * @param debugMode
+     */
+    Capsule( const std::string type, const std::string accessMode, const int rankMPI, const bool debugMode );
+
+    virtual ~Capsule( );
+
+    virtual char* GetData( ) = 0; ///< return the pointer to the raw data buffer
+    virtual char* GetMetadata( ) = 0; ///< return the pointer to the raw metadata buffer
+
+    virtual std::size_t GetDataSize( ) const = 0; ///< get current data buffer size
+    virtual std::size_t GetMetadataSize( ) const = 0; ///< get current metadata buffer size
+
+    virtual void ResizeData( const std::size_t size ); ///< resize data buffer
+    virtual void ResizeMetadata( const std::size_t size ); ///< resize metadata buffer
+
+
+protected:
+
+    const int m_RankMPI = 0; ///< current MPI rank
+    const bool m_DebugMode = false; ///< true: extra checks
+
+};
+
+
+
+} //end namespace
+
+#endif /* CAPSULE_H_ */
diff --git a/include/core/Engine.h b/include/core/Engine.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a176b2f4657a2f490401d552dc516aa795fa8d2
--- /dev/null
+++ b/include/core/Engine.h
@@ -0,0 +1,449 @@
+/*
+ * Engine.h
+ *
+ *  Created on: Nov 7, 2016
+ *      Author: wfg
+ */
+
+#ifndef ENGINE_H_
+#define ENGINE_H_
+
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <vector>
+#include <string>
+#include <memory> //std::shared_ptr
+#include <map>
+#include <utility> //std::pair
+#include <complex> //std::complex
+/// \endcond
+
+#ifdef ADIOS_NOMPI
+  #include "mpidummy.h"
+#else
+  #include <mpi.h>
+#endif
+
+#include "ADIOSTypes.h"
+#include "ADIOS.h"
+#include "core/Method.h"
+#include "core/Variable.h"
+#include "core/VariableCompound.h"
+#include "core/Transform.h"
+#include "core/Transport.h"
+#include "core/Capsule.h"
+#include "core/Profiler.h"
+
+namespace adios
+{
+
+typedef enum { NONBLOCKINGREAD = 0, BLOCKINGREAD = 1 } PerformReadMode;
+
+
+typedef enum {
+    APPEND = 0, UPDATE = 1,                    // writer advance modes
+    NEXT_AVAILABLE = 2, LATEST_AVAILABLE = 3,  // reader advance modes
+} AdvanceMode;
+
+/**
+ * Base class for Engine operations managing shared-memory, and buffer and variables transform and transport operations
+ */
+class Engine
+{
+
+public:
+
+    MPI_Comm m_MPIComm = MPI_COMM_SELF;
+
+    const std::string m_EngineType; ///< from derived class
+    const std::string m_Name; ///< name used for this engine
+    const std::string m_AccessMode; ///< accessMode for buffers used by this engine
+    const Method& m_Method; ///< associated method containing engine metadata
+
+    int m_RankMPI = 0; ///< current MPI rank process
+    int m_SizeMPI = 1; ///< current MPI processes size
+
+    const std::string m_HostLanguage = "C++"; ///< default host language
+
+    /**
+     * Unique constructor
+     * @param adios
+     * @param engineType
+     * @param name
+     * @param accessMode
+     * @param mpiComm
+     * @param method
+     * @param debugMode
+     * @param nthreads
+     * @param endMessage
+     */
+    Engine( ADIOS& adios, const std::string engineType, const std::string name, const std::string accessMode,
+            MPI_Comm mpiComm, const Method& method, const bool debugMode, const unsigned int nthreads,
+            const std::string endMessage );
+
+    virtual ~Engine( );
+
+
+    /** @brief Let ADIOS allocate memory for a variable, which can be used by the user.
+     *
+     * To decrease the cost of copying memory, a user may let ADIOS allocate the memory for a user-variable,
+     * according to the definition of an ADIOS-variable. The memory will be part of the ADIOS buffer used
+     * by the engine and it lives until the engine (file, stream) is closed.
+     * A variable that has been allocated this way (cannot have its local dimensions changed, and AdvanceAsync() should be
+     * used instead of Advance() and the user-variable must not be modified by the application until the notification arrives.
+     * This is required so that any reader can access the written data before the application overwrites it.
+     * @param var Variable with defined local dimensions and offsets in global space
+     * @param fillValue Fill the allocated array with this value
+     * @return A constant pointer to the non-constant allocated array. User should not deallocate this pointer.
+     */
+    template<class T> inline
+    T * const AllocateVariable( Variable<T>& var, T fillValue = 0 )
+    {
+        throw std::invalid_argument( "ERROR: type not supported for variable " + var->name + " in call to GetVariable\n" );
+    }
+
+    /**
+     * Needed for DataMan Engine
+     * @param callback function passed from the user
+     */
+    virtual void SetCallBack( std::function<void( const void*, std::string, std::string, std::string, Dims )> callback );
+
+    /**
+     * Write function that adds static checking on the variable to be passed by values
+     * It then calls its corresponding derived class virtual function
+     * This version uses m_Group to look for the variableName.
+     * @param variable name of variable to the written
+     * @param values pointer passed from the application
+     */
+    template< class T >
+    void Write( Variable<T>& variable, const T* values )
+    {
+        Write( variable, values );
+    }
+
+    /**
+     * String version
+     * @param variableName
+     * @param values
+     */
+    template< class T >
+    void Write( const std::string variableName, const T* values )
+    {
+        Write( variableName, values );
+    }
+
+    /**
+     * Single value version
+     * @param variable
+     * @param values
+     */
+    template< class T >
+    void Write( Variable<T>& variable, const T values )
+    {
+        const T val = values;
+        Write( variable, &val );
+    }
+
+    /**
+     * Single value version using string as variable handlers, allows rvalues to be passed
+     * @param variableName
+     * @param values
+     */
+    template< class T >
+    void Write( const std::string variableName, const T values )
+    {
+        const T val = values;
+        Write( variableName, &val );
+    }
+
+    virtual void Write( Variable<char>& variable,                      const char* values );
+    virtual void Write( Variable<unsigned char>& variable,             const unsigned char* values );
+    virtual void Write( Variable<short>& variable,                     const short* values );
+    virtual void Write( Variable<unsigned short>& variable,            const unsigned short* values );
+    virtual void Write( Variable<int>& variable,                       const int* values );
+    virtual void Write( Variable<unsigned int>& variable,              const unsigned int* values );
+    virtual void Write( Variable<long int>& variable,                  const long int* values );
+    virtual void Write( Variable<unsigned long int>& variable,         const unsigned long int* values );
+    virtual void Write( Variable<long long int>& variable,             const long long int* values );
+    virtual void Write( Variable<unsigned long long int>& variable,    const unsigned long long int* values );
+    virtual void Write( Variable<float>& variable,                     const float* values );
+    virtual void Write( Variable<double>& variable,                    const double* values );
+    virtual void Write( Variable<long double>& variable,               const long double* values );
+    virtual void Write( Variable<std::complex<float>>& variable,       const std::complex<float>* values );
+    virtual void Write( Variable<std::complex<double>>& variable,      const std::complex<double>* values );
+    virtual void Write( Variable<std::complex<long double>>& variable, const std::complex<long double>* values );
+    virtual void Write( VariableCompound& variable,                    const void* values );
+
+
+    /**
+     * @brief Write functions can be overridden by derived classes. Base class behavior is to:
+     * 1) Write to Variable values (m_Values) using the pointer to default group *m_Group set with SetDefaultGroup function
+     * 2) Transform the data
+     * 3) Write to all capsules -> data and metadata
+     * @param variableName
+     * @param values coming from user app
+     */
+    virtual void Write( const std::string variableName, const char* values );
+    virtual void Write( const std::string variableName, const unsigned char* values );
+    virtual void Write( const std::string variableName, const short* values );
+    virtual void Write( const std::string variableName, const unsigned short* values );
+    virtual void Write( const std::string variableName, const int* values );
+    virtual void Write( const std::string variableName, const unsigned int* values );
+    virtual void Write( const std::string variableName, const long int* values );
+    virtual void Write( const std::string variableName, const unsigned long int* values );
+    virtual void Write( const std::string variableName, const long long int* values );
+    virtual void Write( const std::string variableName, const unsigned long long int* values );
+    virtual void Write( const std::string variableName, const float* values );
+    virtual void Write( const std::string variableName, const double* values );
+    virtual void Write( const std::string variableName, const long double* values );
+    virtual void Write( const std::string variableName, const std::complex<float>* values );
+    virtual void Write( const std::string variableName, const std::complex<double>* values );
+    virtual void Write( const std::string variableName, const std::complex<long double>* values );
+    virtual void Write( const std::string variableName, const void* values );
+
+    /**
+     * Read function that adds static checking on the variable to be passed by values
+     * It then calls its corresponding derived class virtual function
+     * This version uses m_Group to look for the variableName.
+     * @param variable name of variable to the written
+     * @param values pointer passed from the application, nullptr not allowed, must use Read(variable) instead intentionally
+     */
+    template< class T >
+    void Read( Variable<T>& variable, const T* values )
+    {
+        Read( variable, values );
+    }
+
+    /**
+     * String version
+     * @param variableName
+     * @param values
+     */
+    template< class T >
+    void Read( const std::string variableName, const T* values )
+    {
+        Read( variableName, values );
+    }
+
+    /**
+     * Single value version
+     * @param variable
+     * @param values
+     */
+    template< class T >
+    void Read( Variable<T>& variable, const T& values)
+    {
+        Read( variable, &values );
+    }
+
+    /**
+     * Single value version using string as variable handlers
+     * @param variableName
+     * @param values
+     */
+    template< class T >
+    void Read( const std::string variableName, const T& values )
+    {
+        Read( variableName, &values );
+    }
+
+    /**
+     * Unallocated version, ADIOS will allocate space for incoming data
+     * @param variable
+     */
+    template< class T >
+    void Read( Variable<T>& variable )
+    {
+        Read( variable, nullptr );
+    }
+
+    /**
+     * Unallocated version, ADIOS will allocate space for incoming data
+     * @param variableName
+     */
+    template< class T >
+    void Read( const std::string variableName )
+    {
+        Read( variableName, nullptr );
+    }
+
+
+    virtual void Read( Variable<double>& variable,                    const double* values );
+
+
+    /**
+     * Read function that adds static checking on the variable to be passed by values
+     * It then calls its corresponding derived class virtual function
+     * This version uses m_Group to look for the variableName.
+     * @param variable name of variable to the written
+     * @param values pointer passed from the application
+     */
+    template< class T >
+    void ScheduleRead( Variable<T>& variable, const T* values )
+    {
+        ScheduleRead( variable, values );
+    }
+
+    /**
+     * String version
+     * @param variableName
+     * @param values
+     */
+    template< class T >
+    void ScheduleRead( const std::string variableName, const T* values )
+    {
+        ScheduleRead( variableName, values );
+    }
+
+    /**
+     * Single value version
+     * @param variable
+     * @param values
+     */
+    template< class T >
+    void ScheduleRead( Variable<T>& variable, const T& values )
+    {
+        ScheduleRead( variable, &values );
+    }
+
+    /**
+     * Single value version using string as variable handlers
+     * @param variableName
+     * @param values
+     */
+    template< class T >
+    void ScheduleRead( const std::string variableName, const T& values )
+    {
+        ScheduleRead( variableName, &values );
+    }
+
+    /**
+     * Unallocated version, ADIOS will allocate space for incoming data
+     * @param variableName
+     */
+    void ScheduleRead( const std::string variableName )
+    {
+        ScheduleRead( variableName, nullptr );
+    }
+
+    /**
+     * Unallocated unspecified version, ADIOS will receive any variable and will allocate space for incoming data
+     */
+    void ScheduleRead( )
+    {
+        ScheduleRead( nullptr, nullptr );
+    }
+
+    virtual void ScheduleRead( Variable<double>& variable,                    const double* values );
+
+    /**
+     * Perform all scheduled reads, either blocking until all reads completed, or return immediately.
+     * @param mode Blocking or non-blocking modes
+     */
+    void PerformReads( PerformReadMode mode );
+
+    /**
+     * Reader application indicates that no more data will be read from the current stream before advancing.
+     * This is necessary to allow writers to advance as soon as possible.
+     */
+    virtual void Release( );
+
+    /**
+     * Indicates that a new step is going to be written as new variables come in.
+     */
+    virtual void Advance( float timeout_sec=0.0 );
+
+    /**
+     * Indicates that a new step is going to be written as new variables come in.
+     * @param mode Advance mode, there are different options for writers and readers
+     */
+    virtual void Advance( AdvanceMode mode, float timeout_sec=0.0 );
+
+    /** @brief Advance asynchronously and get a callback when readers release access to the buffered step.
+     *
+     * User variables that were allocated through AllocateVariable()
+     * must not be modified until advance is completed.
+     * @param mode Advance mode, there are different options for writers and readers
+     * @param callback Will be called when advance is completed.
+     */
+    virtual void AdvanceAsync ( AdvanceMode mode, std::function<void( std::shared_ptr<adios::Engine> )> callback );
+
+
+    //Read API
+    /**
+     * Inquires and (optionally) allocates and copies the contents of a variable
+     * If success: it returns a pointer to the internal stored variable object in ADIOS class.
+     * If failure: it returns nullptr
+     * @param name variable name to look for
+     * @param readIn if true: reads the full variable and payload, allocating values in memory, if false: internal payload is nullptr
+     * @return success: it returns a pointer to the internal stored variable object in ADIOS class, failure: nullptr
+     */
+    virtual Variable<void>* InquireVariable( const std::string name, const bool readIn = true );
+    virtual Variable<char>* InquireVariableChar( const std::string name, const bool readIn = true );
+    virtual Variable<unsigned char>* InquireVariableUChar( const std::string name, const bool readIn = true );
+    virtual Variable<short>* InquireVariableShort( const std::string name, const bool readIn = true );
+    virtual Variable<unsigned short>* InquireVariableUShort( const std::string name, const bool readIn = true );
+    virtual Variable<int>* InquireVariableInt( const std::string name, const bool readIn = true );
+    virtual Variable<unsigned int>* InquireVariableUInt( const std::string name, const bool readIn = true );
+    virtual Variable<long int>* InquireVariableLInt( const std::string name, const bool readIn = true );
+    virtual Variable<unsigned long int>* InquireVariableULInt( const std::string name, const bool readIn = true );
+    virtual Variable<long long int>* InquireVariableLLInt( const std::string name, const bool readIn = true );
+    virtual Variable<unsigned long long int>* InquireVariableULLInt( const std::string name, const bool readIn = true );
+    virtual Variable<float>* InquireVariableFloat( const std::string name, const bool readIn = true );
+    virtual Variable<double>* InquireVariableDouble( const std::string name, const bool readIn = true );
+    virtual Variable<long double>* InquireVariableLDouble( const std::string name, const bool readIn = true );
+    virtual Variable<std::complex<float>>* InquireVariableCFloat( const std::string name, const bool readIn = true );
+    virtual Variable<std::complex<double>>* InquireVariableCDouble( const std::string name, const bool readIn = true );
+    virtual Variable<std::complex<long double>>* InquireVariableCLDouble( const std::string name, const bool readIn = true );
+    virtual VariableCompound* InquireVariableCompound( const std::string name, const bool readIn = true );
+
+
+    /** Return the names of all variables present in a stream/file opened for reading
+     *
+     * @return a vector of strings
+     */
+    std::vector<std::string> VariableNames();
+
+    virtual void Close( const int transportIndex = -1 ) = 0; ///< Closes a particular transport, or all if -1
+
+
+protected:
+
+    ADIOS& m_ADIOS; ///< reference to ADIOS object that creates this Engine at Open
+    std::vector< std::shared_ptr<Transport> > m_Transports; ///< transports managed
+    const bool m_DebugMode = false; ///< true: additional checks, false: by-pass checks
+    unsigned int m_nThreads = 0;
+    const std::string m_EndMessage; ///< added to exceptions to improve debugging
+    std::set<std::string> m_WrittenVariables; ///< contains the names of the variables that are being written
+
+    virtual void Init( ); ///< Initialize m_Capsules and m_Transports, called from constructor
+    virtual void InitParameters( ); ///< Initialize parameters from Method, called from Initi in constructor
+    virtual void InitTransports( ); ///< Initialize transports from Method, called from Init in constructor
+
+    /**
+     * Used to verify parameters in m_Method containers
+     * @param itParam iterator to a certain parameter
+     * @param parameters map of parameters, from m_Method
+     * @param parameterName used if exception is thrown to provide debugging information
+     * @param hint used if exception is thrown to provide debugging information
+     */
+    void CheckParameter( const std::map<std::string, std::string>::const_iterator itParam,
+                         const std::map<std::string, std::string>& parameters,
+                         const std::string parameterName,
+                         const std::string hint ) const;
+
+    bool TransportNamesUniqueness( ) const; ///< checks if transport names are unique among the same types (file I/O)
+
+
+    /**
+     * Throws an exception in debug mode if transport index is out of range.
+     * @param transportIndex must be in the range [ -1 , m_Transports.size()-1 ]
+     */
+    void CheckTransportIndex( const int transportIndex );
+
+};
+
+
+} //end namespace
+
+#endif /* ENGINE_H_ */
diff --git a/include/core/Method.h b/include/core/Method.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c42b9a916300da8149e82896163913406c58d49
--- /dev/null
+++ b/include/core/Method.h
@@ -0,0 +1,116 @@
+/*
+ * Method.h
+ *
+ *  Created on: Dec 16, 2016
+ *      Author: wfg
+ */
+
+#ifndef METHOD_H_
+#define METHOD_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <vector>
+#include <string>
+#include <map>
+/// \endcond
+
+#include "ADIOSTypes.h"
+#include "functions/adiosFunctions.h"
+
+namespace adios
+{
+
+typedef enum {
+    GLOBAL_READERS = 2, ROUNDROBIN_READERS = 3, FIFO_READERS = 4,
+    OPEN_ALL_STEPS = 5
+} ReadMultiplexPattern;
+
+typedef enum { NOWAITFORSTREAM = 0, WAITFORSTREAM = 1 } StreamOpenMode; // default: wait for stream
+
+/**
+ * Serves as metadata to define an engine
+ */
+class Method
+{
+
+public:
+
+    const std::string m_Name; ///< Method name (as defined in XML)
+    const bool m_DebugMode = false; ///< true: on, throws exceptions and do additional checks, false: off, faster, but unsafe
+    int m_nThreads;
+    std::string m_Type; ///< Method's engine type
+    std::map<std::string, std::string> m_Parameters; ///< method parameters
+    std::vector< std::map<std::string, std::string> > m_TransportParameters; ///< each is a separate Transport containing their own parameters
+
+    /**
+     * Constructor
+     * @param name is a label that can be used in the config file to set up the method at runtime
+     */
+    Method( const std::string name, const bool debugMode = false );
+
+    ~Method( );
+
+    /** Check if the method was defined by the user in the config file.
+     * @return true if the method was user-defined, false otherwise when method is set with default parameters
+     */
+    bool isUserDefined();
+
+
+    /**
+     * Define the engine type
+     * @param type must be a valid engine type
+     */
+    void SetEngine( const std::string type );
+
+
+    /**
+     * Set how many threads the engine can use for its operations (e.g. file io, compression, staging).
+     * If 1 is allowed, no extra threads will be created during the ADIOS calls for asynchronous operations.
+     * Note that some transports may require and use extra thread(s). See their documentation for their
+     * requirements. E.g. some staging transports always create an extra thread for communication.
+     * Set this parameter like you set it for OpenMP, i.e. count one thread for the main process that calls
+     * ADIOS functions.
+     * @param number of threads, minimum 1 is required
+     */
+    void AllowThreads( const int nThreads );
+
+    /**
+     * Sets parameters for the method in "parameter=value" format
+     * @param args list of parameters with format "parameter1=value1", ..., "parameterN=valueN"
+     */
+    template< class ...Args>
+    void SetParameters( Args... args )
+    {
+        std::vector<std::string> parameters = { args... };
+        m_Parameters = BuildParametersMap( parameters, m_DebugMode );
+    }
+
+    /**
+     * Adds a transport and its parameters for the method
+     * @param type must be a supported transport type under /include/transport
+     * @param args list of parameters for a transport with format "parameter1=value1", ..., "parameterN=valueN"
+     */
+    template< class ...Args>
+    void AddTransport( const std::string type, Args... args )
+    {
+        std::vector<std::string> parameters = { args... };
+        AddTransportParameters( type, parameters );
+    }
+
+    void SetReadMultiplexPattern( const ReadMultiplexPattern pattern );  // How to split stream content among readers
+    void SetStreamOpenMode( const StreamOpenMode mode);  // In Read mode, should Open() wait for the first step appear  (default)
+
+    void SetVerbose( const Verbose verbose = Verbose::WARN ) { m_Verbose = verbose; };
+    Verbose GetVerbose( ) { return m_Verbose; };
+
+private:
+    Verbose m_Verbose = Verbose::WARN;
+
+    void AddTransportParameters( const std::string type, const std::vector<std::string>& parameters );
+
+};
+
+
+} //end namespace
+
+#endif /* METHOD_H_ */
diff --git a/include/core/Profiler.h b/include/core/Profiler.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca446ef3a145fc0b0f9e328e1a3f780128efa494
--- /dev/null
+++ b/include/core/Profiler.h
@@ -0,0 +1,95 @@
+/*
+ * Profiler.h
+ *
+ *  Created on: Mar 9, 2017
+ *      Author: wfg
+ */
+
+#ifndef PROFILER_H_
+#define PROFILER_H_
+
+#include <chrono>
+
+#include "Support.h"
+
+namespace adios
+{
+
+class Timer
+{
+
+public:
+    const std::string Process;
+    unsigned long long int ProcessTime = 0;
+
+    Timer( const std::string process, const Support::Resolutions resolution ):
+        Process{ process },
+        Resolution{ resolution }
+        { }
+
+        void SetInitialTime( )
+        {
+            InitialTime = std::chrono::high_resolution_clock::now();
+        }
+
+        void SetTime( )
+        {
+            ElapsedTime = std::chrono::high_resolution_clock::now();
+            ProcessTime += GetTime( );
+        }
+
+        long long int GetTime( )
+        {
+            if( Resolution == Support::Resolutions::mus )
+                return std::chrono::duration_cast<std::chrono::microseconds>( ElapsedTime - InitialTime ).count();
+
+            else if( Resolution == Support::Resolutions::ms )
+                return std::chrono::duration_cast<std::chrono::milliseconds>( ElapsedTime - InitialTime ).count();
+
+            else if( Resolution == Support::Resolutions::s )
+                return std::chrono::duration_cast<std::chrono::seconds>( ElapsedTime - InitialTime ).count();
+
+            else if( Resolution == Support::Resolutions::m )
+                return std::chrono::duration_cast<std::chrono::minutes>( ElapsedTime - InitialTime ).count();
+
+            else if( Resolution == Support::Resolutions::h )
+                return std::chrono::duration_cast<std::chrono::hours>( ElapsedTime - InitialTime ).count();
+
+            return -1; //failure
+        }
+
+        std::string GetUnits( ) const
+        {
+            std::string units;
+            if( Resolution == Support::Resolutions::mus )      units = "mus";
+            else if( Resolution == Support::Resolutions::ms )  units = "ms";
+            else if( Resolution == Support::Resolutions::s )   units = "s";
+            else if( Resolution == Support::Resolutions::m )   units = "m";
+            else if( Resolution == Support::Resolutions::h )   units = "h";
+            return units;
+        }
+
+private:
+
+        const Support::Resolutions Resolution;
+        std::chrono::time_point<std::chrono::high_resolution_clock> InitialTime;
+        std::chrono::time_point<std::chrono::high_resolution_clock> ElapsedTime;
+        bool InitialTimeSet = false;
+};
+
+
+/**
+ * Utilities for profiling using the chrono header in C++11
+ */
+struct Profiler
+{
+    std::vector<Timer> m_Timers;
+    std::vector<unsigned long long int> m_TotalBytes;
+    bool m_IsActive = false;
+};
+
+} //end namespace
+
+
+
+#endif /* PROFILER_H_ */
diff --git a/include/core/Support.h b/include/core/Support.h
new file mode 100644
index 0000000000000000000000000000000000000000..f8830a2586825460cd02ed2230e6d9acdc6edfbc
--- /dev/null
+++ b/include/core/Support.h
@@ -0,0 +1,41 @@
+/*
+ * SSupport.h
+ *
+ *  Created on: Oct 10, 2016
+ *      Author: wfg
+ */
+
+#ifndef SUPPORT_H_
+#define SUPPORT_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <set>
+#include <string>
+#include <map>
+#include <array>
+/// \endcond
+
+namespace adios
+{
+
+
+struct Support
+{
+    static const std::string Version; ///< current ADIOS version
+    static const std::set<std::string> HostLanguages; ///< supported languages: C, C++, Fortran, Python, Java
+    static const std::set<std::string> Numbers;
+    static const std::set<std::string> Transports; ///< supported transport methods
+    static const std::set<std::string> Transforms; ///< supported data transform methods
+    static const std::map<std::string, std::set<std::string> > Datatypes; ///< supported data types, key: host language, value: all supported types
+    static const std::map<std::string, std::set<std::string> > DatatypesAliases; ///< all supported int aliases, key: C++ type (e.g. int), value: aliases to type in key (e.g. int, integer)
+
+    static const std::set<std::string> FileTransports; ///< file I/O transports
+
+    enum class Resolutions { mus, ms, s, m, h };
+};
+
+
+} //end namespace
+
+
+#endif /* SUPPORT_H_ */
diff --git a/include/core/Transform.h b/include/core/Transform.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c8a08451c82ec845dcbc72597713e0ed7422b82
--- /dev/null
+++ b/include/core/Transform.h
@@ -0,0 +1,47 @@
+/*
+ * Transform.h
+ *
+ *  Created on: Oct 17, 2016
+ *      Author: wfg
+ */
+
+#ifndef TRANSFORM_H_
+#define TRANSFORM_H_
+
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+#include <vector>
+/// \endcond
+
+
+namespace adios
+{
+
+/**
+ * Parent class that defines data variable transformations. Used as a member of CVariable
+ */
+class Transform
+{
+
+public:
+
+    const std::string m_Method;
+
+    /**
+     * Initialize parent method
+     * @param method zlib, bzip2, szip
+     */
+    Transform( const std::string method );
+
+    virtual ~Transform( );
+
+    virtual void Compress( const std::vector<char>& bufferIn, std::vector<char>& bufferOut );
+
+    virtual void Decompress( const std::vector<char>& bufferIn, std::vector<char>& bufferOut );
+
+};
+
+
+} //end namespace
+#endif /* TRANSFORM_H_ */
diff --git a/include/core/Transport.h b/include/core/Transport.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c2c0d0bacec7fb76e4584ab5774723b0c0da8fd
--- /dev/null
+++ b/include/core/Transport.h
@@ -0,0 +1,94 @@
+/*
+ * Transport.h
+ *
+ *  Created on: Oct 6, 2016
+ *      Author: wfg
+ */
+
+#ifndef TRANSPORT_H_
+#define TRANSPORT_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+#include <vector>
+/// \endcond
+
+#ifdef ADIOS_NOMPI
+  #include "mpidummy.h"
+#else
+  #include <mpi.h>
+#endif
+
+#include "core/Profiler.h"
+
+
+namespace adios
+{
+
+class Transport
+{
+
+public:
+
+    const std::string m_Type; ///< transport type from derived class
+    std::string m_Name; ///< from Open
+    std::string m_AccessMode; ///< from Open
+    bool m_IsOpen = false;
+
+    MPI_Comm m_MPIComm = MPI_COMM_SELF;
+
+    int m_RankMPI = 0; ///< current MPI rank process
+    int m_SizeMPI = 1; ///< current MPI processes size
+    Profiler m_Profiler; ///< collects information about Open and bytes Transport
+
+    /**
+     * Base constructor that all derived classes pass
+     * @param
+     * @param mpiComm passed to m_MPIComm
+     * @param debugMode passed to m_DebugMode
+     */
+    Transport( const std::string type, MPI_Comm mpiComm, const bool debugMode );
+
+
+    virtual ~Transport( ); ///< empty destructor, using STL for memory management
+
+    /**
+     * Open Output file accesing a mode
+     * @param name name of stream or file
+     * @param accessMode r or read, w or write, a or append
+     */
+    virtual void Open( const std::string name, const std::string accessMode ) = 0;
+
+    /**
+     * Set buffer and size for a particular transport
+     * @param buffer raw data buffer
+     * @param size raw data buffer size
+     */
+    virtual void SetBuffer( char* buffer, std::size_t size );
+
+    /**
+     * Write function for a transport
+     * @param buffer pointer to buffer to be written
+     * @param size size of buffer to be written
+     */
+    virtual void Write( const char* buffer, std::size_t size ) = 0;
+
+    virtual void Flush( ); ///< flushes current contents to physical medium without closing the transport
+
+    virtual void Close( ); ///< closes current transport and flushes everything, transport becomes unreachable
+
+
+    virtual void InitProfiler( const std::string accessMode, const Support::Resolutions resolution );
+
+protected:
+
+    const bool m_DebugMode = false; ///< if true: additional checks and exceptions
+};
+
+
+
+} //end namespace
+
+
+
+#endif /* TRANSPORT_H_ */
diff --git a/include/core/Variable.h b/include/core/Variable.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec8c636df6507073bf214f61037af98536a4d020
--- /dev/null
+++ b/include/core/Variable.h
@@ -0,0 +1,111 @@
+/*
+ * Variable.h
+ *
+ *  Created on: Oct 6, 2016
+ *      Author: wfg
+ */
+
+#ifndef VARIABLE_H_
+#define VARIABLE_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+#include <vector>
+#include <map>
+#include <ostream> //std::ostream in MonitorGroups
+/// \endcond
+
+#include "core/VariableBase.h"
+#include "core/Transform.h"
+
+
+namespace adios
+{
+
+
+struct TransformData
+{
+    Transform& Operation; ///< pointer to transform object
+    std::map<std::string, std::string> Parameters; ///< transforms parameters
+    std::vector<std::size_t> Size;  ///< vector that carries the sizes after a transformation is applied
+};
+
+/**
+ * @param Base (parent) class for template derived (child) class CVariable. Required to put CVariable objects in STL containers.
+ */
+template< class T >
+class Variable : public VariableBase
+{
+
+public:
+
+    const T* m_AppValues = nullptr; ///< pointer to values passed from user in ADIOS Write, it might change in ADIOS Read
+
+    std::vector< TransformData > m_Transforms; ///< associated transforms, sequence determines application order, e.g. first Transforms[0] then Transforms[1]. Pointer used as reference (no memory management).
+
+    Variable<T>( const std::string name, const Dims dimensions, const Dims globalDimensions, const Dims globalOffsets,
+                 const bool debugMode ):
+        VariableBase( name, GetType<T>(), sizeof(T), dimensions, globalDimensions, globalOffsets, debugMode )
+    {
+        if( m_Dimensions == Dims{1} )
+            m_IsScalar = true;
+    }
+
+    template< class ...Args>
+    void AddTransform( Transform& transform, Args... args )
+    {
+        std::vector<std::string> parameters = { args... };
+        m_Transforms.emplace_back( transform, BuildParametersMap( parameters, m_DebugMode ) ); //need to check
+    }
+
+    /** Return the global dimensions of the variable
+     *  @return vector of std::size_t values
+     */
+    std::vector<std::size_t> GetGlobalDimensions();
+
+    /** Return the number of steps available for the variable
+     *  @return Number of steps
+     */
+    int GetSteps();
+    
+    void Monitor( std::ostream& logInfo ) const noexcept
+    {
+        logInfo << "Variable: " << m_Name << "\n";
+        logInfo << "Type: " << m_Type << "\n";
+        logInfo << "Size: " << TotalSize() << " elements\n";
+        logInfo << "Payload: " << PayLoadSize() << " bytes\n";
+
+        if( m_AppValues != nullptr )
+        {
+            logInfo << "Values (first 10 or max_size): \n";
+            std::size_t size = TotalSize();
+            if( size > 10 )
+                size = 10;
+
+            if( m_Type.find("complex") != m_Type.npos ) //it's complex
+            {
+                for( unsigned int i = 0; i < size; ++i  )
+                {
+                    logInfo << "( " << std::real( m_AppValues[i] ) << " , " << std::imag( m_AppValues[i] ) << " )  ";
+                }
+            }
+            else
+            {
+                for( unsigned int i = 0; i < size; ++i  )
+                {
+                    logInfo << m_AppValues[i] << " ";
+                }
+            }
+
+            logInfo << " ...";
+        }
+        logInfo << "\n";
+    }
+
+};
+
+
+} //end namespace
+
+
+#endif /* VARIABLE_H_ */
diff --git a/include/core/VariableBase.h b/include/core/VariableBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..4dddf13b7858cf116017c1b2ff8716871dc296ac
--- /dev/null
+++ b/include/core/VariableBase.h
@@ -0,0 +1,115 @@
+/*
+ * VariableBase.h
+ *
+ *  Created on: Feb 20, 2017
+ *      Author: wfg
+ */
+
+#ifndef VARIABLEBASE_H_
+#define VARIABLEBASE_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <vector>
+#include <string>
+#include <sstream>
+#include <iterator>
+/// \endcond
+
+#include "functions/adiosFunctions.h" //GetTotalSize
+#include "functions/adiosTemplates.h" //GetType<T>
+
+
+namespace adios
+{
+
+using Dims = std::vector<std::size_t>;
+
+class VariableBase
+{
+
+public:
+
+    const std::string m_Name; ///< variable name
+    const std::string m_Type; ///< variable type
+    const std::size_t m_ElementSize; ///< Variable -> sizeof(T), VariableCompound -> from constructor
+
+    bool m_IsScalar = false;
+    const bool m_IsDimension = false;
+
+
+    VariableBase( const std::string name, const std::string type, const std::size_t elementSize,
+                  const Dims dimensions, const Dims globalDimensions, const Dims globalOffsets,
+                  const bool debugMode ):
+        m_Name{ name },
+        m_Type{ type },
+        m_ElementSize{ elementSize },
+        m_Dimensions{ dimensions },
+        m_GlobalDimensions{ globalDimensions },
+        m_GlobalOffsets{ globalOffsets },
+        m_DebugMode{ debugMode }
+    { }
+
+    virtual ~VariableBase( )
+    { }
+
+
+    std::size_t DimensionsSize( ) const noexcept
+    {
+        return m_Dimensions.size();
+    }
+
+    /**
+     * Returns the payload size in bytes
+     * @return TotalSize * sizeof(T)
+     */
+    std::size_t PayLoadSize( ) const noexcept
+    {
+        return GetTotalSize( m_Dimensions ) * m_ElementSize;
+    }
+
+    /**
+     * Returns the total size
+     * @return number of elements
+     */
+    std::size_t TotalSize( ) const noexcept
+    {
+        return GetTotalSize( m_Dimensions );
+    }
+
+
+//protected: off for now
+
+    Dims m_Dimensions; ///< array of local dimensions
+    Dims m_GlobalDimensions; ///< array of global dimensions
+    Dims m_GlobalOffsets; ///< array of global offsets
+    const bool m_DebugMode = false;
+
+
+    std::string GetDimensionAsString() { return dimsToString( m_Dimensions ); }
+    std::string GetGlobalDimensionAsString() { return dimsToString( m_GlobalDimensions ); }
+    std::string GetOffsetsAsString() { return dimsToString( m_GlobalOffsets ); }
+
+
+private:
+    std::string dimsToString( Dims dims )
+    {
+        std::ostringstream oss;
+        if (!dims.empty())
+        {
+            // Convert all but the last element to avoid a trailing ","
+            std::copy(dims.begin(), dims.end()-1,
+                    std::ostream_iterator<std::size_t>(oss, ","));
+            // Now add the last element with no delimiter
+            oss << dims.back();
+        }
+        return oss.str();
+    }
+};
+
+
+
+
+}
+
+
+#endif /* VARIABLEBASE_H_ */
diff --git a/include/core/VariableCompound.h b/include/core/VariableCompound.h
new file mode 100644
index 0000000000000000000000000000000000000000..1fda61ab485d8007eea108a90ab1b114d6231987
--- /dev/null
+++ b/include/core/VariableCompound.h
@@ -0,0 +1,67 @@
+/*
+ * VariableCompound.h
+ *
+ *  Created on: Feb 20, 2017
+ *      Author: wfg
+ */
+
+#ifndef VARIABLECOMPOUND_H_
+#define VARIABLECOMPOUND_H_
+
+#include "core/VariableBase.h"
+
+namespace adios
+{
+
+struct CompoundElement
+{
+    const std::string m_Name;
+    const std::size_t m_Offset;
+    const std::string m_Type;
+};
+
+
+/**
+ * @param Base (parent) class for template derived (child) class CVariable. Required to put CVariable objects in STL containers.
+ */
+class VariableCompound : public VariableBase
+{
+
+public:
+
+    const void* m_AppValue = nullptr;
+
+
+    VariableCompound( const std::string name, const std::size_t sizeOfStruct, const Dims dimensions,
+                      const Dims globalDimensions, const Dims globalOffsets, const bool debugMode ):
+        VariableBase( name, "compound", sizeOfStruct, dimensions, globalDimensions, globalOffsets, debugMode )
+    { }
+
+    template< class U >
+    void InsertMember( const std::string name, const std::size_t offset )
+    {
+        m_Elements.push_back( CompoundElement{ name, offset, GetType<U>() } );
+    }
+
+    void Monitor( std::ostream& logInfo ) const noexcept
+    {
+        logInfo << "Variable Compound: " << m_Name << "\n";
+        logInfo << "Type: " << m_Type << "\n";
+        logInfo << "Size: " << TotalSize() << " elements\n";
+        logInfo << "Payload: " << PayLoadSize() << " bytes\n";
+    }
+
+
+private:
+
+    std::vector<CompoundElement> m_Elements; ///< vector of element types
+
+};
+
+
+
+
+} //end namespace
+
+
+#endif /* VARIABLECOMPOUND_H_ */
diff --git a/include/engine/adios1/ADIOS1Reader.h b/include/engine/adios1/ADIOS1Reader.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a91b9a6c1e67a1c81651cf5343f1360ff6f8cb1
--- /dev/null
+++ b/include/engine/adios1/ADIOS1Reader.h
@@ -0,0 +1,104 @@
+/*
+ * ADIOS1Reader.h
+ * Class to read files using old adios 1.x library.
+ * It requires adios 1.x installed
+ *
+ *  Created on: Mar 27, 2017
+ *      Author: pnb
+ */
+
+#ifndef BPFILEREADER_H_
+#define BPFILEREADER_H_
+
+#include <iostream> //this must go away
+
+#include "core/Engine.h"
+
+//supported capsules
+#include "capsule/heap/STLVector.h"
+
+
+namespace adios
+{
+
+
+class BPFileReader : public Engine
+{
+
+public:
+
+    /**
+     * Constructor for single BP capsule engine, writes in BP format into a single heap capsule
+     * @param name unique name given to the engine
+     * @param accessMode
+     * @param mpiComm
+     * @param method
+     * @param debugMode
+     * @param hostLanguage
+     */
+    BPFileReader( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                   const Method& method, const IOMode iomode, const float timeout_sec,
+                   const bool debugMode = false, const unsigned int nthreads = 1 );
+
+    ~BPFileReader( );
+
+
+    Variable<void>* InquireVariable( const std::string name, const bool readIn = true );
+    Variable<char>* InquireVariableChar( const std::string name, const bool readIn = true );
+    Variable<unsigned char>* InquireVariableUChar( const std::string name, const bool readIn = true );
+    Variable<short>* InquireVariableShort( const std::string name, const bool readIn = true );
+    Variable<unsigned short>* InquireVariableUShort( const std::string name, const bool readIn = true );
+    Variable<int>* InquireVariableInt( const std::string name, const bool readIn = true );
+    Variable<unsigned int>* InquireVariableUInt( const std::string name, const bool readIn = true );
+    Variable<long int>* InquireVariableLInt( const std::string name, const bool readIn = true );
+    Variable<unsigned long int>* InquireVariableULInt( const std::string name, const bool readIn = true );
+    Variable<long long int>* InquireVariableLLInt( const std::string name, const bool readIn = true );
+    Variable<unsigned long long int>* InquireVariableULLInt( const std::string name, const bool readIn = true );
+    Variable<float>* InquireVariableFloat( const std::string name, const bool readIn = true );
+    Variable<double>* InquireVariableDouble( const std::string name, const bool readIn = true );
+    Variable<long double>* InquireVariableLDouble( const std::string name, const bool readIn = true );
+    Variable<std::complex<float>>* InquireVariableCFloat( const std::string name, const bool readIn = true );
+    Variable<std::complex<double>>* InquireVariableCDouble( const std::string name, const bool readIn = true );
+    Variable<std::complex<long double>>* InquireVariableCLDouble( const std::string name, const bool readIn = true );
+
+    /**
+     * Not implemented
+     * @param name
+     * @param readIn
+     * @return
+     */
+    VariableCompound* InquireVariableCompound( const std::string name, const bool readIn = true );
+
+
+    void Close( const int transportIndex = -1 );
+
+private:
+
+    capsule::STLVector m_Buffer; ///< heap capsule, contains data and metadata buffers
+    //format::BP1Writer m_BP1Writer; ///< format object will provide the required BP functionality to be applied on m_Buffer and m_Transports
+
+    void Init( );  ///< calls InitCapsules and InitTransports based on Method, called from constructor
+    void InitCapsules( );
+    void InitTransports( ); ///< from Transports
+
+    std::string GetMdtmParameter( const std::string parameter, const std::map<std::string,std::string>& mdtmParameters );
+
+
+    template< class T >
+    Variable<T>* InquireVariableCommon( const std::string name, const bool readIn )
+    {
+        std::cout << "Hello BPReaderCommon\n";
+
+        //here read variable metadata (dimensions, type, etc.)...then create a Variable like below:
+        //Variable<T>& variable = m_ADIOS.DefineVariable<T>( m_Name + "/" + name, )
+        //return &variable; //return address if success
+        return nullptr; //on failure
+    }
+};
+
+
+
+} //end namespace adios
+
+
+#endif /* BPFILEREADER_H_ */
diff --git a/include/engine/adios1/ADIOS1Writer.h b/include/engine/adios1/ADIOS1Writer.h
new file mode 100644
index 0000000000000000000000000000000000000000..bfa235ba02c44c062f206598c2ab2583943a26ed
--- /dev/null
+++ b/include/engine/adios1/ADIOS1Writer.h
@@ -0,0 +1,118 @@
+/*
+ * ADIOS1Writer.h
+ * Class to write files using old adios 1.x library.
+ * It requires adios 1.x installed
+ *
+ *  Created on: Mar 27, 2017
+ *      Author: pnb
+ */
+
+#ifndef ADIOS1WRITER_H_
+#define ADIOS1WRITER_H_
+
+#include "core/Engine.h"
+
+
+namespace adios
+{
+
+#ifdef ADIOS_NOMPI
+#  define _NOMPI 1
+#endif
+#include "adios.h"  // this is adios 1.x header file
+
+
+class ADIOS1Writer : public Engine
+{
+
+public:
+
+    /**
+     * Constructor for Writer writes in ADIOS 1.x BP format
+     * @param name unique name given to the engine
+     * @param accessMode
+     * @param mpiComm
+     * @param method
+     * @param debugMode
+     */
+    ADIOS1Writer( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                  const Method& method, const IOMode iomode, const float timeout_sec,
+                  const bool debugMode = false, const unsigned int nthreads = 1 );
+
+    ~ADIOS1Writer( );
+
+    void Write( Variable<char>& variable, const char* values );
+    void Write( Variable<unsigned char>& variable, const unsigned char* values );
+    void Write( Variable<short>& variable, const short* values );
+    void Write( Variable<unsigned short>& variable, const unsigned short* values );
+    void Write( Variable<int>& variable, const int* values );
+    void Write( Variable<unsigned int>& variable, const unsigned int* values );
+    void Write( Variable<long int>& variable, const long int* values );
+    void Write( Variable<unsigned long int>& variable, const unsigned long int* values );
+    void Write( Variable<long long int>& variable, const long long int* values );
+    void Write( Variable<unsigned long long int>& variable, const unsigned long long int* values );
+    void Write( Variable<float>& variable, const float* values );
+    void Write( Variable<double>& variable, const double* values );
+    void Write( Variable<long double>& variable, const long double* values );
+    void Write( Variable<std::complex<float>>& variable,       const std::complex<float>* values );
+    void Write( Variable<std::complex<double>>& variable,      const std::complex<double>* values );
+    void Write( Variable<std::complex<long double>>& variable, const std::complex<long double>* values );
+    void Write( VariableCompound& variable, const void* values );
+
+    void Write( const std::string variableName, const char* values );
+    void Write( const std::string variableName, const unsigned char* values );
+    void Write( const std::string variableName, const short* values );
+    void Write( const std::string variableName, const unsigned short* values );
+    void Write( const std::string variableName, const int* values );
+    void Write( const std::string variableName, const unsigned int* values );
+    void Write( const std::string variableName, const long int* values );
+    void Write( const std::string variableName, const unsigned long int* values );
+    void Write( const std::string variableName, const long long int* values );
+    void Write( const std::string variableName, const unsigned long long int* values );
+    void Write( const std::string variableName, const float* values );
+    void Write( const std::string variableName, const double* values );
+    void Write( const std::string variableName, const long double* values );
+    void Write( const std::string variableName, const std::complex<float>* values );
+    void Write( const std::string variableName, const std::complex<double>* values );
+    void Write( const std::string variableName, const std::complex<long double>* values );
+    void Write( const std::string variableName, const void* values );
+
+    void Advance( );
+
+    /**
+     * Closes a single transport or all transports
+     * @param transportIndex, if -1 (default) closes all transports, otherwise it closes a transport in m_Transport[transportIndex]. In debug mode the latter is bounds-checked.
+     */
+    void Close( const int transportIndex = -1 );
+
+
+private:
+
+    const char * m_groupname; ///< ADIOS1 group name created from the method's name. Must be a unique group name.
+    const char * m_filename; ///< Save file name from constructor for Advance() when we re-open in ADIOS1
+    MPI_Comm m_comm; ///< Save MPI communicator from constructor for Advance() when we re-open in ADIOS1
+
+    bool m_initialized = false; ///< set to true after calling adios_init()
+    int64_t m_adios_file = 0;  ///< ADIOS1 file handler returned by adios_open()
+    int64_t m_adios_group = 0;  ///< ADIOS1 group pointer that holds the ADIOS1 variable definitions
+    bool m_IsFileOpen = false;
+
+    void Init( );
+    // these are unused yet, keeping here to see if we need them
+    void InitParameters( );
+    void InitTransports( );
+    void InitProcessGroup( );
+
+    bool ReOpenAsNeeded( ); // return true if file is open or reopened
+    void DefineVariable( std::string name, bool isScalar, enum ADIOS_DATATYPES vartype,
+                         std::string ldims, std::string gdims, std::string offs );
+    void WriteVariable( std::string name, bool isScalar, enum ADIOS_DATATYPES vartype,
+                        std::string ldims, std::string gdims, std::string offs, const void * values );
+
+};
+
+
+} //end namespace adios
+
+
+#endif /* ADIOS1WRITER_H_ */
diff --git a/include/engine/bp/BPFileReader.h b/include/engine/bp/BPFileReader.h
new file mode 100644
index 0000000000000000000000000000000000000000..445713c974c082f0035230c9e460beaf47323efc
--- /dev/null
+++ b/include/engine/bp/BPFileReader.h
@@ -0,0 +1,102 @@
+/*
+ * BPReader.h
+ *
+ *  Created on: Feb 27, 2017
+ *      Author: wfg
+ */
+
+#ifndef BPFILEREADER_H_
+#define BPFILEREADER_H_
+
+#include <iostream> //this must go away
+
+#include "core/Engine.h"
+
+//supported capsules
+#include "capsule/heap/STLVector.h"
+
+
+namespace adios
+{
+
+
+class BPFileReader : public Engine
+{
+
+public:
+
+    /**
+     * Constructor for single BP capsule engine, writes in BP format into a single heap capsule
+     * @param name unique name given to the engine
+     * @param accessMode
+     * @param mpiComm
+     * @param method
+     * @param debugMode
+     * @param hostLanguage
+     */
+    BPFileReader( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                   const Method& method, const IOMode iomode, const float timeout_sec,
+                   const bool debugMode = false, const unsigned int nthreads = 1 );
+
+    ~BPFileReader( );
+
+
+    Variable<void>* InquireVariable( const std::string name, const bool readIn = true );
+    Variable<char>* InquireVariableChar( const std::string name, const bool readIn = true );
+    Variable<unsigned char>* InquireVariableUChar( const std::string name, const bool readIn = true );
+    Variable<short>* InquireVariableShort( const std::string name, const bool readIn = true );
+    Variable<unsigned short>* InquireVariableUShort( const std::string name, const bool readIn = true );
+    Variable<int>* InquireVariableInt( const std::string name, const bool readIn = true );
+    Variable<unsigned int>* InquireVariableUInt( const std::string name, const bool readIn = true );
+    Variable<long int>* InquireVariableLInt( const std::string name, const bool readIn = true );
+    Variable<unsigned long int>* InquireVariableULInt( const std::string name, const bool readIn = true );
+    Variable<long long int>* InquireVariableLLInt( const std::string name, const bool readIn = true );
+    Variable<unsigned long long int>* InquireVariableULLInt( const std::string name, const bool readIn = true );
+    Variable<float>* InquireVariableFloat( const std::string name, const bool readIn = true );
+    Variable<double>* InquireVariableDouble( const std::string name, const bool readIn = true );
+    Variable<long double>* InquireVariableLDouble( const std::string name, const bool readIn = true );
+    Variable<std::complex<float>>* InquireVariableCFloat( const std::string name, const bool readIn = true );
+    Variable<std::complex<double>>* InquireVariableCDouble( const std::string name, const bool readIn = true );
+    Variable<std::complex<long double>>* InquireVariableCLDouble( const std::string name, const bool readIn = true );
+
+    /**
+     * Not implemented
+     * @param name
+     * @param readIn
+     * @return
+     */
+    VariableCompound* InquireVariableCompound( const std::string name, const bool readIn = true );
+
+
+    void Close( const int transportIndex = -1 );
+
+private:
+
+    capsule::STLVector m_Buffer; ///< heap capsule, contains data and metadata buffers
+    //format::BP1Writer m_BP1Writer; ///< format object will provide the required BP functionality to be applied on m_Buffer and m_Transports
+
+    void Init( );  ///< calls InitCapsules and InitTransports based on Method, called from constructor
+    void InitCapsules( );
+    void InitTransports( ); ///< from Transports
+
+    std::string GetMdtmParameter( const std::string parameter, const std::map<std::string,std::string>& mdtmParameters );
+
+
+    template< class T >
+    Variable<T>* InquireVariableCommon( const std::string name, const bool readIn )
+    {
+        std::cout << "Hello BPReaderCommon\n";
+
+        //here read variable metadata (dimensions, type, etc.)...then create a Variable like below:
+        //Variable<T>& variable = m_ADIOS.DefineVariable<T>( m_Name + "/" + name, )
+        //return &variable; //return address if success
+        return nullptr; //on failure
+    }
+};
+
+
+
+} //end namespace adios
+
+
+#endif /* BPFILEREADER_H_ */
diff --git a/include/engine/bp/BPFileWriter.h b/include/engine/bp/BPFileWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..923d0b22764be8fa10977f6bb4c36be2e096ea82
--- /dev/null
+++ b/include/engine/bp/BPFileWriter.h
@@ -0,0 +1,160 @@
+/*
+ * BPWriter.h
+ *
+ *  Created on: Dec 16, 2016
+ *      Author: wfg
+ */
+
+#ifndef BPFILEWRITER_H_
+#define BPFILEWRITER_H_
+
+#include "core/Engine.h"
+#include "format/BP1Writer.h"
+#include "format/BP1Aggregator.h"
+
+//supported capsules
+#include "capsule/heap/STLVector.h"
+
+
+namespace adios
+{
+
+class BPFileWriter : public Engine
+{
+
+public:
+
+    /**
+     * Constructor for Writer writes in BP format into a single heap capsule, manages several transports
+     * @param name unique name given to the engine
+     * @param accessMode
+     * @param mpiComm
+     * @param method
+     * @param debugMode
+     */
+    BPFileWriter( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                  const Method& method, const IOMode iomode = IOMode::INDEPENDENT, const float timeout_sec = 0.,
+                  const bool debugMode = false, const unsigned int nthreads = 1 );
+
+    ~BPFileWriter( );
+
+    void Write( Variable<char>& variable, const char* values );
+    void Write( Variable<unsigned char>& variable, const unsigned char* values );
+    void Write( Variable<short>& variable, const short* values );
+    void Write( Variable<unsigned short>& variable, const unsigned short* values );
+    void Write( Variable<int>& variable, const int* values );
+    void Write( Variable<unsigned int>& variable, const unsigned int* values );
+    void Write( Variable<long int>& variable, const long int* values );
+    void Write( Variable<unsigned long int>& variable, const unsigned long int* values );
+    void Write( Variable<long long int>& variable, const long long int* values );
+    void Write( Variable<unsigned long long int>& variable, const unsigned long long int* values );
+    void Write( Variable<float>& variable, const float* values );
+    void Write( Variable<double>& variable, const double* values );
+    void Write( Variable<long double>& variable, const long double* values );
+    void Write( Variable<std::complex<float>>& variable,       const std::complex<float>* values );
+    void Write( Variable<std::complex<double>>& variable,      const std::complex<double>* values );
+    void Write( Variable<std::complex<long double>>& variable, const std::complex<long double>* values );
+    void Write( VariableCompound& variable, const void* values );
+
+    void Write( const std::string variableName, const char* values );
+    void Write( const std::string variableName, const unsigned char* values );
+    void Write( const std::string variableName, const short* values );
+    void Write( const std::string variableName, const unsigned short* values );
+    void Write( const std::string variableName, const int* values );
+    void Write( const std::string variableName, const unsigned int* values );
+    void Write( const std::string variableName, const long int* values );
+    void Write( const std::string variableName, const unsigned long int* values );
+    void Write( const std::string variableName, const long long int* values );
+    void Write( const std::string variableName, const unsigned long long int* values );
+    void Write( const std::string variableName, const float* values );
+    void Write( const std::string variableName, const double* values );
+    void Write( const std::string variableName, const long double* values );
+    void Write( const std::string variableName, const std::complex<float>* values );
+    void Write( const std::string variableName, const std::complex<double>* values );
+    void Write( const std::string variableName, const std::complex<long double>* values );
+    void Write( const std::string variableName, const void* values );
+
+    void Advance( float timeout_sec = 0.0 );
+
+    /**
+     * Closes a single transport or all transports
+     * @param transportIndex, if -1 (default) closes all transports, otherwise it closes a transport in m_Transport[transportIndex]. In debug mode the latter is bounds-checked.
+     */
+    void Close( const int transportIndex = -1 );
+
+
+private:
+
+    capsule::STLVector m_Buffer; ///< heap capsule using STL std::vector<char>
+    format::BP1Writer m_BP1Writer; ///< format object will provide the required BP functionality to be applied on m_Buffer and m_Transports
+    format::BP1MetadataSet m_MetadataSet; ///< metadata set accompanying the heap buffer data in bp format. Needed by m_BP1Writer
+    format::BP1Aggregator m_BP1Aggregator;
+
+    bool m_IsFirstClose = true; ///< set to false after first Close is reached so metadata doesn't have to be accommodated for a subsequent Close
+    std::size_t m_MaxBufferSize; ///< maximum allowed memory to be allocated
+    float m_GrowthFactor = 1.5; ///< capsule memory growth factor, new_memory = m_GrowthFactor * current_memory
+
+    bool m_TransportFlush = false; ///< true: transport flush happened, buffer must be reset
+    bool m_CloseProcessGroup = false; ///< set to true if advance is called, this prevents flattening the data and metadata in Close
+
+    void Init( );
+    void InitParameters( );
+    void InitTransports( );
+    void InitProcessGroup( );
+
+    void WriteProcessGroupIndex( );
+
+    /**
+     * Common function for primitive (including std::complex) writes
+     * @param group
+     * @param variableName
+     * @param variable
+     */
+    template< class T >
+    void WriteVariableCommon( Variable<T>& variable, const T* values )
+    {
+        if( m_MetadataSet.Log.m_IsActive == true )
+            m_MetadataSet.Log.m_Timers[0].SetInitialTime();
+
+        //set variable
+        variable.m_AppValues = values;
+        m_WrittenVariables.insert( variable.m_Name );
+
+        //if first timestep Write
+        if( m_MetadataSet.DataPGIsOpen == false ) //create a new pg index
+            WriteProcessGroupIndex( );
+
+        //pre-calculate new metadata and payload sizes
+//        m_TransportFlush = CheckBufferAllocation( m_BP1Writer.GetVariableIndexSize( variable ) + variable.PayLoadSize(),
+//                                                  m_GrowthFactor, m_MaxBufferSize, m_Buffer.m_Data );
+
+        //WRITE INDEX to data buffer and metadata structure (in memory)//
+        m_BP1Writer.WriteVariableMetadata( variable, m_Buffer, m_MetadataSet );
+
+        if( m_TransportFlush == true ) //in batches
+        {
+            //write pg index
+
+            //flush to transports
+
+            //reset relative positions to zero, update absolute position
+
+        }
+        else //Write data to buffer
+        {
+            m_BP1Writer.WriteVariablePayload( variable, m_Buffer, m_nThreads );
+        }
+
+        variable.m_AppValues = nullptr; //setting pointer to null as not needed after write
+
+        if( m_MetadataSet.Log.m_IsActive == true )
+            m_MetadataSet.Log.m_Timers[0].SetTime();
+    }
+
+};
+
+
+} //end namespace adios
+
+
+#endif /* BPFILEWRITER_H_ */
diff --git a/include/engine/dataman/DataManReader.h b/include/engine/dataman/DataManReader.h
new file mode 100644
index 0000000000000000000000000000000000000000..85a02c06122c8f967bebe528b117f796d3e415f5
--- /dev/null
+++ b/include/engine/dataman/DataManReader.h
@@ -0,0 +1,117 @@
+/*
+ * DataManReader.h
+ *
+ *  Created on: Feb 21, 2017
+ *      Author: wfg
+ */
+
+#ifndef DATAMANREADER_H_
+#define DATAMANREADER_H_
+
+#include <iostream> //std::cout << Needs to go
+
+#include "core/Engine.h"
+#include "format/BP1Writer.h"
+
+//supported capsules
+#include "capsule/heap/STLVector.h"
+
+#include "DataManager.h"
+
+namespace adios
+{
+
+class DataManReader : public Engine
+{
+
+public:
+
+    /**
+     * Constructor for dataman engine Reader for WAN communications
+     * @param adios
+     * @param name
+     * @param accessMode
+     * @param mpiComm
+     * @param method
+     * @param debugMode
+     * @param nthreads
+     */
+    DataManReader( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                   const Method& method, const IOMode iomode, const float timeout_sec,
+                   const bool debugMode = false, const unsigned int nthreads = 1 );
+
+    ~DataManReader( );
+
+    /**
+     * Set callback function from user application
+     * @param callback function (get) provided by the user to be applied in DataMan
+     */
+    void SetCallBack( std::function<void( const void*, std::string, std::string, std::string, Dims )> callback );
+
+    Variable<void>* InquireVariable( const std::string name, const bool readIn = true );
+    Variable<char>* InquireVariableChar( const std::string name, const bool readIn = true );
+    Variable<unsigned char>* InquireVariableUChar( const std::string name, const bool readIn = true );
+    Variable<short>* InquireVariableShort( const std::string name, const bool readIn = true );
+    Variable<unsigned short>* InquireVariableUShort( const std::string name, const bool readIn = true );
+    Variable<int>* InquireVariableInt( const std::string name, const bool readIn = true );
+    Variable<unsigned int>* InquireVariableUInt( const std::string name, const bool readIn = true );
+    Variable<long int>* InquireVariableLInt( const std::string name, const bool readIn = true );
+    Variable<unsigned long int>* InquireVariableULInt( const std::string name, const bool readIn = true );
+    Variable<long long int>* InquireVariableLLInt( const std::string name, const bool readIn = true );
+    Variable<unsigned long long int>* InquireVariableULLInt( const std::string name, const bool readIn = true );
+    Variable<float>* InquireVariableFloat( const std::string name, const bool readIn = true );
+    Variable<double>* InquireVariableDouble( const std::string name, const bool readIn = true );
+    Variable<long double>* InquireVariableLDouble( const std::string name, const bool readIn = true );
+    Variable<std::complex<float>>* InquireVariableCFloat( const std::string name, const bool readIn = true );
+    Variable<std::complex<double>>* InquireVariableCDouble( const std::string name, const bool readIn = true );
+    Variable<std::complex<long double>>* InquireVariableCLDouble( const std::string name, const bool readIn = true );
+
+    /**
+     * Not implemented
+     * @param name
+     * @param readIn
+     * @return
+     */
+    VariableCompound* InquireVariableCompound( const std::string name, const bool readIn = true );
+
+
+    void Close( const int transportIndex = -1 );
+
+private:
+
+    capsule::STLVector m_Buffer; ///< heap capsule, contains data and metadata buffers
+    format::BP1Writer m_BP1Writer; ///< format object will provide the required BP functionality to be applied on m_Buffer and m_Transports
+
+    bool m_DoRealTime = false;
+    DataManager m_Man;
+    std::function<void( const void*, std::string, std::string, std::string, Dims )> m_CallBack; ///< call back function
+
+    void Init( );  ///< calls InitCapsules and InitTransports based on Method, called from constructor
+    void InitCapsules( );
+    void InitTransports( ); ///< from Transports
+
+    std::string GetMdtmParameter( const std::string parameter, const std::map<std::string,std::string>& mdtmParameters );
+
+
+    template< class T >
+    Variable<T>* InquireVariableCommon( const std::string name, const bool readIn )
+    {
+        std::cout << "I am hooked to the DataMan library\n";
+        std::cout << "Hello DatamanReader from rank " << m_RankMPI << "\n";
+        std::cout << "Trying to read variable " << name << " from one of the variables coming from a WAN transport\n";
+
+        //here read variable metadata (dimensions, type, etc.)...then create a Variable like below:
+        //Variable<T>& variable = m_ADIOS.DefineVariable<T>( m_Name + "/" + name, )
+        //return &variable; //return address if success
+        return nullptr; //on failure
+    }
+
+
+
+};
+
+
+} //end namespace
+
+
+#endif /* DATAMANREADER_H_ */
diff --git a/include/engine/dataman/DataManWriter.h b/include/engine/dataman/DataManWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..106ae0ef97fcc896e2da44d6a29f33340f10e8d3
--- /dev/null
+++ b/include/engine/dataman/DataManWriter.h
@@ -0,0 +1,163 @@
+/*
+ * DataMan.h
+ *
+ *  Created on: Jan 10, 2017
+ *      Author: wfg
+ */
+
+#ifndef DATAMANWRITER_H_
+#define DATAMANWRITER_H_
+
+#include <iostream> //std::cout must be removed, only used for hello example
+#include <unistd.h> //sleep must be removed
+
+#include "core/Engine.h"
+#include "format/BP1Writer.h"
+
+//supported capsules
+#include "capsule/heap/STLVector.h"
+
+
+#include "DataManager.h"  //here comes your DataMan header
+
+
+namespace adios
+{
+
+class DataManWriter : public Engine
+{
+
+public:
+
+    /**
+     * Constructor for dataman engine Writer for WAN communications
+     * @param adios
+     * @param name unique name given to the engine
+     * @param accessMode
+     * @param mpiComm
+     * @param method
+     * @param debugMode
+     * @param nthreads
+     */
+    DataManWriter( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                   const Method& method, const IOMode iomode, const float timeout_sec,
+                   const bool debugMode = false, const unsigned int nthreads = 1 );
+
+    ~DataManWriter( );
+
+    void SetCallBack( std::function<void( const void*, std::string, std::string, std::string, Dims )> callback );
+
+    void Write( Variable<char>& variable, const char* values );
+    void Write( Variable<unsigned char>& variable, const unsigned char* values );
+    void Write( Variable<short>& variable, const short* values );
+    void Write( Variable<unsigned short>& variable, const unsigned short* values );
+    void Write( Variable<int>& variable, const int* values );
+    void Write( Variable<unsigned int>& variable, const unsigned int* values );
+    void Write( Variable<long int>& variable, const long int* values );
+    void Write( Variable<unsigned long int>& variable, const unsigned long int* values );
+    void Write( Variable<long long int>& variable, const long long int* values );
+    void Write( Variable<unsigned long long int>& variable, const unsigned long long int* values ) ;
+    void Write( Variable<float>& variable, const float* values );
+    void Write( Variable<double>& variable, const double* values );
+    void Write( Variable<long double>& variable, const long double* values );
+    void Write( Variable<std::complex<float>>& variable, const std::complex<float>* values );
+    void Write( Variable<std::complex<double>>& variable, const std::complex<double>* values );
+    void Write( Variable<std::complex<long double>>& variable, const std::complex<long double>* values );
+
+    void Write( const std::string variableName, const char* values );
+    void Write( const std::string variableName, const unsigned char* values );
+    void Write( const std::string variableName, const short* values );
+    void Write( const std::string variableName, const unsigned short* values );
+    void Write( const std::string variableName, const int* values );
+    void Write( const std::string variableName, const unsigned int* values );
+    void Write( const std::string variableName, const long int* values );
+    void Write( const std::string variableName, const unsigned long int* values );
+    void Write( const std::string variableName, const long long int* values );
+    void Write( const std::string variableName, const unsigned long long int* values );
+    void Write( const std::string variableName, const float* values );
+    void Write( const std::string variableName, const double* values );
+    void Write( const std::string variableName, const long double* values );
+    void Write( const std::string variableName, const std::complex<float>* values );
+    void Write( const std::string variableName, const std::complex<double>* values );
+    void Write( const std::string variableName, const std::complex<long double>* values );
+
+    void Close( const int transportIndex = -1 );
+
+private:
+
+    capsule::STLVector m_Buffer; ///< heap capsule, contains data and metadata buffers
+    format::BP1Writer m_BP1Writer; ///< format object will provide the required BP functionality to be applied on m_Buffer and m_Transports
+
+    bool m_DoRealTime = false;
+    bool m_DoMonitor = false;
+    DataManager m_Man;
+    std::function<void( const void*, std::string, std::string, std::string, Dims )> m_CallBack; ///< call back function
+
+    void Init( );  ///< calls InitCapsules and InitTransports based on Method, called from constructor
+    void InitCapsules( );
+    void InitTransports( ); ///< from Transports
+
+    /**
+     * From transport Mdtm in m_Method
+     * @param parameter must be an accepted parameter
+     * @param mdtmParameters
+     * @return value either returns user-defined from "parameter=value" or a default
+     */
+    std::string GetMdtmParameter( const std::string parameter, const std::map<std::string,std::string>& mdtmParameters );
+
+
+    template<class T>
+    void WriteVariableCommon( Variable<T>& variable, const T* values )
+    {
+        //here comes your magic at Writing now variable.m_UserValues has the data passed by the user
+        //set variable
+        variable.m_AppValues = values;
+        m_WrittenVariables.insert( variable.m_Name );
+
+        //This part will go away, this is just to monitor variables per rank
+
+        json jmsg;
+        jmsg["doid"] = m_Name;
+        jmsg["var"] = variable.m_Name;
+        jmsg["dtype"] = GetType<T>();
+        jmsg["putshape"] = variable.m_Dimensions;
+        if(variable.m_GlobalDimensions.size() == 0) variable.m_GlobalDimensions = variable.m_Dimensions;
+        jmsg["varshape"] = variable.m_GlobalDimensions;
+        if(variable.m_GlobalOffsets.size() == 0) variable.m_GlobalOffsets.assign(variable.m_Dimensions.size(),0);
+        jmsg["offset"] = variable.m_GlobalOffsets;
+        jmsg["timestep"] = 0;
+        m_Man.put(values, jmsg);
+
+        if(m_DoMonitor){
+            MPI_Barrier( m_MPIComm );
+            std::cout << "I am hooked to the DataMan library\n";
+            std::cout << "putshape " << variable.m_Dimensions.size() << endl;
+            std::cout << "varshape " << variable.m_GlobalDimensions.size() << endl;
+            std::cout << "offset " << variable.m_GlobalOffsets.size() << endl;
+            for( int i = 0; i < m_SizeMPI; ++i )
+            {
+                if( i == m_RankMPI )
+                {
+                    std::cout << "Rank: " << m_RankMPI << "\n";
+                    variable.Monitor( std::cout );
+                    std::cout << std::endl;
+                }
+                else
+                {
+                    sleep( 1 );
+                }
+            }
+            MPI_Barrier( m_MPIComm );
+        }
+    }
+
+};
+
+
+} //end namespace adios
+
+
+
+
+
+#endif /* DATAMANWRITER_H_ */
diff --git a/include/external/json.hpp b/include/external/json.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa9b85f2637cfe8cc2d77c89d417c9df8991a6c6
--- /dev/null
+++ b/include/external/json.hpp
@@ -0,0 +1,12310 @@
+/*
+    __ _____ _____ _____
+ __|  |   __|     |   | |  JSON for Modern C++
+|  |  |__   |  |  | | | |  version 2.0.10
+|_____|_____|_____|_|___|  https://github.com/nlohmann/json
+
+Licensed under the MIT License <http://opensource.org/licenses/MIT>.
+Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
+
+Permission is hereby  granted, free of charge, to any  person obtaining a copy
+of this software and associated  documentation files (the "Software"), to deal
+in the Software  without restriction, including without  limitation the rights
+to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
+copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
+IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
+FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
+AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
+LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef NLOHMANN_JSON_HPP
+#define NLOHMANN_JSON_HPP
+
+#include <algorithm> // all_of, for_each, transform
+#include <array> // array
+#include <cassert> // assert
+#include <cctype> // isdigit
+#include <ciso646> // and, not, or
+#include <cmath> // isfinite, ldexp, signbit
+#include <cstddef> // nullptr_t, ptrdiff_t, size_t
+#include <cstdint> // int64_t, uint64_t
+#include <cstdlib> // strtod, strtof, strtold, strtoul
+#include <cstring> // strlen
+#include <functional> // function, hash, less
+#include <initializer_list> // initializer_list
+#include <iomanip> // setw
+#include <iostream> // istream, ostream
+#include <iterator> // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator
+#include <limits> // numeric_limits
+#include <locale> // locale
+#include <map> // map
+#include <memory> // addressof, allocator, allocator_traits, unique_ptr
+#include <numeric> // accumulate
+#include <sstream> // stringstream
+#include <stdexcept> // domain_error, invalid_argument, out_of_range
+#include <string> // getline, stoi, string, to_string
+#include <type_traits> // add_pointer, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference
+#include <utility> // declval, forward, make_pair, move, pair, swap
+#include <vector> // vector
+
+// exclude unsupported compilers
+#if defined(__clang__)
+    #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
+        #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
+    #endif
+#elif defined(__GNUC__)
+    #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
+        #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
+    #endif
+#endif
+
+// disable float-equal warnings on GCC/clang
+#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
+    #pragma GCC diagnostic push
+    #pragma GCC diagnostic ignored "-Wfloat-equal"
+#endif
+
+// disable documentation warnings on clang
+#if defined(__clang__)
+    #pragma GCC diagnostic push
+    #pragma GCC diagnostic ignored "-Wdocumentation"
+#endif
+
+// allow for portable deprecation warnings
+#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
+    #define JSON_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+    #define JSON_DEPRECATED __declspec(deprecated)
+#else
+    #define JSON_DEPRECATED
+#endif
+
+// allow to disable exceptions
+#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS)
+    #define JSON_THROW(exception) throw exception
+    #define JSON_TRY try
+    #define JSON_CATCH(exception) catch(exception)
+#else
+    #define JSON_THROW(exception) std::abort()
+    #define JSON_TRY if(true)
+    #define JSON_CATCH(exception) if(false)
+#endif
+
+/*!
+@brief namespace for Niels Lohmann
+@see https://github.com/nlohmann
+@since version 1.0.0
+*/
+namespace nlohmann
+{
+
+
+/*!
+@brief unnamed namespace with internal helper functions
+@since version 1.0.0
+*/
+namespace
+{
+/*!
+@brief Helper to determine whether there's a key_type for T.
+
+Thus helper is used to tell associative containers apart from other containers
+such as sequence containers. For instance, `std::map` passes the test as it
+contains a `mapped_type`, whereas `std::vector` fails the test.
+
+@sa http://stackoverflow.com/a/7728728/266378
+@since version 1.0.0, overworked in version 2.0.6
+*/
+template<typename T>
+struct has_mapped_type
+{
+  private:
+    template <typename U, typename = typename U::mapped_type>
+    static int detect(U&&);
+
+    static void detect(...);
+  public:
+    static constexpr bool value =
+        std::is_integral<decltype(detect(std::declval<T>()))>::value;
+};
+
+} // namespace
+
+/*!
+@brief a class to store JSON values
+
+@tparam ObjectType type for JSON objects (`std::map` by default; will be used
+in @ref object_t)
+@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
+in @ref array_t)
+@tparam StringType type for JSON strings and object keys (`std::string` by
+default; will be used in @ref string_t)
+@tparam BooleanType type for JSON booleans (`bool` by default; will be used
+in @ref boolean_t)
+@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
+default; will be used in @ref number_integer_t)
+@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
+`uint64_t` by default; will be used in @ref number_unsigned_t)
+@tparam NumberFloatType type for JSON floating-point numbers (`double` by
+default; will be used in @ref number_float_t)
+@tparam AllocatorType type of the allocator to use (`std::allocator` by
+default)
+
+@requirement The class satisfies the following concept requirements:
+- Basic
+ - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
+   JSON values can be default constructed. The result will be a JSON null
+   value.
+ - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
+   A JSON value can be constructed from an rvalue argument.
+ - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
+   A JSON value can be copy-constructed from an lvalue expression.
+ - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
+   A JSON value van be assigned from an rvalue argument.
+ - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
+   A JSON value can be copy-assigned from an lvalue expression.
+ - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
+   JSON values can be destructed.
+- Layout
+ - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
+   JSON values have
+   [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
+   All non-static data members are private and standard layout types, the
+   class has no virtual functions or (virtual) base classes.
+- Library-wide
+ - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
+   JSON values can be compared with `==`, see @ref
+   operator==(const_reference,const_reference).
+ - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable):
+   JSON values can be compared with `<`, see @ref
+   operator<(const_reference,const_reference).
+ - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable):
+   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
+   other compatible types, using unqualified function call @ref swap().
+ - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer):
+   JSON values can be compared against `std::nullptr_t` objects which are used
+   to model the `null` value.
+- Container
+ - [Container](http://en.cppreference.com/w/cpp/concept/Container):
+   JSON values can be used like STL containers and provide iterator access.
+ - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer);
+   JSON values can be used like STL containers and provide reverse iterator
+   access.
+
+@invariant The member variables @a m_value and @a m_type have the following
+relationship:
+- If `m_type == value_t::object`, then `m_value.object != nullptr`.
+- If `m_type == value_t::array`, then `m_value.array != nullptr`.
+- If `m_type == value_t::string`, then `m_value.string != nullptr`.
+The invariants are checked by member function assert_invariant().
+
+@internal
+@note ObjectType trick from http://stackoverflow.com/a/9860911
+@endinternal
+
+@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
+Format](http://rfc7159.net/rfc7159)
+
+@since version 1.0.0
+
+@nosubgrouping
+*/
+template <
+    template<typename U, typename V, typename... Args> class ObjectType = std::map,
+    template<typename U, typename... Args> class ArrayType = std::vector,
+    class StringType = std::string,
+    class BooleanType = bool,
+    class NumberIntegerType = std::int64_t,
+    class NumberUnsignedType = std::uint64_t,
+    class NumberFloatType = double,
+    template<typename U> class AllocatorType = std::allocator
+    >
+class basic_json
+{
+  private:
+    /// workaround type for MSVC
+    using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
+          BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
+          AllocatorType>;
+
+  public:
+    // forward declarations
+    template<typename U> class iter_impl;
+    template<typename Base> class json_reverse_iterator;
+    class json_pointer;
+
+    /////////////////////
+    // container types //
+    /////////////////////
+
+    /// @name container types
+    /// The canonic container types to use @ref basic_json like any other STL
+    /// container.
+    /// @{
+
+    /// the type of elements in a basic_json container
+    using value_type = basic_json;
+
+    /// the type of an element reference
+    using reference = value_type&;
+    /// the type of an element const reference
+    using const_reference = const value_type&;
+
+    /// a type to represent differences between iterators
+    using difference_type = std::ptrdiff_t;
+    /// a type to represent container sizes
+    using size_type = std::size_t;
+
+    /// the allocator type
+    using allocator_type = AllocatorType<basic_json>;
+
+    /// the type of an element pointer
+    using pointer = typename std::allocator_traits<allocator_type>::pointer;
+    /// the type of an element const pointer
+    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
+
+    /// an iterator for a basic_json container
+    using iterator = iter_impl<basic_json>;
+    /// a const iterator for a basic_json container
+    using const_iterator = iter_impl<const basic_json>;
+    /// a reverse iterator for a basic_json container
+    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
+    /// a const reverse iterator for a basic_json container
+    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
+
+    /// @}
+
+
+    /*!
+    @brief returns the allocator associated with the container
+    */
+    static allocator_type get_allocator()
+    {
+        return allocator_type();
+    }
+
+    /*!
+    @brief returns version information on the library
+    */
+    static basic_json meta()
+    {
+        basic_json result;
+
+        result["copyright"] = "(C) 2013-2017 Niels Lohmann";
+        result["name"] = "JSON for Modern C++";
+        result["url"] = "https://github.com/nlohmann/json";
+        result["version"] =
+        {
+            {"string", "2.0.10"},
+            {"major", 2},
+            {"minor", 0},
+            {"patch", 10},
+        };
+
+#ifdef _WIN32
+        result["platform"] = "win32";
+#elif defined __linux__
+        result["platform"] = "linux";
+#elif defined __APPLE__
+        result["platform"] = "apple";
+#elif defined __unix__
+        result["platform"] = "unix";
+#else
+        result["platform"] = "unknown";
+#endif
+
+#if defined(__clang__)
+        result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
+#elif defined(__ICC) || defined(__INTEL_COMPILER)
+        result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
+#elif defined(__GNUC__) || defined(__GNUG__)
+        result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}};
+#elif defined(__HP_cc) || defined(__HP_aCC)
+        result["compiler"] = "hp"
+#elif defined(__IBMCPP__)
+        result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
+#elif defined(_MSC_VER)
+        result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
+#elif defined(__PGI)
+        result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
+#elif defined(__SUNPRO_CC)
+        result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
+#else
+        result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
+#endif
+
+#ifdef __cplusplus
+        result["compiler"]["c++"] = std::to_string(__cplusplus);
+#else
+        result["compiler"]["c++"] = "unknown";
+#endif
+        return result;
+    }
+
+
+    ///////////////////////////
+    // JSON value data types //
+    ///////////////////////////
+
+    /// @name JSON value data types
+    /// The data types to store a JSON value. These types are derived from
+    /// the template arguments passed to class @ref basic_json.
+    /// @{
+
+    /*!
+    @brief a type for an object
+
+    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
+    > An object is an unordered collection of zero or more name/value pairs,
+    > where a name is a string and a value is a string, number, boolean, null,
+    > object, or array.
+
+    To store objects in C++, a type is defined by the template parameters
+    described below.
+
+    @tparam ObjectType  the container to store objects (e.g., `std::map` or
+    `std::unordered_map`)
+    @tparam StringType the type of the keys or names (e.g., `std::string`).
+    The comparison function `std::less<StringType>` is used to order elements
+    inside the container.
+    @tparam AllocatorType the allocator to use for objects (e.g.,
+    `std::allocator`)
+
+    #### Default type
+
+    With the default values for @a ObjectType (`std::map`), @a StringType
+    (`std::string`), and @a AllocatorType (`std::allocator`), the default
+    value for @a object_t is:
+
+    @code {.cpp}
+    std::map<
+      std::string, // key_type
+      basic_json, // value_type
+      std::less<std::string>, // key_compare
+      std::allocator<std::pair<const std::string, basic_json>> // allocator_type
+    >
+    @endcode
+
+    #### Behavior
+
+    The choice of @a object_t influences the behavior of the JSON class. With
+    the default type, objects have the following behavior:
+
+    - When all names are unique, objects will be interoperable in the sense
+      that all software implementations receiving that object will agree on
+      the name-value mappings.
+    - When the names within an object are not unique, later stored name/value
+      pairs overwrite previously stored name/value pairs, leaving the used
+      names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
+      be treated as equal and both stored as `{"key": 1}`.
+    - Internally, name/value pairs are stored in lexicographical order of the
+      names. Objects will also be serialized (see @ref dump) in this order.
+      For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
+      and serialized as `{"a": 2, "b": 1}`.
+    - When comparing objects, the order of the name/value pairs is irrelevant.
+      This makes objects interoperable in the sense that they will not be
+      affected by these differences. For instance, `{"b": 1, "a": 2}` and
+      `{"a": 2, "b": 1}` will be treated as equal.
+
+    #### Limits
+
+    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
+    > An implementation may set limits on the maximum depth of nesting.
+
+    In this class, the object's limit of nesting is not constraint explicitly.
+    However, a maximum depth of nesting may be introduced by the compiler or
+    runtime environment. A theoretical limit can be queried by calling the
+    @ref max_size function of a JSON object.
+
+    #### Storage
+
+    Objects are stored as pointers in a @ref basic_json type. That is, for any
+    access to object values, a pointer of type `object_t*` must be
+    dereferenced.
+
+    @sa @ref array_t -- type for an array value
+
+    @since version 1.0.0
+
+    @note The order name/value pairs are added to the object is *not*
+    preserved by the library. Therefore, iterating an object may return
+    name/value pairs in a different order than they were originally stored. In
+    fact, keys will be traversed in alphabetical order as `std::map` with
+    `std::less` is used by default. Please note this behavior conforms to [RFC
+    7159](http://rfc7159.net/rfc7159), because any order implements the
+    specified "unordered" nature of JSON objects.
+    */
+    using object_t = ObjectType<StringType,
+          basic_json,
+          std::less<StringType>,
+          AllocatorType<std::pair<const StringType,
+          basic_json>>>;
+
+    /*!
+    @brief a type for an array
+
+    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
+    > An array is an ordered sequence of zero or more values.
+
+    To store objects in C++, a type is defined by the template parameters
+    explained below.
+
+    @tparam ArrayType  container type to store arrays (e.g., `std::vector` or
+    `std::list`)
+    @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
+
+    #### Default type
+
+    With the default values for @a ArrayType (`std::vector`) and @a
+    AllocatorType (`std::allocator`), the default value for @a array_t is:
+
+    @code {.cpp}
+    std::vector<
+      basic_json, // value_type
+      std::allocator<basic_json> // allocator_type
+    >
+    @endcode
+
+    #### Limits
+
+    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
+    > An implementation may set limits on the maximum depth of nesting.
+
+    In this class, the array's limit of nesting is not constraint explicitly.
+    However, a maximum depth of nesting may be introduced by the compiler or
+    runtime environment. A theoretical limit can be queried by calling the
+    @ref max_size function of a JSON array.
+
+    #### Storage
+
+    Arrays are stored as pointers in a @ref basic_json type. That is, for any
+    access to array values, a pointer of type `array_t*` must be dereferenced.
+
+    @sa @ref object_t -- type for an object value
+
+    @since version 1.0.0
+    */
+    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
+
+    /*!
+    @brief a type for a string
+
+    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
+    > A string is a sequence of zero or more Unicode characters.
+
+    To store objects in C++, a type is defined by the template parameter
+    described below. Unicode values are split by the JSON class into
+    byte-sized characters during deserialization.
+
+    @tparam StringType  the container to store strings (e.g., `std::string`).
+    Note this container is used for keys/names in objects, see @ref object_t.
+
+    #### Default type
+
+    With the default values for @a StringType (`std::string`), the default
+    value for @a string_t is:
+
+    @code {.cpp}
+    std::string
+    @endcode
+
+    #### Encoding
+
+    Strings are stored in UTF-8 encoding. Therefore, functions like
+    `std::string::size()` or `std::string::length()` return the number of
+    bytes in the string rather than the number of characters or glyphs.
+
+    #### String comparison
+
+    [RFC 7159](http://rfc7159.net/rfc7159) states:
+    > Software implementations are typically required to test names of object
+    > members for equality. Implementations that transform the textual
+    > representation into sequences of Unicode code units and then perform the
+    > comparison numerically, code unit by code unit, are interoperable in the
+    > sense that implementations will agree in all cases on equality or
+    > inequality of two strings. For example, implementations that compare
+    > strings with escaped characters unconverted may incorrectly find that
+    > `"a\\b"` and `"a\u005Cb"` are not equal.
+
+    This implementation is interoperable as it does compare strings code unit
+    by code unit.
+
+    #### Storage
+
+    String values are stored as pointers in a @ref basic_json type. That is,
+    for any access to string values, a pointer of type `string_t*` must be
+    dereferenced.
+
+    @since version 1.0.0
+    */
+    using string_t = StringType;
+
+    /*!
+    @brief a type for a boolean
+
+    [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
+    type which differentiates the two literals `true` and `false`.
+
+    To store objects in C++, a type is defined by the template parameter @a
+    BooleanType which chooses the type to use.
+
+    #### Default type
+
+    With the default values for @a BooleanType (`bool`), the default value for
+    @a boolean_t is:
+
+    @code {.cpp}
+    bool
+    @endcode
+
+    #### Storage
+
+    Boolean values are stored directly inside a @ref basic_json type.
+
+    @since version 1.0.0
+    */
+    using boolean_t = BooleanType;
+
+    /*!
+    @brief a type for a number (integer)
+
+    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
+    > The representation of numbers is similar to that used in most
+    > programming languages. A number is represented in base 10 using decimal
+    > digits. It contains an integer component that may be prefixed with an
+    > optional minus sign, which may be followed by a fraction part and/or an
+    > exponent part. Leading zeros are not allowed. (...) Numeric values that
+    > cannot be represented in the grammar below (such as Infinity and NaN)
+    > are not permitted.
+
+    This description includes both integer and floating-point numbers.
+    However, C++ allows more precise storage if it is known whether the number
+    is a signed integer, an unsigned integer or a floating-point number.
+    Therefore, three different types, @ref number_integer_t, @ref
+    number_unsigned_t and @ref number_float_t are used.
+
+    To store integer numbers in C++, a type is defined by the template
+    parameter @a NumberIntegerType which chooses the type to use.
+
+    #### Default type
+
+    With the default values for @a NumberIntegerType (`int64_t`), the default
+    value for @a number_integer_t is:
+
+    @code {.cpp}
+    int64_t
+    @endcode
+
+    #### Default behavior
+
+    - The restrictions about leading zeros is not enforced in C++. Instead,
+      leading zeros in integer literals lead to an interpretation as octal
+      number. Internally, the value will be stored as decimal number. For
+      instance, the C++ integer literal `010` will be serialized to `8`.
+      During deserialization, leading zeros yield an error.
+    - Not-a-number (NaN) values will be serialized to `null`.
+
+    #### Limits
+
+    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
+    > An implementation may set limits on the range and precision of numbers.
+
+    When the default type is used, the maximal integer number that can be
+    stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
+    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
+    that are out of range will yield over/underflow when used in a
+    constructor. During deserialization, too large or small integer numbers
+    will be automatically be stored as @ref number_unsigned_t or @ref
+    number_float_t.
+
+    [RFC 7159](http://rfc7159.net/rfc7159) further states:
+    > Note that when such software is used, numbers that are integers and are
+    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
+    > that implementations will agree exactly on their numeric values.
+
+    As this range is a subrange of the exactly supported range [INT64_MIN,
+    INT64_MAX], this class's integer type is interoperable.
+
+    #### Storage
+
+    Integer number values are stored directly inside a @ref basic_json type.
+
+    @sa @ref number_float_t -- type for number values (floating-point)
+
+    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
+
+    @since version 1.0.0
+    */
+    using number_integer_t = NumberIntegerType;
+
+    /*!
+    @brief a type for a number (unsigned)
+
+    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
+    > The representation of numbers is similar to that used in most
+    > programming languages. A number is represented in base 10 using decimal
+    > digits. It contains an integer component that may be prefixed with an
+    > optional minus sign, which may be followed by a fraction part and/or an
+    > exponent part. Leading zeros are not allowed. (...) Numeric values that
+    > cannot be represented in the grammar below (such as Infinity and NaN)
+    > are not permitted.
+
+    This description includes both integer and floating-point numbers.
+    However, C++ allows more precise storage if it is known whether the number
+    is a signed integer, an unsigned integer or a floating-point number.
+    Therefore, three different types, @ref number_integer_t, @ref
+    number_unsigned_t and @ref number_float_t are used.
+
+    To store unsigned integer numbers in C++, a type is defined by the
+    template parameter @a NumberUnsignedType which chooses the type to use.
+
+    #### Default type
+
+    With the default values for @a NumberUnsignedType (`uint64_t`), the
+    default value for @a number_unsigned_t is:
+
+    @code {.cpp}
+    uint64_t
+    @endcode
+
+    #### Default behavior
+
+    - The restrictions about leading zeros is not enforced in C++. Instead,
+      leading zeros in integer literals lead to an interpretation as octal
+      number. Internally, the value will be stored as decimal number. For
+      instance, the C++ integer literal `010` will be serialized to `8`.
+      During deserialization, leading zeros yield an error.
+    - Not-a-number (NaN) values will be serialized to `null`.
+
+    #### Limits
+
+    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
+    > An implementation may set limits on the range and precision of numbers.
+
+    When the default type is used, the maximal integer number that can be
+    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
+    number that can be stored is `0`. Integer numbers that are out of range
+    will yield over/underflow when used in a constructor. During
+    deserialization, too large or small integer numbers will be automatically
+    be stored as @ref number_integer_t or @ref number_float_t.
+
+    [RFC 7159](http://rfc7159.net/rfc7159) further states:
+    > Note that when such software is used, numbers that are integers and are
+    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
+    > that implementations will agree exactly on their numeric values.
+
+    As this range is a subrange (when considered in conjunction with the
+    number_integer_t type) of the exactly supported range [0, UINT64_MAX],
+    this class's integer type is interoperable.
+
+    #### Storage
+
+    Integer number values are stored directly inside a @ref basic_json type.
+
+    @sa @ref number_float_t -- type for number values (floating-point)
+    @sa @ref number_integer_t -- type for number values (integer)
+
+    @since version 2.0.0
+    */
+    using number_unsigned_t = NumberUnsignedType;
+
+    /*!
+    @brief a type for a number (floating-point)
+
+    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
+    > The representation of numbers is similar to that used in most
+    > programming languages. A number is represented in base 10 using decimal
+    > digits. It contains an integer component that may be prefixed with an
+    > optional minus sign, which may be followed by a fraction part and/or an
+    > exponent part. Leading zeros are not allowed. (...) Numeric values that
+    > cannot be represented in the grammar below (such as Infinity and NaN)
+    > are not permitted.
+
+    This description includes both integer and floating-point numbers.
+    However, C++ allows more precise storage if it is known whether the number
+    is a signed integer, an unsigned integer or a floating-point number.
+    Therefore, three different types, @ref number_integer_t, @ref
+    number_unsigned_t and @ref number_float_t are used.
+
+    To store floating-point numbers in C++, a type is defined by the template
+    parameter @a NumberFloatType which chooses the type to use.
+
+    #### Default type
+
+    With the default values for @a NumberFloatType (`double`), the default
+    value for @a number_float_t is:
+
+    @code {.cpp}
+    double
+    @endcode
+
+    #### Default behavior
+
+    - The restrictions about leading zeros is not enforced in C++. Instead,
+      leading zeros in floating-point literals will be ignored. Internally,
+      the value will be stored as decimal number. For instance, the C++
+      floating-point literal `01.2` will be serialized to `1.2`. During
+      deserialization, leading zeros yield an error.
+    - Not-a-number (NaN) values will be serialized to `null`.
+
+    #### Limits
+
+    [RFC 7159](http://rfc7159.net/rfc7159) states:
+    > This specification allows implementations to set limits on the range and
+    > precision of numbers accepted. Since software that implements IEEE
+    > 754-2008 binary64 (double precision) numbers is generally available and
+    > widely used, good interoperability can be achieved by implementations
+    > that expect no more precision or range than these provide, in the sense
+    > that implementations will approximate JSON numbers within the expected
+    > precision.
+
+    This implementation does exactly follow this approach, as it uses double
+    precision floating-point numbers. Note values smaller than
+    `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
+    will be stored as NaN internally and be serialized to `null`.
+
+    #### Storage
+
+    Floating-point number values are stored directly inside a @ref basic_json
+    type.
+
+    @sa @ref number_integer_t -- type for number values (integer)
+
+    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
+
+    @since version 1.0.0
+    */
+    using number_float_t = NumberFloatType;
+
+    /// @}
+
+
+    ///////////////////////////
+    // JSON type enumeration //
+    ///////////////////////////
+
+    /*!
+    @brief the JSON type enumeration
+
+    This enumeration collects the different JSON types. It is internally used
+    to distinguish the stored values, and the functions @ref is_null(), @ref
+    is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref
+    is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and
+    @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and
+    @ref is_structured() rely on it.
+
+    @note There are three enumeration entries (number_integer,
+    number_unsigned, and number_float), because the library distinguishes
+    these three types for numbers: @ref number_unsigned_t is used for unsigned
+    integers, @ref number_integer_t is used for signed integers, and @ref
+    number_float_t is used for floating-point numbers or to approximate
+    integers which do not fit in the limits of their respective type.
+
+    @sa @ref basic_json(const value_t value_type) -- create a JSON value with
+    the default value for a given type
+
+    @since version 1.0.0
+    */
+    enum class value_t : uint8_t
+    {
+        null,            ///< null value
+        object,          ///< object (unordered set of name/value pairs)
+        array,           ///< array (ordered collection of values)
+        string,          ///< string value
+        boolean,         ///< boolean value
+        number_integer,  ///< number value (signed integer)
+        number_unsigned, ///< number value (unsigned integer)
+        number_float,    ///< number value (floating-point)
+        discarded        ///< discarded by the the parser callback function
+    };
+
+
+  private:
+
+    /// helper for exception-safe object creation
+    template<typename T, typename... Args>
+    static T* create(Args&& ... args)
+    {
+        AllocatorType<T> alloc;
+        auto deleter = [&](T * object)
+        {
+            alloc.deallocate(object, 1);
+        };
+        std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
+        alloc.construct(object.get(), std::forward<Args>(args)...);
+        assert(object != nullptr);
+        return object.release();
+    }
+
+    ////////////////////////
+    // JSON value storage //
+    ////////////////////////
+
+    /*!
+    @brief a JSON value
+
+    The actual storage for a JSON value of the @ref basic_json class. This
+    union combines the different storage types for the JSON value types
+    defined in @ref value_t.
+
+    JSON type | value_t type    | used type
+    --------- | --------------- | ------------------------
+    object    | object          | pointer to @ref object_t
+    array     | array           | pointer to @ref array_t
+    string    | string          | pointer to @ref string_t
+    boolean   | boolean         | @ref boolean_t
+    number    | number_integer  | @ref number_integer_t
+    number    | number_unsigned | @ref number_unsigned_t
+    number    | number_float    | @ref number_float_t
+    null      | null            | *no value is stored*
+
+    @note Variable-length types (objects, arrays, and strings) are stored as
+    pointers. The size of the union should not exceed 64 bits if the default
+    value types are used.
+
+    @since version 1.0.0
+    */
+    union json_value
+    {
+        /// object (stored with pointer to save storage)
+        object_t* object;
+        /// array (stored with pointer to save storage)
+        array_t* array;
+        /// string (stored with pointer to save storage)
+        string_t* string;
+        /// boolean
+        boolean_t boolean;
+        /// number (integer)
+        number_integer_t number_integer;
+        /// number (unsigned integer)
+        number_unsigned_t number_unsigned;
+        /// number (floating-point)
+        number_float_t number_float;
+
+        /// default constructor (for null values)
+        json_value() = default;
+        /// constructor for booleans
+        json_value(boolean_t v) noexcept : boolean(v) {}
+        /// constructor for numbers (integer)
+        json_value(number_integer_t v) noexcept : number_integer(v) {}
+        /// constructor for numbers (unsigned)
+        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
+        /// constructor for numbers (floating-point)
+        json_value(number_float_t v) noexcept : number_float(v) {}
+        /// constructor for empty values of a given type
+        json_value(value_t t)
+        {
+            switch (t)
+            {
+                case value_t::object:
+                {
+                    object = create<object_t>();
+                    break;
+                }
+
+                case value_t::array:
+                {
+                    array = create<array_t>();
+                    break;
+                }
+
+                case value_t::string:
+                {
+                    string = create<string_t>("");
+                    break;
+                }
+
+                case value_t::boolean:
+                {
+                    boolean = boolean_t(false);
+                    break;
+                }
+
+                case value_t::number_integer:
+                {
+                    number_integer = number_integer_t(0);
+                    break;
+                }
+
+                case value_t::number_unsigned:
+                {
+                    number_unsigned = number_unsigned_t(0);
+                    break;
+                }
+
+                case value_t::number_float:
+                {
+                    number_float = number_float_t(0.0);
+                    break;
+                }
+
+                case value_t::null:
+                {
+                    break;
+                }
+
+                default:
+                {
+                    if (t == value_t::null)
+                    {
+                        JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10")); // LCOV_EXCL_LINE
+                    }
+                    break;
+                }
+            }
+        }
+
+        /// constructor for strings
+        json_value(const string_t& value)
+        {
+            string = create<string_t>(value);
+        }
+
+        /// constructor for objects
+        json_value(const object_t& value)
+        {
+            object = create<object_t>(value);
+        }
+
+        /// constructor for arrays
+        json_value(const array_t& value)
+        {
+            array = create<array_t>(value);
+        }
+    };
+
+    /*!
+    @brief checks the class invariants
+
+    This function asserts the class invariants. It needs to be called at the
+    end of every constructor to make sure that created objects respect the
+    invariant. Furthermore, it has to be called each time the type of a JSON
+    value is changed, because the invariant expresses a relationship between
+    @a m_type and @a m_value.
+    */
+    void assert_invariant() const
+    {
+        assert(m_type != value_t::object or m_value.object != nullptr);
+        assert(m_type != value_t::array or m_value.array != nullptr);
+        assert(m_type != value_t::string or m_value.string != nullptr);
+    }
+
+  public:
+    //////////////////////////
+    // JSON parser callback //
+    //////////////////////////
+
+    /*!
+    @brief JSON callback events
+
+    This enumeration lists the parser events that can trigger calling a
+    callback function of type @ref parser_callback_t during parsing.
+
+    @image html callback_events.png "Example when certain parse events are triggered"
+
+    @since version 1.0.0
+    */
+    enum class parse_event_t : uint8_t
+    {
+        /// the parser read `{` and started to process a JSON object
+        object_start,
+        /// the parser read `}` and finished processing a JSON object
+        object_end,
+        /// the parser read `[` and started to process a JSON array
+        array_start,
+        /// the parser read `]` and finished processing a JSON array
+        array_end,
+        /// the parser read a key of a value in an object
+        key,
+        /// the parser finished reading a JSON value
+        value
+    };
+
+    /*!
+    @brief per-element parser callback type
+
+    With a parser callback function, the result of parsing a JSON text can be
+    influenced. When passed to @ref parse(std::istream&, const
+    parser_callback_t) or @ref parse(const CharT, const parser_callback_t),
+    it is called on certain events (passed as @ref parse_event_t via parameter
+    @a event) with a set recursion depth @a depth and context JSON value
+    @a parsed. The return value of the callback function is a boolean
+    indicating whether the element that emitted the callback shall be kept or
+    not.
+
+    We distinguish six scenarios (determined by the event type) in which the
+    callback function can be called. The following table describes the values
+    of the parameters @a depth, @a event, and @a parsed.
+
+    parameter @a event | description | parameter @a depth | parameter @a parsed
+    ------------------ | ----------- | ------------------ | -------------------
+    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
+    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
+    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
+    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
+    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
+    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
+
+    @image html callback_events.png "Example when certain parse events are triggered"
+
+    Discarding a value (i.e., returning `false`) has different effects
+    depending on the context in which function was called:
+
+    - Discarded values in structured types are skipped. That is, the parser
+      will behave as if the discarded value was never read.
+    - In case a value outside a structured type is skipped, it is replaced
+      with `null`. This case happens if the top-level element is skipped.
+
+    @param[in] depth  the depth of the recursion during parsing
+
+    @param[in] event  an event of type parse_event_t indicating the context in
+    the callback function has been called
+
+    @param[in,out] parsed  the current intermediate parse result; note that
+    writing to this value has no effect for parse_event_t::key events
+
+    @return Whether the JSON value which called the function during parsing
+    should be kept (`true`) or not (`false`). In the latter case, it is either
+    skipped completely or replaced by an empty discarded object.
+
+    @sa @ref parse(std::istream&, parser_callback_t) or
+    @ref parse(const CharT, const parser_callback_t) for examples
+
+    @since version 1.0.0
+    */
+    using parser_callback_t = std::function<bool(int depth,
+                              parse_event_t event,
+                              basic_json& parsed)>;
+
+
+    //////////////////
+    // constructors //
+    //////////////////
+
+    /// @name constructors and destructors
+    /// Constructors of class @ref basic_json, copy/move constructor, copy
+    /// assignment, static functions creating objects, and the destructor.
+    /// @{
+
+    /*!
+    @brief create an empty value with a given type
+
+    Create an empty JSON value with a given type. The value will be default
+    initialized with an empty value which depends on the type:
+
+    Value type  | initial value
+    ----------- | -------------
+    null        | `null`
+    boolean     | `false`
+    string      | `""`
+    number      | `0`
+    object      | `{}`
+    array       | `[]`
+
+    @param[in] value_type  the type of the value to create
+
+    @complexity Constant.
+
+    @throw std::bad_alloc if allocation for object, array, or string value
+    fails
+
+    @liveexample{The following code shows the constructor for different @ref
+    value_t values,basic_json__value_t}
+
+    @sa @ref basic_json(std::nullptr_t) -- create a `null` value
+    @sa @ref basic_json(boolean_t value) -- create a boolean value
+    @sa @ref basic_json(const string_t&) -- create a string value
+    @sa @ref basic_json(const object_t&) -- create a object value
+    @sa @ref basic_json(const array_t&) -- create a array value
+    @sa @ref basic_json(const number_float_t) -- create a number
+    (floating-point) value
+    @sa @ref basic_json(const number_integer_t) -- create a number (integer)
+    value
+    @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned)
+    value
+
+    @since version 1.0.0
+    */
+    basic_json(const value_t value_type)
+        : m_type(value_type), m_value(value_type)
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create a null object
+
+    Create a `null` JSON value. It either takes a null pointer as parameter
+    (explicitly creating `null`) or no parameter (implicitly creating `null`).
+    The passed null pointer itself is not read -- it is only used to choose
+    the right constructor.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this constructor never throws
+    exceptions.
+
+    @liveexample{The following code shows the constructor with and without a
+    null pointer parameter.,basic_json__nullptr_t}
+
+    @since version 1.0.0
+    */
+    basic_json(std::nullptr_t = nullptr) noexcept
+        : basic_json(value_t::null)
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an object (explicit)
+
+    Create an object JSON value with a given content.
+
+    @param[in] val  a value for the object
+
+    @complexity Linear in the size of the passed @a val.
+
+    @throw std::bad_alloc if allocation for object value fails
+
+    @liveexample{The following code shows the constructor with an @ref
+    object_t parameter.,basic_json__object_t}
+
+    @sa @ref basic_json(const CompatibleObjectType&) -- create an object value
+    from a compatible STL container
+
+    @since version 1.0.0
+    */
+    basic_json(const object_t& val)
+        : m_type(value_t::object), m_value(val)
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an object (implicit)
+
+    Create an object JSON value with a given content. This constructor allows
+    any type @a CompatibleObjectType that can be used to construct values of
+    type @ref object_t.
+
+    @tparam CompatibleObjectType An object type whose `key_type` and
+    `value_type` is compatible to @ref object_t. Examples include `std::map`,
+    `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with
+    a `key_type` of `std::string`, and a `value_type` from which a @ref
+    basic_json value can be constructed.
+
+    @param[in] val  a value for the object
+
+    @complexity Linear in the size of the passed @a val.
+
+    @throw std::bad_alloc if allocation for object value fails
+
+    @liveexample{The following code shows the constructor with several
+    compatible object type parameters.,basic_json__CompatibleObjectType}
+
+    @sa @ref basic_json(const object_t&) -- create an object value
+
+    @since version 1.0.0
+    */
+    template<class CompatibleObjectType, typename std::enable_if<
+                 std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
+                 std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0>
+    basic_json(const CompatibleObjectType& val)
+        : m_type(value_t::object)
+    {
+        using std::begin;
+        using std::end;
+        m_value.object = create<object_t>(begin(val), end(val));
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an array (explicit)
+
+    Create an array JSON value with a given content.
+
+    @param[in] val  a value for the array
+
+    @complexity Linear in the size of the passed @a val.
+
+    @throw std::bad_alloc if allocation for array value fails
+
+    @liveexample{The following code shows the constructor with an @ref array_t
+    parameter.,basic_json__array_t}
+
+    @sa @ref basic_json(const CompatibleArrayType&) -- create an array value
+    from a compatible STL containers
+
+    @since version 1.0.0
+    */
+    basic_json(const array_t& val)
+        : m_type(value_t::array), m_value(val)
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an array (implicit)
+
+    Create an array JSON value with a given content. This constructor allows
+    any type @a CompatibleArrayType that can be used to construct values of
+    type @ref array_t.
+
+    @tparam CompatibleArrayType An object type whose `value_type` is
+    compatible to @ref array_t. Examples include `std::vector`, `std::deque`,
+    `std::list`, `std::forward_list`, `std::array`, `std::set`,
+    `std::unordered_set`, `std::multiset`, and `unordered_multiset` with a
+    `value_type` from which a @ref basic_json value can be constructed.
+
+    @param[in] val  a value for the array
+
+    @complexity Linear in the size of the passed @a val.
+
+    @throw std::bad_alloc if allocation for array value fails
+
+    @liveexample{The following code shows the constructor with several
+    compatible array type parameters.,basic_json__CompatibleArrayType}
+
+    @sa @ref basic_json(const array_t&) -- create an array value
+
+    @since version 1.0.0
+    */
+    template<class CompatibleArrayType, typename std::enable_if<
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
+                 not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
+                 std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
+    basic_json(const CompatibleArrayType& val)
+        : m_type(value_t::array)
+    {
+        using std::begin;
+        using std::end;
+        m_value.array = create<array_t>(begin(val), end(val));
+        assert_invariant();
+    }
+
+    /*!
+    @brief create a string (explicit)
+
+    Create an string JSON value with a given content.
+
+    @param[in] val  a value for the string
+
+    @complexity Linear in the size of the passed @a val.
+
+    @throw std::bad_alloc if allocation for string value fails
+
+    @liveexample{The following code shows the constructor with an @ref
+    string_t parameter.,basic_json__string_t}
+
+    @sa @ref basic_json(const typename string_t::value_type*) -- create a
+    string value from a character pointer
+    @sa @ref basic_json(const CompatibleStringType&) -- create a string value
+    from a compatible string container
+
+    @since version 1.0.0
+    */
+    basic_json(const string_t& val)
+        : m_type(value_t::string), m_value(val)
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create a string (explicit)
+
+    Create a string JSON value with a given content.
+
+    @param[in] val  a literal value for the string
+
+    @complexity Linear in the size of the passed @a val.
+
+    @throw std::bad_alloc if allocation for string value fails
+
+    @liveexample{The following code shows the constructor with string literal
+    parameter.,basic_json__string_t_value_type}
+
+    @sa @ref basic_json(const string_t&) -- create a string value
+    @sa @ref basic_json(const CompatibleStringType&) -- create a string value
+    from a compatible string container
+
+    @since version 1.0.0
+    */
+    basic_json(const typename string_t::value_type* val)
+        : basic_json(string_t(val))
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create a string (implicit)
+
+    Create a string JSON value with a given content.
+
+    @param[in] val  a value for the string
+
+    @tparam CompatibleStringType an string type which is compatible to @ref
+    string_t, for instance `std::string`.
+
+    @complexity Linear in the size of the passed @a val.
+
+    @throw std::bad_alloc if allocation for string value fails
+
+    @liveexample{The following code shows the construction of a string value
+    from a compatible type.,basic_json__CompatibleStringType}
+
+    @sa @ref basic_json(const string_t&) -- create a string value
+    @sa @ref basic_json(const typename string_t::value_type*) -- create a
+    string value from a character pointer
+
+    @since version 1.0.0
+    */
+    template<class CompatibleStringType, typename std::enable_if<
+                 std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0>
+    basic_json(const CompatibleStringType& val)
+        : basic_json(string_t(val))
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create a boolean (explicit)
+
+    Creates a JSON boolean type from a given value.
+
+    @param[in] val  a boolean value to store
+
+    @complexity Constant.
+
+    @liveexample{The example below demonstrates boolean
+    values.,basic_json__boolean_t}
+
+    @since version 1.0.0
+    */
+    basic_json(boolean_t val) noexcept
+        : m_type(value_t::boolean), m_value(val)
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an integer number (explicit)
+
+    Create an integer number JSON value with a given content.
+
+    @tparam T A helper type to remove this function via SFINAE in case @ref
+    number_integer_t is the same as `int`. In this case, this constructor
+    would have the same signature as @ref basic_json(const int value). Note
+    the helper type @a T is not visible in this constructor's interface.
+
+    @param[in] val  an integer to create a JSON number from
+
+    @complexity Constant.
+
+    @liveexample{The example below shows the construction of an integer
+    number value.,basic_json__number_integer_t}
+
+    @sa @ref basic_json(const int) -- create a number value (integer)
+    @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
+    value (integer) from a compatible number type
+
+    @since version 1.0.0
+    */
+    template<typename T, typename std::enable_if<
+                 not (std::is_same<T, int>::value) and
+                 std::is_same<T, number_integer_t>::value, int>::type = 0>
+    basic_json(const number_integer_t val) noexcept
+        : m_type(value_t::number_integer), m_value(val)
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an integer number from an enum type (explicit)
+
+    Create an integer number JSON value with a given content.
+
+    @param[in] val  an integer to create a JSON number from
+
+    @note This constructor allows to pass enums directly to a constructor. As
+    C++ has no way of specifying the type of an anonymous enum explicitly, we
+    can only rely on the fact that such values implicitly convert to int. As
+    int may already be the same type of number_integer_t, we may need to
+    switch off the constructor @ref basic_json(const number_integer_t).
+
+    @complexity Constant.
+
+    @liveexample{The example below shows the construction of an integer
+    number value from an anonymous enum.,basic_json__const_int}
+
+    @sa @ref basic_json(const number_integer_t) -- create a number value
+    (integer)
+    @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
+    value (integer) from a compatible number type
+
+    @since version 1.0.0
+    */
+    basic_json(const int val) noexcept
+        : m_type(value_t::number_integer),
+          m_value(static_cast<number_integer_t>(val))
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an integer number (implicit)
+
+    Create an integer number JSON value with a given content. This constructor
+    allows any type @a CompatibleNumberIntegerType that can be used to
+    construct values of type @ref number_integer_t.
+
+    @tparam CompatibleNumberIntegerType An integer type which is compatible to
+    @ref number_integer_t. Examples include the types `int`, `int32_t`,
+    `long`, and `short`.
+
+    @param[in] val  an integer to create a JSON number from
+
+    @complexity Constant.
+
+    @liveexample{The example below shows the construction of several integer
+    number values from compatible
+    types.,basic_json__CompatibleIntegerNumberType}
+
+    @sa @ref basic_json(const number_integer_t) -- create a number value
+    (integer)
+    @sa @ref basic_json(const int) -- create a number value (integer)
+
+    @since version 1.0.0
+    */
+    template<typename CompatibleNumberIntegerType, typename std::enable_if<
+                 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
+                 std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
+                 std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
+                 CompatibleNumberIntegerType>::type = 0>
+    basic_json(const CompatibleNumberIntegerType val) noexcept
+        : m_type(value_t::number_integer),
+          m_value(static_cast<number_integer_t>(val))
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an unsigned integer number (explicit)
+
+    Create an unsigned integer number JSON value with a given content.
+
+    @tparam T  helper type to compare number_unsigned_t and unsigned int (not
+    visible in) the interface.
+
+    @param[in] val  an integer to create a JSON number from
+
+    @complexity Constant.
+
+    @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number
+    value (unsigned integer) from a compatible number type
+
+    @since version 2.0.0
+    */
+    template<typename T, typename std::enable_if<
+                 not (std::is_same<T, int>::value) and
+                 std::is_same<T, number_unsigned_t>::value, int>::type = 0>
+    basic_json(const number_unsigned_t val) noexcept
+        : m_type(value_t::number_unsigned), m_value(val)
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an unsigned number (implicit)
+
+    Create an unsigned number JSON value with a given content. This
+    constructor allows any type @a CompatibleNumberUnsignedType that can be
+    used to construct values of type @ref number_unsigned_t.
+
+    @tparam CompatibleNumberUnsignedType An integer type which is compatible
+    to @ref number_unsigned_t. Examples may include the types `unsigned int`,
+    `uint32_t`, or `unsigned short`.
+
+    @param[in] val  an unsigned integer to create a JSON number from
+
+    @complexity Constant.
+
+    @sa @ref basic_json(const number_unsigned_t) -- create a number value
+    (unsigned)
+
+    @since version 2.0.0
+    */
+    template<typename CompatibleNumberUnsignedType, typename std::enable_if <
+                 std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
+                 std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
+                 not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
+                 CompatibleNumberUnsignedType>::type = 0>
+    basic_json(const CompatibleNumberUnsignedType val) noexcept
+        : m_type(value_t::number_unsigned),
+          m_value(static_cast<number_unsigned_t>(val))
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create a floating-point number (explicit)
+
+    Create a floating-point number JSON value with a given content.
+
+    @param[in] val  a floating-point value to create a JSON number from
+
+    @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
+    disallows NaN values:
+    > Numeric values that cannot be represented in the grammar below (such as
+    > Infinity and NaN) are not permitted.
+    In case the parameter @a val is not a number, a JSON null value is created
+    instead.
+
+    @complexity Constant.
+
+    @liveexample{The following example creates several floating-point
+    values.,basic_json__number_float_t}
+
+    @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number
+    value (floating-point) from a compatible number type
+
+    @since version 1.0.0
+    */
+    basic_json(const number_float_t val) noexcept
+        : m_type(value_t::number_float), m_value(val)
+    {
+        // replace infinity and NAN by null
+        if (not std::isfinite(val))
+        {
+            m_type = value_t::null;
+            m_value = json_value();
+        }
+
+        assert_invariant();
+    }
+
+    /*!
+    @brief create an floating-point number (implicit)
+
+    Create an floating-point number JSON value with a given content. This
+    constructor allows any type @a CompatibleNumberFloatType that can be used
+    to construct values of type @ref number_float_t.
+
+    @tparam CompatibleNumberFloatType A floating-point type which is
+    compatible to @ref number_float_t. Examples may include the types `float`
+    or `double`.
+
+    @param[in] val  a floating-point to create a JSON number from
+
+    @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
+    disallows NaN values:
+    > Numeric values that cannot be represented in the grammar below (such as
+    > Infinity and NaN) are not permitted.
+    In case the parameter @a val is not a number, a JSON null value is
+    created instead.
+
+    @complexity Constant.
+
+    @liveexample{The example below shows the construction of several
+    floating-point number values from compatible
+    types.,basic_json__CompatibleNumberFloatType}
+
+    @sa @ref basic_json(const number_float_t) -- create a number value
+    (floating-point)
+
+    @since version 1.0.0
+    */
+    template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
+                 std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
+                 std::is_floating_point<CompatibleNumberFloatType>::value>::type>
+    basic_json(const CompatibleNumberFloatType val) noexcept
+        : basic_json(number_float_t(val))
+    {
+        assert_invariant();
+    }
+
+    /*!
+    @brief create a container (array or object) from an initializer list
+
+    Creates a JSON value of type array or object from the passed initializer
+    list @a init. In case @a type_deduction is `true` (default), the type of
+    the JSON value to be created is deducted from the initializer list @a init
+    according to the following rules:
+
+    1. If the list is empty, an empty JSON object value `{}` is created.
+    2. If the list consists of pairs whose first element is a string, a JSON
+       object value is created where the first elements of the pairs are
+       treated as keys and the second elements are as values.
+    3. In all other cases, an array is created.
+
+    The rules aim to create the best fit between a C++ initializer list and
+    JSON values. The rationale is as follows:
+
+    1. The empty initializer list is written as `{}` which is exactly an empty
+       JSON object.
+    2. C++ has now way of describing mapped types other than to list a list of
+       pairs. As JSON requires that keys must be of type string, rule 2 is the
+       weakest constraint one can pose on initializer lists to interpret them
+       as an object.
+    3. In all other cases, the initializer list could not be interpreted as
+       JSON object type, so interpreting it as JSON array type is safe.
+
+    With the rules described above, the following JSON values cannot be
+    expressed by an initializer list:
+
+    - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>)
+      with an empty initializer list in this case
+    - arrays whose elements satisfy rule 2: use @ref
+      array(std::initializer_list<basic_json>) with the same initializer list
+      in this case
+
+    @note When used without parentheses around an empty initializer list, @ref
+    basic_json() is called instead of this function, yielding the JSON null
+    value.
+
+    @param[in] init  initializer list with JSON values
+
+    @param[in] type_deduction internal parameter; when set to `true`, the type
+    of the JSON value is deducted from the initializer list @a init; when set
+    to `false`, the type provided via @a manual_type is forced. This mode is
+    used by the functions @ref array(std::initializer_list<basic_json>) and
+    @ref object(std::initializer_list<basic_json>).
+
+    @param[in] manual_type internal parameter; when @a type_deduction is set
+    to `false`, the created JSON value will use the provided type (only @ref
+    value_t::array and @ref value_t::object are valid); when @a type_deduction
+    is set to `true`, this parameter has no effect
+
+    @throw std::domain_error if @a type_deduction is `false`, @a manual_type
+    is `value_t::object`, but @a init contains an element which is not a pair
+    whose first element is a string; example: `"cannot create object from
+    initializer list"`
+
+    @complexity Linear in the size of the initializer list @a init.
+
+    @liveexample{The example below shows how JSON values are created from
+    initializer lists.,basic_json__list_init_t}
+
+    @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
+    value from an initializer list
+    @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
+    value from an initializer list
+
+    @since version 1.0.0
+    */
+    basic_json(std::initializer_list<basic_json> init,
+               bool type_deduction = true,
+               value_t manual_type = value_t::array)
+    {
+        // check if each element is an array with two elements whose first
+        // element is a string
+        bool is_an_object = std::all_of(init.begin(), init.end(),
+                                        [](const basic_json & element)
+        {
+            return element.is_array() and element.size() == 2 and element[0].is_string();
+        });
+
+        // adjust type if type deduction is not wanted
+        if (not type_deduction)
+        {
+            // if array is wanted, do not create an object though possible
+            if (manual_type == value_t::array)
+            {
+                is_an_object = false;
+            }
+
+            // if object is wanted but impossible, throw an exception
+            if (manual_type == value_t::object and not is_an_object)
+            {
+                JSON_THROW(std::domain_error("cannot create object from initializer list"));
+            }
+        }
+
+        if (is_an_object)
+        {
+            // the initializer list is a list of pairs -> create object
+            m_type = value_t::object;
+            m_value = value_t::object;
+
+            std::for_each(init.begin(), init.end(), [this](const basic_json & element)
+            {
+                m_value.object->emplace(*(element[0].m_value.string), element[1]);
+            });
+        }
+        else
+        {
+            // the initializer list describes an array -> create array
+            m_type = value_t::array;
+            m_value.array = create<array_t>(init);
+        }
+
+        assert_invariant();
+    }
+
+    /*!
+    @brief explicitly create an array from an initializer list
+
+    Creates a JSON array value from a given initializer list. That is, given a
+    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
+    initializer list is empty, the empty array `[]` is created.
+
+    @note This function is only needed to express two edge cases that cannot
+    be realized with the initializer list constructor (@ref
+    basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
+    are:
+    1. creating an array whose elements are all pairs whose first element is a
+    string -- in this case, the initializer list constructor would create an
+    object, taking the first elements as keys
+    2. creating an empty array -- passing the empty initializer list to the
+    initializer list constructor yields an empty object
+
+    @param[in] init  initializer list with JSON values to create an array from
+    (optional)
+
+    @return JSON array value
+
+    @complexity Linear in the size of @a init.
+
+    @liveexample{The following code shows an example for the `array`
+    function.,array}
+
+    @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
+    create a JSON value from an initializer list
+    @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
+    value from an initializer list
+
+    @since version 1.0.0
+    */
+    static basic_json array(std::initializer_list<basic_json> init =
+                                std::initializer_list<basic_json>())
+    {
+        return basic_json(init, false, value_t::array);
+    }
+
+    /*!
+    @brief explicitly create an object from an initializer list
+
+    Creates a JSON object value from a given initializer list. The initializer
+    lists elements must be pairs, and their first elements must be strings. If
+    the initializer list is empty, the empty object `{}` is created.
+
+    @note This function is only added for symmetry reasons. In contrast to the
+    related function @ref array(std::initializer_list<basic_json>), there are
+    no cases which can only be expressed by this function. That is, any
+    initializer list @a init can also be passed to the initializer list
+    constructor @ref basic_json(std::initializer_list<basic_json>, bool,
+    value_t).
+
+    @param[in] init  initializer list to create an object from (optional)
+
+    @return JSON object value
+
+    @throw std::domain_error if @a init is not a pair whose first elements are
+    strings; thrown by
+    @ref basic_json(std::initializer_list<basic_json>, bool, value_t)
+
+    @complexity Linear in the size of @a init.
+
+    @liveexample{The following code shows an example for the `object`
+    function.,object}
+
+    @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
+    create a JSON value from an initializer list
+    @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
+    value from an initializer list
+
+    @since version 1.0.0
+    */
+    static basic_json object(std::initializer_list<basic_json> init =
+                                 std::initializer_list<basic_json>())
+    {
+        return basic_json(init, false, value_t::object);
+    }
+
+    /*!
+    @brief construct an array with count copies of given value
+
+    Constructs a JSON array value by creating @a cnt copies of a passed value.
+    In case @a cnt is `0`, an empty array is created. As postcondition,
+    `std::distance(begin(),end()) == cnt` holds.
+
+    @param[in] cnt  the number of JSON copies of @a val to create
+    @param[in] val  the JSON value to copy
+
+    @complexity Linear in @a cnt.
+
+    @liveexample{The following code shows examples for the @ref
+    basic_json(size_type\, const basic_json&)
+    constructor.,basic_json__size_type_basic_json}
+
+    @since version 1.0.0
+    */
+    basic_json(size_type cnt, const basic_json& val)
+        : m_type(value_t::array)
+    {
+        m_value.array = create<array_t>(cnt, val);
+        assert_invariant();
+    }
+
+    /*!
+    @brief construct a JSON container given an iterator range
+
+    Constructs the JSON value with the contents of the range `[first, last)`.
+    The semantics depends on the different types a JSON value can have:
+    - In case of primitive types (number, boolean, or string), @a first must
+      be `begin()` and @a last must be `end()`. In this case, the value is
+      copied. Otherwise, std::out_of_range is thrown.
+    - In case of structured types (array, object), the constructor behaves as
+      similar versions for `std::vector`.
+    - In case of a null type, std::domain_error is thrown.
+
+    @tparam InputIT an input iterator type (@ref iterator or @ref
+    const_iterator)
+
+    @param[in] first begin of the range to copy from (included)
+    @param[in] last end of the range to copy from (excluded)
+
+    @pre Iterators @a first and @a last must be initialized. **This
+         precondition is enforced with an assertion.**
+
+    @throw std::domain_error if iterators are not compatible; that is, do not
+    belong to the same JSON value; example: `"iterators are not compatible"`
+    @throw std::out_of_range if iterators are for a primitive type (number,
+    boolean, or string) where an out of range error can be detected easily;
+    example: `"iterators out of range"`
+    @throw std::bad_alloc if allocation for object, array, or string fails
+    @throw std::domain_error if called with a null value; example: `"cannot
+    use construct with iterators from null"`
+
+    @complexity Linear in distance between @a first and @a last.
+
+    @liveexample{The example below shows several ways to create JSON values by
+    specifying a subrange with iterators.,basic_json__InputIt_InputIt}
+
+    @since version 1.0.0
+    */
+    template<class InputIT, typename std::enable_if<
+                 std::is_same<InputIT, typename basic_json_t::iterator>::value or
+                 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
+    basic_json(InputIT first, InputIT last)
+    {
+        assert(first.m_object != nullptr);
+        assert(last.m_object != nullptr);
+
+        // make sure iterator fits the current value
+        if (first.m_object != last.m_object)
+        {
+            JSON_THROW(std::domain_error("iterators are not compatible"));
+        }
+
+        // copy type from first iterator
+        m_type = first.m_object->m_type;
+
+        // check if iterator range is complete for primitive values
+        switch (m_type)
+        {
+            case value_t::boolean:
+            case value_t::number_float:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::string:
+            {
+                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
+                {
+                    JSON_THROW(std::out_of_range("iterators out of range"));
+                }
+                break;
+            }
+
+            default:
+            {
+                break;
+            }
+        }
+
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            {
+                m_value.number_integer = first.m_object->m_value.number_integer;
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                m_value.number_unsigned = first.m_object->m_value.number_unsigned;
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                m_value.number_float = first.m_object->m_value.number_float;
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                m_value.boolean = first.m_object->m_value.boolean;
+                break;
+            }
+
+            case value_t::string:
+            {
+                m_value = *first.m_object->m_value.string;
+                break;
+            }
+
+            case value_t::object:
+            {
+                m_value.object = create<object_t>(first.m_it.object_iterator,
+                                                  last.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_value.array = create<array_t>(first.m_it.array_iterator,
+                                                last.m_it.array_iterator);
+                break;
+            }
+
+            default:
+            {
+                JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()));
+            }
+        }
+
+        assert_invariant();
+    }
+
+    /*!
+    @brief construct a JSON value given an input stream
+
+    @param[in,out] i  stream to read a serialized JSON value from
+    @param[in] cb a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @deprecated This constructor is deprecated and will be removed in version
+      3.0.0 to unify the interface of the library. Deserialization will be
+      done by stream operators or by calling one of the `parse` functions,
+      e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls
+      like `json j(i);` for an input stream @a i need to be replaced by
+      `json j = json::parse(i);`. See the example below.
+
+    @liveexample{The example below demonstrates constructing a JSON value from
+    a `std::stringstream` with and without callback
+    function.,basic_json__istream}
+
+    @since version 2.0.0, deprecated in version 2.0.3, to be removed in
+           version 3.0.0
+    */
+    JSON_DEPRECATED
+    explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)
+    {
+        *this = parser(i, cb).parse();
+        assert_invariant();
+    }
+
+    ///////////////////////////////////////
+    // other constructors and destructor //
+    ///////////////////////////////////////
+
+    /*!
+    @brief copy constructor
+
+    Creates a copy of a given JSON value.
+
+    @param[in] other  the JSON value to copy
+
+    @complexity Linear in the size of @a other.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is linear.
+    - As postcondition, it holds: `other == basic_json(other)`.
+
+    @throw std::bad_alloc if allocation for object, array, or string fails.
+
+    @liveexample{The following code shows an example for the copy
+    constructor.,basic_json__basic_json}
+
+    @since version 1.0.0
+    */
+    basic_json(const basic_json& other)
+        : m_type(other.m_type)
+    {
+        // check of passed value is valid
+        other.assert_invariant();
+
+        switch (m_type)
+        {
+            case value_t::object:
+            {
+                m_value = *other.m_value.object;
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_value = *other.m_value.array;
+                break;
+            }
+
+            case value_t::string:
+            {
+                m_value = *other.m_value.string;
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                m_value = other.m_value.boolean;
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                m_value = other.m_value.number_integer;
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                m_value = other.m_value.number_unsigned;
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                m_value = other.m_value.number_float;
+                break;
+            }
+
+            default:
+            {
+                break;
+            }
+        }
+
+        assert_invariant();
+    }
+
+    /*!
+    @brief move constructor
+
+    Move constructor. Constructs a JSON value with the contents of the given
+    value @a other using move semantics. It "steals" the resources from @a
+    other and leaves it as JSON null value.
+
+    @param[in,out] other  value to move to this object
+
+    @post @a other is a JSON null value
+
+    @complexity Constant.
+
+    @liveexample{The code below shows the move constructor explicitly called
+    via std::move.,basic_json__moveconstructor}
+
+    @since version 1.0.0
+    */
+    basic_json(basic_json&& other) noexcept
+        : m_type(std::move(other.m_type)),
+          m_value(std::move(other.m_value))
+    {
+        // check that passed value is valid
+        other.assert_invariant();
+
+        // invalidate payload
+        other.m_type = value_t::null;
+        other.m_value = {};
+
+        assert_invariant();
+    }
+
+    /*!
+    @brief copy assignment
+
+    Copy assignment operator. Copies a JSON value via the "copy and swap"
+    strategy: It is expressed in terms of the copy constructor, destructor,
+    and the swap() member function.
+
+    @param[in] other  value to copy from
+
+    @complexity Linear.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is linear.
+
+    @liveexample{The code below shows and example for the copy assignment. It
+    creates a copy of value `a` which is then swapped with `b`. Finally\, the
+    copy of `a` (which is the null value after the swap) is
+    destroyed.,basic_json__copyassignment}
+
+    @since version 1.0.0
+    */
+    reference& operator=(basic_json other) noexcept (
+        std::is_nothrow_move_constructible<value_t>::value and
+        std::is_nothrow_move_assignable<value_t>::value and
+        std::is_nothrow_move_constructible<json_value>::value and
+        std::is_nothrow_move_assignable<json_value>::value
+    )
+    {
+        // check that passed value is valid
+        other.assert_invariant();
+
+        using std::swap;
+        swap(m_type, other.m_type);
+        swap(m_value, other.m_value);
+
+        assert_invariant();
+        return *this;
+    }
+
+    /*!
+    @brief destructor
+
+    Destroys the JSON value and frees all allocated memory.
+
+    @complexity Linear.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is linear.
+    - All stored elements are destroyed and all memory is freed.
+
+    @since version 1.0.0
+    */
+    ~basic_json()
+    {
+        assert_invariant();
+
+        switch (m_type)
+        {
+            case value_t::object:
+            {
+                AllocatorType<object_t> alloc;
+                alloc.destroy(m_value.object);
+                alloc.deallocate(m_value.object, 1);
+                break;
+            }
+
+            case value_t::array:
+            {
+                AllocatorType<array_t> alloc;
+                alloc.destroy(m_value.array);
+                alloc.deallocate(m_value.array, 1);
+                break;
+            }
+
+            case value_t::string:
+            {
+                AllocatorType<string_t> alloc;
+                alloc.destroy(m_value.string);
+                alloc.deallocate(m_value.string, 1);
+                break;
+            }
+
+            default:
+            {
+                // all other types need no specific destructor
+                break;
+            }
+        }
+    }
+
+    /// @}
+
+  public:
+    ///////////////////////
+    // object inspection //
+    ///////////////////////
+
+    /// @name object inspection
+    /// Functions to inspect the type of a JSON value.
+    /// @{
+
+    /*!
+    @brief serialization
+
+    Serialization function for JSON values. The function tries to mimic
+    Python's `json.dumps()` function, and currently supports its @a indent
+    parameter.
+
+    @param[in] indent If indent is nonnegative, then array elements and object
+    members will be pretty-printed with that indent level. An indent level of
+    `0` will only insert newlines. `-1` (the default) selects the most compact
+    representation.
+
+    @return string containing the serialization of the JSON value
+
+    @complexity Linear.
+
+    @liveexample{The following example shows the effect of different @a indent
+    parameters to the result of the serialization.,dump}
+
+    @see https://docs.python.org/2/library/json.html#json.dump
+
+    @since version 1.0.0
+    */
+    string_t dump(const int indent = -1) const
+    {
+        std::stringstream ss;
+        // fix locale problems
+        ss.imbue(std::locale::classic());
+
+        // 6, 15 or 16 digits of precision allows round-trip IEEE 754
+        // string->float->string, string->double->string or string->long
+        // double->string; to be safe, we read this value from
+        // std::numeric_limits<number_float_t>::digits10
+        ss.precision(std::numeric_limits<double>::digits10);
+
+        if (indent >= 0)
+        {
+            dump(ss, true, static_cast<unsigned int>(indent));
+        }
+        else
+        {
+            dump(ss, false, 0);
+        }
+
+        return ss.str();
+    }
+
+    /*!
+    @brief return the type of the JSON value (explicit)
+
+    Return the type of the JSON value as a value from the @ref value_t
+    enumeration.
+
+    @return the type of the JSON value
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `type()` for all JSON
+    types.,type}
+
+    @since version 1.0.0
+    */
+    constexpr value_t type() const noexcept
+    {
+        return m_type;
+    }
+
+    /*!
+    @brief return whether type is primitive
+
+    This function returns true iff the JSON type is primitive (string, number,
+    boolean, or null).
+
+    @return `true` if type is primitive (string, number, boolean, or null),
+    `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_primitive()` for all JSON
+    types.,is_primitive}
+
+    @sa @ref is_structured() -- returns whether JSON value is structured
+    @sa @ref is_null() -- returns whether JSON value is `null`
+    @sa @ref is_string() -- returns whether JSON value is a string
+    @sa @ref is_boolean() -- returns whether JSON value is a boolean
+    @sa @ref is_number() -- returns whether JSON value is a number
+
+    @since version 1.0.0
+    */
+    constexpr bool is_primitive() const noexcept
+    {
+        return is_null() or is_string() or is_boolean() or is_number();
+    }
+
+    /*!
+    @brief return whether type is structured
+
+    This function returns true iff the JSON type is structured (array or
+    object).
+
+    @return `true` if type is structured (array or object), `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_structured()` for all JSON
+    types.,is_structured}
+
+    @sa @ref is_primitive() -- returns whether value is primitive
+    @sa @ref is_array() -- returns whether value is an array
+    @sa @ref is_object() -- returns whether value is an object
+
+    @since version 1.0.0
+    */
+    constexpr bool is_structured() const noexcept
+    {
+        return is_array() or is_object();
+    }
+
+    /*!
+    @brief return whether value is null
+
+    This function returns true iff the JSON value is null.
+
+    @return `true` if type is null, `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_null()` for all JSON
+    types.,is_null}
+
+    @since version 1.0.0
+    */
+    constexpr bool is_null() const noexcept
+    {
+        return m_type == value_t::null;
+    }
+
+    /*!
+    @brief return whether value is a boolean
+
+    This function returns true iff the JSON value is a boolean.
+
+    @return `true` if type is boolean, `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_boolean()` for all JSON
+    types.,is_boolean}
+
+    @since version 1.0.0
+    */
+    constexpr bool is_boolean() const noexcept
+    {
+        return m_type == value_t::boolean;
+    }
+
+    /*!
+    @brief return whether value is a number
+
+    This function returns true iff the JSON value is a number. This includes
+    both integer and floating-point values.
+
+    @return `true` if type is number (regardless whether integer, unsigned
+    integer or floating-type), `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_number()` for all JSON
+    types.,is_number}
+
+    @sa @ref is_number_integer() -- check if value is an integer or unsigned
+    integer number
+    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+    number
+    @sa @ref is_number_float() -- check if value is a floating-point number
+
+    @since version 1.0.0
+    */
+    constexpr bool is_number() const noexcept
+    {
+        return is_number_integer() or is_number_float();
+    }
+
+    /*!
+    @brief return whether value is an integer number
+
+    This function returns true iff the JSON value is an integer or unsigned
+    integer number. This excludes floating-point values.
+
+    @return `true` if type is an integer or unsigned integer number, `false`
+    otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_number_integer()` for all
+    JSON types.,is_number_integer}
+
+    @sa @ref is_number() -- check if value is a number
+    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+    number
+    @sa @ref is_number_float() -- check if value is a floating-point number
+
+    @since version 1.0.0
+    */
+    constexpr bool is_number_integer() const noexcept
+    {
+        return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
+    }
+
+    /*!
+    @brief return whether value is an unsigned integer number
+
+    This function returns true iff the JSON value is an unsigned integer
+    number. This excludes floating-point and (signed) integer values.
+
+    @return `true` if type is an unsigned integer number, `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_number_unsigned()` for all
+    JSON types.,is_number_unsigned}
+
+    @sa @ref is_number() -- check if value is a number
+    @sa @ref is_number_integer() -- check if value is an integer or unsigned
+    integer number
+    @sa @ref is_number_float() -- check if value is a floating-point number
+
+    @since version 2.0.0
+    */
+    constexpr bool is_number_unsigned() const noexcept
+    {
+        return m_type == value_t::number_unsigned;
+    }
+
+    /*!
+    @brief return whether value is a floating-point number
+
+    This function returns true iff the JSON value is a floating-point number.
+    This excludes integer and unsigned integer values.
+
+    @return `true` if type is a floating-point number, `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_number_float()` for all
+    JSON types.,is_number_float}
+
+    @sa @ref is_number() -- check if value is number
+    @sa @ref is_number_integer() -- check if value is an integer number
+    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+    number
+
+    @since version 1.0.0
+    */
+    constexpr bool is_number_float() const noexcept
+    {
+        return m_type == value_t::number_float;
+    }
+
+    /*!
+    @brief return whether value is an object
+
+    This function returns true iff the JSON value is an object.
+
+    @return `true` if type is object, `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_object()` for all JSON
+    types.,is_object}
+
+    @since version 1.0.0
+    */
+    constexpr bool is_object() const noexcept
+    {
+        return m_type == value_t::object;
+    }
+
+    /*!
+    @brief return whether value is an array
+
+    This function returns true iff the JSON value is an array.
+
+    @return `true` if type is array, `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_array()` for all JSON
+    types.,is_array}
+
+    @since version 1.0.0
+    */
+    constexpr bool is_array() const noexcept
+    {
+        return m_type == value_t::array;
+    }
+
+    /*!
+    @brief return whether value is a string
+
+    This function returns true iff the JSON value is a string.
+
+    @return `true` if type is string, `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_string()` for all JSON
+    types.,is_string}
+
+    @since version 1.0.0
+    */
+    constexpr bool is_string() const noexcept
+    {
+        return m_type == value_t::string;
+    }
+
+    /*!
+    @brief return whether value is discarded
+
+    This function returns true iff the JSON value was discarded during parsing
+    with a callback function (see @ref parser_callback_t).
+
+    @note This function will always be `false` for JSON values after parsing.
+    That is, discarded values can only occur during parsing, but will be
+    removed when inside a structured value or replaced by null in other cases.
+
+    @return `true` if type is discarded, `false` otherwise.
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies `is_discarded()` for all JSON
+    types.,is_discarded}
+
+    @since version 1.0.0
+    */
+    constexpr bool is_discarded() const noexcept
+    {
+        return m_type == value_t::discarded;
+    }
+
+    /*!
+    @brief return the type of the JSON value (implicit)
+
+    Implicitly return the type of the JSON value as a value from the @ref
+    value_t enumeration.
+
+    @return the type of the JSON value
+
+    @complexity Constant.
+
+    @exceptionsafety No-throw guarantee: this member function never throws
+    exceptions.
+
+    @liveexample{The following code exemplifies the @ref value_t operator for
+    all JSON types.,operator__value_t}
+
+    @since version 1.0.0
+    */
+    constexpr operator value_t() const noexcept
+    {
+        return m_type;
+    }
+
+    /// @}
+
+  private:
+    //////////////////
+    // value access //
+    //////////////////
+
+    /// get an object (explicit)
+    template<class T, typename std::enable_if<
+                 std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
+                 std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
+    T get_impl(T* /*unused*/) const
+    {
+        if (is_object())
+        {
+            return T(m_value.object->begin(), m_value.object->end());
+        }
+
+        JSON_THROW(std::domain_error("type must be object, but is " + type_name()));
+    }
+
+    /// get an object (explicit)
+    object_t get_impl(object_t* /*unused*/) const
+    {
+        if (is_object())
+        {
+            return *(m_value.object);
+        }
+
+        JSON_THROW(std::domain_error("type must be object, but is " + type_name()));
+    }
+
+    /// get an array (explicit)
+    template<class T, typename std::enable_if<
+                 std::is_convertible<basic_json_t, typename T::value_type>::value and
+                 not std::is_same<basic_json_t, typename T::value_type>::value and
+                 not std::is_arithmetic<T>::value and
+                 not std::is_convertible<std::string, T>::value and
+                 not has_mapped_type<T>::value, int>::type = 0>
+    T get_impl(T* /*unused*/) const
+    {
+        if (is_array())
+        {
+            T to_vector;
+            std::transform(m_value.array->begin(), m_value.array->end(),
+                           std::inserter(to_vector, to_vector.end()), [](basic_json i)
+            {
+                return i.get<typename T::value_type>();
+            });
+            return to_vector;
+        }
+
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
+    }
+
+    /// get an array (explicit)
+    template<class T, typename std::enable_if<
+                 std::is_convertible<basic_json_t, T>::value and
+                 not std::is_same<basic_json_t, T>::value, int>::type = 0>
+    std::vector<T> get_impl(std::vector<T>* /*unused*/) const
+    {
+        if (is_array())
+        {
+            std::vector<T> to_vector;
+            to_vector.reserve(m_value.array->size());
+            std::transform(m_value.array->begin(), m_value.array->end(),
+                           std::inserter(to_vector, to_vector.end()), [](basic_json i)
+            {
+                return i.get<T>();
+            });
+            return to_vector;
+        }
+
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
+    }
+
+    /// get an array (explicit)
+    template<class T, typename std::enable_if<
+                 std::is_same<basic_json, typename T::value_type>::value and
+                 not has_mapped_type<T>::value, int>::type = 0>
+    T get_impl(T* /*unused*/) const
+    {
+        if (is_array())
+        {
+            return T(m_value.array->begin(), m_value.array->end());
+        }
+
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
+    }
+
+    /// get an array (explicit)
+    array_t get_impl(array_t* /*unused*/) const
+    {
+        if (is_array())
+        {
+            return *(m_value.array);
+        }
+
+        JSON_THROW(std::domain_error("type must be array, but is " + type_name()));
+    }
+
+    /// get a string (explicit)
+    template<typename T, typename std::enable_if<
+                 std::is_convertible<string_t, T>::value, int>::type = 0>
+    T get_impl(T* /*unused*/) const
+    {
+        if (is_string())
+        {
+            return *m_value.string;
+        }
+
+        JSON_THROW(std::domain_error("type must be string, but is " + type_name()));
+    }
+
+    /// get a number (explicit)
+    template<typename T, typename std::enable_if<
+                 std::is_arithmetic<T>::value, int>::type = 0>
+    T get_impl(T* /*unused*/) const
+    {
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            {
+                return static_cast<T>(m_value.number_integer);
+            }
+
+            case value_t::number_unsigned:
+            {
+                return static_cast<T>(m_value.number_unsigned);
+            }
+
+            case value_t::number_float:
+            {
+                return static_cast<T>(m_value.number_float);
+            }
+
+            default:
+            {
+                JSON_THROW(std::domain_error("type must be number, but is " + type_name()));
+            }
+        }
+    }
+
+    /// get a boolean (explicit)
+    boolean_t get_impl(boolean_t* /*unused*/) const
+    {
+        if (is_boolean())
+        {
+            return m_value.boolean;
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("type must be boolean, but is " + type_name()));
+        }
+    }
+
+    /// get a pointer to the value (object)
+    object_t* get_impl_ptr(object_t* /*unused*/) noexcept
+    {
+        return is_object() ? m_value.object : nullptr;
+    }
+
+    /// get a pointer to the value (object)
+    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
+    {
+        return is_object() ? m_value.object : nullptr;
+    }
+
+    /// get a pointer to the value (array)
+    array_t* get_impl_ptr(array_t* /*unused*/) noexcept
+    {
+        return is_array() ? m_value.array : nullptr;
+    }
+
+    /// get a pointer to the value (array)
+    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
+    {
+        return is_array() ? m_value.array : nullptr;
+    }
+
+    /// get a pointer to the value (string)
+    string_t* get_impl_ptr(string_t* /*unused*/) noexcept
+    {
+        return is_string() ? m_value.string : nullptr;
+    }
+
+    /// get a pointer to the value (string)
+    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
+    {
+        return is_string() ? m_value.string : nullptr;
+    }
+
+    /// get a pointer to the value (boolean)
+    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
+    {
+        return is_boolean() ? &m_value.boolean : nullptr;
+    }
+
+    /// get a pointer to the value (boolean)
+    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
+    {
+        return is_boolean() ? &m_value.boolean : nullptr;
+    }
+
+    /// get a pointer to the value (integer number)
+    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
+    {
+        return is_number_integer() ? &m_value.number_integer : nullptr;
+    }
+
+    /// get a pointer to the value (integer number)
+    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
+    {
+        return is_number_integer() ? &m_value.number_integer : nullptr;
+    }
+
+    /// get a pointer to the value (unsigned number)
+    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
+    {
+        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
+    }
+
+    /// get a pointer to the value (unsigned number)
+    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
+    {
+        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
+    }
+
+    /// get a pointer to the value (floating-point number)
+    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
+    {
+        return is_number_float() ? &m_value.number_float : nullptr;
+    }
+
+    /// get a pointer to the value (floating-point number)
+    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
+    {
+        return is_number_float() ? &m_value.number_float : nullptr;
+    }
+
+    /*!
+    @brief helper function to implement get_ref()
+
+    This funcion helps to implement get_ref() without code duplication for
+    const and non-const overloads
+
+    @tparam ThisType will be deduced as `basic_json` or `const basic_json`
+
+    @throw std::domain_error if ReferenceType does not match underlying value
+    type of the current JSON
+    */
+    template<typename ReferenceType, typename ThisType>
+    static ReferenceType get_ref_impl(ThisType& obj)
+    {
+        // helper type
+        using PointerType = typename std::add_pointer<ReferenceType>::type;
+
+        // delegate the call to get_ptr<>()
+        auto ptr = obj.template get_ptr<PointerType>();
+
+        if (ptr != nullptr)
+        {
+            return *ptr;
+        }
+
+        throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
+                                obj.type_name());
+    }
+
+  public:
+
+    /// @name value access
+    /// Direct access to the stored value of a JSON value.
+    /// @{
+
+    /*!
+    @brief get a value (explicit)
+
+    Explicit type conversion between the JSON value and a compatible value.
+
+    @tparam ValueType non-pointer type compatible to the JSON value, for
+    instance `int` for JSON integer numbers, `bool` for JSON booleans, or
+    `std::vector` types for JSON arrays
+
+    @return copy of the JSON value, converted to type @a ValueType
+
+    @throw std::domain_error in case passed type @a ValueType is incompatible
+    to JSON; example: `"type must be object, but is null"`
+
+    @complexity Linear in the size of the JSON value.
+
+    @liveexample{The example below shows several conversions from JSON values
+    to other types. There a few things to note: (1) Floating-point numbers can
+    be converted to integers\, (2) A JSON array can be converted to a standard
+    `std::vector<short>`\, (3) A JSON object can be converted to C++
+    associative containers such as `std::unordered_map<std::string\,
+    json>`.,get__ValueType_const}
+
+    @internal
+    The idea of using a casted null pointer to choose the correct
+    implementation is from <http://stackoverflow.com/a/8315197/266378>.
+    @endinternal
+
+    @sa @ref operator ValueType() const for implicit conversion
+    @sa @ref get() for pointer-member access
+
+    @since version 1.0.0
+    */
+    template<typename ValueType, typename std::enable_if<
+                 not std::is_pointer<ValueType>::value, int>::type = 0>
+    ValueType get() const
+    {
+        return get_impl(static_cast<ValueType*>(nullptr));
+    }
+
+    /*!
+    @brief get a pointer value (explicit)
+
+    Explicit pointer access to the internally stored JSON value. No copies are
+    made.
+
+    @warning The pointer becomes invalid if the underlying JSON object
+    changes.
+
+    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
+    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
+    @ref number_unsigned_t, or @ref number_float_t.
+
+    @return pointer to the internally stored JSON value if the requested
+    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how pointers to internal values of a
+    JSON value can be requested. Note that no type conversions are made and a
+    `nullptr` is returned if the value and the requested pointer type does not
+    match.,get__PointerType}
+
+    @sa @ref get_ptr() for explicit pointer-member access
+
+    @since version 1.0.0
+    */
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
+    PointerType get() noexcept
+    {
+        // delegate the call to get_ptr
+        return get_ptr<PointerType>();
+    }
+
+    /*!
+    @brief get a pointer value (explicit)
+    @copydoc get()
+    */
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
+    constexpr const PointerType get() const noexcept
+    {
+        // delegate the call to get_ptr
+        return get_ptr<PointerType>();
+    }
+
+    /*!
+    @brief get a pointer value (implicit)
+
+    Implicit pointer access to the internally stored JSON value. No copies are
+    made.
+
+    @warning Writing data to the pointee of the result yields an undefined
+    state.
+
+    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
+    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
+    @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
+    assertion.
+
+    @return pointer to the internally stored JSON value if the requested
+    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how pointers to internal values of a
+    JSON value can be requested. Note that no type conversions are made and a
+    `nullptr` is returned if the value and the requested pointer type does not
+    match.,get_ptr}
+
+    @since version 1.0.0
+    */
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value, int>::type = 0>
+    PointerType get_ptr() noexcept
+    {
+        // get the type of the PointerType (remove pointer and const)
+        using pointee_t = typename std::remove_const<typename
+                          std::remove_pointer<typename
+                          std::remove_const<PointerType>::type>::type>::type;
+        // make sure the type matches the allowed types
+        static_assert(
+            std::is_same<object_t, pointee_t>::value
+            or std::is_same<array_t, pointee_t>::value
+            or std::is_same<string_t, pointee_t>::value
+            or std::is_same<boolean_t, pointee_t>::value
+            or std::is_same<number_integer_t, pointee_t>::value
+            or std::is_same<number_unsigned_t, pointee_t>::value
+            or std::is_same<number_float_t, pointee_t>::value
+            , "incompatible pointer type");
+
+        // delegate the call to get_impl_ptr<>()
+        return get_impl_ptr(static_cast<PointerType>(nullptr));
+    }
+
+    /*!
+    @brief get a pointer value (implicit)
+    @copydoc get_ptr()
+    */
+    template<typename PointerType, typename std::enable_if<
+                 std::is_pointer<PointerType>::value and
+                 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
+    constexpr const PointerType get_ptr() const noexcept
+    {
+        // get the type of the PointerType (remove pointer and const)
+        using pointee_t = typename std::remove_const<typename
+                          std::remove_pointer<typename
+                          std::remove_const<PointerType>::type>::type>::type;
+        // make sure the type matches the allowed types
+        static_assert(
+            std::is_same<object_t, pointee_t>::value
+            or std::is_same<array_t, pointee_t>::value
+            or std::is_same<string_t, pointee_t>::value
+            or std::is_same<boolean_t, pointee_t>::value
+            or std::is_same<number_integer_t, pointee_t>::value
+            or std::is_same<number_unsigned_t, pointee_t>::value
+            or std::is_same<number_float_t, pointee_t>::value
+            , "incompatible pointer type");
+
+        // delegate the call to get_impl_ptr<>() const
+        return get_impl_ptr(static_cast<const PointerType>(nullptr));
+    }
+
+    /*!
+    @brief get a reference value (implicit)
+
+    Implict reference access to the internally stored JSON value. No copies
+    are made.
+
+    @warning Writing data to the referee of the result yields an undefined
+    state.
+
+    @tparam ReferenceType reference type; must be a reference to @ref array_t,
+    @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
+    @ref number_float_t. Enforced by static assertion.
+
+    @return reference to the internally stored JSON value if the requested
+    reference type @a ReferenceType fits to the JSON value; throws
+    std::domain_error otherwise
+
+    @throw std::domain_error in case passed type @a ReferenceType is
+    incompatible with the stored JSON value
+
+    @complexity Constant.
+
+    @liveexample{The example shows several calls to `get_ref()`.,get_ref}
+
+    @since version 1.1.0
+    */
+    template<typename ReferenceType, typename std::enable_if<
+                 std::is_reference<ReferenceType>::value, int>::type = 0>
+    ReferenceType get_ref()
+    {
+        // delegate call to get_ref_impl
+        return get_ref_impl<ReferenceType>(*this);
+    }
+
+    /*!
+    @brief get a reference value (implicit)
+    @copydoc get_ref()
+    */
+    template<typename ReferenceType, typename std::enable_if<
+                 std::is_reference<ReferenceType>::value and
+                 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
+    ReferenceType get_ref() const
+    {
+        // delegate call to get_ref_impl
+        return get_ref_impl<ReferenceType>(*this);
+    }
+
+    /*!
+    @brief get a value (implicit)
+
+    Implicit type conversion between the JSON value and a compatible value.
+    The call is realized by calling @ref get() const.
+
+    @tparam ValueType non-pointer type compatible to the JSON value, for
+    instance `int` for JSON integer numbers, `bool` for JSON booleans, or
+    `std::vector` types for JSON arrays. The character type of @ref string_t
+    as well as an initializer list of this type is excluded to avoid
+    ambiguities as these types implicitly convert to `std::string`.
+
+    @return copy of the JSON value, converted to type @a ValueType
+
+    @throw std::domain_error in case passed type @a ValueType is incompatible
+    to JSON, thrown by @ref get() const
+
+    @complexity Linear in the size of the JSON value.
+
+    @liveexample{The example below shows several conversions from JSON values
+    to other types. There a few things to note: (1) Floating-point numbers can
+    be converted to integers\, (2) A JSON array can be converted to a standard
+    `std::vector<short>`\, (3) A JSON object can be converted to C++
+    associative containers such as `std::unordered_map<std::string\,
+    json>`.,operator__ValueType}
+
+    @since version 1.0.0
+    */
+    template < typename ValueType, typename std::enable_if <
+                   not std::is_pointer<ValueType>::value and
+                   not std::is_same<ValueType, typename string_t::value_type>::value
+#ifndef _MSC_VER  // fix for issue #167 operator<< abiguity under VS2015
+                   and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
+#endif
+                   , int >::type = 0 >
+    operator ValueType() const
+    {
+        // delegate the call to get<>() const
+        return get<ValueType>();
+    }
+
+    /// @}
+
+
+    ////////////////////
+    // element access //
+    ////////////////////
+
+    /// @name element access
+    /// Access to the JSON value.
+    /// @{
+
+    /*!
+    @brief access specified array element with bounds checking
+
+    Returns a reference to the element at specified location @a idx, with
+    bounds checking.
+
+    @param[in] idx  index of the element to access
+
+    @return reference to the element at index @a idx
+
+    @throw std::domain_error if the JSON value is not an array; example:
+    `"cannot use at() with string"`
+    @throw std::out_of_range if the index @a idx is out of range of the array;
+    that is, `idx >= size()`; example: `"array index 7 is out of range"`
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how array elements can be read and
+    written using `at()`.,at__size_type}
+
+    @since version 1.0.0
+    */
+    reference at(size_type idx)
+    {
+        // at only works for arrays
+        if (is_array())
+        {
+            JSON_TRY
+            {
+                return m_value.array->at(idx);
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                // create better exception explanation
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
+            }
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+        }
+    }
+
+    /*!
+    @brief access specified array element with bounds checking
+
+    Returns a const reference to the element at specified location @a idx,
+    with bounds checking.
+
+    @param[in] idx  index of the element to access
+
+    @return const reference to the element at index @a idx
+
+    @throw std::domain_error if the JSON value is not an array; example:
+    `"cannot use at() with string"`
+    @throw std::out_of_range if the index @a idx is out of range of the array;
+    that is, `idx >= size()`; example: `"array index 7 is out of range"`
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how array elements can be read using
+    `at()`.,at__size_type_const}
+
+    @since version 1.0.0
+    */
+    const_reference at(size_type idx) const
+    {
+        // at only works for arrays
+        if (is_array())
+        {
+            JSON_TRY
+            {
+                return m_value.array->at(idx);
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                // create better exception explanation
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
+            }
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+        }
+    }
+
+    /*!
+    @brief access specified object element with bounds checking
+
+    Returns a reference to the element at with specified key @a key, with
+    bounds checking.
+
+    @param[in] key  key of the element to access
+
+    @return reference to the element at key @a key
+
+    @throw std::domain_error if the JSON value is not an object; example:
+    `"cannot use at() with boolean"`
+    @throw std::out_of_range if the key @a key is is not stored in the object;
+    that is, `find(key) == end()`; example: `"key "the fast" not found"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be read and
+    written using `at()`.,at__object_t_key_type}
+
+    @sa @ref operator[](const typename object_t::key_type&) for unchecked
+    access by reference
+    @sa @ref value() for access by value with a default value
+
+    @since version 1.0.0
+    */
+    reference at(const typename object_t::key_type& key)
+    {
+        // at only works for objects
+        if (is_object())
+        {
+            JSON_TRY
+            {
+                return m_value.object->at(key);
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                // create better exception explanation
+                JSON_THROW(std::out_of_range("key '" + key + "' not found"));
+            }
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+        }
+    }
+
+    /*!
+    @brief access specified object element with bounds checking
+
+    Returns a const reference to the element at with specified key @a key,
+    with bounds checking.
+
+    @param[in] key  key of the element to access
+
+    @return const reference to the element at key @a key
+
+    @throw std::domain_error if the JSON value is not an object; example:
+    `"cannot use at() with boolean"`
+    @throw std::out_of_range if the key @a key is is not stored in the object;
+    that is, `find(key) == end()`; example: `"key "the fast" not found"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be read using
+    `at()`.,at__object_t_key_type_const}
+
+    @sa @ref operator[](const typename object_t::key_type&) for unchecked
+    access by reference
+    @sa @ref value() for access by value with a default value
+
+    @since version 1.0.0
+    */
+    const_reference at(const typename object_t::key_type& key) const
+    {
+        // at only works for objects
+        if (is_object())
+        {
+            JSON_TRY
+            {
+                return m_value.object->at(key);
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                // create better exception explanation
+                JSON_THROW(std::out_of_range("key '" + key + "' not found"));
+            }
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use at() with " + type_name()));
+        }
+    }
+
+    /*!
+    @brief access specified array element
+
+    Returns a reference to the element at specified location @a idx.
+
+    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
+    then the array is silently filled up with `null` values to make `idx` a
+    valid reference to the last stored element.
+
+    @param[in] idx  index of the element to access
+
+    @return reference to the element at index @a idx
+
+    @throw std::domain_error if JSON is not an array or null; example:
+    `"cannot use operator[] with string"`
+
+    @complexity Constant if @a idx is in the range of the array. Otherwise
+    linear in `idx - size()`.
+
+    @liveexample{The example below shows how array elements can be read and
+    written using `[]` operator. Note the addition of `null`
+    values.,operatorarray__size_type}
+
+    @since version 1.0.0
+    */
+    reference operator[](size_type idx)
+    {
+        // implicitly convert null value to an empty array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value.array = create<array_t>();
+            assert_invariant();
+        }
+
+        // operator[] only works for arrays
+        if (is_array())
+        {
+            // fill up array with null values if given idx is outside range
+            if (idx >= m_value.array->size())
+            {
+                m_value.array->insert(m_value.array->end(),
+                                      idx - m_value.array->size() + 1,
+                                      basic_json());
+            }
+
+            return m_value.array->operator[](idx);
+        }
+
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
+    }
+
+    /*!
+    @brief access specified array element
+
+    Returns a const reference to the element at specified location @a idx.
+
+    @param[in] idx  index of the element to access
+
+    @return const reference to the element at index @a idx
+
+    @throw std::domain_error if JSON is not an array; example: `"cannot use
+    operator[] with null"`
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how array elements can be read using
+    the `[]` operator.,operatorarray__size_type_const}
+
+    @since version 1.0.0
+    */
+    const_reference operator[](size_type idx) const
+    {
+        // const operator[] only works for arrays
+        if (is_array())
+        {
+            return m_value.array->operator[](idx);
+        }
+
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
+    }
+
+    /*!
+    @brief access specified object element
+
+    Returns a reference to the element at with specified key @a key.
+
+    @note If @a key is not found in the object, then it is silently added to
+    the object and filled with a `null` value to make `key` a valid reference.
+    In case the value was `null` before, it is converted to an object.
+
+    @param[in] key  key of the element to access
+
+    @return reference to the element at key @a key
+
+    @throw std::domain_error if JSON is not an object or null; example:
+    `"cannot use operator[] with string"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be read and
+    written using the `[]` operator.,operatorarray__key_type}
+
+    @sa @ref at(const typename object_t::key_type&) for access by reference
+    with range checking
+    @sa @ref value() for access by value with a default value
+
+    @since version 1.0.0
+    */
+    reference operator[](const typename object_t::key_type& key)
+    {
+        // implicitly convert null value to an empty object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value.object = create<object_t>();
+            assert_invariant();
+        }
+
+        // operator[] only works for objects
+        if (is_object())
+        {
+            return m_value.object->operator[](key);
+        }
+
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
+    }
+
+    /*!
+    @brief read-only access specified object element
+
+    Returns a const reference to the element at with specified key @a key. No
+    bounds checking is performed.
+
+    @warning If the element with key @a key does not exist, the behavior is
+    undefined.
+
+    @param[in] key  key of the element to access
+
+    @return const reference to the element at key @a key
+
+    @pre The element with key @a key must exist. **This precondition is
+         enforced with an assertion.**
+
+    @throw std::domain_error if JSON is not an object; example: `"cannot use
+    operator[] with null"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be read using
+    the `[]` operator.,operatorarray__key_type_const}
+
+    @sa @ref at(const typename object_t::key_type&) for access by reference
+    with range checking
+    @sa @ref value() for access by value with a default value
+
+    @since version 1.0.0
+    */
+    const_reference operator[](const typename object_t::key_type& key) const
+    {
+        // const operator[] only works for objects
+        if (is_object())
+        {
+            assert(m_value.object->find(key) != m_value.object->end());
+            return m_value.object->find(key)->second;
+        }
+
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
+    }
+
+    /*!
+    @brief access specified object element
+
+    Returns a reference to the element at with specified key @a key.
+
+    @note If @a key is not found in the object, then it is silently added to
+    the object and filled with a `null` value to make `key` a valid reference.
+    In case the value was `null` before, it is converted to an object.
+
+    @param[in] key  key of the element to access
+
+    @return reference to the element at key @a key
+
+    @throw std::domain_error if JSON is not an object or null; example:
+    `"cannot use operator[] with string"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be read and
+    written using the `[]` operator.,operatorarray__key_type}
+
+    @sa @ref at(const typename object_t::key_type&) for access by reference
+    with range checking
+    @sa @ref value() for access by value with a default value
+
+    @since version 1.0.0
+    */
+    template<typename T, std::size_t n>
+    reference operator[](T * (&key)[n])
+    {
+        return operator[](static_cast<const T>(key));
+    }
+
+    /*!
+    @brief read-only access specified object element
+
+    Returns a const reference to the element at with specified key @a key. No
+    bounds checking is performed.
+
+    @warning If the element with key @a key does not exist, the behavior is
+    undefined.
+
+    @note This function is required for compatibility reasons with Clang.
+
+    @param[in] key  key of the element to access
+
+    @return const reference to the element at key @a key
+
+    @throw std::domain_error if JSON is not an object; example: `"cannot use
+    operator[] with null"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be read using
+    the `[]` operator.,operatorarray__key_type_const}
+
+    @sa @ref at(const typename object_t::key_type&) for access by reference
+    with range checking
+    @sa @ref value() for access by value with a default value
+
+    @since version 1.0.0
+    */
+    template<typename T, std::size_t n>
+    const_reference operator[](T * (&key)[n]) const
+    {
+        return operator[](static_cast<const T>(key));
+    }
+
+    /*!
+    @brief access specified object element
+
+    Returns a reference to the element at with specified key @a key.
+
+    @note If @a key is not found in the object, then it is silently added to
+    the object and filled with a `null` value to make `key` a valid reference.
+    In case the value was `null` before, it is converted to an object.
+
+    @param[in] key  key of the element to access
+
+    @return reference to the element at key @a key
+
+    @throw std::domain_error if JSON is not an object or null; example:
+    `"cannot use operator[] with string"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be read and
+    written using the `[]` operator.,operatorarray__key_type}
+
+    @sa @ref at(const typename object_t::key_type&) for access by reference
+    with range checking
+    @sa @ref value() for access by value with a default value
+
+    @since version 1.1.0
+    */
+    template<typename T>
+    reference operator[](T* key)
+    {
+        // implicitly convert null to object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value = value_t::object;
+            assert_invariant();
+        }
+
+        // at only works for objects
+        if (is_object())
+        {
+            return m_value.object->operator[](key);
+        }
+
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
+    }
+
+    /*!
+    @brief read-only access specified object element
+
+    Returns a const reference to the element at with specified key @a key. No
+    bounds checking is performed.
+
+    @warning If the element with key @a key does not exist, the behavior is
+    undefined.
+
+    @param[in] key  key of the element to access
+
+    @return const reference to the element at key @a key
+
+    @pre The element with key @a key must exist. **This precondition is
+         enforced with an assertion.**
+
+    @throw std::domain_error if JSON is not an object; example: `"cannot use
+    operator[] with null"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be read using
+    the `[]` operator.,operatorarray__key_type_const}
+
+    @sa @ref at(const typename object_t::key_type&) for access by reference
+    with range checking
+    @sa @ref value() for access by value with a default value
+
+    @since version 1.1.0
+    */
+    template<typename T>
+    const_reference operator[](T* key) const
+    {
+        // at only works for objects
+        if (is_object())
+        {
+            assert(m_value.object->find(key) != m_value.object->end());
+            return m_value.object->find(key)->second;
+        }
+
+        JSON_THROW(std::domain_error("cannot use operator[] with " + type_name()));
+    }
+
+    /*!
+    @brief access specified object element with default value
+
+    Returns either a copy of an object's element at the specified key @a key
+    or a given default value if no element with key @a key exists.
+
+    The function is basically equivalent to executing
+    @code {.cpp}
+    try {
+        return at(key);
+    } catch(std::out_of_range) {
+        return default_value;
+    }
+    @endcode
+
+    @note Unlike @ref at(const typename object_t::key_type&), this function
+    does not throw if the given key @a key was not found.
+
+    @note Unlike @ref operator[](const typename object_t::key_type& key), this
+    function does not implicitly add an element to the position defined by @a
+    key. This function is furthermore also applicable to const objects.
+
+    @param[in] key  key of the element to access
+    @param[in] default_value  the value to return if @a key is not found
+
+    @tparam ValueType type compatible to JSON values, for instance `int` for
+    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
+    JSON arrays. Note the type of the expected value at @a key and the default
+    value @a default_value must be compatible.
+
+    @return copy of the element at key @a key or @a default_value if @a key
+    is not found
+
+    @throw std::domain_error if JSON is not an object; example: `"cannot use
+    value() with null"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be queried
+    with a default value.,basic_json__value}
+
+    @sa @ref at(const typename object_t::key_type&) for access by reference
+    with range checking
+    @sa @ref operator[](const typename object_t::key_type&) for unchecked
+    access by reference
+
+    @since version 1.0.0
+    */
+    template<class ValueType, typename std::enable_if<
+                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
+    ValueType value(const typename object_t::key_type& key, ValueType default_value) const
+    {
+        // at only works for objects
+        if (is_object())
+        {
+            // if key is found, return value and given default value otherwise
+            const auto it = find(key);
+            if (it != end())
+            {
+                return *it;
+            }
+
+            return default_value;
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use value() with " + type_name()));
+        }
+    }
+
+    /*!
+    @brief overload for a default value of type const char*
+    @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const
+    */
+    string_t value(const typename object_t::key_type& key, const char* default_value) const
+    {
+        return value(key, string_t(default_value));
+    }
+
+    /*!
+    @brief access specified object element via JSON Pointer with default value
+
+    Returns either a copy of an object's element at the specified key @a key
+    or a given default value if no element with key @a key exists.
+
+    The function is basically equivalent to executing
+    @code {.cpp}
+    try {
+        return at(ptr);
+    } catch(std::out_of_range) {
+        return default_value;
+    }
+    @endcode
+
+    @note Unlike @ref at(const json_pointer&), this function does not throw
+    if the given key @a key was not found.
+
+    @param[in] ptr  a JSON pointer to the element to access
+    @param[in] default_value  the value to return if @a ptr found no value
+
+    @tparam ValueType type compatible to JSON values, for instance `int` for
+    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
+    JSON arrays. Note the type of the expected value at @a key and the default
+    value @a default_value must be compatible.
+
+    @return copy of the element at key @a key or @a default_value if @a key
+    is not found
+
+    @throw std::domain_error if JSON is not an object; example: `"cannot use
+    value() with null"`
+
+    @complexity Logarithmic in the size of the container.
+
+    @liveexample{The example below shows how object elements can be queried
+    with a default value.,basic_json__value_ptr}
+
+    @sa @ref operator[](const json_pointer&) for unchecked access by reference
+
+    @since version 2.0.2
+    */
+    template<class ValueType, typename std::enable_if<
+                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
+    ValueType value(const json_pointer& ptr, ValueType default_value) const
+    {
+        // at only works for objects
+        if (is_object())
+        {
+            // if pointer resolves a value, return it or use default value
+            JSON_TRY
+            {
+                return ptr.get_checked(this);
+            }
+            JSON_CATCH (std::out_of_range&)
+            {
+                return default_value;
+            }
+        }
+
+        JSON_THROW(std::domain_error("cannot use value() with " + type_name()));
+    }
+
+    /*!
+    @brief overload for a default value of type const char*
+    @copydoc basic_json::value(const json_pointer&, ValueType) const
+    */
+    string_t value(const json_pointer& ptr, const char* default_value) const
+    {
+        return value(ptr, string_t(default_value));
+    }
+
+    /*!
+    @brief access the first element
+
+    Returns a reference to the first element in the container. For a JSON
+    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
+
+    @return In case of a structured type (array or object), a reference to the
+    first element is returned. In case of number, string, or boolean values, a
+    reference to the value is returned.
+
+    @complexity Constant.
+
+    @pre The JSON value must not be `null` (would throw `std::out_of_range`)
+    or an empty array or object (undefined behavior, **guarded by
+    assertions**).
+    @post The JSON value remains unchanged.
+
+    @throw std::out_of_range when called on `null` value
+
+    @liveexample{The following code shows an example for `front()`.,front}
+
+    @sa @ref back() -- access the last element
+
+    @since version 1.0.0
+    */
+    reference front()
+    {
+        return *begin();
+    }
+
+    /*!
+    @copydoc basic_json::front()
+    */
+    const_reference front() const
+    {
+        return *cbegin();
+    }
+
+    /*!
+    @brief access the last element
+
+    Returns a reference to the last element in the container. For a JSON
+    container `c`, the expression `c.back()` is equivalent to
+    @code {.cpp}
+    auto tmp = c.end();
+    --tmp;
+    return *tmp;
+    @endcode
+
+    @return In case of a structured type (array or object), a reference to the
+    last element is returned. In case of number, string, or boolean values, a
+    reference to the value is returned.
+
+    @complexity Constant.
+
+    @pre The JSON value must not be `null` (would throw `std::out_of_range`)
+    or an empty array or object (undefined behavior, **guarded by
+    assertions**).
+    @post The JSON value remains unchanged.
+
+    @throw std::out_of_range when called on `null` value.
+
+    @liveexample{The following code shows an example for `back()`.,back}
+
+    @sa @ref front() -- access the first element
+
+    @since version 1.0.0
+    */
+    reference back()
+    {
+        auto tmp = end();
+        --tmp;
+        return *tmp;
+    }
+
+    /*!
+    @copydoc basic_json::back()
+    */
+    const_reference back() const
+    {
+        auto tmp = cend();
+        --tmp;
+        return *tmp;
+    }
+
+    /*!
+    @brief remove element given an iterator
+
+    Removes the element specified by iterator @a pos. The iterator @a pos must
+    be valid and dereferenceable. Thus the `end()` iterator (which is valid,
+    but is not dereferenceable) cannot be used as a value for @a pos.
+
+    If called on a primitive type other than `null`, the resulting JSON value
+    will be `null`.
+
+    @param[in] pos iterator to the element to remove
+    @return Iterator following the last removed element. If the iterator @a
+    pos refers to the last element, the `end()` iterator is returned.
+
+    @tparam IteratorType an @ref iterator or @ref const_iterator
+
+    @post Invalidates iterators and references at or after the point of the
+    erase, including the `end()` iterator.
+
+    @throw std::domain_error if called on a `null` value; example: `"cannot
+    use erase() with null"`
+    @throw std::domain_error if called on an iterator which does not belong to
+    the current JSON value; example: `"iterator does not fit current value"`
+    @throw std::out_of_range if called on a primitive type with invalid
+    iterator (i.e., any iterator which is not `begin()`); example: `"iterator
+    out of range"`
+
+    @complexity The complexity depends on the type:
+    - objects: amortized constant
+    - arrays: linear in distance between pos and the end of the container
+    - strings: linear in the length of the string
+    - other types: constant
+
+    @liveexample{The example shows the result of `erase()` for different JSON
+    types.,erase__IteratorType}
+
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
+    the given range
+    @sa @ref erase(const typename object_t::key_type&) -- removes the element
+    from an object at the given key
+    @sa @ref erase(const size_type) -- removes the element from an array at
+    the given index
+
+    @since version 1.0.0
+    */
+    template<class IteratorType, typename std::enable_if<
+                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
+                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
+             = 0>
+    IteratorType erase(IteratorType pos)
+    {
+        // make sure iterator fits the current value
+        if (this != pos.m_object)
+        {
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
+        }
+
+        IteratorType result = end();
+
+        switch (m_type)
+        {
+            case value_t::boolean:
+            case value_t::number_float:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::string:
+            {
+                if (not pos.m_it.primitive_iterator.is_begin())
+                {
+                    JSON_THROW(std::out_of_range("iterator out of range"));
+                }
+
+                if (is_string())
+                {
+                    AllocatorType<string_t> alloc;
+                    alloc.destroy(m_value.string);
+                    alloc.deallocate(m_value.string, 1);
+                    m_value.string = nullptr;
+                }
+
+                m_type = value_t::null;
+                assert_invariant();
+                break;
+            }
+
+            case value_t::object:
+            {
+                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
+                break;
+            }
+
+            default:
+            {
+                JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
+            }
+        }
+
+        return result;
+    }
+
+    /*!
+    @brief remove elements given an iterator range
+
+    Removes the element specified by the range `[first; last)`. The iterator
+    @a first does not need to be dereferenceable if `first == last`: erasing
+    an empty range is a no-op.
+
+    If called on a primitive type other than `null`, the resulting JSON value
+    will be `null`.
+
+    @param[in] first iterator to the beginning of the range to remove
+    @param[in] last iterator past the end of the range to remove
+    @return Iterator following the last removed element. If the iterator @a
+    second refers to the last element, the `end()` iterator is returned.
+
+    @tparam IteratorType an @ref iterator or @ref const_iterator
+
+    @post Invalidates iterators and references at or after the point of the
+    erase, including the `end()` iterator.
+
+    @throw std::domain_error if called on a `null` value; example: `"cannot
+    use erase() with null"`
+    @throw std::domain_error if called on iterators which does not belong to
+    the current JSON value; example: `"iterators do not fit current value"`
+    @throw std::out_of_range if called on a primitive type with invalid
+    iterators (i.e., if `first != begin()` and `last != end()`); example:
+    `"iterators out of range"`
+
+    @complexity The complexity depends on the type:
+    - objects: `log(size()) + std::distance(first, last)`
+    - arrays: linear in the distance between @a first and @a last, plus linear
+      in the distance between @a last and end of the container
+    - strings: linear in the length of the string
+    - other types: constant
+
+    @liveexample{The example shows the result of `erase()` for different JSON
+    types.,erase__IteratorType_IteratorType}
+
+    @sa @ref erase(IteratorType) -- removes the element at a given position
+    @sa @ref erase(const typename object_t::key_type&) -- removes the element
+    from an object at the given key
+    @sa @ref erase(const size_type) -- removes the element from an array at
+    the given index
+
+    @since version 1.0.0
+    */
+    template<class IteratorType, typename std::enable_if<
+                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
+                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
+             = 0>
+    IteratorType erase(IteratorType first, IteratorType last)
+    {
+        // make sure iterator fits the current value
+        if (this != first.m_object or this != last.m_object)
+        {
+            JSON_THROW(std::domain_error("iterators do not fit current value"));
+        }
+
+        IteratorType result = end();
+
+        switch (m_type)
+        {
+            case value_t::boolean:
+            case value_t::number_float:
+            case value_t::number_integer:
+            case value_t::number_unsigned:
+            case value_t::string:
+            {
+                if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
+                {
+                    JSON_THROW(std::out_of_range("iterators out of range"));
+                }
+
+                if (is_string())
+                {
+                    AllocatorType<string_t> alloc;
+                    alloc.destroy(m_value.string);
+                    alloc.deallocate(m_value.string, 1);
+                    m_value.string = nullptr;
+                }
+
+                m_type = value_t::null;
+                assert_invariant();
+                break;
+            }
+
+            case value_t::object:
+            {
+                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
+                                              last.m_it.object_iterator);
+                break;
+            }
+
+            case value_t::array:
+            {
+                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
+                                             last.m_it.array_iterator);
+                break;
+            }
+
+            default:
+            {
+                JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
+            }
+        }
+
+        return result;
+    }
+
+    /*!
+    @brief remove element from a JSON object given a key
+
+    Removes elements from a JSON object with the key value @a key.
+
+    @param[in] key value of the elements to remove
+
+    @return Number of elements removed. If @a ObjectType is the default
+    `std::map` type, the return value will always be `0` (@a key was not
+    found) or `1` (@a key was found).
+
+    @post References and iterators to the erased elements are invalidated.
+    Other references and iterators are not affected.
+
+    @throw std::domain_error when called on a type other than JSON object;
+    example: `"cannot use erase() with null"`
+
+    @complexity `log(size()) + count(key)`
+
+    @liveexample{The example shows the effect of `erase()`.,erase__key_type}
+
+    @sa @ref erase(IteratorType) -- removes the element at a given position
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
+    the given range
+    @sa @ref erase(const size_type) -- removes the element from an array at
+    the given index
+
+    @since version 1.0.0
+    */
+    size_type erase(const typename object_t::key_type& key)
+    {
+        // this erase only works for objects
+        if (is_object())
+        {
+            return m_value.object->erase(key);
+        }
+
+        JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
+    }
+
+    /*!
+    @brief remove element from a JSON array given an index
+
+    Removes element from a JSON array at the index @a idx.
+
+    @param[in] idx index of the element to remove
+
+    @throw std::domain_error when called on a type other than JSON array;
+    example: `"cannot use erase() with null"`
+    @throw std::out_of_range when `idx >= size()`; example: `"array index 17
+    is out of range"`
+
+    @complexity Linear in distance between @a idx and the end of the container.
+
+    @liveexample{The example shows the effect of `erase()`.,erase__size_type}
+
+    @sa @ref erase(IteratorType) -- removes the element at a given position
+    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
+    the given range
+    @sa @ref erase(const typename object_t::key_type&) -- removes the element
+    from an object at the given key
+
+    @since version 1.0.0
+    */
+    void erase(const size_type idx)
+    {
+        // this erase only works for arrays
+        if (is_array())
+        {
+            if (idx >= size())
+            {
+                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
+            }
+
+            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use erase() with " + type_name()));
+        }
+    }
+
+    /// @}
+
+
+    ////////////
+    // lookup //
+    ////////////
+
+    /// @name lookup
+    /// @{
+
+    /*!
+    @brief find an element in a JSON object
+
+    Finds an element in a JSON object with key equivalent to @a key. If the
+    element is not found or the JSON value is not an object, end() is
+    returned.
+
+    @note This method always returns @ref end() when executed on a JSON type
+          that is not an object.
+
+    @param[in] key key value of the element to search for
+
+    @return Iterator to an element with key equivalent to @a key. If no such
+    element is found or the JSON value is not an object, past-the-end (see
+    @ref end()) iterator is returned.
+
+    @complexity Logarithmic in the size of the JSON object.
+
+    @liveexample{The example shows how `find()` is used.,find__key_type}
+
+    @since version 1.0.0
+    */
+    iterator find(typename object_t::key_type key)
+    {
+        auto result = end();
+
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(key);
+        }
+
+        return result;
+    }
+
+    /*!
+    @brief find an element in a JSON object
+    @copydoc find(typename object_t::key_type)
+    */
+    const_iterator find(typename object_t::key_type key) const
+    {
+        auto result = cend();
+
+        if (is_object())
+        {
+            result.m_it.object_iterator = m_value.object->find(key);
+        }
+
+        return result;
+    }
+
+    /*!
+    @brief returns the number of occurrences of a key in a JSON object
+
+    Returns the number of elements with key @a key. If ObjectType is the
+    default `std::map` type, the return value will always be `0` (@a key was
+    not found) or `1` (@a key was found).
+
+    @note This method always returns `0` when executed on a JSON type that is
+          not an object.
+
+    @param[in] key key value of the element to count
+
+    @return Number of elements with key @a key. If the JSON value is not an
+    object, the return value will be `0`.
+
+    @complexity Logarithmic in the size of the JSON object.
+
+    @liveexample{The example shows how `count()` is used.,count}
+
+    @since version 1.0.0
+    */
+    size_type count(typename object_t::key_type key) const
+    {
+        // return 0 for all nonobject types
+        return is_object() ? m_value.object->count(key) : 0;
+    }
+
+    /// @}
+
+
+    ///////////////
+    // iterators //
+    ///////////////
+
+    /// @name iterators
+    /// @{
+
+    /*!
+    @brief returns an iterator to the first element
+
+    Returns an iterator to the first element.
+
+    @image html range-begin-end.svg "Illustration from cppreference.com"
+
+    @return iterator to the first element
+
+    @complexity Constant.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is constant.
+
+    @liveexample{The following code shows an example for `begin()`.,begin}
+
+    @sa @ref cbegin() -- returns a const iterator to the beginning
+    @sa @ref end() -- returns an iterator to the end
+    @sa @ref cend() -- returns a const iterator to the end
+
+    @since version 1.0.0
+    */
+    iterator begin() noexcept
+    {
+        iterator result(this);
+        result.set_begin();
+        return result;
+    }
+
+    /*!
+    @copydoc basic_json::cbegin()
+    */
+    const_iterator begin() const noexcept
+    {
+        return cbegin();
+    }
+
+    /*!
+    @brief returns a const iterator to the first element
+
+    Returns a const iterator to the first element.
+
+    @image html range-begin-end.svg "Illustration from cppreference.com"
+
+    @return const iterator to the first element
+
+    @complexity Constant.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
+
+    @liveexample{The following code shows an example for `cbegin()`.,cbegin}
+
+    @sa @ref begin() -- returns an iterator to the beginning
+    @sa @ref end() -- returns an iterator to the end
+    @sa @ref cend() -- returns a const iterator to the end
+
+    @since version 1.0.0
+    */
+    const_iterator cbegin() const noexcept
+    {
+        const_iterator result(this);
+        result.set_begin();
+        return result;
+    }
+
+    /*!
+    @brief returns an iterator to one past the last element
+
+    Returns an iterator to one past the last element.
+
+    @image html range-begin-end.svg "Illustration from cppreference.com"
+
+    @return iterator one past the last element
+
+    @complexity Constant.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is constant.
+
+    @liveexample{The following code shows an example for `end()`.,end}
+
+    @sa @ref cend() -- returns a const iterator to the end
+    @sa @ref begin() -- returns an iterator to the beginning
+    @sa @ref cbegin() -- returns a const iterator to the beginning
+
+    @since version 1.0.0
+    */
+    iterator end() noexcept
+    {
+        iterator result(this);
+        result.set_end();
+        return result;
+    }
+
+    /*!
+    @copydoc basic_json::cend()
+    */
+    const_iterator end() const noexcept
+    {
+        return cend();
+    }
+
+    /*!
+    @brief returns a const iterator to one past the last element
+
+    Returns a const iterator to one past the last element.
+
+    @image html range-begin-end.svg "Illustration from cppreference.com"
+
+    @return const iterator one past the last element
+
+    @complexity Constant.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of `const_cast<const basic_json&>(*this).end()`.
+
+    @liveexample{The following code shows an example for `cend()`.,cend}
+
+    @sa @ref end() -- returns an iterator to the end
+    @sa @ref begin() -- returns an iterator to the beginning
+    @sa @ref cbegin() -- returns a const iterator to the beginning
+
+    @since version 1.0.0
+    */
+    const_iterator cend() const noexcept
+    {
+        const_iterator result(this);
+        result.set_end();
+        return result;
+    }
+
+    /*!
+    @brief returns an iterator to the reverse-beginning
+
+    Returns an iterator to the reverse-beginning; that is, the last element.
+
+    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
+
+    @complexity Constant.
+
+    @requirement This function helps `basic_json` satisfying the
+    [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of `reverse_iterator(end())`.
+
+    @liveexample{The following code shows an example for `rbegin()`.,rbegin}
+
+    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
+    @sa @ref rend() -- returns a reverse iterator to the end
+    @sa @ref crend() -- returns a const reverse iterator to the end
+
+    @since version 1.0.0
+    */
+    reverse_iterator rbegin() noexcept
+    {
+        return reverse_iterator(end());
+    }
+
+    /*!
+    @copydoc basic_json::crbegin()
+    */
+    const_reverse_iterator rbegin() const noexcept
+    {
+        return crbegin();
+    }
+
+    /*!
+    @brief returns an iterator to the reverse-end
+
+    Returns an iterator to the reverse-end; that is, one before the first
+    element.
+
+    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
+
+    @complexity Constant.
+
+    @requirement This function helps `basic_json` satisfying the
+    [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of `reverse_iterator(begin())`.
+
+    @liveexample{The following code shows an example for `rend()`.,rend}
+
+    @sa @ref crend() -- returns a const reverse iterator to the end
+    @sa @ref rbegin() -- returns a reverse iterator to the beginning
+    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
+
+    @since version 1.0.0
+    */
+    reverse_iterator rend() noexcept
+    {
+        return reverse_iterator(begin());
+    }
+
+    /*!
+    @copydoc basic_json::crend()
+    */
+    const_reverse_iterator rend() const noexcept
+    {
+        return crend();
+    }
+
+    /*!
+    @brief returns a const reverse iterator to the last element
+
+    Returns a const iterator to the reverse-beginning; that is, the last
+    element.
+
+    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
+
+    @complexity Constant.
+
+    @requirement This function helps `basic_json` satisfying the
+    [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
+
+    @liveexample{The following code shows an example for `crbegin()`.,crbegin}
+
+    @sa @ref rbegin() -- returns a reverse iterator to the beginning
+    @sa @ref rend() -- returns a reverse iterator to the end
+    @sa @ref crend() -- returns a const reverse iterator to the end
+
+    @since version 1.0.0
+    */
+    const_reverse_iterator crbegin() const noexcept
+    {
+        return const_reverse_iterator(cend());
+    }
+
+    /*!
+    @brief returns a const reverse iterator to one before the first
+
+    Returns a const reverse iterator to the reverse-end; that is, one before
+    the first element.
+
+    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
+
+    @complexity Constant.
+
+    @requirement This function helps `basic_json` satisfying the
+    [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
+
+    @liveexample{The following code shows an example for `crend()`.,crend}
+
+    @sa @ref rend() -- returns a reverse iterator to the end
+    @sa @ref rbegin() -- returns a reverse iterator to the beginning
+    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
+
+    @since version 1.0.0
+    */
+    const_reverse_iterator crend() const noexcept
+    {
+        return const_reverse_iterator(cbegin());
+    }
+
+  private:
+    // forward declaration
+    template<typename IteratorType> class iteration_proxy;
+
+  public:
+    /*!
+    @brief wrapper to access iterator member functions in range-based for
+
+    This function allows to access @ref iterator::key() and @ref
+    iterator::value() during range-based for loops. In these loops, a
+    reference to the JSON values is returned, so there is no access to the
+    underlying iterator.
+
+    @note The name of this function is not yet final and may change in the
+    future.
+    */
+    static iteration_proxy<iterator> iterator_wrapper(reference cont)
+    {
+        return iteration_proxy<iterator>(cont);
+    }
+
+    /*!
+    @copydoc iterator_wrapper(reference)
+    */
+    static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont)
+    {
+        return iteration_proxy<const_iterator>(cont);
+    }
+
+    /// @}
+
+
+    //////////////
+    // capacity //
+    //////////////
+
+    /// @name capacity
+    /// @{
+
+    /*!
+    @brief checks whether the container is empty
+
+    Checks if a JSON value has no elements.
+
+    @return The return value depends on the different types and is
+            defined as follows:
+            Value type  | return value
+            ----------- | -------------
+            null        | `true`
+            boolean     | `false`
+            string      | `false`
+            number      | `false`
+            object      | result of function `object_t::empty()`
+            array       | result of function `array_t::empty()`
+
+    @note This function does not return whether a string stored as JSON value
+    is empty - it returns whether the JSON container itself is empty which is
+    false in the case of a string.
+
+    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
+    the Container concept; that is, their `empty()` functions have constant
+    complexity.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of `begin() == end()`.
+
+    @liveexample{The following code uses `empty()` to check if a JSON
+    object contains any elements.,empty}
+
+    @sa @ref size() -- returns the number of elements
+
+    @since version 1.0.0
+    */
+    bool empty() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+            {
+                // null values are empty
+                return true;
+            }
+
+            case value_t::array:
+            {
+                // delegate call to array_t::empty()
+                return m_value.array->empty();
+            }
+
+            case value_t::object:
+            {
+                // delegate call to object_t::empty()
+                return m_value.object->empty();
+            }
+
+            default:
+            {
+                // all other types are nonempty
+                return false;
+            }
+        }
+    }
+
+    /*!
+    @brief returns the number of elements
+
+    Returns the number of elements in a JSON value.
+
+    @return The return value depends on the different types and is
+            defined as follows:
+            Value type  | return value
+            ----------- | -------------
+            null        | `0`
+            boolean     | `1`
+            string      | `1`
+            number      | `1`
+            object      | result of function object_t::size()
+            array       | result of function array_t::size()
+
+    @note This function does not return the length of a string stored as JSON
+    value - it returns the number of elements in the JSON value which is 1 in
+    the case of a string.
+
+    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
+    the Container concept; that is, their size() functions have constant
+    complexity.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of `std::distance(begin(), end())`.
+
+    @liveexample{The following code calls `size()` on the different value
+    types.,size}
+
+    @sa @ref empty() -- checks whether the container is empty
+    @sa @ref max_size() -- returns the maximal number of elements
+
+    @since version 1.0.0
+    */
+    size_type size() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+            {
+                // null values are empty
+                return 0;
+            }
+
+            case value_t::array:
+            {
+                // delegate call to array_t::size()
+                return m_value.array->size();
+            }
+
+            case value_t::object:
+            {
+                // delegate call to object_t::size()
+                return m_value.object->size();
+            }
+
+            default:
+            {
+                // all other types have size 1
+                return 1;
+            }
+        }
+    }
+
+    /*!
+    @brief returns the maximum possible number of elements
+
+    Returns the maximum number of elements a JSON value is able to hold due to
+    system or library implementation limitations, i.e. `std::distance(begin(),
+    end())` for the JSON value.
+
+    @return The return value depends on the different types and is
+            defined as follows:
+            Value type  | return value
+            ----------- | -------------
+            null        | `0` (same as `size()`)
+            boolean     | `1` (same as `size()`)
+            string      | `1` (same as `size()`)
+            number      | `1` (same as `size()`)
+            object      | result of function `object_t::max_size()`
+            array       | result of function `array_t::max_size()`
+
+    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
+    the Container concept; that is, their `max_size()` functions have constant
+    complexity.
+
+    @requirement This function helps `basic_json` satisfying the
+    [Container](http://en.cppreference.com/w/cpp/concept/Container)
+    requirements:
+    - The complexity is constant.
+    - Has the semantics of returning `b.size()` where `b` is the largest
+      possible JSON value.
+
+    @liveexample{The following code calls `max_size()` on the different value
+    types. Note the output is implementation specific.,max_size}
+
+    @sa @ref size() -- returns the number of elements
+
+    @since version 1.0.0
+    */
+    size_type max_size() const noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::array:
+            {
+                // delegate call to array_t::max_size()
+                return m_value.array->max_size();
+            }
+
+            case value_t::object:
+            {
+                // delegate call to object_t::max_size()
+                return m_value.object->max_size();
+            }
+
+            default:
+            {
+                // all other types have max_size() == size()
+                return size();
+            }
+        }
+    }
+
+    /// @}
+
+
+    ///////////////
+    // modifiers //
+    ///////////////
+
+    /// @name modifiers
+    /// @{
+
+    /*!
+    @brief clears the contents
+
+    Clears the content of a JSON value and resets it to the default value as
+    if @ref basic_json(value_t) would have been called:
+
+    Value type  | initial value
+    ----------- | -------------
+    null        | `null`
+    boolean     | `false`
+    string      | `""`
+    number      | `0`
+    object      | `{}`
+    array       | `[]`
+
+    @complexity Linear in the size of the JSON value.
+
+    @liveexample{The example below shows the effect of `clear()` to different
+    JSON types.,clear}
+
+    @since version 1.0.0
+    */
+    void clear() noexcept
+    {
+        switch (m_type)
+        {
+            case value_t::number_integer:
+            {
+                m_value.number_integer = 0;
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                m_value.number_unsigned = 0;
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                m_value.number_float = 0.0;
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                m_value.boolean = false;
+                break;
+            }
+
+            case value_t::string:
+            {
+                m_value.string->clear();
+                break;
+            }
+
+            case value_t::array:
+            {
+                m_value.array->clear();
+                break;
+            }
+
+            case value_t::object:
+            {
+                m_value.object->clear();
+                break;
+            }
+
+            default:
+            {
+                break;
+            }
+        }
+    }
+
+    /*!
+    @brief add an object to an array
+
+    Appends the given element @a val to the end of the JSON value. If the
+    function is called on a JSON null value, an empty array is created before
+    appending @a val.
+
+    @param[in] val the value to add to the JSON array
+
+    @throw std::domain_error when called on a type other than JSON array or
+    null; example: `"cannot use push_back() with number"`
+
+    @complexity Amortized constant.
+
+    @liveexample{The example shows how `push_back()` and `+=` can be used to
+    add elements to a JSON array. Note how the `null` value was silently
+    converted to a JSON array.,push_back}
+
+    @since version 1.0.0
+    */
+    void push_back(basic_json&& val)
+    {
+        // push_back only works for null objects or arrays
+        if (not(is_null() or is_array()))
+        {
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
+        }
+
+        // transform null object into an array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value = value_t::array;
+            assert_invariant();
+        }
+
+        // add element to array (move semantics)
+        m_value.array->push_back(std::move(val));
+        // invalidate object
+        val.m_type = value_t::null;
+    }
+
+    /*!
+    @brief add an object to an array
+    @copydoc push_back(basic_json&&)
+    */
+    reference operator+=(basic_json&& val)
+    {
+        push_back(std::move(val));
+        return *this;
+    }
+
+    /*!
+    @brief add an object to an array
+    @copydoc push_back(basic_json&&)
+    */
+    void push_back(const basic_json& val)
+    {
+        // push_back only works for null objects or arrays
+        if (not(is_null() or is_array()))
+        {
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
+        }
+
+        // transform null object into an array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value = value_t::array;
+            assert_invariant();
+        }
+
+        // add element to array
+        m_value.array->push_back(val);
+    }
+
+    /*!
+    @brief add an object to an array
+    @copydoc push_back(basic_json&&)
+    */
+    reference operator+=(const basic_json& val)
+    {
+        push_back(val);
+        return *this;
+    }
+
+    /*!
+    @brief add an object to an object
+
+    Inserts the given element @a val to the JSON object. If the function is
+    called on a JSON null value, an empty object is created before inserting
+    @a val.
+
+    @param[in] val the value to add to the JSON object
+
+    @throw std::domain_error when called on a type other than JSON object or
+    null; example: `"cannot use push_back() with number"`
+
+    @complexity Logarithmic in the size of the container, O(log(`size()`)).
+
+    @liveexample{The example shows how `push_back()` and `+=` can be used to
+    add elements to a JSON object. Note how the `null` value was silently
+    converted to a JSON object.,push_back__object_t__value}
+
+    @since version 1.0.0
+    */
+    void push_back(const typename object_t::value_type& val)
+    {
+        // push_back only works for null objects or objects
+        if (not(is_null() or is_object()))
+        {
+            JSON_THROW(std::domain_error("cannot use push_back() with " + type_name()));
+        }
+
+        // transform null object into an object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value = value_t::object;
+            assert_invariant();
+        }
+
+        // add element to array
+        m_value.object->insert(val);
+    }
+
+    /*!
+    @brief add an object to an object
+    @copydoc push_back(const typename object_t::value_type&)
+    */
+    reference operator+=(const typename object_t::value_type& val)
+    {
+        push_back(val);
+        return *this;
+    }
+
+    /*!
+    @brief add an object to an object
+
+    This function allows to use `push_back` with an initializer list. In case
+
+    1. the current value is an object,
+    2. the initializer list @a init contains only two elements, and
+    3. the first element of @a init is a string,
+
+    @a init is converted into an object element and added using
+    @ref push_back(const typename object_t::value_type&). Otherwise, @a init
+    is converted to a JSON value and added using @ref push_back(basic_json&&).
+
+    @param init  an initializer list
+
+    @complexity Linear in the size of the initializer list @a init.
+
+    @note This function is required to resolve an ambiguous overload error,
+          because pairs like `{"key", "value"}` can be both interpreted as
+          `object_t::value_type` or `std::initializer_list<basic_json>`, see
+          https://github.com/nlohmann/json/issues/235 for more information.
+
+    @liveexample{The example shows how initializer lists are treated as
+    objects when possible.,push_back__initializer_list}
+    */
+    void push_back(std::initializer_list<basic_json> init)
+    {
+        if (is_object() and init.size() == 2 and init.begin()->is_string())
+        {
+            const string_t key = *init.begin();
+            push_back(typename object_t::value_type(key, *(init.begin() + 1)));
+        }
+        else
+        {
+            push_back(basic_json(init));
+        }
+    }
+
+    /*!
+    @brief add an object to an object
+    @copydoc push_back(std::initializer_list<basic_json>)
+    */
+    reference operator+=(std::initializer_list<basic_json> init)
+    {
+        push_back(init);
+        return *this;
+    }
+
+    /*!
+    @brief add an object to an array
+
+    Creates a JSON value from the passed parameters @a args to the end of the
+    JSON value. If the function is called on a JSON null value, an empty array
+    is created before appending the value created from @a args.
+
+    @param[in] args arguments to forward to a constructor of @ref basic_json
+    @tparam Args compatible types to create a @ref basic_json object
+
+    @throw std::domain_error when called on a type other than JSON array or
+    null; example: `"cannot use emplace_back() with number"`
+
+    @complexity Amortized constant.
+
+    @liveexample{The example shows how `push_back()` can be used to add
+    elements to a JSON array. Note how the `null` value was silently converted
+    to a JSON array.,emplace_back}
+
+    @since version 2.0.8
+    */
+    template<class... Args>
+    void emplace_back(Args&& ... args)
+    {
+        // emplace_back only works for null objects or arrays
+        if (not(is_null() or is_array()))
+        {
+            JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name()));
+        }
+
+        // transform null object into an array
+        if (is_null())
+        {
+            m_type = value_t::array;
+            m_value = value_t::array;
+            assert_invariant();
+        }
+
+        // add element to array (perfect forwarding)
+        m_value.array->emplace_back(std::forward<Args>(args)...);
+    }
+
+    /*!
+    @brief add an object to an object if key does not exist
+
+    Inserts a new element into a JSON object constructed in-place with the
+    given @a args if there is no element with the key in the container. If the
+    function is called on a JSON null value, an empty object is created before
+    appending the value created from @a args.
+
+    @param[in] args arguments to forward to a constructor of @ref basic_json
+    @tparam Args compatible types to create a @ref basic_json object
+
+    @return a pair consisting of an iterator to the inserted element, or the
+            already-existing element if no insertion happened, and a bool
+            denoting whether the insertion took place.
+
+    @throw std::domain_error when called on a type other than JSON object or
+    null; example: `"cannot use emplace() with number"`
+
+    @complexity Logarithmic in the size of the container, O(log(`size()`)).
+
+    @liveexample{The example shows how `emplace()` can be used to add elements
+    to a JSON object. Note how the `null` value was silently converted to a
+    JSON object. Further note how no value is added if there was already one
+    value stored with the same key.,emplace}
+
+    @since version 2.0.8
+    */
+    template<class... Args>
+    std::pair<iterator, bool> emplace(Args&& ... args)
+    {
+        // emplace only works for null objects or arrays
+        if (not(is_null() or is_object()))
+        {
+            JSON_THROW(std::domain_error("cannot use emplace() with " + type_name()));
+        }
+
+        // transform null object into an object
+        if (is_null())
+        {
+            m_type = value_t::object;
+            m_value = value_t::object;
+            assert_invariant();
+        }
+
+        // add element to array (perfect forwarding)
+        auto res = m_value.object->emplace(std::forward<Args>(args)...);
+        // create result iterator and set iterator to the result of emplace
+        auto it = begin();
+        it.m_it.object_iterator = res.first;
+
+        // return pair of iterator and boolean
+        return {it, res.second};
+    }
+
+    /*!
+    @brief inserts element
+
+    Inserts element @a val before iterator @a pos.
+
+    @param[in] pos iterator before which the content will be inserted; may be
+    the end() iterator
+    @param[in] val element to insert
+    @return iterator pointing to the inserted @a val.
+
+    @throw std::domain_error if called on JSON values other than arrays;
+    example: `"cannot use insert() with string"`
+    @throw std::domain_error if @a pos is not an iterator of *this; example:
+    `"iterator does not fit current value"`
+
+    @complexity Constant plus linear in the distance between pos and end of
+    the container.
+
+    @liveexample{The example shows how `insert()` is used.,insert}
+
+    @since version 1.0.0
+    */
+    iterator insert(const_iterator pos, const basic_json& val)
+    {
+        // insert only works for arrays
+        if (is_array())
+        {
+            // check if iterator pos fits to this JSON value
+            if (pos.m_object != this)
+            {
+                JSON_THROW(std::domain_error("iterator does not fit current value"));
+            }
+
+            // insert to array and return iterator
+            iterator result(this);
+            result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
+            return result;
+        }
+
+        JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
+    }
+
+    /*!
+    @brief inserts element
+    @copydoc insert(const_iterator, const basic_json&)
+    */
+    iterator insert(const_iterator pos, basic_json&& val)
+    {
+        return insert(pos, val);
+    }
+
+    /*!
+    @brief inserts elements
+
+    Inserts @a cnt copies of @a val before iterator @a pos.
+
+    @param[in] pos iterator before which the content will be inserted; may be
+    the end() iterator
+    @param[in] cnt number of copies of @a val to insert
+    @param[in] val element to insert
+    @return iterator pointing to the first element inserted, or @a pos if
+    `cnt==0`
+
+    @throw std::domain_error if called on JSON values other than arrays;
+    example: `"cannot use insert() with string"`
+    @throw std::domain_error if @a pos is not an iterator of *this; example:
+    `"iterator does not fit current value"`
+
+    @complexity Linear in @a cnt plus linear in the distance between @a pos
+    and end of the container.
+
+    @liveexample{The example shows how `insert()` is used.,insert__count}
+
+    @since version 1.0.0
+    */
+    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
+    {
+        // insert only works for arrays
+        if (is_array())
+        {
+            // check if iterator pos fits to this JSON value
+            if (pos.m_object != this)
+            {
+                JSON_THROW(std::domain_error("iterator does not fit current value"));
+            }
+
+            // insert to array and return iterator
+            iterator result(this);
+            result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
+            return result;
+        }
+
+        JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
+    }
+
+    /*!
+    @brief inserts elements
+
+    Inserts elements from range `[first, last)` before iterator @a pos.
+
+    @param[in] pos iterator before which the content will be inserted; may be
+    the end() iterator
+    @param[in] first begin of the range of elements to insert
+    @param[in] last end of the range of elements to insert
+
+    @throw std::domain_error if called on JSON values other than arrays;
+    example: `"cannot use insert() with string"`
+    @throw std::domain_error if @a pos is not an iterator of *this; example:
+    `"iterator does not fit current value"`
+    @throw std::domain_error if @a first and @a last do not belong to the same
+    JSON value; example: `"iterators do not fit"`
+    @throw std::domain_error if @a first or @a last are iterators into
+    container for which insert is called; example: `"passed iterators may not
+    belong to container"`
+
+    @return iterator pointing to the first element inserted, or @a pos if
+    `first==last`
+
+    @complexity Linear in `std::distance(first, last)` plus linear in the
+    distance between @a pos and end of the container.
+
+    @liveexample{The example shows how `insert()` is used.,insert__range}
+
+    @since version 1.0.0
+    */
+    iterator insert(const_iterator pos, const_iterator first, const_iterator last)
+    {
+        // insert only works for arrays
+        if (not is_array())
+        {
+            JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
+        }
+
+        // check if iterator pos fits to this JSON value
+        if (pos.m_object != this)
+        {
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
+        }
+
+        // check if range iterators belong to the same JSON object
+        if (first.m_object != last.m_object)
+        {
+            JSON_THROW(std::domain_error("iterators do not fit"));
+        }
+
+        if (first.m_object == this or last.m_object == this)
+        {
+            JSON_THROW(std::domain_error("passed iterators may not belong to container"));
+        }
+
+        // insert to array and return iterator
+        iterator result(this);
+        result.m_it.array_iterator = m_value.array->insert(
+                                         pos.m_it.array_iterator,
+                                         first.m_it.array_iterator,
+                                         last.m_it.array_iterator);
+        return result;
+    }
+
+    /*!
+    @brief inserts elements
+
+    Inserts elements from initializer list @a ilist before iterator @a pos.
+
+    @param[in] pos iterator before which the content will be inserted; may be
+    the end() iterator
+    @param[in] ilist initializer list to insert the values from
+
+    @throw std::domain_error if called on JSON values other than arrays;
+    example: `"cannot use insert() with string"`
+    @throw std::domain_error if @a pos is not an iterator of *this; example:
+    `"iterator does not fit current value"`
+
+    @return iterator pointing to the first element inserted, or @a pos if
+    `ilist` is empty
+
+    @complexity Linear in `ilist.size()` plus linear in the distance between
+    @a pos and end of the container.
+
+    @liveexample{The example shows how `insert()` is used.,insert__ilist}
+
+    @since version 1.0.0
+    */
+    iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
+    {
+        // insert only works for arrays
+        if (not is_array())
+        {
+            JSON_THROW(std::domain_error("cannot use insert() with " + type_name()));
+        }
+
+        // check if iterator pos fits to this JSON value
+        if (pos.m_object != this)
+        {
+            JSON_THROW(std::domain_error("iterator does not fit current value"));
+        }
+
+        // insert to array and return iterator
+        iterator result(this);
+        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
+        return result;
+    }
+
+    /*!
+    @brief exchanges the values
+
+    Exchanges the contents of the JSON value with those of @a other. Does not
+    invoke any move, copy, or swap operations on individual elements. All
+    iterators and references remain valid. The past-the-end iterator is
+    invalidated.
+
+    @param[in,out] other JSON value to exchange the contents with
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how JSON values can be swapped with
+    `swap()`.,swap__reference}
+
+    @since version 1.0.0
+    */
+    void swap(reference other) noexcept (
+        std::is_nothrow_move_constructible<value_t>::value and
+        std::is_nothrow_move_assignable<value_t>::value and
+        std::is_nothrow_move_constructible<json_value>::value and
+        std::is_nothrow_move_assignable<json_value>::value
+    )
+    {
+        std::swap(m_type, other.m_type);
+        std::swap(m_value, other.m_value);
+        assert_invariant();
+    }
+
+    /*!
+    @brief exchanges the values
+
+    Exchanges the contents of a JSON array with those of @a other. Does not
+    invoke any move, copy, or swap operations on individual elements. All
+    iterators and references remain valid. The past-the-end iterator is
+    invalidated.
+
+    @param[in,out] other array to exchange the contents with
+
+    @throw std::domain_error when JSON value is not an array; example:
+    `"cannot use swap() with string"`
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how arrays can be swapped with
+    `swap()`.,swap__array_t}
+
+    @since version 1.0.0
+    */
+    void swap(array_t& other)
+    {
+        // swap only works for arrays
+        if (is_array())
+        {
+            std::swap(*(m_value.array), other);
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
+        }
+    }
+
+    /*!
+    @brief exchanges the values
+
+    Exchanges the contents of a JSON object with those of @a other. Does not
+    invoke any move, copy, or swap operations on individual elements. All
+    iterators and references remain valid. The past-the-end iterator is
+    invalidated.
+
+    @param[in,out] other object to exchange the contents with
+
+    @throw std::domain_error when JSON value is not an object; example:
+    `"cannot use swap() with string"`
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how objects can be swapped with
+    `swap()`.,swap__object_t}
+
+    @since version 1.0.0
+    */
+    void swap(object_t& other)
+    {
+        // swap only works for objects
+        if (is_object())
+        {
+            std::swap(*(m_value.object), other);
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
+        }
+    }
+
+    /*!
+    @brief exchanges the values
+
+    Exchanges the contents of a JSON string with those of @a other. Does not
+    invoke any move, copy, or swap operations on individual elements. All
+    iterators and references remain valid. The past-the-end iterator is
+    invalidated.
+
+    @param[in,out] other string to exchange the contents with
+
+    @throw std::domain_error when JSON value is not a string; example: `"cannot
+    use swap() with boolean"`
+
+    @complexity Constant.
+
+    @liveexample{The example below shows how strings can be swapped with
+    `swap()`.,swap__string_t}
+
+    @since version 1.0.0
+    */
+    void swap(string_t& other)
+    {
+        // swap only works for strings
+        if (is_string())
+        {
+            std::swap(*(m_value.string), other);
+        }
+        else
+        {
+            JSON_THROW(std::domain_error("cannot use swap() with " + type_name()));
+        }
+    }
+
+    /// @}
+
+
+    //////////////////////////////////////////
+    // lexicographical comparison operators //
+    //////////////////////////////////////////
+
+    /// @name lexicographical comparison operators
+    /// @{
+
+  private:
+    /*!
+    @brief comparison operator for JSON types
+
+    Returns an ordering that is similar to Python:
+    - order: null < boolean < number < object < array < string
+    - furthermore, each type is not smaller than itself
+
+    @since version 1.0.0
+    */
+    friend bool operator<(const value_t lhs, const value_t rhs) noexcept
+    {
+        static constexpr std::array<uint8_t, 8> order = {{
+                0, // null
+                3, // object
+                4, // array
+                5, // string
+                1, // boolean
+                2, // integer
+                2, // unsigned
+                2, // float
+            }
+        };
+
+        // discarded values are not comparable
+        if (lhs == value_t::discarded or rhs == value_t::discarded)
+        {
+            return false;
+        }
+
+        return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)];
+    }
+
+  public:
+    /*!
+    @brief comparison: equal
+
+    Compares two JSON values for equality according to the following rules:
+    - Two JSON values are equal if (1) they are from the same type and (2)
+      their stored values are the same.
+    - Integer and floating-point numbers are automatically converted before
+      comparison. Floating-point numbers are compared indirectly: two
+      floating-point numbers `f1` and `f2` are considered equal if neither
+      `f1 > f2` nor `f2 > f1` holds.
+    - Two JSON null values are equal.
+
+    @param[in] lhs  first JSON value to consider
+    @param[in] rhs  second JSON value to consider
+    @return whether the values @a lhs and @a rhs are equal
+
+    @complexity Linear.
+
+    @liveexample{The example demonstrates comparing several JSON
+    types.,operator__equal}
+
+    @since version 1.0.0
+    */
+    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
+    {
+        const auto lhs_type = lhs.type();
+        const auto rhs_type = rhs.type();
+
+        if (lhs_type == rhs_type)
+        {
+            switch (lhs_type)
+            {
+                case value_t::array:
+                {
+                    return *lhs.m_value.array == *rhs.m_value.array;
+                }
+                case value_t::object:
+                {
+                    return *lhs.m_value.object == *rhs.m_value.object;
+                }
+                case value_t::null:
+                {
+                    return true;
+                }
+                case value_t::string:
+                {
+                    return *lhs.m_value.string == *rhs.m_value.string;
+                }
+                case value_t::boolean:
+                {
+                    return lhs.m_value.boolean == rhs.m_value.boolean;
+                }
+                case value_t::number_integer:
+                {
+                    return lhs.m_value.number_integer == rhs.m_value.number_integer;
+                }
+                case value_t::number_unsigned:
+                {
+                    return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
+                }
+                case value_t::number_float:
+                {
+                    return lhs.m_value.number_float == rhs.m_value.number_float;
+                }
+                default:
+                {
+                    return false;
+                }
+            }
+        }
+        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
+        {
+            return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
+        }
+        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
+        {
+            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
+        }
+        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
+        {
+            return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
+        }
+        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
+        {
+            return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
+        }
+        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
+        {
+            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
+        }
+        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
+        {
+            return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
+        }
+
+        return false;
+    }
+
+    /*!
+    @brief comparison: equal
+
+    The functions compares the given JSON value against a null pointer. As the
+    null pointer can be used to initialize a JSON value to null, a comparison
+    of JSON value @a v with a null pointer should be equivalent to call
+    `v.is_null()`.
+
+    @param[in] v  JSON value to consider
+    @return whether @a v is null
+
+    @complexity Constant.
+
+    @liveexample{The example compares several JSON types to the null pointer.
+    ,operator__equal__nullptr_t}
+
+    @since version 1.0.0
+    */
+    friend bool operator==(const_reference v, std::nullptr_t) noexcept
+    {
+        return v.is_null();
+    }
+
+    /*!
+    @brief comparison: equal
+    @copydoc operator==(const_reference, std::nullptr_t)
+    */
+    friend bool operator==(std::nullptr_t, const_reference v) noexcept
+    {
+        return v.is_null();
+    }
+
+    /*!
+    @brief comparison: not equal
+
+    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.
+
+    @param[in] lhs  first JSON value to consider
+    @param[in] rhs  second JSON value to consider
+    @return whether the values @a lhs and @a rhs are not equal
+
+    @complexity Linear.
+
+    @liveexample{The example demonstrates comparing several JSON
+    types.,operator__notequal}
+
+    @since version 1.0.0
+    */
+    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
+    {
+        return not (lhs == rhs);
+    }
+
+    /*!
+    @brief comparison: not equal
+
+    The functions compares the given JSON value against a null pointer. As the
+    null pointer can be used to initialize a JSON value to null, a comparison
+    of JSON value @a v with a null pointer should be equivalent to call
+    `not v.is_null()`.
+
+    @param[in] v  JSON value to consider
+    @return whether @a v is not null
+
+    @complexity Constant.
+
+    @liveexample{The example compares several JSON types to the null pointer.
+    ,operator__notequal__nullptr_t}
+
+    @since version 1.0.0
+    */
+    friend bool operator!=(const_reference v, std::nullptr_t) noexcept
+    {
+        return not v.is_null();
+    }
+
+    /*!
+    @brief comparison: not equal
+    @copydoc operator!=(const_reference, std::nullptr_t)
+    */
+    friend bool operator!=(std::nullptr_t, const_reference v) noexcept
+    {
+        return not v.is_null();
+    }
+
+    /*!
+    @brief comparison: less than
+
+    Compares whether one JSON value @a lhs is less than another JSON value @a
+    rhs according to the following rules:
+    - If @a lhs and @a rhs have the same type, the values are compared using
+      the default `<` operator.
+    - Integer and floating-point numbers are automatically converted before
+      comparison
+    - In case @a lhs and @a rhs have different types, the values are ignored
+      and the order of the types is considered, see
+      @ref operator<(const value_t, const value_t).
+
+    @param[in] lhs  first JSON value to consider
+    @param[in] rhs  second JSON value to consider
+    @return whether @a lhs is less than @a rhs
+
+    @complexity Linear.
+
+    @liveexample{The example demonstrates comparing several JSON
+    types.,operator__less}
+
+    @since version 1.0.0
+    */
+    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
+    {
+        const auto lhs_type = lhs.type();
+        const auto rhs_type = rhs.type();
+
+        if (lhs_type == rhs_type)
+        {
+            switch (lhs_type)
+            {
+                case value_t::array:
+                {
+                    return *lhs.m_value.array < *rhs.m_value.array;
+                }
+                case value_t::object:
+                {
+                    return *lhs.m_value.object < *rhs.m_value.object;
+                }
+                case value_t::null:
+                {
+                    return false;
+                }
+                case value_t::string:
+                {
+                    return *lhs.m_value.string < *rhs.m_value.string;
+                }
+                case value_t::boolean:
+                {
+                    return lhs.m_value.boolean < rhs.m_value.boolean;
+                }
+                case value_t::number_integer:
+                {
+                    return lhs.m_value.number_integer < rhs.m_value.number_integer;
+                }
+                case value_t::number_unsigned:
+                {
+                    return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
+                }
+                case value_t::number_float:
+                {
+                    return lhs.m_value.number_float < rhs.m_value.number_float;
+                }
+                default:
+                {
+                    return false;
+                }
+            }
+        }
+        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
+        {
+            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
+        }
+        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
+        {
+            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
+        }
+        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
+        {
+            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
+        }
+        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
+        {
+            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
+        }
+        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
+        {
+            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
+        }
+        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
+        {
+            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
+        }
+
+        // We only reach this line if we cannot compare values. In that case,
+        // we compare types. Note we have to call the operator explicitly,
+        // because MSVC has problems otherwise.
+        return operator<(lhs_type, rhs_type);
+    }
+
+    /*!
+    @brief comparison: less than or equal
+
+    Compares whether one JSON value @a lhs is less than or equal to another
+    JSON value by calculating `not (rhs < lhs)`.
+
+    @param[in] lhs  first JSON value to consider
+    @param[in] rhs  second JSON value to consider
+    @return whether @a lhs is less than or equal to @a rhs
+
+    @complexity Linear.
+
+    @liveexample{The example demonstrates comparing several JSON
+    types.,operator__greater}
+
+    @since version 1.0.0
+    */
+    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
+    {
+        return not (rhs < lhs);
+    }
+
+    /*!
+    @brief comparison: greater than
+
+    Compares whether one JSON value @a lhs is greater than another
+    JSON value by calculating `not (lhs <= rhs)`.
+
+    @param[in] lhs  first JSON value to consider
+    @param[in] rhs  second JSON value to consider
+    @return whether @a lhs is greater than to @a rhs
+
+    @complexity Linear.
+
+    @liveexample{The example demonstrates comparing several JSON
+    types.,operator__lessequal}
+
+    @since version 1.0.0
+    */
+    friend bool operator>(const_reference lhs, const_reference rhs) noexcept
+    {
+        return not (lhs <= rhs);
+    }
+
+    /*!
+    @brief comparison: greater than or equal
+
+    Compares whether one JSON value @a lhs is greater than or equal to another
+    JSON value by calculating `not (lhs < rhs)`.
+
+    @param[in] lhs  first JSON value to consider
+    @param[in] rhs  second JSON value to consider
+    @return whether @a lhs is greater than or equal to @a rhs
+
+    @complexity Linear.
+
+    @liveexample{The example demonstrates comparing several JSON
+    types.,operator__greaterequal}
+
+    @since version 1.0.0
+    */
+    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
+    {
+        return not (lhs < rhs);
+    }
+
+    /// @}
+
+
+    ///////////////////
+    // serialization //
+    ///////////////////
+
+    /// @name serialization
+    /// @{
+
+    /*!
+    @brief serialize to stream
+
+    Serialize the given JSON value @a j to the output stream @a o. The JSON
+    value will be serialized using the @ref dump member function. The
+    indentation of the output can be controlled with the member variable
+    `width` of the output stream @a o. For instance, using the manipulator
+    `std::setw(4)` on @a o sets the indentation level to `4` and the
+    serialization result is the same as calling `dump(4)`.
+
+    @note During serializaion, the locale and the precision of the output
+    stream @a o are changed. The original values are restored when the
+    function returns.
+
+    @param[in,out] o  stream to serialize to
+    @param[in] j  JSON value to serialize
+
+    @return the stream @a o
+
+    @complexity Linear.
+
+    @liveexample{The example below shows the serialization with different
+    parameters to `width` to adjust the indentation level.,operator_serialize}
+
+    @since version 1.0.0
+    */
+    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
+    {
+        // read width member and use it as indentation parameter if nonzero
+        const bool pretty_print = (o.width() > 0);
+        const auto indentation = (pretty_print ? o.width() : 0);
+
+        // reset width to 0 for subsequent calls to this stream
+        o.width(0);
+
+        // fix locale problems
+        const auto old_locale = o.imbue(std::locale::classic());
+        // set precision
+
+        // 6, 15 or 16 digits of precision allows round-trip IEEE 754
+        // string->float->string, string->double->string or string->long
+        // double->string; to be safe, we read this value from
+        // std::numeric_limits<number_float_t>::digits10
+        const auto old_precision = o.precision(std::numeric_limits<double>::digits10);
+
+        // do the actual serialization
+        j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
+
+        // reset locale and precision
+        o.imbue(old_locale);
+        o.precision(old_precision);
+        return o;
+    }
+
+    /*!
+    @brief serialize to stream
+    @copydoc operator<<(std::ostream&, const basic_json&)
+    */
+    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
+    {
+        return o << j;
+    }
+
+    /// @}
+
+
+    /////////////////////
+    // deserialization //
+    /////////////////////
+
+    /// @name deserialization
+    /// @{
+
+    /*!
+    @brief deserialize from an array
+
+    This function reads from an array of 1-byte values.
+
+    @pre Each element of the container has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @param[in] array  array to read from
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from an array.,parse__array__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class T, std::size_t N>
+    static basic_json parse(T (&array)[N],
+                            const parser_callback_t cb = nullptr)
+    {
+        // delegate the call to the iterator-range parse overload
+        return parse(std::begin(array), std::end(array), cb);
+    }
+
+    /*!
+    @brief deserialize from string literal
+
+    @tparam CharT character/literal type with size of 1 byte
+    @param[in] s  string literal to read a serialized JSON value from
+    @param[in] cb a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+    @note String containers like `std::string` or @ref string_t can be parsed
+          with @ref parse(const ContiguousContainer&, const parser_callback_t)
+
+    @liveexample{The example below demonstrates the `parse()` function with
+    and without callback function.,parse__string__parser_callback_t}
+
+    @sa @ref parse(std::istream&, const parser_callback_t) for a version that
+    reads from an input stream
+
+    @since version 1.0.0 (originally for @ref string_t)
+    */
+    template<typename CharT, typename std::enable_if<
+                 std::is_pointer<CharT>::value and
+                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
+                 sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0>
+    static basic_json parse(const CharT s,
+                            const parser_callback_t cb = nullptr)
+    {
+        return parser(reinterpret_cast<const char*>(s), cb).parse();
+    }
+
+    /*!
+    @brief deserialize from stream
+
+    @param[in,out] i  stream to read a serialized JSON value from
+    @param[in] cb a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates the `parse()` function with
+    and without callback function.,parse__istream__parser_callback_t}
+
+    @sa @ref parse(const CharT, const parser_callback_t) for a version
+    that reads from a string
+
+    @since version 1.0.0
+    */
+    static basic_json parse(std::istream& i,
+                            const parser_callback_t cb = nullptr)
+    {
+        return parser(i, cb).parse();
+    }
+
+    /*!
+    @copydoc parse(std::istream&, const parser_callback_t)
+    */
+    static basic_json parse(std::istream&& i,
+                            const parser_callback_t cb = nullptr)
+    {
+        return parser(i, cb).parse();
+    }
+
+    /*!
+    @brief deserialize from an iterator range with contiguous storage
+
+    This function reads from an iterator range of a container with contiguous
+    storage of 1-byte values. Compatible container types include
+    `std::vector`, `std::string`, `std::array`, `std::valarray`, and
+    `std::initializer_list`. Furthermore, C-style arrays can be used with
+    `std::begin()`/`std::end()`. User-defined containers can be used as long
+    as they implement random-access iterators and a contiguous storage.
+
+    @pre The iterator range is contiguous. Violating this precondition yields
+    undefined behavior. **This precondition is enforced with an assertion.**
+    @pre Each element in the range has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @warning There is no way to enforce all preconditions at compile-time. If
+             the function is called with noncompliant iterators and with
+             assertions switched off, the behavior is undefined and will most
+             likely yield segmentation violation.
+
+    @tparam IteratorType iterator of container with contiguous storage
+    @param[in] first  begin of the range to parse (included)
+    @param[in] last  end of the range to parse (excluded)
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from an iterator range.,parse__iteratortype__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class IteratorType, typename std::enable_if<
+                 std::is_base_of<
+                     std::random_access_iterator_tag,
+                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
+    static basic_json parse(IteratorType first, IteratorType last,
+                            const parser_callback_t cb = nullptr)
+    {
+        // assertion to check that the iterator range is indeed contiguous,
+        // see http://stackoverflow.com/a/35008842/266378 for more discussion
+        assert(std::accumulate(first, last, std::pair<bool, int>(true, 0),
+                               [&first](std::pair<bool, int> res, decltype(*first) val)
+        {
+            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
+            return res;
+        }).first);
+
+        // assertion to check that each element is 1 byte long
+        static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
+                      "each element in the iterator range must have the size of 1 byte");
+
+        // if iterator range is empty, create a parser with an empty string
+        // to generate "unexpected EOF" error message
+        if (std::distance(first, last) <= 0)
+        {
+            return parser("").parse();
+        }
+
+        return parser(first, last, cb).parse();
+    }
+
+    /*!
+    @brief deserialize from a container with contiguous storage
+
+    This function reads from a container with contiguous storage of 1-byte
+    values. Compatible container types include `std::vector`, `std::string`,
+    `std::array`, and `std::initializer_list`. User-defined containers can be
+    used as long as they implement random-access iterators and a contiguous
+    storage.
+
+    @pre The container storage is contiguous. Violating this precondition
+    yields undefined behavior. **This precondition is enforced with an
+    assertion.**
+    @pre Each element of the container has a size of 1 byte. Violating this
+    precondition yields undefined behavior. **This precondition is enforced
+    with a static assertion.**
+
+    @warning There is no way to enforce all preconditions at compile-time. If
+             the function is called with a noncompliant container and with
+             assertions switched off, the behavior is undefined and will most
+             likely yield segmentation violation.
+
+    @tparam ContiguousContainer container type with contiguous storage
+    @param[in] c  container to read from
+    @param[in] cb  a parser callback function of type @ref parser_callback_t
+    which is used to control the deserialization by filtering unwanted values
+    (optional)
+
+    @return result of the deserialization
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser. The complexity can be higher if the parser callback function
+    @a cb has a super-linear complexity.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below demonstrates the `parse()` function reading
+    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
+
+    @since version 2.0.3
+    */
+    template<class ContiguousContainer, typename std::enable_if<
+                 not std::is_pointer<ContiguousContainer>::value and
+                 std::is_base_of<
+                     std::random_access_iterator_tag,
+                     typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
+                 , int>::type = 0>
+    static basic_json parse(const ContiguousContainer& c,
+                            const parser_callback_t cb = nullptr)
+    {
+        // delegate the call to the iterator-range parse overload
+        return parse(std::begin(c), std::end(c), cb);
+    }
+
+    /*!
+    @brief deserialize from stream
+
+    Deserializes an input stream to a JSON value.
+
+    @param[in,out] i  input stream to read a serialized JSON value from
+    @param[in,out] j  JSON value to write the deserialized input to
+
+    @throw std::invalid_argument in case of parse errors
+
+    @complexity Linear in the length of the input. The parser is a predictive
+    LL(1) parser.
+
+    @note A UTF-8 byte order mark is silently ignored.
+
+    @liveexample{The example below shows how a JSON value is constructed by
+    reading a serialization from a stream.,operator_deserialize}
+
+    @sa parse(std::istream&, const parser_callback_t) for a variant with a
+    parser callback function to filter values while parsing
+
+    @since version 1.0.0
+    */
+    friend std::istream& operator<<(basic_json& j, std::istream& i)
+    {
+        j = parser(i).parse();
+        return i;
+    }
+
+    /*!
+    @brief deserialize from stream
+    @copydoc operator<<(basic_json&, std::istream&)
+    */
+    friend std::istream& operator>>(std::istream& i, basic_json& j)
+    {
+        j = parser(i).parse();
+        return i;
+    }
+
+    /// @}
+
+    //////////////////////////////////////////
+    // binary serialization/deserialization //
+    //////////////////////////////////////////
+
+    /// @name binary serialization/deserialization support
+    /// @{
+
+  private:
+    template<typename T>
+    static void add_to_vector(std::vector<uint8_t>& vec, size_t bytes, const T number)
+    {
+        assert(bytes == 1 or bytes == 2 or bytes == 4 or bytes == 8);
+
+        switch (bytes)
+        {
+            case 8:
+            {
+                vec.push_back(static_cast<uint8_t>((number >> 070) & 0xff));
+                vec.push_back(static_cast<uint8_t>((number >> 060) & 0xff));
+                vec.push_back(static_cast<uint8_t>((number >> 050) & 0xff));
+                vec.push_back(static_cast<uint8_t>((number >> 040) & 0xff));
+                // intentional fall-through
+            }
+
+            case 4:
+            {
+                vec.push_back(static_cast<uint8_t>((number >> 030) & 0xff));
+                vec.push_back(static_cast<uint8_t>((number >> 020) & 0xff));
+                // intentional fall-through
+            }
+
+            case 2:
+            {
+                vec.push_back(static_cast<uint8_t>((number >> 010) & 0xff));
+                // intentional fall-through
+            }
+
+            case 1:
+            {
+                vec.push_back(static_cast<uint8_t>(number & 0xff));
+                break;
+            }
+        }
+    }
+
+    /*!
+    @brief take sufficient bytes from a vector to fill an integer variable
+
+    In the context of binary serialization formats, we need to read several
+    bytes from a byte vector and combine them to multi-byte integral data
+    types.
+
+    @param[in] vec  byte vector to read from
+    @param[in] current_index  the position in the vector after which to read
+
+    @return the next sizeof(T) bytes from @a vec, in reverse order as T
+
+    @tparam T the integral return type
+
+    @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the
+           vector @a vec to read
+
+    In the for loop, the bytes from the vector are copied in reverse order into
+    the return value. In the figures below, let sizeof(T)=4 and `i` be the loop
+    variable.
+
+    Precondition:
+
+    vec:   |   |   | a | b | c | d |      T: |   |   |   |   |
+                 ^               ^             ^                ^
+           current_index         i            ptr        sizeof(T)
+
+    Postcondition:
+
+    vec:   |   |   | a | b | c | d |      T: | d | c | b | a |
+                 ^   ^                                     ^
+                 |   i                                    ptr
+           current_index
+
+    @sa Code adapted from <http://stackoverflow.com/a/41031865/266378>.
+    */
+    template<typename T>
+    static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_index)
+    {
+        if (current_index + sizeof(T) + 1 > vec.size())
+        {
+            JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"));
+        }
+
+        T result;
+        auto* ptr = reinterpret_cast<uint8_t*>(&result);
+        for (size_t i = 0; i < sizeof(T); ++i)
+        {
+            *ptr++ = vec[current_index + sizeof(T) - i];
+        }
+        return result;
+    }
+
+    /*!
+    @brief create a MessagePack serialization of a given JSON value
+
+    This is a straightforward implementation of the MessagePack specification.
+
+    @param[in] j  JSON value to serialize
+    @param[in,out] v  byte vector to write the serialization to
+
+    @sa https://github.com/msgpack/msgpack/blob/master/spec.md
+    */
+    static void to_msgpack_internal(const basic_json& j, std::vector<uint8_t>& v)
+    {
+        switch (j.type())
+        {
+            case value_t::null:
+            {
+                // nil
+                v.push_back(0xc0);
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                // true and false
+                v.push_back(j.m_value.boolean ? 0xc3 : 0xc2);
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                if (j.m_value.number_integer >= 0)
+                {
+                    // MessagePack does not differentiate between positive
+                    // signed integers and unsigned integers. Therefore, we
+                    // used the code from the value_t::number_unsigned case
+                    // here.
+                    if (j.m_value.number_unsigned < 128)
+                    {
+                        // positive fixnum
+                        add_to_vector(v, 1, j.m_value.number_unsigned);
+                    }
+                    else if (j.m_value.number_unsigned <= UINT8_MAX)
+                    {
+                        // uint 8
+                        v.push_back(0xcc);
+                        add_to_vector(v, 1, j.m_value.number_unsigned);
+                    }
+                    else if (j.m_value.number_unsigned <= UINT16_MAX)
+                    {
+                        // uint 16
+                        v.push_back(0xcd);
+                        add_to_vector(v, 2, j.m_value.number_unsigned);
+                    }
+                    else if (j.m_value.number_unsigned <= UINT32_MAX)
+                    {
+                        // uint 32
+                        v.push_back(0xce);
+                        add_to_vector(v, 4, j.m_value.number_unsigned);
+                    }
+                    else if (j.m_value.number_unsigned <= UINT64_MAX)
+                    {
+                        // uint 64
+                        v.push_back(0xcf);
+                        add_to_vector(v, 8, j.m_value.number_unsigned);
+                    }
+                }
+                else
+                {
+                    if (j.m_value.number_integer >= -32)
+                    {
+                        // negative fixnum
+                        add_to_vector(v, 1, j.m_value.number_integer);
+                    }
+                    else if (j.m_value.number_integer >= INT8_MIN and j.m_value.number_integer <= INT8_MAX)
+                    {
+                        // int 8
+                        v.push_back(0xd0);
+                        add_to_vector(v, 1, j.m_value.number_integer);
+                    }
+                    else if (j.m_value.number_integer >= INT16_MIN and j.m_value.number_integer <= INT16_MAX)
+                    {
+                        // int 16
+                        v.push_back(0xd1);
+                        add_to_vector(v, 2, j.m_value.number_integer);
+                    }
+                    else if (j.m_value.number_integer >= INT32_MIN and j.m_value.number_integer <= INT32_MAX)
+                    {
+                        // int 32
+                        v.push_back(0xd2);
+                        add_to_vector(v, 4, j.m_value.number_integer);
+                    }
+                    else if (j.m_value.number_integer >= INT64_MIN and j.m_value.number_integer <= INT64_MAX)
+                    {
+                        // int 64
+                        v.push_back(0xd3);
+                        add_to_vector(v, 8, j.m_value.number_integer);
+                    }
+                }
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                if (j.m_value.number_unsigned < 128)
+                {
+                    // positive fixnum
+                    add_to_vector(v, 1, j.m_value.number_unsigned);
+                }
+                else if (j.m_value.number_unsigned <= UINT8_MAX)
+                {
+                    // uint 8
+                    v.push_back(0xcc);
+                    add_to_vector(v, 1, j.m_value.number_unsigned);
+                }
+                else if (j.m_value.number_unsigned <= UINT16_MAX)
+                {
+                    // uint 16
+                    v.push_back(0xcd);
+                    add_to_vector(v, 2, j.m_value.number_unsigned);
+                }
+                else if (j.m_value.number_unsigned <= UINT32_MAX)
+                {
+                    // uint 32
+                    v.push_back(0xce);
+                    add_to_vector(v, 4, j.m_value.number_unsigned);
+                }
+                else if (j.m_value.number_unsigned <= UINT64_MAX)
+                {
+                    // uint 64
+                    v.push_back(0xcf);
+                    add_to_vector(v, 8, j.m_value.number_unsigned);
+                }
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                // float 64
+                v.push_back(0xcb);
+                const auto* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
+                for (size_t i = 0; i < 8; ++i)
+                {
+                    v.push_back(helper[7 - i]);
+                }
+                break;
+            }
+
+            case value_t::string:
+            {
+                const auto N = j.m_value.string->size();
+                if (N <= 31)
+                {
+                    // fixstr
+                    v.push_back(static_cast<uint8_t>(0xa0 | N));
+                }
+                else if (N <= 255)
+                {
+                    // str 8
+                    v.push_back(0xd9);
+                    add_to_vector(v, 1, N);
+                }
+                else if (N <= 65535)
+                {
+                    // str 16
+                    v.push_back(0xda);
+                    add_to_vector(v, 2, N);
+                }
+                else if (N <= 4294967295)
+                {
+                    // str 32
+                    v.push_back(0xdb);
+                    add_to_vector(v, 4, N);
+                }
+
+                // append string
+                std::copy(j.m_value.string->begin(), j.m_value.string->end(),
+                          std::back_inserter(v));
+                break;
+            }
+
+            case value_t::array:
+            {
+                const auto N = j.m_value.array->size();
+                if (N <= 15)
+                {
+                    // fixarray
+                    v.push_back(static_cast<uint8_t>(0x90 | N));
+                }
+                else if (N <= 0xffff)
+                {
+                    // array 16
+                    v.push_back(0xdc);
+                    add_to_vector(v, 2, N);
+                }
+                else if (N <= 0xffffffff)
+                {
+                    // array 32
+                    v.push_back(0xdd);
+                    add_to_vector(v, 4, N);
+                }
+
+                // append each element
+                for (const auto& el : *j.m_value.array)
+                {
+                    to_msgpack_internal(el, v);
+                }
+                break;
+            }
+
+            case value_t::object:
+            {
+                const auto N = j.m_value.object->size();
+                if (N <= 15)
+                {
+                    // fixmap
+                    v.push_back(static_cast<uint8_t>(0x80 | (N & 0xf)));
+                }
+                else if (N <= 65535)
+                {
+                    // map 16
+                    v.push_back(0xde);
+                    add_to_vector(v, 2, N);
+                }
+                else if (N <= 4294967295)
+                {
+                    // map 32
+                    v.push_back(0xdf);
+                    add_to_vector(v, 4, N);
+                }
+
+                // append each element
+                for (const auto& el : *j.m_value.object)
+                {
+                    to_msgpack_internal(el.first, v);
+                    to_msgpack_internal(el.second, v);
+                }
+                break;
+            }
+
+            default:
+            {
+                break;
+            }
+        }
+    }
+
+    /*!
+    @brief create a CBOR serialization of a given JSON value
+
+    This is a straightforward implementation of the CBOR specification.
+
+    @param[in] j  JSON value to serialize
+    @param[in,out] v  byte vector to write the serialization to
+
+    @sa https://tools.ietf.org/html/rfc7049
+    */
+    static void to_cbor_internal(const basic_json& j, std::vector<uint8_t>& v)
+    {
+        switch (j.type())
+        {
+            case value_t::null:
+            {
+                v.push_back(0xf6);
+                break;
+            }
+
+            case value_t::boolean:
+            {
+                v.push_back(j.m_value.boolean ? 0xf5 : 0xf4);
+                break;
+            }
+
+            case value_t::number_integer:
+            {
+                if (j.m_value.number_integer >= 0)
+                {
+                    // CBOR does not differentiate between positive signed
+                    // integers and unsigned integers. Therefore, we used the
+                    // code from the value_t::number_unsigned case here.
+                    if (j.m_value.number_integer <= 0x17)
+                    {
+                        add_to_vector(v, 1, j.m_value.number_integer);
+                    }
+                    else if (j.m_value.number_integer <= UINT8_MAX)
+                    {
+                        v.push_back(0x18);
+                        // one-byte uint8_t
+                        add_to_vector(v, 1, j.m_value.number_integer);
+                    }
+                    else if (j.m_value.number_integer <= UINT16_MAX)
+                    {
+                        v.push_back(0x19);
+                        // two-byte uint16_t
+                        add_to_vector(v, 2, j.m_value.number_integer);
+                    }
+                    else if (j.m_value.number_integer <= UINT32_MAX)
+                    {
+                        v.push_back(0x1a);
+                        // four-byte uint32_t
+                        add_to_vector(v, 4, j.m_value.number_integer);
+                    }
+                    else
+                    {
+                        v.push_back(0x1b);
+                        // eight-byte uint64_t
+                        add_to_vector(v, 8, j.m_value.number_integer);
+                    }
+                }
+                else
+                {
+                    // The conversions below encode the sign in the first
+                    // byte, and the value is converted to a positive number.
+                    const auto positive_number = -1 - j.m_value.number_integer;
+                    if (j.m_value.number_integer >= -24)
+                    {
+                        v.push_back(static_cast<uint8_t>(0x20 + positive_number));
+                    }
+                    else if (positive_number <= UINT8_MAX)
+                    {
+                        // int 8
+                        v.push_back(0x38);
+                        add_to_vector(v, 1, positive_number);
+                    }
+                    else if (positive_number <= UINT16_MAX)
+                    {
+                        // int 16
+                        v.push_back(0x39);
+                        add_to_vector(v, 2, positive_number);
+                    }
+                    else if (positive_number <= UINT32_MAX)
+                    {
+                        // int 32
+                        v.push_back(0x3a);
+                        add_to_vector(v, 4, positive_number);
+                    }
+                    else
+                    {
+                        // int 64
+                        v.push_back(0x3b);
+                        add_to_vector(v, 8, positive_number);
+                    }
+                }
+                break;
+            }
+
+            case value_t::number_unsigned:
+            {
+                if (j.m_value.number_unsigned <= 0x17)
+                {
+                    v.push_back(static_cast<uint8_t>(j.m_value.number_unsigned));
+                }
+                else if (j.m_value.number_unsigned <= 0xff)
+                {
+                    v.push_back(0x18);
+                    // one-byte uint8_t
+                    add_to_vector(v, 1, j.m_value.number_unsigned);
+                }
+                else if (j.m_value.number_unsigned <= 0xffff)
+                {
+                    v.push_back(0x19);
+                    // two-byte uint16_t
+                    add_to_vector(v, 2, j.m_value.number_unsigned);
+                }
+                else if (j.m_value.number_unsigned <= 0xffffffff)
+                {
+                    v.push_back(0x1a);
+                    // four-byte uint32_t
+                    add_to_vector(v, 4, j.m_value.number_unsigned);
+                }
+                else if (j.m_value.number_unsigned <= 0xffffffffffffffff)
+                {
+                    v.push_back(0x1b);
+                    // eight-byte uint64_t
+                    add_to_vector(v, 8, j.m_value.number_unsigned);
+                }
+                break;
+            }
+
+            case value_t::number_float:
+            {
+                // Double-Precision Float
+                v.push_back(0xfb);
+                const auto* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
+                for (size_t i = 0; i < 8; ++i)
+                {
+                    v.push_back(helper[7 - i]);
+                }
+                break;
+            }
+
+            case value_t::string:
+            {
+                const auto N = j.m_value.string->size();
+                if (N <= 0x17)
+                {
+                    v.push_back(0x60 + N);  // 1 byte for string + size
+                }
+                else if (N <= 0xff)
+                {
+                    v.push_back(0x78);  // one-byte uint8_t for N
+                    add_to_vector(v, 1, N);
+                }
+                else if (N <= 0xffff)
+                {
+                    v.push_back(0x79);  // two-byte uint16_t for N
+                    add_to_vector(v, 2, N);
+                }
+                else if (N <= 0xffffffff)
+                {
+                    v.push_back(0x7a); // four-byte uint32_t for N
+                    add_to_vector(v, 4, N);
+                }
+                // LCOV_EXCL_START
+                else if (N <= 0xffffffffffffffff)
+                {
+                    v.push_back(0x7b);  // eight-byte uint64_t for N
+                    add_to_vector(v, 8, N);
+                }
+                // LCOV_EXCL_STOP
+
+                // append string
+                std::copy(j.m_value.string->begin(), j.m_value.string->end(),
+                          std::back_inserter(v));
+                break;
+            }
+
+            case value_t::array:
+            {
+                const auto N = j.m_value.array->size();
+                if (N <= 0x17)
+                {
+                    v.push_back(0x80 + N);  // 1 byte for array + size
+                }
+                else if (N <= 0xff)
+                {
+                    v.push_back(0x98);  // one-byte uint8_t for N
+                    add_to_vector(v, 1, N);
+                }
+                else if (N <= 0xffff)
+                {
+                    v.push_back(0x99);  // two-byte uint16_t for N
+                    add_to_vector(v, 2, N);
+                }
+                else if (N <= 0xffffffff)
+                {
+                    v.push_back(0x9a);  // four-byte uint32_t for N
+                    add_to_vector(v, 4, N);
+                }
+                // LCOV_EXCL_START
+                else if (N <= 0xffffffffffffffff)
+                {
+                    v.push_back(0x9b);  // eight-byte uint64_t for N
+                    add_to_vector(v, 8, N);
+                }
+                // LCOV_EXCL_STOP
+
+                // append each element
+                for (const auto& el : *j.m_value.array)
+                {
+                    to_cbor_internal(el, v);
+                }
+                break;
+            }
+
+            case value_t::object:
+            {
+                const auto N = j.m_value.object->size();
+                if (N <= 0x17)
+                {
+                    v.push_back(0xa0 + N);  // 1 byte for object + size
+                }
+                else if (N <= 0xff)
+                {
+                    v.push_back(0xb8);
+                    add_to_vector(v, 1, N);  // one-byte uint8_t for N
+                }
+                else if (N <= 0xffff)
+                {
+                    v.push_back(0xb9);
+                    add_to_vector(v, 2, N);  // two-byte uint16_t for N
+                }
+                else if (N <= 0xffffffff)
+                {
+                    v.push_back(0xba);
+                    add_to_vector(v, 4, N);  // four-byte uint32_t for N
+                }
+                // LCOV_EXCL_START
+                else if (N <= 0xffffffffffffffff)
+                {
+                    v.push_back(0xbb);
+                    add_to_vector(v, 8, N);  // eight-byte uint64_t for N
+                }
+                // LCOV_EXCL_STOP
+
+                // append each element
+                for (const auto& el : *j.m_value.object)
+                {
+                    to_cbor_internal(el.first, v);
+                    to_cbor_internal(el.second, v);
+                }
+                break;
+            }
+
+            default:
+            {
+                break;
+            }
+        }
+    }
+
+
+    /*
+    @brief checks if given lengths do not exceed the size of a given vector
+
+    To secure the access to the byte vector during CBOR/MessagePack
+    deserialization, bytes are copied from the vector into buffers. This
+    function checks if the number of bytes to copy (@a len) does not exceed
+    the size @s size of the vector. Additionally, an @a offset is given from
+    where to start reading the bytes.
+
+    This function checks whether reading the bytes is safe; that is, offset is
+    a valid index in the vector, offset+len
+
+    @param[in] size    size of the byte vector
+    @param[in] len     number of bytes to read
+    @param[in] offset  offset where to start reading
+
+    vec:  x x x x x X X X X X
+          ^         ^         ^
+          0         offset    len
+
+    @throws out_of_range if `len > v.size()`
+    */
+    static void check_length(const size_t size, const size_t len, const size_t offset)
+    {
+        // simple case: requested length is greater than the vector's length
+        if (len > size or offset > size)
+        {
+            JSON_THROW(std::out_of_range("len out of range"));
+        }
+
+        // second case: adding offset would result in overflow
+        if ((size > (std::numeric_limits<size_t>::max() - offset)))
+        {
+            JSON_THROW(std::out_of_range("len+offset out of range"));
+        }
+
+        // last case: reading past the end of the vector
+        if (len + offset > size)
+        {
+            JSON_THROW(std::out_of_range("len+offset out of range"));
+        }
+    }
+
+    /*!
+    @brief create a JSON value from a given MessagePack vector
+
+    @param[in] v  MessagePack serialization
+    @param[in] idx  byte index to start reading from @a v
+
+    @return deserialized JSON value
+
+    @throw std::invalid_argument if unsupported features from MessagePack were
+    used in the given vector @a v or if the input is not valid MessagePack
+    @throw std::out_of_range if the given vector ends prematurely
+
+    @sa https://github.com/msgpack/msgpack/blob/master/spec.md
+    */
+    static basic_json from_msgpack_internal(const std::vector<uint8_t>& v, size_t& idx)
+    {
+        // make sure reading 1 byte is safe
+        check_length(v.size(), 1, idx);
+
+        // store and increment index
+        const size_t current_idx = idx++;
+
+        if (v[current_idx] <= 0xbf)
+        {
+            if (v[current_idx] <= 0x7f) // positive fixint
+            {
+                return v[current_idx];
+            }
+            if (v[current_idx] <= 0x8f) // fixmap
+            {
+                basic_json result = value_t::object;
+                const size_t len = v[current_idx] & 0x0f;
+                for (size_t i = 0; i < len; ++i)
+                {
+                    std::string key = from_msgpack_internal(v, idx);
+                    result[key] = from_msgpack_internal(v, idx);
+                }
+                return result;
+            }
+            else if (v[current_idx] <= 0x9f) // fixarray
+            {
+                basic_json result = value_t::array;
+                const size_t len = v[current_idx] & 0x0f;
+                for (size_t i = 0; i < len; ++i)
+                {
+                    result.push_back(from_msgpack_internal(v, idx));
+                }
+                return result;
+            }
+            else // fixstr
+            {
+                const size_t len = v[current_idx] & 0x1f;
+                const size_t offset = current_idx + 1;
+                idx += len; // skip content bytes
+                check_length(v.size(), len, offset);
+                return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+            }
+        }
+        else if (v[current_idx] >= 0xe0) // negative fixint
+        {
+            return static_cast<int8_t>(v[current_idx]);
+        }
+        else
+        {
+            switch (v[current_idx])
+            {
+                case 0xc0: // nil
+                {
+                    return value_t::null;
+                }
+
+                case 0xc2: // false
+                {
+                    return false;
+                }
+
+                case 0xc3: // true
+                {
+                    return true;
+                }
+
+                case 0xca: // float 32
+                {
+                    // copy bytes in reverse order into the double variable
+                    float res;
+                    for (size_t byte = 0; byte < sizeof(float); ++byte)
+                    {
+                        reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte);
+                    }
+                    idx += sizeof(float); // skip content bytes
+                    return res;
+                }
+
+                case 0xcb: // float 64
+                {
+                    // copy bytes in reverse order into the double variable
+                    double res;
+                    for (size_t byte = 0; byte < sizeof(double); ++byte)
+                    {
+                        reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte);
+                    }
+                    idx += sizeof(double); // skip content bytes
+                    return res;
+                }
+
+                case 0xcc: // uint 8
+                {
+                    idx += 1; // skip content byte
+                    return get_from_vector<uint8_t>(v, current_idx);
+                }
+
+                case 0xcd: // uint 16
+                {
+                    idx += 2; // skip 2 content bytes
+                    return get_from_vector<uint16_t>(v, current_idx);
+                }
+
+                case 0xce: // uint 32
+                {
+                    idx += 4; // skip 4 content bytes
+                    return get_from_vector<uint32_t>(v, current_idx);
+                }
+
+                case 0xcf: // uint 64
+                {
+                    idx += 8; // skip 8 content bytes
+                    return get_from_vector<uint64_t>(v, current_idx);
+                }
+
+                case 0xd0: // int 8
+                {
+                    idx += 1; // skip content byte
+                    return get_from_vector<int8_t>(v, current_idx);
+                }
+
+                case 0xd1: // int 16
+                {
+                    idx += 2; // skip 2 content bytes
+                    return get_from_vector<int16_t>(v, current_idx);
+                }
+
+                case 0xd2: // int 32
+                {
+                    idx += 4; // skip 4 content bytes
+                    return get_from_vector<int32_t>(v, current_idx);
+                }
+
+                case 0xd3: // int 64
+                {
+                    idx += 8; // skip 8 content bytes
+                    return get_from_vector<int64_t>(v, current_idx);
+                }
+
+                case 0xd9: // str 8
+                {
+                    const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
+                    const size_t offset = current_idx + 2;
+                    idx += len + 1; // skip size byte + content bytes
+                    check_length(v.size(), len, offset);
+                    return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+                }
+
+                case 0xda: // str 16
+                {
+                    const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+                    const size_t offset = current_idx + 3;
+                    idx += len + 2; // skip 2 size bytes + content bytes
+                    check_length(v.size(), len, offset);
+                    return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+                }
+
+                case 0xdb: // str 32
+                {
+                    const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+                    const size_t offset = current_idx + 5;
+                    idx += len + 4; // skip 4 size bytes + content bytes
+                    check_length(v.size(), len, offset);
+                    return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+                }
+
+                case 0xdc: // array 16
+                {
+                    basic_json result = value_t::array;
+                    const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+                    idx += 2; // skip 2 size bytes
+                    for (size_t i = 0; i < len; ++i)
+                    {
+                        result.push_back(from_msgpack_internal(v, idx));
+                    }
+                    return result;
+                }
+
+                case 0xdd: // array 32
+                {
+                    basic_json result = value_t::array;
+                    const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+                    idx += 4; // skip 4 size bytes
+                    for (size_t i = 0; i < len; ++i)
+                    {
+                        result.push_back(from_msgpack_internal(v, idx));
+                    }
+                    return result;
+                }
+
+                case 0xde: // map 16
+                {
+                    basic_json result = value_t::object;
+                    const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+                    idx += 2; // skip 2 size bytes
+                    for (size_t i = 0; i < len; ++i)
+                    {
+                        std::string key = from_msgpack_internal(v, idx);
+                        result[key] = from_msgpack_internal(v, idx);
+                    }
+                    return result;
+                }
+
+                case 0xdf: // map 32
+                {
+                    basic_json result = value_t::object;
+                    const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+                    idx += 4; // skip 4 size bytes
+                    for (size_t i = 0; i < len; ++i)
+                    {
+                        std::string key = from_msgpack_internal(v, idx);
+                        result[key] = from_msgpack_internal(v, idx);
+                    }
+                    return result;
+                }
+
+                default:
+                {
+                    JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))));
+                }
+            }
+        }
+    }
+
+    /*!
+    @brief create a JSON value from a given CBOR vector
+
+    @param[in] v  CBOR serialization
+    @param[in] idx  byte index to start reading from @a v
+
+    @return deserialized JSON value
+
+    @throw std::invalid_argument if unsupported features from CBOR were used in
+    the given vector @a v or if the input is not valid CBOR
+    @throw std::out_of_range if the given vector ends prematurely
+
+    @sa https://tools.ietf.org/html/rfc7049
+    */
+    static basic_json from_cbor_internal(const std::vector<uint8_t>& v, size_t& idx)
+    {
+        // store and increment index
+        const size_t current_idx = idx++;
+
+        switch (v.at(current_idx))
+        {
+            // Integer 0x00..0x17 (0..23)
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0c:
+            case 0x0d:
+            case 0x0e:
+            case 0x0f:
+            case 0x10:
+            case 0x11:
+            case 0x12:
+            case 0x13:
+            case 0x14:
+            case 0x15:
+            case 0x16:
+            case 0x17:
+            {
+                return v[current_idx];
+            }
+
+            case 0x18: // Unsigned integer (one-byte uint8_t follows)
+            {
+                idx += 1; // skip content byte
+                return get_from_vector<uint8_t>(v, current_idx);
+            }
+
+            case 0x19: // Unsigned integer (two-byte uint16_t follows)
+            {
+                idx += 2; // skip 2 content bytes
+                return get_from_vector<uint16_t>(v, current_idx);
+            }
+
+            case 0x1a: // Unsigned integer (four-byte uint32_t follows)
+            {
+                idx += 4; // skip 4 content bytes
+                return get_from_vector<uint32_t>(v, current_idx);
+            }
+
+            case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
+            {
+                idx += 8; // skip 8 content bytes
+                return get_from_vector<uint64_t>(v, current_idx);
+            }
+
+            // Negative integer -1-0x00..-1-0x17 (-1..-24)
+            case 0x20:
+            case 0x21:
+            case 0x22:
+            case 0x23:
+            case 0x24:
+            case 0x25:
+            case 0x26:
+            case 0x27:
+            case 0x28:
+            case 0x29:
+            case 0x2a:
+            case 0x2b:
+            case 0x2c:
+            case 0x2d:
+            case 0x2e:
+            case 0x2f:
+            case 0x30:
+            case 0x31:
+            case 0x32:
+            case 0x33:
+            case 0x34:
+            case 0x35:
+            case 0x36:
+            case 0x37:
+            {
+                return static_cast<int8_t>(0x20 - 1 - v[current_idx]);
+            }
+
+            case 0x38: // Negative integer (one-byte uint8_t follows)
+            {
+                idx += 1; // skip content byte
+                // must be uint8_t !
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint8_t>(v, current_idx);
+            }
+
+            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
+            {
+                idx += 2; // skip 2 content bytes
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint16_t>(v, current_idx);
+            }
+
+            case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
+            {
+                idx += 4; // skip 4 content bytes
+                return static_cast<number_integer_t>(-1) - get_from_vector<uint32_t>(v, current_idx);
+            }
+
+            case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
+            {
+                idx += 8; // skip 8 content bytes
+                return static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(get_from_vector<uint64_t>(v, current_idx));
+            }
+
+            // UTF-8 string (0x00..0x17 bytes follow)
+            case 0x60:
+            case 0x61:
+            case 0x62:
+            case 0x63:
+            case 0x64:
+            case 0x65:
+            case 0x66:
+            case 0x67:
+            case 0x68:
+            case 0x69:
+            case 0x6a:
+            case 0x6b:
+            case 0x6c:
+            case 0x6d:
+            case 0x6e:
+            case 0x6f:
+            case 0x70:
+            case 0x71:
+            case 0x72:
+            case 0x73:
+            case 0x74:
+            case 0x75:
+            case 0x76:
+            case 0x77:
+            {
+                const auto len = static_cast<size_t>(v[current_idx] - 0x60);
+                const size_t offset = current_idx + 1;
+                idx += len; // skip content bytes
+                check_length(v.size(), len, offset);
+                return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+            }
+
+            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+            {
+                const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
+                const size_t offset = current_idx + 2;
+                idx += len + 1; // skip size byte + content bytes
+                check_length(v.size(), len, offset);
+                return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+            }
+
+            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+            {
+                const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+                const size_t offset = current_idx + 3;
+                idx += len + 2; // skip 2 size bytes + content bytes
+                check_length(v.size(), len, offset);
+                return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+            }
+
+            case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
+            {
+                const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+                const size_t offset = current_idx + 5;
+                idx += len + 4; // skip 4 size bytes + content bytes
+                check_length(v.size(), len, offset);
+                return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+            }
+
+            case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
+            {
+                const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
+                const size_t offset = current_idx + 9;
+                idx += len + 8; // skip 8 size bytes + content bytes
+                check_length(v.size(), len, offset);
+                return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+            }
+
+            case 0x7f: // UTF-8 string (indefinite length)
+            {
+                std::string result;
+                while (v.at(idx) != 0xff)
+                {
+                    string_t s = from_cbor_internal(v, idx);
+                    result += s;
+                }
+                // skip break byte (0xFF)
+                idx += 1;
+                return result;
+            }
+
+            // array (0x00..0x17 data items follow)
+            case 0x80:
+            case 0x81:
+            case 0x82:
+            case 0x83:
+            case 0x84:
+            case 0x85:
+            case 0x86:
+            case 0x87:
+            case 0x88:
+            case 0x89:
+            case 0x8a:
+            case 0x8b:
+            case 0x8c:
+            case 0x8d:
+            case 0x8e:
+            case 0x8f:
+            case 0x90:
+            case 0x91:
+            case 0x92:
+            case 0x93:
+            case 0x94:
+            case 0x95:
+            case 0x96:
+            case 0x97:
+            {
+                basic_json result = value_t::array;
+                const auto len = static_cast<size_t>(v[current_idx] - 0x80);
+                for (size_t i = 0; i < len; ++i)
+                {
+                    result.push_back(from_cbor_internal(v, idx));
+                }
+                return result;
+            }
+
+            case 0x98: // array (one-byte uint8_t for n follows)
+            {
+                basic_json result = value_t::array;
+                const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
+                idx += 1; // skip 1 size byte
+                for (size_t i = 0; i < len; ++i)
+                {
+                    result.push_back(from_cbor_internal(v, idx));
+                }
+                return result;
+            }
+
+            case 0x99: // array (two-byte uint16_t for n follow)
+            {
+                basic_json result = value_t::array;
+                const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+                idx += 2; // skip 4 size bytes
+                for (size_t i = 0; i < len; ++i)
+                {
+                    result.push_back(from_cbor_internal(v, idx));
+                }
+                return result;
+            }
+
+            case 0x9a: // array (four-byte uint32_t for n follow)
+            {
+                basic_json result = value_t::array;
+                const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+                idx += 4; // skip 4 size bytes
+                for (size_t i = 0; i < len; ++i)
+                {
+                    result.push_back(from_cbor_internal(v, idx));
+                }
+                return result;
+            }
+
+            case 0x9b: // array (eight-byte uint64_t for n follow)
+            {
+                basic_json result = value_t::array;
+                const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
+                idx += 8; // skip 8 size bytes
+                for (size_t i = 0; i < len; ++i)
+                {
+                    result.push_back(from_cbor_internal(v, idx));
+                }
+                return result;
+            }
+
+            case 0x9f: // array (indefinite length)
+            {
+                basic_json result = value_t::array;
+                while (v.at(idx) != 0xff)
+                {
+                    result.push_back(from_cbor_internal(v, idx));
+                }
+                // skip break byte (0xFF)
+                idx += 1;
+                return result;
+            }
+
+            // map (0x00..0x17 pairs of data items follow)
+            case 0xa0:
+            case 0xa1:
+            case 0xa2:
+            case 0xa3:
+            case 0xa4:
+            case 0xa5:
+            case 0xa6:
+            case 0xa7:
+            case 0xa8:
+            case 0xa9:
+            case 0xaa:
+            case 0xab:
+            case 0xac:
+            case 0xad:
+            case 0xae:
+            case 0xaf:
+            case 0xb0:
+            case 0xb1:
+            case 0xb2:
+            case 0xb3:
+            case 0xb4:
+            case 0xb5:
+            case 0xb6:
+            case 0xb7:
+            {
+                basic_json result = value_t::object;
+                const auto len = static_cast<size_t>(v[current_idx] - 0xa0);
+                for (size_t i = 0; i < len; ++i)
+                {
+                    std::string key = from_cbor_internal(v, idx);
+                    result[key] = from_cbor_internal(v, idx);
+                }
+                return result;
+            }
+
+            case 0xb8: // map (one-byte uint8_t for n follows)
+            {
+                basic_json result = value_t::object;
+                const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
+                idx += 1; // skip 1 size byte
+                for (size_t i = 0; i < len; ++i)
+                {
+                    std::string key = from_cbor_internal(v, idx);
+                    result[key] = from_cbor_internal(v, idx);
+                }
+                return result;
+            }
+
+            case 0xb9: // map (two-byte uint16_t for n follow)
+            {
+                basic_json result = value_t::object;
+                const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+                idx += 2; // skip 2 size bytes
+                for (size_t i = 0; i < len; ++i)
+                {
+                    std::string key = from_cbor_internal(v, idx);
+                    result[key] = from_cbor_internal(v, idx);
+                }
+                return result;
+            }
+
+            case 0xba: // map (four-byte uint32_t for n follow)
+            {
+                basic_json result = value_t::object;
+                const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+                idx += 4; // skip 4 size bytes
+                for (size_t i = 0; i < len; ++i)
+                {
+                    std::string key = from_cbor_internal(v, idx);
+                    result[key] = from_cbor_internal(v, idx);
+                }
+                return result;
+            }
+
+            case 0xbb: // map (eight-byte uint64_t for n follow)
+            {
+                basic_json result = value_t::object;
+                const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
+                idx += 8; // skip 8 size bytes
+                for (size_t i = 0; i < len; ++i)
+                {
+                    std::string key = from_cbor_internal(v, idx);
+                    result[key] = from_cbor_internal(v, idx);
+                }
+                return result;
+            }
+
+            case 0xbf: // map (indefinite length)
+            {
+                basic_json result = value_t::object;
+                while (v.at(idx) != 0xff)
+                {
+                    std::string key = from_cbor_internal(v, idx);
+                    result[key] = from_cbor_internal(v, idx);
+                }
+                // skip break byte (0xFF)
+                idx += 1;
+                return result;
+            }
+
+            case 0xf4: // false
+            {
+                return false;
+            }
+
+            case 0xf5: // true
+            {
+                return true;
+            }
+
+            case 0xf6: // null
+            {
+                return value_t::null;
+            }
+
+            case 0xf9: // Half-Precision Float (two-byte IEEE 754)
+            {
+                idx += 2; // skip two content bytes
+
+                // code from RFC 7049, Appendix D, Figure 3:
+                // As half-precision floating-point numbers were only added to
+                // IEEE 754 in 2008, today's programming platforms often still
+                // only have limited support for them. It is very easy to
+                // include at least decoding support for them even without such
+                // support. An example of a small decoder for half-precision
+                // floating-point numbers in the C language is shown in Fig. 3.
+                const int half = (v.at(current_idx + 1) << 8) + v.at(current_idx + 2);
+                const int exp = (half >> 10) & 0x1f;
+                const int mant = half & 0x3ff;
+                double val;
+                if (exp == 0)
+                {
+                    val = std::ldexp(mant, -24);
+                }
+                else if (exp != 31)
+                {
+                    val = std::ldexp(mant + 1024, exp - 25);
+                }
+                else
+                {
+                    val = mant == 0 ? INFINITY : NAN;
+                }
+                return (half & 0x8000) != 0 ? -val : val;
+            }
+
+            case 0xfa: // Single-Precision Float (four-byte IEEE 754)
+            {
+                // copy bytes in reverse order into the float variable
+                float res;
+                for (size_t byte = 0; byte < sizeof(float); ++byte)
+                {
+                    reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte);
+                }
+                idx += sizeof(float); // skip content bytes
+                return res;
+            }
+
+            case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
+            {
+                // copy bytes in reverse order into the double variable
+                double res;
+                for (size_t byte = 0; byte < sizeof(double); ++byte)
+                {
+                    reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte);
+                }
+                idx += sizeof(double); // skip content bytes
+                return res;
+            }
+
+            default: // anything else (0xFF is handled inside the other types)
+            {
+                JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))));
+            }
+        }
+    }
+
+  public:
+    /*!
+    @brief create a MessagePack serialization of a given JSON value
+
+    Serializes a given JSON value @a j to a byte vector using the MessagePack
+    serialization format. MessagePack is a binary serialization format which
+    aims to be more compact than JSON itself, yet more efficient to parse.
+
+    @param[in] j  JSON value to serialize
+    @return MessagePack serialization as byte vector
+
+    @complexity Linear in the size of the JSON value @a j.
+
+    @liveexample{The example shows the serialization of a JSON value to a byte
+    vector in MessagePack format.,to_msgpack}
+
+    @sa http://msgpack.org
+    @sa @ref from_msgpack(const std::vector<uint8_t>&) for the analogous
+        deserialization
+    @sa @ref to_cbor(const basic_json& for the related CBOR format
+    */
+    static std::vector<uint8_t> to_msgpack(const basic_json& j)
+    {
+        std::vector<uint8_t> result;
+        to_msgpack_internal(j, result);
+        return result;
+    }
+
+    /*!
+    @brief create a JSON value from a byte vector in MessagePack format
+
+    Deserializes a given byte vector @a v to a JSON value using the MessagePack
+    serialization format.
+
+    @param[in] v  a byte vector in MessagePack format
+    @return deserialized JSON value
+
+    @throw std::invalid_argument if unsupported features from MessagePack were
+    used in the given vector @a v or if the input is not valid MessagePack
+    @throw std::out_of_range if the given vector ends prematurely
+
+    @complexity Linear in the size of the byte vector @a v.
+
+    @liveexample{The example shows the deserialization of a byte vector in
+    MessagePack format to a JSON value.,from_msgpack}
+
+    @sa http://msgpack.org
+    @sa @ref to_msgpack(const basic_json&) for the analogous serialization
+    @sa @ref from_cbor(const std::vector<uint8_t>&) for the related CBOR format
+    */
+    static basic_json from_msgpack(const std::vector<uint8_t>& v)
+    {
+        size_t i = 0;
+        return from_msgpack_internal(v, i);
+    }
+
+    /*!
+    @brief create a MessagePack serialization of a given JSON value
+
+    Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
+    Binary Object Representation) serialization format. CBOR is a binary
+    serialization format which aims to be more compact than JSON itself, yet
+    more efficient to parse.
+
+    @param[in] j  JSON value to serialize
+    @return MessagePack serialization as byte vector
+
+    @complexity Linear in the size of the JSON value @a j.
+
+    @liveexample{The example shows the serialization of a JSON value to a byte
+    vector in CBOR format.,to_cbor}
+
+    @sa http://cbor.io
+    @sa @ref from_cbor(const std::vector<uint8_t>&) for the analogous
+        deserialization
+    @sa @ref to_msgpack(const basic_json& for the related MessagePack format
+    */
+    static std::vector<uint8_t> to_cbor(const basic_json& j)
+    {
+        std::vector<uint8_t> result;
+        to_cbor_internal(j, result);
+        return result;
+    }
+
+    /*!
+    @brief create a JSON value from a byte vector in CBOR format
+
+    Deserializes a given byte vector @a v to a JSON value using the CBOR
+    (Concise Binary Object Representation) serialization format.
+
+    @param[in] v  a byte vector in CBOR format
+    @return deserialized JSON value
+
+    @throw std::invalid_argument if unsupported features from CBOR were used in
+    the given vector @a v or if the input is not valid MessagePack
+    @throw std::out_of_range if the given vector ends prematurely
+
+    @complexity Linear in the size of the byte vector @a v.
+
+    @liveexample{The example shows the deserialization of a byte vector in CBOR
+    format to a JSON value.,from_cbor}
+
+    @sa http://cbor.io
+    @sa @ref to_cbor(const basic_json&) for the analogous serialization
+    @sa @ref from_msgpack(const std::vector<uint8_t>&) for the related
+        MessagePack format
+    */
+    static basic_json from_cbor(const std::vector<uint8_t>& v)
+    {
+        size_t i = 0;
+        return from_cbor_internal(v, i);
+    }
+
+    /// @}
+
+  private:
+    ///////////////////////////
+    // convenience functions //
+    ///////////////////////////
+
+    /*!
+    @brief return the type as string
+
+    Returns the type name as string to be used in error messages - usually to
+    indicate that a function was called on a wrong JSON type.
+
+    @return basically a string representation of a the @a m_type member
+
+    @complexity Constant.
+
+    @since version 1.0.0
+    */
+    std::string type_name() const
+    {
+        switch (m_type)
+        {
+            case value_t::null:
+                return "null";
+            case value_t::object:
+                return "object";
+            case value_t::array:
+                return "array";
+            case value_t::string:
+                return "string";
+            case value_t::boolean:
+                return "boolean";
+            case value_t::discarded:
+                return "discarded";
+            default:
+                return "number";
+        }
+    }
+
+    /*!
+    @brief calculates the extra space to escape a JSON string
+
+    @param[in] s  the string to escape
+    @return the number of characters required to escape string @a s
+
+    @complexity Linear in the length of string @a s.
+    */
+    static std::size_t extra_space(const string_t& s) noexcept
+    {
+        return std::accumulate(s.begin(), s.end(), size_t{},
+                               [](size_t res, typename string_t::value_type c)
+        {
+            switch (c)
+            {
+                case '"':
+                case '\\':
+                case '\b':
+                case '\f':
+                case '\n':
+                case '\r':
+                case '\t':
+                {
+                    // from c (1 byte) to \x (2 bytes)
+                    return res + 1;
+                }
+
+                default:
+                {
+                    if (c >= 0x00 and c <= 0x1f)
+                    {
+                        // from c (1 byte) to \uxxxx (6 bytes)
+                        return res + 5;
+                    }
+
+                    return res;
+                }
+            }
+        });
+    }
+
+    /*!
+    @brief escape a string
+
+    Escape a string by replacing certain special characters by a sequence of
+    an escape character (backslash) and another character and other control
+    characters by a sequence of "\u" followed by a four-digit hex
+    representation.
+
+    @param[in] s  the string to escape
+    @return  the escaped string
+
+    @complexity Linear in the length of string @a s.
+    */
+    static string_t escape_string(const string_t& s)
+    {
+        const auto space = extra_space(s);
+        if (space == 0)
+        {
+            return s;
+        }
+
+        // create a result string of necessary size
+        string_t result(s.size() + space, '\\');
+        std::size_t pos = 0;
+
+        for (const auto& c : s)
+        {
+            switch (c)
+            {
+                // quotation mark (0x22)
+                case '"':
+                {
+                    result[pos + 1] = '"';
+                    pos += 2;
+                    break;
+                }
+
+                // reverse solidus (0x5c)
+                case '\\':
+                {
+                    // nothing to change
+                    pos += 2;
+                    break;
+                }
+
+                // backspace (0x08)
+                case '\b':
+                {
+                    result[pos + 1] = 'b';
+                    pos += 2;
+                    break;
+                }
+
+                // formfeed (0x0c)
+                case '\f':
+                {
+                    result[pos + 1] = 'f';
+                    pos += 2;
+                    break;
+                }
+
+                // newline (0x0a)
+                case '\n':
+                {
+                    result[pos + 1] = 'n';
+                    pos += 2;
+                    break;
+                }
+
+                // carriage return (0x0d)
+                case '\r':
+                {
+                    result[pos + 1] = 'r';
+                    pos += 2;
+                    break;
+                }
+
+                // horizontal tab (0x09)
+                case '\t':
+                {
+                    result[pos + 1] = 't';
+                    pos += 2;
+                    break;
+                }
+
+                default:
+                {
+                    if (c >= 0x00 and c <= 0x1f)
+                    {
+                        // convert a number 0..15 to its hex representation
+                        // (0..f)
+                        static const char hexify[16] =
+                        {
+                            '0', '1', '2', '3', '4', '5', '6', '7',
+                            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+                        };
+
+                        // print character c as \uxxxx
+                        for (const char m :
+                    { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]
+                        })
+                        {
+                            result[++pos] = m;
+                        }
+
+                        ++pos;
+                    }
+                    else
+                    {
+                        // all other characters are added as-is
+                        result[pos++] = c;
+                    }
+                    break;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /*!
+    @brief internal implementation of the serialization function
+
+    This function is called by the public member function dump and organizes
+    the serialization internally. The indentation level is propagated as
+    additional parameter. In case of arrays and objects, the function is
+    called recursively. Note that
+
+    - strings and object keys are escaped using `escape_string()`
+    - integer numbers are converted implicitly via `operator<<`
+    - floating-point numbers are converted to a string using `"%g"` format
+
+    @param[out] o              stream to write to
+    @param[in] pretty_print    whether the output shall be pretty-printed
+    @param[in] indent_step     the indent level
+    @param[in] current_indent  the current indent level (only used internally)
+    */
+    void dump(std::ostream& o,
+              const bool pretty_print,
+              const unsigned int indent_step,
+              const unsigned int current_indent = 0) const
+    {
+        // variable to hold indentation for recursive calls
+        unsigned int new_indent = current_indent;
+
+        switch (m_type)
+        {
+            case value_t::object:
+            {
+                if (m_value.object->empty())
+                {
+                    o << "{}";
+                    return;
+                }
+
+                o << "{";
+
+                // increase indentation
+                if (pretty_print)
+                {
+                    new_indent += indent_step;
+                    o << "\n";
+                }
+
+                for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i)
+                {
+                    if (i != m_value.object->cbegin())
+                    {
+                        o << (pretty_print ? ",\n" : ",");
+                    }
+                    o << string_t(new_indent, ' ') << "\""
+                      << escape_string(i->first) << "\":"
+                      << (pretty_print ? " " : "");
+                    i->second.dump(o, pretty_print, indent_step, new_indent);
+                }
+
+                // decrease indentation
+                if (pretty_print)
+                {
+                    new_indent -= indent_step;
+                    o << "\n";
+                }
+
+                o << string_t(new_indent, ' ') + "}";
+                return;
+            }
+
+            case value_t::array:
+            {
+                if (m_value.array->empty())
+                {
+                    o << "[]";
+                    return;
+                }
+
+                o << "[";
+
+                // increase indentation
+                if (pretty_print)
+                {
+                    new_indent += indent_step;
+                    o << "\n";
+                }
+
+                for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i)
+                {
+                    if (i != m_value.array->cbegin())
+                    {
+                        o << (pretty_print ? ",\n" : ",");
+                    }
+                    o << string_t(new_indent, ' ');
+                    i->dump(o, pretty_print, indent_step, new_indent);
+                }
+
+                // decrease indentation
+                if (pretty_print)
+                {
+                    new_indent -= indent_step;
+                    o << "\n";
+                }
+
+                o << string_t(new_indent, ' ') << "]";
+                return;
+            }
+
+            case value_t::string:
+            {
+                o << string_t("\"") << escape_string(*m_value.string) << "\"";
+                return;
+            }
+
+            case value_t::boolean:
+            {
+                o << (m_value.boolean ? "true" : "false");
+                return;
+            }
+
+            case value_t::number_integer:
+            {
+                o << m_value.number_integer;
+                return;
+            }
+
+            case value_t::number_unsigned:
+            {
+                o << m_value.number_unsigned;
+                return;
+            }
+
+            case value_t::number_float:
+            {
+                if (m_value.number_float == 0)
+                {
+                    // special case for zero to get "0.0"/"-0.0"
+                    o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0");
+                }
+                else
+                {
+                    o << m_value.number_float;
+                }
+                return;
+            }
+
+            case value_t::discarded:
+            {
+                o << "<discarded>";
+                return;
+            }
+
+            case value_t::null:
+            {
+                o << "null";
+                return;
+            }
+        }
+    }
+
+  private:
+    //////////////////////
+    // member variables //
+    //////////////////////
+
+    /// the type of the current element
+    value_t m_type = value_t::null;
+
+    /// the value of the current element
+    json_value m_value = {};
+
+
+  private:
+    ///////////////
+    // iterators //
+    ///////////////
+
+    /*!
+    @brief an iterator for primitive JSON types
+
+    This class models an iterator for primitive JSON types (boolean, number,
+    string). It's only purpose is to allow the iterator/const_iterator classes
+    to "iterate" over primitive values. Internally, the iterator is modeled by
+    a `difference_type` variable. Value begin_value (`0`) models the begin,
+    end_value (`1`) models past the end.
+    */
+    class primitive_iterator_t
+    {
+      public:
+        /// set iterator to a defined beginning
+        void set_begin() noexcept
+        {
+            m_it = begin_value;
+        }
+
+        /// set iterator to a defined past the end
+        void set_end() noexcept
+        {
+            m_it = end_value;
+        }
+
+        /// return whether the iterator can be dereferenced
+        constexpr bool is_begin() const noexcept
+        {
+            return (m_it == begin_value);
+        }
+
+        /// return whether the iterator is at end
+        constexpr bool is_end() const noexcept
+        {
+            return (m_it == end_value);
+        }
+
+        /// return reference to the value to change and compare
+        operator difference_type& () noexcept
+        {
+            return m_it;
+        }
+
+        /// return value to compare
+        constexpr operator difference_type () const noexcept
+        {
+            return m_it;
+        }
+
+      private:
+        static constexpr difference_type begin_value = 0;
+        static constexpr difference_type end_value = begin_value + 1;
+
+        /// iterator as signed integer type
+        difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min();
+    };
+
+    /*!
+    @brief an iterator value
+
+    @note This structure could easily be a union, but MSVC currently does not
+    allow unions members with complex constructors, see
+    https://github.com/nlohmann/json/pull/105.
+    */
+    struct internal_iterator
+    {
+        /// iterator for JSON objects
+        typename object_t::iterator object_iterator;
+        /// iterator for JSON arrays
+        typename array_t::iterator array_iterator;
+        /// generic iterator for all other types
+        primitive_iterator_t primitive_iterator;
+
+        /// create an uninitialized internal_iterator
+        internal_iterator() noexcept
+            : object_iterator(), array_iterator(), primitive_iterator()
+        {}
+    };
+
+    /// proxy class for the iterator_wrapper functions
+    template<typename IteratorType>
+    class iteration_proxy
+    {
+      private:
+        /// helper class for iteration
+        class iteration_proxy_internal
+        {
+          private:
+            /// the iterator
+            IteratorType anchor;
+            /// an index for arrays (used to create key names)
+            size_t array_index = 0;
+
+          public:
+            explicit iteration_proxy_internal(IteratorType it) noexcept
+                : anchor(it)
+            {}
+
+            /// dereference operator (needed for range-based for)
+            iteration_proxy_internal& operator*()
+            {
+                return *this;
+            }
+
+            /// increment operator (needed for range-based for)
+            iteration_proxy_internal& operator++()
+            {
+                ++anchor;
+                ++array_index;
+
+                return *this;
+            }
+
+            /// inequality operator (needed for range-based for)
+            bool operator!= (const iteration_proxy_internal& o) const
+            {
+                return anchor != o.anchor;
+            }
+
+            /// return key of the iterator
+            typename basic_json::string_t key() const
+            {
+                assert(anchor.m_object != nullptr);
+
+                switch (anchor.m_object->type())
+                {
+                    // use integer array index as key
+                    case value_t::array:
+                    {
+                        return std::to_string(array_index);
+                    }
+
+                    // use key from the object
+                    case value_t::object:
+                    {
+                        return anchor.key();
+                    }
+
+                    // use an empty key for all primitive types
+                    default:
+                    {
+                        return "";
+                    }
+                }
+            }
+
+            /// return value of the iterator
+            typename IteratorType::reference value() const
+            {
+                return anchor.value();
+            }
+        };
+
+        /// the container to iterate
+        typename IteratorType::reference container;
+
+      public:
+        /// construct iteration proxy from a container
+        explicit iteration_proxy(typename IteratorType::reference cont)
+            : container(cont)
+        {}
+
+        /// return iterator begin (needed for range-based for)
+        iteration_proxy_internal begin() noexcept
+        {
+            return iteration_proxy_internal(container.begin());
+        }
+
+        /// return iterator end (needed for range-based for)
+        iteration_proxy_internal end() noexcept
+        {
+            return iteration_proxy_internal(container.end());
+        }
+    };
+
+  public:
+    /*!
+    @brief a template for a random access iterator for the @ref basic_json class
+
+    This class implements a both iterators (iterator and const_iterator) for the
+    @ref basic_json class.
+
+    @note An iterator is called *initialized* when a pointer to a JSON value
+          has been set (e.g., by a constructor or a copy assignment). If the
+          iterator is default-constructed, it is *uninitialized* and most
+          methods are undefined. **The library uses assertions to detect calls
+          on uninitialized iterators.**
+
+    @requirement The class satisfies the following concept requirements:
+    - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
+      The iterator that can be moved to point (forward and backward) to any
+      element in constant time.
+
+    @since version 1.0.0, simplified in version 2.0.9
+    */
+    template<typename U>
+    class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
+    {
+        /// allow basic_json to access private members
+        friend class basic_json;
+
+        // make sure U is basic_json or const basic_json
+        static_assert(std::is_same<U, basic_json>::value
+                      or std::is_same<U, const basic_json>::value,
+                      "iter_impl only accepts (const) basic_json");
+
+      public:
+        /// the type of the values when the iterator is dereferenced
+        using value_type = typename basic_json::value_type;
+        /// a type to represent differences between iterators
+        using difference_type = typename basic_json::difference_type;
+        /// defines a pointer to the type iterated over (value_type)
+        using pointer = typename std::conditional<std::is_const<U>::value,
+              typename basic_json::const_pointer,
+              typename basic_json::pointer>::type;
+        /// defines a reference to the type iterated over (value_type)
+        using reference = typename std::conditional<std::is_const<U>::value,
+              typename basic_json::const_reference,
+              typename basic_json::reference>::type;
+        /// the category of the iterator
+        using iterator_category = std::bidirectional_iterator_tag;
+
+        /// default constructor
+        iter_impl() = default;
+
+        /*!
+        @brief constructor for a given JSON instance
+        @param[in] object  pointer to a JSON object for this iterator
+        @pre object != nullptr
+        @post The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        explicit iter_impl(pointer object) noexcept
+            : m_object(object)
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    m_it.object_iterator = typename object_t::iterator();
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    m_it.array_iterator = typename array_t::iterator();
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator = primitive_iterator_t();
+                    break;
+                }
+            }
+        }
+
+        /*
+        Use operator `const_iterator` instead of `const_iterator(const iterator&
+        other) noexcept` to avoid two class definitions for @ref iterator and
+        @ref const_iterator.
+
+        This function is only called if this class is an @ref iterator. If this
+        class is a @ref const_iterator this function is not called.
+        */
+        operator const_iterator() const
+        {
+            const_iterator ret;
+
+            if (m_object)
+            {
+                ret.m_object = m_object;
+                ret.m_it = m_it;
+            }
+
+            return ret;
+        }
+
+        /*!
+        @brief copy constructor
+        @param[in] other  iterator to copy from
+        @note It is not checked whether @a other is initialized.
+        */
+        iter_impl(const iter_impl& other) noexcept
+            : m_object(other.m_object), m_it(other.m_it)
+        {}
+
+        /*!
+        @brief copy assignment
+        @param[in,out] other  iterator to copy from
+        @note It is not checked whether @a other is initialized.
+        */
+        iter_impl& operator=(iter_impl other) noexcept(
+            std::is_nothrow_move_constructible<pointer>::value and
+            std::is_nothrow_move_assignable<pointer>::value and
+            std::is_nothrow_move_constructible<internal_iterator>::value and
+            std::is_nothrow_move_assignable<internal_iterator>::value
+        )
+        {
+            std::swap(m_object, other.m_object);
+            std::swap(m_it, other.m_it);
+            return *this;
+        }
+
+      private:
+        /*!
+        @brief set the iterator to the first value
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        void set_begin() noexcept
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    m_it.object_iterator = m_object->m_value.object->begin();
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    m_it.array_iterator = m_object->m_value.array->begin();
+                    break;
+                }
+
+                case basic_json::value_t::null:
+                {
+                    // set to end so begin()==end() is true: null is empty
+                    m_it.primitive_iterator.set_end();
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator.set_begin();
+                    break;
+                }
+            }
+        }
+
+        /*!
+        @brief set the iterator past the last value
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        void set_end() noexcept
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    m_it.object_iterator = m_object->m_value.object->end();
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    m_it.array_iterator = m_object->m_value.array->end();
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator.set_end();
+                    break;
+                }
+            }
+        }
+
+      public:
+        /*!
+        @brief return a reference to the value pointed to by the iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference operator*() const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    assert(m_it.object_iterator != m_object->m_value.object->end());
+                    return m_it.object_iterator->second;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    assert(m_it.array_iterator != m_object->m_value.array->end());
+                    return *m_it.array_iterator;
+                }
+
+                case basic_json::value_t::null:
+                {
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+
+                default:
+                {
+                    if (m_it.primitive_iterator.is_begin())
+                    {
+                        return *m_object;
+                    }
+
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+            }
+        }
+
+        /*!
+        @brief dereference the iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        pointer operator->() const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    assert(m_it.object_iterator != m_object->m_value.object->end());
+                    return &(m_it.object_iterator->second);
+                }
+
+                case basic_json::value_t::array:
+                {
+                    assert(m_it.array_iterator != m_object->m_value.array->end());
+                    return &*m_it.array_iterator;
+                }
+
+                default:
+                {
+                    if (m_it.primitive_iterator.is_begin())
+                    {
+                        return m_object;
+                    }
+
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+            }
+        }
+
+        /*!
+        @brief post-increment (it++)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator++(int)
+        {
+            auto result = *this;
+            ++(*this);
+            return result;
+        }
+
+        /*!
+        @brief pre-increment (++it)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator++()
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    std::advance(m_it.object_iterator, 1);
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, 1);
+                    break;
+                }
+
+                default:
+                {
+                    ++m_it.primitive_iterator;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief post-decrement (it--)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator--(int)
+        {
+            auto result = *this;
+            --(*this);
+            return result;
+        }
+
+        /*!
+        @brief pre-decrement (--it)
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator--()
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    std::advance(m_it.object_iterator, -1);
+                    break;
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, -1);
+                    break;
+                }
+
+                default:
+                {
+                    --m_it.primitive_iterator;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief  comparison: equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator==(const iter_impl& other) const
+        {
+            // if objects are not the same, the comparison is undefined
+            if (m_object != other.m_object)
+            {
+                JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
+            }
+
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    return (m_it.object_iterator == other.m_it.object_iterator);
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return (m_it.array_iterator == other.m_it.array_iterator);
+                }
+
+                default:
+                {
+                    return (m_it.primitive_iterator == other.m_it.primitive_iterator);
+                }
+            }
+        }
+
+        /*!
+        @brief  comparison: not equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator!=(const iter_impl& other) const
+        {
+            return not operator==(other);
+        }
+
+        /*!
+        @brief  comparison: smaller
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator<(const iter_impl& other) const
+        {
+            // if objects are not the same, the comparison is undefined
+            if (m_object != other.m_object)
+            {
+                JSON_THROW(std::domain_error("cannot compare iterators of different containers"));
+            }
+
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot compare order of object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return (m_it.array_iterator < other.m_it.array_iterator);
+                }
+
+                default:
+                {
+                    return (m_it.primitive_iterator < other.m_it.primitive_iterator);
+                }
+            }
+        }
+
+        /*!
+        @brief  comparison: less than or equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator<=(const iter_impl& other) const
+        {
+            return not other.operator < (*this);
+        }
+
+        /*!
+        @brief  comparison: greater than
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator>(const iter_impl& other) const
+        {
+            return not operator<=(other);
+        }
+
+        /*!
+        @brief  comparison: greater than or equal
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        bool operator>=(const iter_impl& other) const
+        {
+            return not operator<(other);
+        }
+
+        /*!
+        @brief  add to iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator+=(difference_type i)
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    std::advance(m_it.array_iterator, i);
+                    break;
+                }
+
+                default:
+                {
+                    m_it.primitive_iterator += i;
+                    break;
+                }
+            }
+
+            return *this;
+        }
+
+        /*!
+        @brief  subtract from iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl& operator-=(difference_type i)
+        {
+            return operator+=(-i);
+        }
+
+        /*!
+        @brief  add to iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator+(difference_type i)
+        {
+            auto result = *this;
+            result += i;
+            return result;
+        }
+
+        /*!
+        @brief  subtract from iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        iter_impl operator-(difference_type i)
+        {
+            auto result = *this;
+            result -= i;
+            return result;
+        }
+
+        /*!
+        @brief  return difference
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        difference_type operator-(const iter_impl& other) const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use offsets with object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return m_it.array_iterator - other.m_it.array_iterator;
+                }
+
+                default:
+                {
+                    return m_it.primitive_iterator - other.m_it.primitive_iterator;
+                }
+            }
+        }
+
+        /*!
+        @brief  access to successor
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference operator[](difference_type n) const
+        {
+            assert(m_object != nullptr);
+
+            switch (m_object->m_type)
+            {
+                case basic_json::value_t::object:
+                {
+                    JSON_THROW(std::domain_error("cannot use operator[] for object iterators"));
+                }
+
+                case basic_json::value_t::array:
+                {
+                    return *std::next(m_it.array_iterator, n);
+                }
+
+                case basic_json::value_t::null:
+                {
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+
+                default:
+                {
+                    if (m_it.primitive_iterator == -n)
+                    {
+                        return *m_object;
+                    }
+
+                    JSON_THROW(std::out_of_range("cannot get value"));
+                }
+            }
+        }
+
+        /*!
+        @brief  return the key of an object iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        typename object_t::key_type key() const
+        {
+            assert(m_object != nullptr);
+
+            if (m_object->is_object())
+            {
+                return m_it.object_iterator->first;
+            }
+
+            JSON_THROW(std::domain_error("cannot use key() for non-object iterators"));
+        }
+
+        /*!
+        @brief  return the value of an iterator
+        @pre The iterator is initialized; i.e. `m_object != nullptr`.
+        */
+        reference value() const
+        {
+            return operator*();
+        }
+
+      private:
+        /// associated JSON instance
+        pointer m_object = nullptr;
+        /// the actual iterator of the associated instance
+        internal_iterator m_it = internal_iterator();
+    };
+
+    /*!
+    @brief a template for a reverse iterator class
+
+    @tparam Base the base iterator type to reverse. Valid types are @ref
+    iterator (to create @ref reverse_iterator) and @ref const_iterator (to
+    create @ref const_reverse_iterator).
+
+    @requirement The class satisfies the following concept requirements:
+    - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
+      The iterator that can be moved to point (forward and backward) to any
+      element in constant time.
+    - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator):
+      It is possible to write to the pointed-to element (only if @a Base is
+      @ref iterator).
+
+    @since version 1.0.0
+    */
+    template<typename Base>
+    class json_reverse_iterator : public std::reverse_iterator<Base>
+    {
+      public:
+        /// shortcut to the reverse iterator adaptor
+        using base_iterator = std::reverse_iterator<Base>;
+        /// the reference type for the pointed-to element
+        using reference = typename Base::reference;
+
+        /// create reverse iterator from iterator
+        json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
+            : base_iterator(it)
+        {}
+
+        /// create reverse iterator from base class
+        json_reverse_iterator(const base_iterator& it) noexcept
+            : base_iterator(it)
+        {}
+
+        /// post-increment (it++)
+        json_reverse_iterator operator++(int)
+        {
+            return base_iterator::operator++(1);
+        }
+
+        /// pre-increment (++it)
+        json_reverse_iterator& operator++()
+        {
+            base_iterator::operator++();
+            return *this;
+        }
+
+        /// post-decrement (it--)
+        json_reverse_iterator operator--(int)
+        {
+            return base_iterator::operator--(1);
+        }
+
+        /// pre-decrement (--it)
+        json_reverse_iterator& operator--()
+        {
+            base_iterator::operator--();
+            return *this;
+        }
+
+        /// add to iterator
+        json_reverse_iterator& operator+=(difference_type i)
+        {
+            base_iterator::operator+=(i);
+            return *this;
+        }
+
+        /// add to iterator
+        json_reverse_iterator operator+(difference_type i) const
+        {
+            auto result = *this;
+            result += i;
+            return result;
+        }
+
+        /// subtract from iterator
+        json_reverse_iterator operator-(difference_type i) const
+        {
+            auto result = *this;
+            result -= i;
+            return result;
+        }
+
+        /// return difference
+        difference_type operator-(const json_reverse_iterator& other) const
+        {
+            return this->base() - other.base();
+        }
+
+        /// access to successor
+        reference operator[](difference_type n) const
+        {
+            return *(this->operator+(n));
+        }
+
+        /// return the key of an object iterator
+        typename object_t::key_type key() const
+        {
+            auto it = --this->base();
+            return it.key();
+        }
+
+        /// return the value of an iterator
+        reference value() const
+        {
+            auto it = --this->base();
+            return it.operator * ();
+        }
+    };
+
+
+  private:
+    //////////////////////
+    // lexer and parser //
+    //////////////////////
+
+    /*!
+    @brief lexical analysis
+
+    This class organizes the lexical analysis during JSON deserialization. The
+    core of it is a scanner generated by [re2c](http://re2c.org) that
+    processes a buffer and recognizes tokens according to RFC 7159.
+    */
+    class lexer
+    {
+      public:
+        /// token types for the parser
+        enum class token_type
+        {
+            uninitialized,   ///< indicating the scanner is uninitialized
+            literal_true,    ///< the `true` literal
+            literal_false,   ///< the `false` literal
+            literal_null,    ///< the `null` literal
+            value_string,    ///< a string -- use get_string() for actual value
+            value_number,    ///< a number -- use get_number() for actual value
+            begin_array,     ///< the character for array begin `[`
+            begin_object,    ///< the character for object begin `{`
+            end_array,       ///< the character for array end `]`
+            end_object,      ///< the character for object end `}`
+            name_separator,  ///< the name separator `:`
+            value_separator, ///< the value separator `,`
+            parse_error,     ///< indicating a parse error
+            end_of_input     ///< indicating the end of the input buffer
+        };
+
+        /// the char type to use in the lexer
+        using lexer_char_t = unsigned char;
+
+        /// a lexer from a buffer with given length
+        lexer(const lexer_char_t* buff, const size_t len) noexcept
+            : m_content(buff)
+        {
+            assert(m_content != nullptr);
+            m_start = m_cursor = m_content;
+            m_limit = m_content + len;
+        }
+
+        /// a lexer from an input stream
+        explicit lexer(std::istream& s)
+            : m_stream(&s), m_line_buffer()
+        {
+            // immediately abort if stream is erroneous
+            if (s.fail())
+            {
+                JSON_THROW(std::invalid_argument("stream error"));
+            }
+
+            // fill buffer
+            fill_line_buffer();
+
+            // skip UTF-8 byte-order mark
+            if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF")
+            {
+                m_line_buffer[0] = ' ';
+                m_line_buffer[1] = ' ';
+                m_line_buffer[2] = ' ';
+            }
+        }
+
+        // switch off unwanted functions (due to pointer members)
+        lexer() = delete;
+        lexer(const lexer&) = delete;
+        lexer operator=(const lexer&) = delete;
+
+        /*!
+        @brief create a string from one or two Unicode code points
+
+        There are two cases: (1) @a codepoint1 is in the Basic Multilingual
+        Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2)
+        @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to
+        represent a code point above U+FFFF.
+
+        @param[in] codepoint1  the code point (can be high surrogate)
+        @param[in] codepoint2  the code point (can be low surrogate or 0)
+
+        @return string representation of the code point; the length of the
+        result string is between 1 and 4 characters.
+
+        @throw std::out_of_range if code point is > 0x10ffff; example: `"code
+        points above 0x10FFFF are invalid"`
+        @throw std::invalid_argument if the low surrogate is invalid; example:
+        `""missing or wrong low surrogate""`
+
+        @complexity Constant.
+
+        @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
+        */
+        static string_t to_unicode(const std::size_t codepoint1,
+                                   const std::size_t codepoint2 = 0)
+        {
+            // calculate the code point from the given code points
+            std::size_t codepoint = codepoint1;
+
+            // check if codepoint1 is a high surrogate
+            if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF)
+            {
+                // check if codepoint2 is a low surrogate
+                if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
+                {
+                    codepoint =
+                        // high surrogate occupies the most significant 22 bits
+                        (codepoint1 << 10)
+                        // low surrogate occupies the least significant 15 bits
+                        + codepoint2
+                        // there is still the 0xD800, 0xDC00 and 0x10000 noise
+                        // in the result so we have to subtract with:
+                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
+                        - 0x35FDC00;
+                }
+                else
+                {
+                    JSON_THROW(std::invalid_argument("missing or wrong low surrogate"));
+                }
+            }
+
+            string_t result;
+
+            if (codepoint < 0x80)
+            {
+                // 1-byte characters: 0xxxxxxx (ASCII)
+                result.append(1, static_cast<typename string_t::value_type>(codepoint));
+            }
+            else if (codepoint <= 0x7ff)
+            {
+                // 2-byte characters: 110xxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else if (codepoint <= 0xffff)
+            {
+                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else if (codepoint <= 0x10ffff)
+            {
+                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+                result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
+                result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
+            }
+            else
+            {
+                JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid"));
+            }
+
+            return result;
+        }
+
+        /// return name of values of type token_type (only used for errors)
+        static std::string token_type_name(const token_type t)
+        {
+            switch (t)
+            {
+                case token_type::uninitialized:
+                    return "<uninitialized>";
+                case token_type::literal_true:
+                    return "true literal";
+                case token_type::literal_false:
+                    return "false literal";
+                case token_type::literal_null:
+                    return "null literal";
+                case token_type::value_string:
+                    return "string literal";
+                case token_type::value_number:
+                    return "number literal";
+                case token_type::begin_array:
+                    return "'['";
+                case token_type::begin_object:
+                    return "'{'";
+                case token_type::end_array:
+                    return "']'";
+                case token_type::end_object:
+                    return "'}'";
+                case token_type::name_separator:
+                    return "':'";
+                case token_type::value_separator:
+                    return "','";
+                case token_type::parse_error:
+                    return "<parse error>";
+                case token_type::end_of_input:
+                    return "end of input";
+                default:
+                {
+                    // catch non-enum values
+                    return "unknown token"; // LCOV_EXCL_LINE
+                }
+            }
+        }
+
+        /*!
+        This function implements a scanner for JSON. It is specified using
+        regular expressions that try to follow RFC 7159 as close as possible.
+        These regular expressions are then translated into a minimized
+        deterministic finite automaton (DFA) by the tool
+        [re2c](http://re2c.org). As a result, the translated code for this
+        function consists of a large block of code with `goto` jumps.
+
+        @return the class of the next token read from the buffer
+
+        @complexity Linear in the length of the input.\n
+
+        Proposition: The loop below will always terminate for finite input.\n
+
+        Proof (by contradiction): Assume a finite input. To loop forever, the
+        loop must never hit code with a `break` statement. The only code
+        snippets without a `break` statement are the continue statements for
+        whitespace and byte-order-marks. To loop forever, the input must be an
+        infinite sequence of whitespace or byte-order-marks. This contradicts
+        the assumption of finite input, q.e.d.
+        */
+        token_type scan()
+        {
+            while (true)
+            {
+                // pointer for backtracking information
+                m_marker = nullptr;
+
+                // remember the begin of the token
+                m_start = m_cursor;
+                assert(m_start != nullptr);
+
+
+                {
+                    lexer_char_t yych;
+                    unsigned int yyaccept = 0;
+                    static const unsigned char yybm[] =
+                    {
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,  32,  32,   0,   0,  32,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        160, 128,   0, 128, 128, 128, 128, 128,
+                        128, 128, 128, 128, 128, 128, 128, 128,
+                        192, 192, 192, 192, 192, 192, 192, 192,
+                        192, 192, 128, 128, 128, 128, 128, 128,
+                        128, 128, 128, 128, 128, 128, 128, 128,
+                        128, 128, 128, 128, 128, 128, 128, 128,
+                        128, 128, 128, 128, 128, 128, 128, 128,
+                        128, 128, 128, 128,   0, 128, 128, 128,
+                        128, 128, 128, 128, 128, 128, 128, 128,
+                        128, 128, 128, 128, 128, 128, 128, 128,
+                        128, 128, 128, 128, 128, 128, 128, 128,
+                        128, 128, 128, 128, 128, 128, 128, 128,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                        0,   0,   0,   0,   0,   0,   0,   0,
+                    };
+                    if ((m_limit - m_cursor) < 5)
+                    {
+                        fill_line_buffer(5);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yybm[0 + yych] & 32)
+                    {
+                        goto basic_json_parser_6;
+                    }
+                    if (yych <= '[')
+                    {
+                        if (yych <= '-')
+                        {
+                            if (yych <= '"')
+                            {
+                                if (yych <= 0x00)
+                                {
+                                    goto basic_json_parser_2;
+                                }
+                                if (yych <= '!')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                goto basic_json_parser_9;
+                            }
+                            else
+                            {
+                                if (yych <= '+')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                if (yych <= ',')
+                                {
+                                    goto basic_json_parser_10;
+                                }
+                                goto basic_json_parser_12;
+                            }
+                        }
+                        else
+                        {
+                            if (yych <= '9')
+                            {
+                                if (yych <= '/')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                if (yych <= '0')
+                                {
+                                    goto basic_json_parser_13;
+                                }
+                                goto basic_json_parser_15;
+                            }
+                            else
+                            {
+                                if (yych <= ':')
+                                {
+                                    goto basic_json_parser_17;
+                                }
+                                if (yych <= 'Z')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                goto basic_json_parser_19;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (yych <= 'n')
+                        {
+                            if (yych <= 'e')
+                            {
+                                if (yych == ']')
+                                {
+                                    goto basic_json_parser_21;
+                                }
+                                goto basic_json_parser_4;
+                            }
+                            else
+                            {
+                                if (yych <= 'f')
+                                {
+                                    goto basic_json_parser_23;
+                                }
+                                if (yych <= 'm')
+                                {
+                                    goto basic_json_parser_4;
+                                }
+                                goto basic_json_parser_24;
+                            }
+                        }
+                        else
+                        {
+                            if (yych <= 'z')
+                            {
+                                if (yych == 't')
+                                {
+                                    goto basic_json_parser_25;
+                                }
+                                goto basic_json_parser_4;
+                            }
+                            else
+                            {
+                                if (yych <= '{')
+                                {
+                                    goto basic_json_parser_26;
+                                }
+                                if (yych == '}')
+                                {
+                                    goto basic_json_parser_28;
+                                }
+                                goto basic_json_parser_4;
+                            }
+                        }
+                    }
+basic_json_parser_2:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::end_of_input;
+                        break;
+                    }
+basic_json_parser_4:
+                    ++m_cursor;
+basic_json_parser_5:
+                    {
+                        last_token_type = token_type::parse_error;
+                        break;
+                    }
+basic_json_parser_6:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yybm[0 + yych] & 32)
+                    {
+                        goto basic_json_parser_6;
+                    }
+                    {
+                        continue;
+                    }
+basic_json_parser_9:
+                    yyaccept = 0;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych <= 0x1F)
+                    {
+                        goto basic_json_parser_5;
+                    }
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_31;
+                    }
+                    if (yych <= 0xC1)
+                    {
+                        goto basic_json_parser_5;
+                    }
+                    if (yych <= 0xF4)
+                    {
+                        goto basic_json_parser_31;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_10:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::value_separator;
+                        break;
+                    }
+basic_json_parser_12:
+                    yych = *++m_cursor;
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_5;
+                    }
+                    if (yych <= '0')
+                    {
+                        goto basic_json_parser_13;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto basic_json_parser_15;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_13:
+                    yyaccept = 1;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych <= 'D')
+                    {
+                        if (yych == '.')
+                        {
+                            goto basic_json_parser_43;
+                        }
+                    }
+                    else
+                    {
+                        if (yych <= 'E')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        if (yych == 'e')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                    }
+basic_json_parser_14:
+                    {
+                        last_token_type = token_type::value_number;
+                        break;
+                    }
+basic_json_parser_15:
+                    yyaccept = 1;
+                    m_marker = ++m_cursor;
+                    if ((m_limit - m_cursor) < 3)
+                    {
+                        fill_line_buffer(3);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yybm[0 + yych] & 64)
+                    {
+                        goto basic_json_parser_15;
+                    }
+                    if (yych <= 'D')
+                    {
+                        if (yych == '.')
+                        {
+                            goto basic_json_parser_43;
+                        }
+                        goto basic_json_parser_14;
+                    }
+                    else
+                    {
+                        if (yych <= 'E')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        if (yych == 'e')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        goto basic_json_parser_14;
+                    }
+basic_json_parser_17:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::name_separator;
+                        break;
+                    }
+basic_json_parser_19:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::begin_array;
+                        break;
+                    }
+basic_json_parser_21:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::end_array;
+                        break;
+                    }
+basic_json_parser_23:
+                    yyaccept = 0;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych == 'a')
+                    {
+                        goto basic_json_parser_45;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_24:
+                    yyaccept = 0;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych == 'u')
+                    {
+                        goto basic_json_parser_46;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_25:
+                    yyaccept = 0;
+                    yych = *(m_marker = ++m_cursor);
+                    if (yych == 'r')
+                    {
+                        goto basic_json_parser_47;
+                    }
+                    goto basic_json_parser_5;
+basic_json_parser_26:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::begin_object;
+                        break;
+                    }
+basic_json_parser_28:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::end_object;
+                        break;
+                    }
+basic_json_parser_30:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+basic_json_parser_31:
+                    if (yybm[0 + yych] & 128)
+                    {
+                        goto basic_json_parser_30;
+                    }
+                    if (yych <= 0xE0)
+                    {
+                        if (yych <= '\\')
+                        {
+                            if (yych <= 0x1F)
+                            {
+                                goto basic_json_parser_32;
+                            }
+                            if (yych <= '"')
+                            {
+                                goto basic_json_parser_33;
+                            }
+                            goto basic_json_parser_35;
+                        }
+                        else
+                        {
+                            if (yych <= 0xC1)
+                            {
+                                goto basic_json_parser_32;
+                            }
+                            if (yych <= 0xDF)
+                            {
+                                goto basic_json_parser_36;
+                            }
+                            goto basic_json_parser_37;
+                        }
+                    }
+                    else
+                    {
+                        if (yych <= 0xEF)
+                        {
+                            if (yych == 0xED)
+                            {
+                                goto basic_json_parser_39;
+                            }
+                            goto basic_json_parser_38;
+                        }
+                        else
+                        {
+                            if (yych <= 0xF0)
+                            {
+                                goto basic_json_parser_40;
+                            }
+                            if (yych <= 0xF3)
+                            {
+                                goto basic_json_parser_41;
+                            }
+                            if (yych <= 0xF4)
+                            {
+                                goto basic_json_parser_42;
+                            }
+                        }
+                    }
+basic_json_parser_32:
+                    m_cursor = m_marker;
+                    if (yyaccept == 0)
+                    {
+                        goto basic_json_parser_5;
+                    }
+                    else
+                    {
+                        goto basic_json_parser_14;
+                    }
+basic_json_parser_33:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::value_string;
+                        break;
+                    }
+basic_json_parser_35:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 'e')
+                    {
+                        if (yych <= '/')
+                        {
+                            if (yych == '"')
+                            {
+                                goto basic_json_parser_30;
+                            }
+                            if (yych <= '.')
+                            {
+                                goto basic_json_parser_32;
+                            }
+                            goto basic_json_parser_30;
+                        }
+                        else
+                        {
+                            if (yych <= '\\')
+                            {
+                                if (yych <= '[')
+                                {
+                                    goto basic_json_parser_32;
+                                }
+                                goto basic_json_parser_30;
+                            }
+                            else
+                            {
+                                if (yych == 'b')
+                                {
+                                    goto basic_json_parser_30;
+                                }
+                                goto basic_json_parser_32;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (yych <= 'q')
+                        {
+                            if (yych <= 'f')
+                            {
+                                goto basic_json_parser_30;
+                            }
+                            if (yych == 'n')
+                            {
+                                goto basic_json_parser_30;
+                            }
+                            goto basic_json_parser_32;
+                        }
+                        else
+                        {
+                            if (yych <= 's')
+                            {
+                                if (yych <= 'r')
+                                {
+                                    goto basic_json_parser_30;
+                                }
+                                goto basic_json_parser_32;
+                            }
+                            else
+                            {
+                                if (yych <= 't')
+                                {
+                                    goto basic_json_parser_30;
+                                }
+                                if (yych <= 'u')
+                                {
+                                    goto basic_json_parser_48;
+                                }
+                                goto basic_json_parser_32;
+                            }
+                        }
+                    }
+basic_json_parser_36:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_30;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_37:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x9F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_36;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_38:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_36;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_39:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0x9F)
+                    {
+                        goto basic_json_parser_36;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_40:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x8F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_41:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0xBF)
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_42:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 0x7F)
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= 0x8F)
+                    {
+                        goto basic_json_parser_38;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_43:
+                    yych = *++m_cursor;
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto basic_json_parser_49;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_44:
+                    yych = *++m_cursor;
+                    if (yych <= ',')
+                    {
+                        if (yych == '+')
+                        {
+                            goto basic_json_parser_51;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= '-')
+                        {
+                            goto basic_json_parser_51;
+                        }
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_52;
+                        }
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_45:
+                    yych = *++m_cursor;
+                    if (yych == 'l')
+                    {
+                        goto basic_json_parser_54;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_46:
+                    yych = *++m_cursor;
+                    if (yych == 'l')
+                    {
+                        goto basic_json_parser_55;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_47:
+                    yych = *++m_cursor;
+                    if (yych == 'u')
+                    {
+                        goto basic_json_parser_56;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_48:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '@')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_57;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= 'F')
+                        {
+                            goto basic_json_parser_57;
+                        }
+                        if (yych <= '`')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= 'f')
+                        {
+                            goto basic_json_parser_57;
+                        }
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_49:
+                    yyaccept = 1;
+                    m_marker = ++m_cursor;
+                    if ((m_limit - m_cursor) < 3)
+                    {
+                        fill_line_buffer(3);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= 'D')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_14;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_49;
+                        }
+                        goto basic_json_parser_14;
+                    }
+                    else
+                    {
+                        if (yych <= 'E')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        if (yych == 'e')
+                        {
+                            goto basic_json_parser_44;
+                        }
+                        goto basic_json_parser_14;
+                    }
+basic_json_parser_51:
+                    yych = *++m_cursor;
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_32;
+                    }
+                    if (yych >= ':')
+                    {
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_52:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '/')
+                    {
+                        goto basic_json_parser_14;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto basic_json_parser_52;
+                    }
+                    goto basic_json_parser_14;
+basic_json_parser_54:
+                    yych = *++m_cursor;
+                    if (yych == 's')
+                    {
+                        goto basic_json_parser_58;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_55:
+                    yych = *++m_cursor;
+                    if (yych == 'l')
+                    {
+                        goto basic_json_parser_59;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_56:
+                    yych = *++m_cursor;
+                    if (yych == 'e')
+                    {
+                        goto basic_json_parser_61;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_57:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '@')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_63;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= 'F')
+                        {
+                            goto basic_json_parser_63;
+                        }
+                        if (yych <= '`')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= 'f')
+                        {
+                            goto basic_json_parser_63;
+                        }
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_58:
+                    yych = *++m_cursor;
+                    if (yych == 'e')
+                    {
+                        goto basic_json_parser_64;
+                    }
+                    goto basic_json_parser_32;
+basic_json_parser_59:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::literal_null;
+                        break;
+                    }
+basic_json_parser_61:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::literal_true;
+                        break;
+                    }
+basic_json_parser_63:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '@')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_66;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= 'F')
+                        {
+                            goto basic_json_parser_66;
+                        }
+                        if (yych <= '`')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= 'f')
+                        {
+                            goto basic_json_parser_66;
+                        }
+                        goto basic_json_parser_32;
+                    }
+basic_json_parser_64:
+                    ++m_cursor;
+                    {
+                        last_token_type = token_type::literal_false;
+                        break;
+                    }
+basic_json_parser_66:
+                    ++m_cursor;
+                    if (m_limit <= m_cursor)
+                    {
+                        fill_line_buffer(1);    // LCOV_EXCL_LINE
+                    }
+                    yych = *m_cursor;
+                    if (yych <= '@')
+                    {
+                        if (yych <= '/')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= '9')
+                        {
+                            goto basic_json_parser_30;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                    else
+                    {
+                        if (yych <= 'F')
+                        {
+                            goto basic_json_parser_30;
+                        }
+                        if (yych <= '`')
+                        {
+                            goto basic_json_parser_32;
+                        }
+                        if (yych <= 'f')
+                        {
+                            goto basic_json_parser_30;
+                        }
+                        goto basic_json_parser_32;
+                    }
+                }
+
+            }
+
+            return last_token_type;
+        }
+
+        /*!
+        @brief append data from the stream to the line buffer
+
+        This function is called by the scan() function when the end of the
+        buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
+        incremented without leaving the limits of the line buffer. Note re2c
+        decides when to call this function.
+
+        If the lexer reads from contiguous storage, there is no trailing null
+        byte. Therefore, this function must make sure to add these padding
+        null bytes.
+
+        If the lexer reads from an input stream, this function reads the next
+        line of the input.
+
+        @pre
+            p p p p p p u u u u u x . . . . . .
+            ^           ^       ^   ^
+            m_content   m_start |   m_limit
+                                m_cursor
+
+        @post
+            u u u u u x x x x x x x . . . . . .
+            ^       ^               ^
+            |       m_cursor        m_limit
+            m_start
+            m_content
+        */
+        void fill_line_buffer(size_t n = 0)
+        {
+            // if line buffer is used, m_content points to its data
+            assert(m_line_buffer.empty()
+                   or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()));
+
+            // if line buffer is used, m_limit is set past the end of its data
+            assert(m_line_buffer.empty()
+                   or m_limit == m_content + m_line_buffer.size());
+
+            // pointer relationships
+            assert(m_content <= m_start);
+            assert(m_start <= m_cursor);
+            assert(m_cursor <= m_limit);
+            assert(m_marker == nullptr or m_marker  <= m_limit);
+
+            // number of processed characters (p)
+            const auto num_processed_chars = static_cast<size_t>(m_start - m_content);
+            // offset for m_marker wrt. to m_start
+            const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
+            // number of unprocessed characters (u)
+            const auto offset_cursor = m_cursor - m_start;
+
+            // no stream is used or end of file is reached
+            if (m_stream == nullptr or m_stream->eof())
+            {
+                // m_start may or may not be pointing into m_line_buffer at
+                // this point. We trust the standand library to do the right
+                // thing. See http://stackoverflow.com/q/28142011/266378
+                m_line_buffer.assign(m_start, m_limit);
+
+                // append n characters to make sure that there is sufficient
+                // space between m_cursor and m_limit
+                m_line_buffer.append(1, '\x00');
+                if (n > 0)
+                {
+                    m_line_buffer.append(n - 1, '\x01');
+                }
+            }
+            else
+            {
+                // delete processed characters from line buffer
+                m_line_buffer.erase(0, num_processed_chars);
+                // read next line from input stream
+                m_line_buffer_tmp.clear();
+                std::getline(*m_stream, m_line_buffer_tmp, '\n');
+
+                // add line with newline symbol to the line buffer
+                m_line_buffer += m_line_buffer_tmp;
+                m_line_buffer.push_back('\n');
+            }
+
+            // set pointers
+            m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data());
+            assert(m_content != nullptr);
+            m_start  = m_content;
+            m_marker = m_start + offset_marker;
+            m_cursor = m_start + offset_cursor;
+            m_limit  = m_start + m_line_buffer.size();
+        }
+
+        /// return string representation of last read token
+        string_t get_token_string() const
+        {
+            assert(m_start != nullptr);
+            return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
+                            static_cast<size_t>(m_cursor - m_start));
+        }
+
+        /*!
+        @brief return string value for string tokens
+
+        The function iterates the characters between the opening and closing
+        quotes of the string value. The complete string is the range
+        [m_start,m_cursor). Consequently, we iterate from m_start+1 to
+        m_cursor-1.
+
+        We differentiate two cases:
+
+        1. Escaped characters. In this case, a new character is constructed
+           according to the nature of the escape. Some escapes create new
+           characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied
+           as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape
+           `"\\uxxxx"` need special care. In this case, to_unicode takes care
+           of the construction of the values.
+        2. Unescaped characters are copied as is.
+
+        @pre `m_cursor - m_start >= 2`, meaning the length of the last token
+        is at least 2 bytes which is trivially true for any string (which
+        consists of at least two quotes).
+
+            " c1 c2 c3 ... "
+            ^                ^
+            m_start          m_cursor
+
+        @complexity Linear in the length of the string.\n
+
+        Lemma: The loop body will always terminate.\n
+
+        Proof (by contradiction): Assume the loop body does not terminate. As
+        the loop body does not contain another loop, one of the called
+        functions must never return. The called functions are `std::strtoul`
+        and to_unicode. Neither function can loop forever, so the loop body
+        will never loop forever which contradicts the assumption that the loop
+        body does not terminate, q.e.d.\n
+
+        Lemma: The loop condition for the for loop is eventually false.\n
+
+        Proof (by contradiction): Assume the loop does not terminate. Due to
+        the above lemma, this can only be due to a tautological loop
+        condition; that is, the loop condition i < m_cursor - 1 must always be
+        true. Let x be the change of i for any loop iteration. Then
+        m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This
+        can be rephrased to m_cursor - m_start - 2 > x. With the
+        precondition, we x <= 0, meaning that the loop condition holds
+        indefinitly if i is always decreased. However, observe that the value
+        of i is strictly increasing with each iteration, as it is incremented
+        by 1 in the iteration expression and never decremented inside the loop
+        body. Hence, the loop condition will eventually be false which
+        contradicts the assumption that the loop condition is a tautology,
+        q.e.d.
+
+        @return string value of current token without opening and closing
+        quotes
+        @throw std::out_of_range if to_unicode fails
+        */
+        string_t get_string() const
+        {
+            assert(m_cursor - m_start >= 2);
+
+            string_t result;
+            result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
+
+            // iterate the result between the quotes
+            for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
+            {
+                // find next escape character
+                auto e = std::find(i, m_cursor - 1, '\\');
+                if (e != i)
+                {
+                    // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705
+                    for (auto k = i; k < e; k++)
+                    {
+                        result.push_back(static_cast<typename string_t::value_type>(*k));
+                    }
+                    i = e - 1; // -1 because of ++i
+                }
+                else
+                {
+                    // processing escaped character
+                    // read next character
+                    ++i;
+
+                    switch (*i)
+                    {
+                        // the default escapes
+                        case 't':
+                        {
+                            result += "\t";
+                            break;
+                        }
+                        case 'b':
+                        {
+                            result += "\b";
+                            break;
+                        }
+                        case 'f':
+                        {
+                            result += "\f";
+                            break;
+                        }
+                        case 'n':
+                        {
+                            result += "\n";
+                            break;
+                        }
+                        case 'r':
+                        {
+                            result += "\r";
+                            break;
+                        }
+                        case '\\':
+                        {
+                            result += "\\";
+                            break;
+                        }
+                        case '/':
+                        {
+                            result += "/";
+                            break;
+                        }
+                        case '"':
+                        {
+                            result += "\"";
+                            break;
+                        }
+
+                        // unicode
+                        case 'u':
+                        {
+                            // get code xxxx from uxxxx
+                            auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
+                                                          4).c_str(), nullptr, 16);
+
+                            // check if codepoint is a high surrogate
+                            if (codepoint >= 0xD800 and codepoint <= 0xDBFF)
+                            {
+                                // make sure there is a subsequent unicode
+                                if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
+                                {
+                                    JSON_THROW(std::invalid_argument("missing low surrogate"));
+                                }
+
+                                // get code yyyy from uxxxx\uyyyy
+                                auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>
+                                                               (i + 7), 4).c_str(), nullptr, 16);
+                                result += to_unicode(codepoint, codepoint2);
+                                // skip the next 10 characters (xxxx\uyyyy)
+                                i += 10;
+                            }
+                            else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
+                            {
+                                // we found a lone low surrogate
+                                JSON_THROW(std::invalid_argument("missing high surrogate"));
+                            }
+                            else
+                            {
+                                // add unicode character(s)
+                                result += to_unicode(codepoint);
+                                // skip the next four characters (xxxx)
+                                i += 4;
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        /*!
+        @brief parse floating point number
+
+        This function (and its overloads) serves to select the most approprate
+        standard floating point number parsing function based on the type
+        supplied via the first parameter.  Set this to @a
+        static_cast<number_float_t*>(nullptr).
+
+        @param[in,out] endptr recieves a pointer to the first character after
+        the number
+
+        @return the floating point number
+        */
+        long double str_to_float_t(long double* /* type */, char** endptr) const
+        {
+            return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
+        }
+
+        /*!
+        @brief parse floating point number
+
+        This function (and its overloads) serves to select the most approprate
+        standard floating point number parsing function based on the type
+        supplied via the first parameter.  Set this to @a
+        static_cast<number_float_t*>(nullptr).
+
+        @param[in,out] endptr  recieves a pointer to the first character after
+        the number
+
+        @return the floating point number
+        */
+        double str_to_float_t(double* /* type */, char** endptr) const
+        {
+            return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
+        }
+
+        /*!
+        @brief parse floating point number
+
+        This function (and its overloads) serves to select the most approprate
+        standard floating point number parsing function based on the type
+        supplied via the first parameter.  Set this to @a
+        static_cast<number_float_t*>(nullptr).
+
+        @param[in,out] endptr  recieves a pointer to the first character after
+        the number
+
+        @return the floating point number
+        */
+        float str_to_float_t(float* /* type */, char** endptr) const
+        {
+            return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
+        }
+
+        /*!
+        @brief return number value for number tokens
+
+        This function translates the last token into the most appropriate
+        number type (either integer, unsigned integer or floating point),
+        which is passed back to the caller via the result parameter.
+
+        This function parses the integer component up to the radix point or
+        exponent while collecting information about the 'floating point
+        representation', which it stores in the result parameter. If there is
+        no radix point or exponent, and the number can fit into a @ref
+        number_integer_t or @ref number_unsigned_t then it sets the result
+        parameter accordingly.
+
+        If the number is a floating point number the number is then parsed
+        using @a std:strtod (or @a std:strtof or @a std::strtold).
+
+        @param[out] result  @ref basic_json object to receive the number, or
+        NAN if the conversion read past the current token. The latter case
+        needs to be treated by the caller function.
+        */
+        void get_number(basic_json& result) const
+        {
+            assert(m_start != nullptr);
+
+            const lexer::lexer_char_t* curptr = m_start;
+
+            // accumulate the integer conversion result (unsigned for now)
+            number_unsigned_t value = 0;
+
+            // maximum absolute value of the relevant integer type
+            number_unsigned_t max;
+
+            // temporarily store the type to avoid unecessary bitfield access
+            value_t type;
+
+            // look for sign
+            if (*curptr == '-')
+            {
+                type = value_t::number_integer;
+                max = static_cast<uint64_t>((std::numeric_limits<number_integer_t>::max)()) + 1;
+                curptr++;
+            }
+            else
+            {
+                type = value_t::number_unsigned;
+                max = static_cast<uint64_t>((std::numeric_limits<number_unsigned_t>::max)());
+            }
+
+            // count the significant figures
+            for (; curptr < m_cursor; curptr++)
+            {
+                // quickly skip tests if a digit
+                if (*curptr < '0' || *curptr > '9')
+                {
+                    if (*curptr == '.')
+                    {
+                        // don't count '.' but change to float
+                        type = value_t::number_float;
+                        continue;
+                    }
+                    // assume exponent (if not then will fail parse): change to
+                    // float, stop counting and record exponent details
+                    type = value_t::number_float;
+                    break;
+                }
+
+                // skip if definitely not an integer
+                if (type != value_t::number_float)
+                {
+                    auto digit = static_cast<number_unsigned_t>(*curptr - '0');
+
+                    // overflow if value * 10 + digit > max, move terms around
+                    // to avoid overflow in intermediate values
+                    if (value > (max - digit) / 10)
+                    {
+                        // overflow
+                        type = value_t::number_float;
+                    }
+                    else
+                    {
+                        // no overflow
+                        value = value * 10 + digit;
+                    }
+                }
+            }
+
+            // save the value (if not a float)
+            if (type == value_t::number_unsigned)
+            {
+                result.m_value.number_unsigned = value;
+            }
+            else if (type == value_t::number_integer)
+            {
+                // invariant: if we parsed a '-', the absolute value is between
+                // 0 (we allow -0) and max == -INT64_MIN
+                assert(value >= 0);
+                assert(value <= max);
+
+                if (value == max)
+                {
+                    // we cannot simply negate value (== max == -INT64_MIN),
+                    // see https://github.com/nlohmann/json/issues/389
+                    result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN);
+                }
+                else
+                {
+                    // all other values can be negated safely
+                    result.m_value.number_integer = -static_cast<number_integer_t>(value);
+                }
+            }
+            else
+            {
+                // parse with strtod
+                result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), nullptr);
+
+                // replace infinity and NAN by null
+                if (not std::isfinite(result.m_value.number_float))
+                {
+                    type = value_t::null;
+                    result.m_value = basic_json::json_value();
+                }
+            }
+
+            // save the type
+            result.m_type = type;
+        }
+
+      private:
+        /// optional input stream
+        std::istream* m_stream = nullptr;
+        /// line buffer buffer for m_stream
+        string_t m_line_buffer {};
+        /// used for filling m_line_buffer
+        string_t m_line_buffer_tmp {};
+        /// the buffer pointer
+        const lexer_char_t* m_content = nullptr;
+        /// pointer to the beginning of the current symbol
+        const lexer_char_t* m_start = nullptr;
+        /// pointer for backtracking information
+        const lexer_char_t* m_marker = nullptr;
+        /// pointer to the current symbol
+        const lexer_char_t* m_cursor = nullptr;
+        /// pointer to the end of the buffer
+        const lexer_char_t* m_limit = nullptr;
+        /// the last token type
+        token_type last_token_type = token_type::end_of_input;
+    };
+
+    /*!
+    @brief syntax analysis
+
+    This class implements a recursive decent parser.
+    */
+    class parser
+    {
+      public:
+        /// a parser reading from a string literal
+        parser(const char* buff, const parser_callback_t cb = nullptr)
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff))
+        {}
+
+        /// a parser reading from an input stream
+        parser(std::istream& is, const parser_callback_t cb = nullptr)
+            : callback(cb), m_lexer(is)
+        {}
+
+        /// a parser reading from an iterator range with contiguous storage
+        template<class IteratorType, typename std::enable_if<
+                     std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
+                     , int>::type
+                 = 0>
+        parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
+            : callback(cb),
+              m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
+                      static_cast<size_t>(std::distance(first, last)))
+        {}
+
+        /// public parser interface
+        basic_json parse()
+        {
+            // read first token
+            get_token();
+
+            basic_json result = parse_internal(true);
+            result.assert_invariant();
+
+            expect(lexer::token_type::end_of_input);
+
+            // return parser result and replace it with null in case the
+            // top-level value was discarded by the callback function
+            return result.is_discarded() ? basic_json() : std::move(result);
+        }
+
+      private:
+        /// the actual parser
+        basic_json parse_internal(bool keep)
+        {
+            auto result = basic_json(value_t::discarded);
+
+            switch (last_token)
+            {
+                case lexer::token_type::begin_object:
+                {
+                    if (keep and (not callback
+                                  or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
+                    {
+                        // explicitly set result to object to cope with {}
+                        result.m_type = value_t::object;
+                        result.m_value = value_t::object;
+                    }
+
+                    // read next token
+                    get_token();
+
+                    // closing } -> we are done
+                    if (last_token == lexer::token_type::end_object)
+                    {
+                        get_token();
+                        if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
+                        {
+                            result = basic_json(value_t::discarded);
+                        }
+                        return result;
+                    }
+
+                    // no comma is expected here
+                    unexpect(lexer::token_type::value_separator);
+
+                    // otherwise: parse key-value pairs
+                    do
+                    {
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
+                        {
+                            get_token();
+                        }
+
+                        // store key
+                        expect(lexer::token_type::value_string);
+                        const auto key = m_lexer.get_string();
+
+                        bool keep_tag = false;
+                        if (keep)
+                        {
+                            if (callback)
+                            {
+                                basic_json k(key);
+                                keep_tag = callback(depth, parse_event_t::key, k);
+                            }
+                            else
+                            {
+                                keep_tag = true;
+                            }
+                        }
+
+                        // parse separator (:)
+                        get_token();
+                        expect(lexer::token_type::name_separator);
+
+                        // parse and add value
+                        get_token();
+                        auto value = parse_internal(keep);
+                        if (keep and keep_tag and not value.is_discarded())
+                        {
+                            result[key] = std::move(value);
+                        }
+                    }
+                    while (last_token == lexer::token_type::value_separator);
+
+                    // closing }
+                    expect(lexer::token_type::end_object);
+                    get_token();
+                    if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
+                    {
+                        result = basic_json(value_t::discarded);
+                    }
+
+                    return result;
+                }
+
+                case lexer::token_type::begin_array:
+                {
+                    if (keep and (not callback
+                                  or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
+                    {
+                        // explicitly set result to object to cope with []
+                        result.m_type = value_t::array;
+                        result.m_value = value_t::array;
+                    }
+
+                    // read next token
+                    get_token();
+
+                    // closing ] -> we are done
+                    if (last_token == lexer::token_type::end_array)
+                    {
+                        get_token();
+                        if (callback and not callback(--depth, parse_event_t::array_end, result))
+                        {
+                            result = basic_json(value_t::discarded);
+                        }
+                        return result;
+                    }
+
+                    // no comma is expected here
+                    unexpect(lexer::token_type::value_separator);
+
+                    // otherwise: parse values
+                    do
+                    {
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
+                        {
+                            get_token();
+                        }
+
+                        // parse value
+                        auto value = parse_internal(keep);
+                        if (keep and not value.is_discarded())
+                        {
+                            result.push_back(std::move(value));
+                        }
+                    }
+                    while (last_token == lexer::token_type::value_separator);
+
+                    // closing ]
+                    expect(lexer::token_type::end_array);
+                    get_token();
+                    if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
+                    {
+                        result = basic_json(value_t::discarded);
+                    }
+
+                    return result;
+                }
+
+                case lexer::token_type::literal_null:
+                {
+                    get_token();
+                    result.m_type = value_t::null;
+                    break;
+                }
+
+                case lexer::token_type::value_string:
+                {
+                    const auto s = m_lexer.get_string();
+                    get_token();
+                    result = basic_json(s);
+                    break;
+                }
+
+                case lexer::token_type::literal_true:
+                {
+                    get_token();
+                    result.m_type = value_t::boolean;
+                    result.m_value = true;
+                    break;
+                }
+
+                case lexer::token_type::literal_false:
+                {
+                    get_token();
+                    result.m_type = value_t::boolean;
+                    result.m_value = false;
+                    break;
+                }
+
+                case lexer::token_type::value_number:
+                {
+                    m_lexer.get_number(result);
+                    get_token();
+                    break;
+                }
+
+                default:
+                {
+                    // the last token was unexpected
+                    unexpect(last_token);
+                }
+            }
+
+            if (keep and callback and not callback(depth, parse_event_t::value, result))
+            {
+                result = basic_json(value_t::discarded);
+            }
+            return result;
+        }
+
+        /// get next token from lexer
+        typename lexer::token_type get_token()
+        {
+            last_token = m_lexer.scan();
+            return last_token;
+        }
+
+        void expect(typename lexer::token_type t) const
+        {
+            if (t != last_token)
+            {
+                std::string error_msg = "parse error - unexpected ";
+                error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
+                              "'") :
+                              lexer::token_type_name(last_token));
+                error_msg += "; expected " + lexer::token_type_name(t);
+                JSON_THROW(std::invalid_argument(error_msg));
+            }
+        }
+
+        void unexpect(typename lexer::token_type t) const
+        {
+            if (t == last_token)
+            {
+                std::string error_msg = "parse error - unexpected ";
+                error_msg += (last_token == lexer::token_type::parse_error ? ("'" +  m_lexer.get_token_string() +
+                              "'") :
+                              lexer::token_type_name(last_token));
+                JSON_THROW(std::invalid_argument(error_msg));
+            }
+        }
+
+      private:
+        /// current level of recursion
+        int depth = 0;
+        /// callback function
+        const parser_callback_t callback = nullptr;
+        /// the type of the last read token
+        typename lexer::token_type last_token = lexer::token_type::uninitialized;
+        /// the lexer
+        lexer m_lexer;
+    };
+
+  public:
+    /*!
+    @brief JSON Pointer
+
+    A JSON pointer defines a string syntax for identifying a specific value
+    within a JSON document. It can be used with functions `at` and
+    `operator[]`. Furthermore, JSON pointers are the base for JSON patches.
+
+    @sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
+
+    @since version 2.0.0
+    */
+    class json_pointer
+    {
+        /// allow basic_json to access private members
+        friend class basic_json;
+
+      public:
+        /*!
+        @brief create JSON pointer
+
+        Create a JSON pointer according to the syntax described in
+        [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
+
+        @param[in] s  string representing the JSON pointer; if omitted, the
+                      empty string is assumed which references the whole JSON
+                      value
+
+        @throw std::domain_error if reference token is nonempty and does not
+        begin with a slash (`/`); example: `"JSON pointer must be empty or
+        begin with /"`
+        @throw std::domain_error if a tilde (`~`) is not followed by `0`
+        (representing `~`) or `1` (representing `/`); example: `"escape error:
+        ~ must be followed with 0 or 1"`
+
+        @liveexample{The example shows the construction several valid JSON
+        pointers as well as the exceptional behavior.,json_pointer}
+
+        @since version 2.0.0
+        */
+        explicit json_pointer(const std::string& s = "")
+            : reference_tokens(split(s))
+        {}
+
+        /*!
+        @brief return a string representation of the JSON pointer
+
+        @invariant For each JSON pointer `ptr`, it holds:
+        @code {.cpp}
+        ptr == json_pointer(ptr.to_string());
+        @endcode
+
+        @return a string representation of the JSON pointer
+
+        @liveexample{The example shows the result of `to_string`.,
+        json_pointer__to_string}
+
+        @since version 2.0.0
+        */
+        std::string to_string() const noexcept
+        {
+            return std::accumulate(reference_tokens.begin(),
+                                   reference_tokens.end(), std::string{},
+                                   [](const std::string & a, const std::string & b)
+            {
+                return a + "/" + escape(b);
+            });
+        }
+
+        /// @copydoc to_string()
+        operator std::string() const
+        {
+            return to_string();
+        }
+
+      private:
+        /// remove and return last reference pointer
+        std::string pop_back()
+        {
+            if (is_root())
+            {
+                JSON_THROW(std::domain_error("JSON pointer has no parent"));
+            }
+
+            auto last = reference_tokens.back();
+            reference_tokens.pop_back();
+            return last;
+        }
+
+        /// return whether pointer points to the root document
+        bool is_root() const
+        {
+            return reference_tokens.empty();
+        }
+
+        json_pointer top() const
+        {
+            if (is_root())
+            {
+                JSON_THROW(std::domain_error("JSON pointer has no parent"));
+            }
+
+            json_pointer result = *this;
+            result.reference_tokens = {reference_tokens[0]};
+            return result;
+        }
+
+        /*!
+        @brief create and return a reference to the pointed to value
+
+        @complexity Linear in the number of reference tokens.
+        */
+        reference get_and_create(reference j) const
+        {
+            pointer result = &j;
+
+            // in case no reference tokens exist, return a reference to the
+            // JSON value j which will be overwritten by a primitive value
+            for (const auto& reference_token : reference_tokens)
+            {
+                switch (result->m_type)
+                {
+                    case value_t::null:
+                    {
+                        if (reference_token == "0")
+                        {
+                            // start a new array if reference token is 0
+                            result = &result->operator[](0);
+                        }
+                        else
+                        {
+                            // start a new object otherwise
+                            result = &result->operator[](reference_token);
+                        }
+                        break;
+                    }
+
+                    case value_t::object:
+                    {
+                        // create an entry in the object
+                        result = &result->operator[](reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        // create an entry in the array
+                        result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
+                        break;
+                    }
+
+                    /*
+                    The following code is only reached if there exists a
+                    reference token _and_ the current value is primitive. In
+                    this case, we have an error situation, because primitive
+                    values may only occur as single value; that is, with an
+                    empty list of reference tokens.
+                    */
+                    default:
+                    {
+                        JSON_THROW(std::domain_error("invalid value to unflatten"));
+                    }
+                }
+            }
+
+            return *result;
+        }
+
+        /*!
+        @brief return a reference to the pointed to value
+
+        @note This version does not throw if a value is not present, but tries
+        to create nested values instead. For instance, calling this function
+        with pointer `"/this/that"` on a null value is equivalent to calling
+        `operator[]("this").operator[]("that")` on that value, effectively
+        changing the null value to an object.
+
+        @param[in] ptr  a JSON value
+
+        @return reference to the JSON value pointed to by the JSON pointer
+
+        @complexity Linear in the length of the JSON pointer.
+
+        @throw std::out_of_range      if the JSON pointer can not be resolved
+        @throw std::domain_error      if an array index begins with '0'
+        @throw std::invalid_argument  if an array index was not a number
+        */
+        reference get_unchecked(pointer ptr) const
+        {
+            for (const auto& reference_token : reference_tokens)
+            {
+                // convert null values to arrays or objects before continuing
+                if (ptr->m_type == value_t::null)
+                {
+                    // check if reference token is a number
+                    const bool nums = std::all_of(reference_token.begin(),
+                                                  reference_token.end(),
+                                                  [](const char x)
+                    {
+                        return std::isdigit(x);
+                    });
+
+                    // change value to array for numbers or "-" or to object
+                    // otherwise
+                    if (nums or reference_token == "-")
+                    {
+                        *ptr = value_t::array;
+                    }
+                    else
+                    {
+                        *ptr = value_t::object;
+                    }
+                }
+
+                switch (ptr->m_type)
+                {
+                    case value_t::object:
+                    {
+                        // use unchecked object access
+                        ptr = &ptr->operator[](reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        // error condition (cf. RFC 6901, Sect. 4)
+                        if (reference_token.size() > 1 and reference_token[0] == '0')
+                        {
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
+                        }
+
+                        if (reference_token == "-")
+                        {
+                            // explicityly treat "-" as index beyond the end
+                            ptr = &ptr->operator[](ptr->m_value.array->size());
+                        }
+                        else
+                        {
+                            // convert array index to number; unchecked access
+                            ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
+                        }
+                        break;
+                    }
+
+                    default:
+                    {
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
+                    }
+                }
+            }
+
+            return *ptr;
+        }
+
+        reference get_checked(pointer ptr) const
+        {
+            for (const auto& reference_token : reference_tokens)
+            {
+                switch (ptr->m_type)
+                {
+                    case value_t::object:
+                    {
+                        // note: at performs range check
+                        ptr = &ptr->at(reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        if (reference_token == "-")
+                        {
+                            // "-" always fails the range check
+                            throw std::out_of_range("array index '-' (" +
+                                                    std::to_string(ptr->m_value.array->size()) +
+                                                    ") is out of range");
+                        }
+
+                        // error condition (cf. RFC 6901, Sect. 4)
+                        if (reference_token.size() > 1 and reference_token[0] == '0')
+                        {
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
+                        }
+
+                        // note: at performs range check
+                        ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
+                        break;
+                    }
+
+                    default:
+                    {
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
+                    }
+                }
+            }
+
+            return *ptr;
+        }
+
+        /*!
+        @brief return a const reference to the pointed to value
+
+        @param[in] ptr  a JSON value
+
+        @return const reference to the JSON value pointed to by the JSON
+                pointer
+        */
+        const_reference get_unchecked(const_pointer ptr) const
+        {
+            for (const auto& reference_token : reference_tokens)
+            {
+                switch (ptr->m_type)
+                {
+                    case value_t::object:
+                    {
+                        // use unchecked object access
+                        ptr = &ptr->operator[](reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        if (reference_token == "-")
+                        {
+                            // "-" cannot be used for const access
+                            throw std::out_of_range("array index '-' (" +
+                                                    std::to_string(ptr->m_value.array->size()) +
+                                                    ") is out of range");
+                        }
+
+                        // error condition (cf. RFC 6901, Sect. 4)
+                        if (reference_token.size() > 1 and reference_token[0] == '0')
+                        {
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
+                        }
+
+                        // use unchecked array access
+                        ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
+                        break;
+                    }
+
+                    default:
+                    {
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
+                    }
+                }
+            }
+
+            return *ptr;
+        }
+
+        const_reference get_checked(const_pointer ptr) const
+        {
+            for (const auto& reference_token : reference_tokens)
+            {
+                switch (ptr->m_type)
+                {
+                    case value_t::object:
+                    {
+                        // note: at performs range check
+                        ptr = &ptr->at(reference_token);
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        if (reference_token == "-")
+                        {
+                            // "-" always fails the range check
+                            throw std::out_of_range("array index '-' (" +
+                                                    std::to_string(ptr->m_value.array->size()) +
+                                                    ") is out of range");
+                        }
+
+                        // error condition (cf. RFC 6901, Sect. 4)
+                        if (reference_token.size() > 1 and reference_token[0] == '0')
+                        {
+                            JSON_THROW(std::domain_error("array index must not begin with '0'"));
+                        }
+
+                        // note: at performs range check
+                        ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
+                        break;
+                    }
+
+                    default:
+                    {
+                        JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'"));
+                    }
+                }
+            }
+
+            return *ptr;
+        }
+
+        /// split the string input to reference tokens
+        static std::vector<std::string> split(const std::string& reference_string)
+        {
+            std::vector<std::string> result;
+
+            // special case: empty reference string -> no reference tokens
+            if (reference_string.empty())
+            {
+                return result;
+            }
+
+            // check if nonempty reference string begins with slash
+            if (reference_string[0] != '/')
+            {
+                JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'"));
+            }
+
+            // extract the reference tokens:
+            // - slash: position of the last read slash (or end of string)
+            // - start: position after the previous slash
+            for (
+                // search for the first slash after the first character
+                size_t slash = reference_string.find_first_of('/', 1),
+                // set the beginning of the first reference token
+                start = 1;
+                // we can stop if start == string::npos+1 = 0
+                start != 0;
+                // set the beginning of the next reference token
+                // (will eventually be 0 if slash == std::string::npos)
+                start = slash + 1,
+                // find next slash
+                slash = reference_string.find_first_of('/', start))
+            {
+                // use the text between the beginning of the reference token
+                // (start) and the last slash (slash).
+                auto reference_token = reference_string.substr(start, slash - start);
+
+                // check reference tokens are properly escaped
+                for (size_t pos = reference_token.find_first_of('~');
+                        pos != std::string::npos;
+                        pos = reference_token.find_first_of('~', pos + 1))
+                {
+                    assert(reference_token[pos] == '~');
+
+                    // ~ must be followed by 0 or 1
+                    if (pos == reference_token.size() - 1 or
+                            (reference_token[pos + 1] != '0' and
+                             reference_token[pos + 1] != '1'))
+                    {
+                        JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'"));
+                    }
+                }
+
+                // finally, store the reference token
+                unescape(reference_token);
+                result.push_back(reference_token);
+            }
+
+            return result;
+        }
+
+      private:
+        /*!
+        @brief replace all occurrences of a substring by another string
+
+        @param[in,out] s  the string to manipulate; changed so that all
+                          occurrences of @a f are replaced with @a t
+        @param[in]     f  the substring to replace with @a t
+        @param[in]     t  the string to replace @a f
+
+        @pre The search string @a f must not be empty.
+
+        @since version 2.0.0
+        */
+        static void replace_substring(std::string& s,
+                                      const std::string& f,
+                                      const std::string& t)
+        {
+            assert(not f.empty());
+
+            for (
+                size_t pos = s.find(f);         // find first occurrence of f
+                pos != std::string::npos;       // make sure f was found
+                s.replace(pos, f.size(), t),    // replace with t
+                pos = s.find(f, pos + t.size()) // find next occurrence of f
+            );
+        }
+
+        /// escape tilde and slash
+        static std::string escape(std::string s)
+        {
+            // escape "~"" to "~0" and "/" to "~1"
+            replace_substring(s, "~", "~0");
+            replace_substring(s, "/", "~1");
+            return s;
+        }
+
+        /// unescape tilde and slash
+        static void unescape(std::string& s)
+        {
+            // first transform any occurrence of the sequence '~1' to '/'
+            replace_substring(s, "~1", "/");
+            // then transform any occurrence of the sequence '~0' to '~'
+            replace_substring(s, "~0", "~");
+        }
+
+        /*!
+        @param[in] reference_string  the reference string to the current value
+        @param[in] value             the value to consider
+        @param[in,out] result        the result object to insert values to
+
+        @note Empty objects or arrays are flattened to `null`.
+        */
+        static void flatten(const std::string& reference_string,
+                            const basic_json& value,
+                            basic_json& result)
+        {
+            switch (value.m_type)
+            {
+                case value_t::array:
+                {
+                    if (value.m_value.array->empty())
+                    {
+                        // flatten empty array as null
+                        result[reference_string] = nullptr;
+                    }
+                    else
+                    {
+                        // iterate array and use index as reference string
+                        for (size_t i = 0; i < value.m_value.array->size(); ++i)
+                        {
+                            flatten(reference_string + "/" + std::to_string(i),
+                                    value.m_value.array->operator[](i), result);
+                        }
+                    }
+                    break;
+                }
+
+                case value_t::object:
+                {
+                    if (value.m_value.object->empty())
+                    {
+                        // flatten empty object as null
+                        result[reference_string] = nullptr;
+                    }
+                    else
+                    {
+                        // iterate object and use keys as reference string
+                        for (const auto& element : *value.m_value.object)
+                        {
+                            flatten(reference_string + "/" + escape(element.first),
+                                    element.second, result);
+                        }
+                    }
+                    break;
+                }
+
+                default:
+                {
+                    // add primitive value with its reference string
+                    result[reference_string] = value;
+                    break;
+                }
+            }
+        }
+
+        /*!
+        @param[in] value  flattened JSON
+
+        @return unflattened JSON
+        */
+        static basic_json unflatten(const basic_json& value)
+        {
+            if (not value.is_object())
+            {
+                JSON_THROW(std::domain_error("only objects can be unflattened"));
+            }
+
+            basic_json result;
+
+            // iterate the JSON object values
+            for (const auto& element : *value.m_value.object)
+            {
+                if (not element.second.is_primitive())
+                {
+                    JSON_THROW(std::domain_error("values in object must be primitive"));
+                }
+
+                // assign value to reference pointed to by JSON pointer; Note
+                // that if the JSON pointer is "" (i.e., points to the whole
+                // value), function get_and_create returns a reference to
+                // result itself. An assignment will then create a primitive
+                // value.
+                json_pointer(element.first).get_and_create(result) = element.second;
+            }
+
+            return result;
+        }
+
+      private:
+        /// the reference tokens
+        std::vector<std::string> reference_tokens {};
+    };
+
+    //////////////////////////
+    // JSON Pointer support //
+    //////////////////////////
+
+    /// @name JSON Pointer functions
+    /// @{
+
+    /*!
+    @brief access specified element via JSON Pointer
+
+    Uses a JSON pointer to retrieve a reference to the respective JSON value.
+    No bound checking is performed. Similar to @ref operator[](const typename
+    object_t::key_type&), `null` values are created in arrays and objects if
+    necessary.
+
+    In particular:
+    - If the JSON pointer points to an object key that does not exist, it
+      is created an filled with a `null` value before a reference to it
+      is returned.
+    - If the JSON pointer points to an array index that does not exist, it
+      is created an filled with a `null` value before a reference to it
+      is returned. All indices between the current maximum and the given
+      index are also filled with `null`.
+    - The special value `-` is treated as a synonym for the index past the
+      end.
+
+    @param[in] ptr  a JSON pointer
+
+    @return reference to the element pointed to by @a ptr
+
+    @complexity Constant.
+
+    @throw std::out_of_range      if the JSON pointer can not be resolved
+    @throw std::domain_error      if an array index begins with '0'
+    @throw std::invalid_argument  if an array index was not a number
+
+    @liveexample{The behavior is shown in the example.,operatorjson_pointer}
+
+    @since version 2.0.0
+    */
+    reference operator[](const json_pointer& ptr)
+    {
+        return ptr.get_unchecked(this);
+    }
+
+    /*!
+    @brief access specified element via JSON Pointer
+
+    Uses a JSON pointer to retrieve a reference to the respective JSON value.
+    No bound checking is performed. The function does not change the JSON
+    value; no `null` values are created. In particular, the the special value
+    `-` yields an exception.
+
+    @param[in] ptr  JSON pointer to the desired element
+
+    @return const reference to the element pointed to by @a ptr
+
+    @complexity Constant.
+
+    @throw std::out_of_range      if the JSON pointer can not be resolved
+    @throw std::domain_error      if an array index begins with '0'
+    @throw std::invalid_argument  if an array index was not a number
+
+    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
+
+    @since version 2.0.0
+    */
+    const_reference operator[](const json_pointer& ptr) const
+    {
+        return ptr.get_unchecked(this);
+    }
+
+    /*!
+    @brief access specified element via JSON Pointer
+
+    Returns a reference to the element at with specified JSON pointer @a ptr,
+    with bounds checking.
+
+    @param[in] ptr  JSON pointer to the desired element
+
+    @return reference to the element pointed to by @a ptr
+
+    @complexity Constant.
+
+    @throw std::out_of_range      if the JSON pointer can not be resolved
+    @throw std::domain_error      if an array index begins with '0'
+    @throw std::invalid_argument  if an array index was not a number
+
+    @liveexample{The behavior is shown in the example.,at_json_pointer}
+
+    @since version 2.0.0
+    */
+    reference at(const json_pointer& ptr)
+    {
+        return ptr.get_checked(this);
+    }
+
+    /*!
+    @brief access specified element via JSON Pointer
+
+    Returns a const reference to the element at with specified JSON pointer @a
+    ptr, with bounds checking.
+
+    @param[in] ptr  JSON pointer to the desired element
+
+    @return reference to the element pointed to by @a ptr
+
+    @complexity Constant.
+
+    @throw std::out_of_range      if the JSON pointer can not be resolved
+    @throw std::domain_error      if an array index begins with '0'
+    @throw std::invalid_argument  if an array index was not a number
+
+    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
+
+    @since version 2.0.0
+    */
+    const_reference at(const json_pointer& ptr) const
+    {
+        return ptr.get_checked(this);
+    }
+
+    /*!
+    @brief return flattened JSON value
+
+    The function creates a JSON object whose keys are JSON pointers (see [RFC
+    6901](https://tools.ietf.org/html/rfc6901)) and whose values are all
+    primitive. The original JSON value can be restored using the @ref
+    unflatten() function.
+
+    @return an object that maps JSON pointers to primitve values
+
+    @note Empty objects and arrays are flattened to `null` and will not be
+          reconstructed correctly by the @ref unflatten() function.
+
+    @complexity Linear in the size the JSON value.
+
+    @liveexample{The following code shows how a JSON object is flattened to an
+    object whose keys consist of JSON pointers.,flatten}
+
+    @sa @ref unflatten() for the reverse function
+
+    @since version 2.0.0
+    */
+    basic_json flatten() const
+    {
+        basic_json result(value_t::object);
+        json_pointer::flatten("", *this, result);
+        return result;
+    }
+
+    /*!
+    @brief unflatten a previously flattened JSON value
+
+    The function restores the arbitrary nesting of a JSON value that has been
+    flattened before using the @ref flatten() function. The JSON value must
+    meet certain constraints:
+    1. The value must be an object.
+    2. The keys must be JSON pointers (see
+       [RFC 6901](https://tools.ietf.org/html/rfc6901))
+    3. The mapped values must be primitive JSON types.
+
+    @return the original JSON from a flattened version
+
+    @note Empty objects and arrays are flattened by @ref flatten() to `null`
+          values and can not unflattened to their original type. Apart from
+          this example, for a JSON value `j`, the following is always true:
+          `j == j.flatten().unflatten()`.
+
+    @complexity Linear in the size the JSON value.
+
+    @liveexample{The following code shows how a flattened JSON object is
+    unflattened into the original nested JSON object.,unflatten}
+
+    @sa @ref flatten() for the reverse function
+
+    @since version 2.0.0
+    */
+    basic_json unflatten() const
+    {
+        return json_pointer::unflatten(*this);
+    }
+
+    /// @}
+
+    //////////////////////////
+    // JSON Patch functions //
+    //////////////////////////
+
+    /// @name JSON Patch functions
+    /// @{
+
+    /*!
+    @brief applies a JSON patch
+
+    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
+    expressing a sequence of operations to apply to a JSON) document. With
+    this funcion, a JSON Patch is applied to the current JSON value by
+    executing all operations from the patch.
+
+    @param[in] json_patch  JSON patch document
+    @return patched document
+
+    @note The application of a patch is atomic: Either all operations succeed
+          and the patched document is returned or an exception is thrown. In
+          any case, the original value is not changed: the patch is applied
+          to a copy of the value.
+
+    @throw std::out_of_range if a JSON pointer inside the patch could not
+    be resolved successfully in the current JSON value; example: `"key baz
+    not found"`
+    @throw invalid_argument if the JSON patch is malformed (e.g., mandatory
+    attributes are missing); example: `"operation add must have member path"`
+
+    @complexity Linear in the size of the JSON value and the length of the
+    JSON patch. As usually only a fraction of the JSON value is affected by
+    the patch, the complexity can usually be neglected.
+
+    @liveexample{The following code shows how a JSON patch is applied to a
+    value.,patch}
+
+    @sa @ref diff -- create a JSON patch by comparing two JSON values
+
+    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
+    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
+
+    @since version 2.0.0
+    */
+    basic_json patch(const basic_json& json_patch) const
+    {
+        // make a working copy to apply the patch to
+        basic_json result = *this;
+
+        // the valid JSON Patch operations
+        enum class patch_operations {add, remove, replace, move, copy, test, invalid};
+
+        const auto get_op = [](const std::string op)
+        {
+            if (op == "add")
+            {
+                return patch_operations::add;
+            }
+            if (op == "remove")
+            {
+                return patch_operations::remove;
+            }
+            if (op == "replace")
+            {
+                return patch_operations::replace;
+            }
+            if (op == "move")
+            {
+                return patch_operations::move;
+            }
+            if (op == "copy")
+            {
+                return patch_operations::copy;
+            }
+            if (op == "test")
+            {
+                return patch_operations::test;
+            }
+
+            return patch_operations::invalid;
+        };
+
+        // wrapper for "add" operation; add value at ptr
+        const auto operation_add = [&result](json_pointer & ptr, basic_json val)
+        {
+            // adding to the root of the target document means replacing it
+            if (ptr.is_root())
+            {
+                result = val;
+            }
+            else
+            {
+                // make sure the top element of the pointer exists
+                json_pointer top_pointer = ptr.top();
+                if (top_pointer != ptr)
+                {
+                    result.at(top_pointer);
+                }
+
+                // get reference to parent of JSON pointer ptr
+                const auto last_path = ptr.pop_back();
+                basic_json& parent = result[ptr];
+
+                switch (parent.m_type)
+                {
+                    case value_t::null:
+                    case value_t::object:
+                    {
+                        // use operator[] to add value
+                        parent[last_path] = val;
+                        break;
+                    }
+
+                    case value_t::array:
+                    {
+                        if (last_path == "-")
+                        {
+                            // special case: append to back
+                            parent.push_back(val);
+                        }
+                        else
+                        {
+                            const auto idx = std::stoi(last_path);
+                            if (static_cast<size_type>(idx) > parent.size())
+                            {
+                                // avoid undefined behavior
+                                JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
+                            }
+                            else
+                            {
+                                // default case: insert add offset
+                                parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
+                            }
+                        }
+                        break;
+                    }
+
+                    default:
+                    {
+                        // if there exists a parent it cannot be primitive
+                        assert(false);  // LCOV_EXCL_LINE
+                    }
+                }
+            }
+        };
+
+        // wrapper for "remove" operation; remove value at ptr
+        const auto operation_remove = [&result](json_pointer & ptr)
+        {
+            // get reference to parent of JSON pointer ptr
+            const auto last_path = ptr.pop_back();
+            basic_json& parent = result.at(ptr);
+
+            // remove child
+            if (parent.is_object())
+            {
+                // perform range check
+                auto it = parent.find(last_path);
+                if (it != parent.end())
+                {
+                    parent.erase(it);
+                }
+                else
+                {
+                    JSON_THROW(std::out_of_range("key '" + last_path + "' not found"));
+                }
+            }
+            else if (parent.is_array())
+            {
+                // note erase performs range check
+                parent.erase(static_cast<size_type>(std::stoi(last_path)));
+            }
+        };
+
+        // type check
+        if (not json_patch.is_array())
+        {
+            // a JSON patch must be an array of objects
+            JSON_THROW(std::invalid_argument("JSON patch must be an array of objects"));
+        }
+
+        // iterate and apply th eoperations
+        for (const auto& val : json_patch)
+        {
+            // wrapper to get a value for an operation
+            const auto get_value = [&val](const std::string & op,
+                                          const std::string & member,
+                                          bool string_type) -> basic_json&
+            {
+                // find value
+                auto it = val.m_value.object->find(member);
+
+                // context-sensitive error message
+                const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
+
+                // check if desired value is present
+                if (it == val.m_value.object->end())
+                {
+                    JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'"));
+                }
+
+                // check if result is of type string
+                if (string_type and not it->second.is_string())
+                {
+                    JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'"));
+                }
+
+                // no error: return value
+                return it->second;
+            };
+
+            // type check
+            if (not val.is_object())
+            {
+                JSON_THROW(std::invalid_argument("JSON patch must be an array of objects"));
+            }
+
+            // collect mandatory members
+            const std::string op = get_value("op", "op", true);
+            const std::string path = get_value(op, "path", true);
+            json_pointer ptr(path);
+
+            switch (get_op(op))
+            {
+                case patch_operations::add:
+                {
+                    operation_add(ptr, get_value("add", "value", false));
+                    break;
+                }
+
+                case patch_operations::remove:
+                {
+                    operation_remove(ptr);
+                    break;
+                }
+
+                case patch_operations::replace:
+                {
+                    // the "path" location must exist - use at()
+                    result.at(ptr) = get_value("replace", "value", false);
+                    break;
+                }
+
+                case patch_operations::move:
+                {
+                    const std::string from_path = get_value("move", "from", true);
+                    json_pointer from_ptr(from_path);
+
+                    // the "from" location must exist - use at()
+                    basic_json v = result.at(from_ptr);
+
+                    // The move operation is functionally identical to a
+                    // "remove" operation on the "from" location, followed
+                    // immediately by an "add" operation at the target
+                    // location with the value that was just removed.
+                    operation_remove(from_ptr);
+                    operation_add(ptr, v);
+                    break;
+                }
+
+                case patch_operations::copy:
+                {
+                    const std::string from_path = get_value("copy", "from", true);;
+                    const json_pointer from_ptr(from_path);
+
+                    // the "from" location must exist - use at()
+                    result[ptr] = result.at(from_ptr);
+                    break;
+                }
+
+                case patch_operations::test:
+                {
+                    bool success = false;
+                    JSON_TRY
+                    {
+                        // check if "value" matches the one at "path"
+                        // the "path" location must exist - use at()
+                        success = (result.at(ptr) == get_value("test", "value", false));
+                    }
+                    JSON_CATCH (std::out_of_range&)
+                    {
+                        // ignore out of range errors: success remains false
+                    }
+
+                    // throw an exception if test fails
+                    if (not success)
+                    {
+                        JSON_THROW(std::domain_error("unsuccessful: " + val.dump()));
+                    }
+
+                    break;
+                }
+
+                case patch_operations::invalid:
+                {
+                    // op must be "add", "remove", "replace", "move", "copy", or
+                    // "test"
+                    JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid"));
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /*!
+    @brief creates a diff as a JSON patch
+
+    Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can
+    be changed into the value @a target by calling @ref patch function.
+
+    @invariant For two JSON values @a source and @a target, the following code
+    yields always `true`:
+    @code {.cpp}
+    source.patch(diff(source, target)) == target;
+    @endcode
+
+    @note Currently, only `remove`, `add`, and `replace` operations are
+          generated.
+
+    @param[in] source  JSON value to copare from
+    @param[in] target  JSON value to copare against
+    @param[in] path    helper value to create JSON pointers
+
+    @return a JSON patch to convert the @a source to @a target
+
+    @complexity Linear in the lengths of @a source and @a target.
+
+    @liveexample{The following code shows how a JSON patch is created as a
+    diff for two JSON values.,diff}
+
+    @sa @ref patch -- apply a JSON patch
+
+    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
+
+    @since version 2.0.0
+    */
+    static basic_json diff(const basic_json& source,
+                           const basic_json& target,
+                           const std::string& path = "")
+    {
+        // the patch
+        basic_json result(value_t::array);
+
+        // if the values are the same, return empty patch
+        if (source == target)
+        {
+            return result;
+        }
+
+        if (source.type() != target.type())
+        {
+            // different types: replace value
+            result.push_back(
+            {
+                {"op", "replace"},
+                {"path", path},
+                {"value", target}
+            });
+        }
+        else
+        {
+            switch (source.type())
+            {
+                case value_t::array:
+                {
+                    // first pass: traverse common elements
+                    size_t i = 0;
+                    while (i < source.size() and i < target.size())
+                    {
+                        // recursive call to compare array values at index i
+                        auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
+                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
+                        ++i;
+                    }
+
+                    // i now reached the end of at least one array
+                    // in a second pass, traverse the remaining elements
+
+                    // remove my remaining elements
+                    const auto end_index = static_cast<difference_type>(result.size());
+                    while (i < source.size())
+                    {
+                        // add operations in reverse order to avoid invalid
+                        // indices
+                        result.insert(result.begin() + end_index, object(
+                        {
+                            {"op", "remove"},
+                            {"path", path + "/" + std::to_string(i)}
+                        }));
+                        ++i;
+                    }
+
+                    // add other remaining elements
+                    while (i < target.size())
+                    {
+                        result.push_back(
+                        {
+                            {"op", "add"},
+                            {"path", path + "/" + std::to_string(i)},
+                            {"value", target[i]}
+                        });
+                        ++i;
+                    }
+
+                    break;
+                }
+
+                case value_t::object:
+                {
+                    // first pass: traverse this object's elements
+                    for (auto it = source.begin(); it != source.end(); ++it)
+                    {
+                        // escape the key name to be used in a JSON patch
+                        const auto key = json_pointer::escape(it.key());
+
+                        if (target.find(it.key()) != target.end())
+                        {
+                            // recursive call to compare object values at key it
+                            auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
+                            result.insert(result.end(), temp_diff.begin(), temp_diff.end());
+                        }
+                        else
+                        {
+                            // found a key that is not in o -> remove it
+                            result.push_back(object(
+                            {
+                                {"op", "remove"},
+                                {"path", path + "/" + key}
+                            }));
+                        }
+                    }
+
+                    // second pass: traverse other object's elements
+                    for (auto it = target.begin(); it != target.end(); ++it)
+                    {
+                        if (source.find(it.key()) == source.end())
+                        {
+                            // found a key that is not in this -> add it
+                            const auto key = json_pointer::escape(it.key());
+                            result.push_back(
+                            {
+                                {"op", "add"},
+                                {"path", path + "/" + key},
+                                {"value", it.value()}
+                            });
+                        }
+                    }
+
+                    break;
+                }
+
+                default:
+                {
+                    // both primitive type: replace value
+                    result.push_back(
+                    {
+                        {"op", "replace"},
+                        {"path", path},
+                        {"value", target}
+                    });
+                    break;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /// @}
+};
+
+
+/////////////
+// presets //
+/////////////
+
+/*!
+@brief default JSON class
+
+This type is the default specialization of the @ref basic_json class which
+uses the standard template types.
+
+@since version 1.0.0
+*/
+using json = basic_json<>;
+} // namespace nlohmann
+
+
+///////////////////////
+// nonmember support //
+///////////////////////
+
+// specialization of std::swap, and std::hash
+namespace std
+{
+/*!
+@brief exchanges the values of two JSON objects
+
+@since version 1.0.0
+*/
+template<>
+inline void swap(nlohmann::json& j1,
+                 nlohmann::json& j2) noexcept(
+                     is_nothrow_move_constructible<nlohmann::json>::value and
+                     is_nothrow_move_assignable<nlohmann::json>::value
+                 )
+{
+    j1.swap(j2);
+}
+
+/// hash value for JSON objects
+template<>
+struct hash<nlohmann::json>
+{
+    /*!
+    @brief return a hash value for a JSON object
+
+    @since version 1.0.0
+    */
+    std::size_t operator()(const nlohmann::json& j) const
+    {
+        // a naive hashing via the string representation
+        const auto& h = hash<nlohmann::json::string_t>();
+        return h(j.dump());
+    }
+};
+} // namespace std
+
+/*!
+@brief user-defined string literal for JSON values
+
+This operator implements a user-defined string literal for JSON objects. It
+can be used by adding `"_json"` to a string literal and returns a JSON object
+if no parse error occurred.
+
+@param[in] s  a string representation of a JSON object
+@param[in] n  the length of string @a s
+@return a JSON object
+
+@since version 1.0.0
+*/
+inline nlohmann::json operator "" _json(const char* s, std::size_t n)
+{
+    return nlohmann::json::parse(s, s + n);
+}
+
+/*!
+@brief user-defined string literal for JSON pointer
+
+This operator implements a user-defined string literal for JSON Pointers. It
+can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer
+object if no parse error occurred.
+
+@param[in] s  a string representation of a JSON Pointer
+@param[in] n  the length of string @a s
+@return a JSON pointer object
+
+@since version 2.0.0
+*/
+inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
+{
+    return nlohmann::json::json_pointer(std::string(s, n));
+}
+
+// restore GCC/clang diagnostic settings
+#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
+    #pragma GCC diagnostic pop
+#endif
+
+// clean up
+#undef JSON_THROW
+#undef JSON_TRY
+#undef JSON_CATCH
+#undef JSON_DEPRECATED
+
+#endif
diff --git a/include/format/BP1.h b/include/format/BP1.h
new file mode 100644
index 0000000000000000000000000000000000000000..eed6b17be8484e87b5038538fb97ab6544567f6a
--- /dev/null
+++ b/include/format/BP1.h
@@ -0,0 +1,256 @@
+/*
+ * BP1.h
+ *
+ *  Created on: Feb 2, 2017
+ *      Author: wfg
+ */
+
+#ifndef BP1_H_
+#define BP1_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <memory> //std::shared_ptr
+#include <cstdint> //std::uintX_t
+#include <unordered_map>
+#include <vector>
+//#include <queue>  //std::priority_queue to be added later
+/// \endcond
+
+#if ADIOS_NOMPI
+  #include "mpidummy.h"
+#else
+  #include <mpi.h>
+#endif
+
+#include "core/Transport.h"
+#include "core/Profiler.h"
+
+
+namespace adios
+{
+namespace format
+{
+
+/**
+ * Used for Variables and Attributes, needed in a container for characteristic sets merge independently for each Variable or Attribute
+ */
+struct BP1Index
+{
+    std::vector<char> Buffer; ///< metadata variable index, start with 100Kb
+    std::uint64_t Count = 0; ///< number of characteristics sets (time and spatial aggregation)
+    const std::uint32_t MemberID;
+
+    BP1Index( const std::uint32_t memberID ):
+        MemberID{ memberID }
+    {
+        Buffer.reserve( 500 );
+    }
+};
+
+/**
+ * Single struct that tracks metadata indices in bp format
+ */
+struct BP1MetadataSet
+{
+    std::uint32_t TimeStep; ///< current time step, updated with advance step, if append it will be updated to last, starts with one in ADIOS1
+
+    BP1Index PGIndex = BP1Index( 0 ); ///< single buffer for PGIndex
+
+    //no priority for now
+    std::unordered_map< std::string, BP1Index > VarsIndices; ///< key: variable name, value: bp metadata variable index
+    std::unordered_map< std::string, BP1Index > AttributesIndices; ///< key: attribute name, value: bp metadata attribute index
+
+    const unsigned int MiniFooterSize = 28; ///< from bpls reader
+
+    //PG (relative) positions in Data buffer to be updated
+    std::uint64_t DataPGCount = 0;
+    std::size_t DataPGLengthPosition = 0; ///< current PG initial ( relative ) position, needs to be updated in every advance step or init
+    std::uint32_t DataPGVarsCount = 0; ///< variables in current PG
+    std::size_t DataPGVarsCountPosition = 0; ///< current PG variable count ( relative ) position, needs to be updated in every advance step or init
+    bool DataPGIsOpen = false;
+
+    Profiler Log; ///< object that takes buffering profiling info
+};
+
+/**
+ * Base class for BP1Writer and BP1Reader format
+ */
+class BP1
+{
+
+public:
+
+    /**
+     * Checks if input name has .bp extension and returns a .bp directory name
+     * @param name input (might or not have .bp)
+     * @return either name.bp (name has no .bp) or name (name has .bp extension)
+     */
+    std::string GetDirectoryName( const std::string name ) const noexcept;
+
+    /**
+     * Opens rank files in the following format:
+     * if transport.m_MPIComm different from MPI_Comm_SELF --> name.bp.dir/name.bp.rank
+     * @param name might contain .bp or not, if not .bp will be added
+     * @param accessMode "write" "w", "r" "read",  "append" "a"
+     * @param transport file I/O transport
+     */
+    void OpenRankFiles( const std::string name, const std::string accessMode, Transport& transport ) const;
+
+
+protected:
+
+    /**
+     * method type for file I/O
+     */
+    enum IO_METHOD {
+         METHOD_UNKNOWN     = -2//!< ADIOS_METHOD_UNKNOWN
+        ,METHOD_NULL        = -1                 //!< ADIOS_METHOD_NULL
+        ,METHOD_MPI         = 0                  //!< METHOD_MPI
+        ,METHOD_DATATAP     = 1     //OBSOLETE
+        ,METHOD_POSIX       = 2                  //!< METHOD_POSIX
+        ,METHOD_DATASPACES  = 3                  //!< METHOD_DATASPACES
+        ,METHOD_VTK         = 4     //non-existent
+        ,METHOD_POSIX_ASCII = 5     //non-existent
+        ,METHOD_MPI_CIO     = 6     //OBSOLETE
+        ,METHOD_PHDF5       = 7                  //!< METHOD_PHDF5
+        ,METHOD_PROVENANCE  = 8     //OBSOLETE
+        ,METHOD_MPI_STRIPE  = 9     //OBSOLETE
+        ,METHOD_MPI_LUSTRE  = 10                 //!< METHOD_MPI_LUSTRE
+        ,METHOD_MPI_STAGGER = 11    //OBSOLETE
+        ,METHOD_MPI_AGG     = 12    //OBSOLETE
+        ,METHOD_ADAPTIVE    = 13    //OBSOLETE
+        ,METHOD_POSIX1      = 14    //OBSOLETE
+        ,METHOD_NC4         = 15                 //!< METHOD_NC4
+        ,METHOD_MPI_AMR     = 16                 //!< METHOD_MPI_AMR
+        ,METHOD_MPI_AMR1    = 17    //OBSOLETE
+        ,METHOD_FLEXPATH    = 18                 //!< METHOD_FLEXPATH
+        ,METHOD_NSSI_STAGING = 19                //!< METHOD_NSSI_STAGING
+        ,METHOD_NSSI_FILTER  = 20                //!< METHOD_NSSI_FILTER
+        ,METHOD_DIMES        = 21                //!< METHOD_DIMES
+        ,METHOD_VAR_MERGE   = 22                 //!< METHOD_VAR_MERGE
+        ,METHOD_MPI_BGQ     = 23                 //!< METHOD_MPI_BGQ
+        ,METHOD_ICEE        = 24                 //!< METHOD_ICEE
+        ,METHOD_COUNT       = 25                 //!< METHOD_COUNT
+        ,METHOD_FSTREAM     = 26
+        ,METHOD_FILE        = 27
+        ,METHOD_ZMQ         = 28
+        ,METHOD_MDTM        = 29
+    };
+
+
+    /**
+     * DataTypes mapping in BP Format
+     */
+    enum DataTypes
+    {
+        type_unknown = -1,         //!< type_unknown
+        type_byte = 0,             //!< type_byte
+        type_short = 1,            //!< type_short
+        type_integer = 2,          //!< type_integer
+        type_long = 4,             //!< type_long
+
+        type_unsigned_byte = 50,   //!< type_unsigned_byte
+        type_unsigned_short = 51,  //!< type_unsigned_short
+        type_unsigned_integer = 52,//!< type_unsigned_integer
+        type_unsigned_long = 54,   //!< type_unsigned_long
+
+        type_real = 5,             //!< type_real or float
+        type_double = 6,           //!< type_double
+        type_long_double = 7,      //!< type_long_double
+
+        type_string = 9,           //!< type_string
+        type_complex = 10,         //!< type_complex
+        type_double_complex = 11,  //!< type_double_complex
+        type_string_array = 12     //!< type_string_array
+    };
+
+    /**
+     * Characteristic ID in variable metadata
+     */
+    enum VariableCharacteristicID
+    {
+        characteristic_value          = 0, //!< characteristic_value
+        characteristic_min            = 1, //!< Used to read in older bp file format
+        characteristic_max            = 2, //!< Used to read in older bp file format
+        characteristic_offset         = 3, //!< characteristic_offset
+        characteristic_dimensions     = 4, //!< characteristic_dimensions
+        characteristic_var_id         = 5, //!< characteristic_var_id
+        characteristic_payload_offset = 6, //!< characteristic_payload_offset
+        characteristic_file_index     = 7, //!< characteristic_file_index
+        characteristic_time_index     = 8, //!< characteristic_time_index
+        characteristic_bitmap         = 9, //!< characteristic_bitmap
+        characteristic_stat           = 10,//!< characteristic_stat
+        characteristic_transform_type = 11 //!< characteristic_transform_type
+    };
+
+
+    /** Define statistics type for characteristic ID = 10 in bp1 format */
+    enum VariableStatistics
+    {
+        statistic_min             = 0,
+        statistic_max             = 1,
+        statistic_cnt             = 2,
+        statistic_sum             = 3,
+        statistic_sum_square      = 4,
+        statistic_hist            = 5,
+        statistic_finite          = 6
+    };
+
+    template<class T>
+    struct Stats
+	{
+    	T Min;
+    	T Max;
+    	std::uint64_t Offset;
+    	std::uint64_t PayloadOffset;
+    	std::uint32_t TimeIndex;
+    	std::uint32_t MemberID;
+
+
+//		unsigned long int count;
+//		long double sum;
+//		long double sumSquare;
+		//unsigned long int histogram
+		//bool finite??
+	};
+
+
+
+    /**
+     * Returns data type index from enum Datatypes
+     * @param variable input variable
+     * @return data type
+     */
+    template< class T > inline std::int8_t GetDataType( ) const noexcept
+    {
+        return type_unknown;
+    }
+
+    std::vector<std::uint8_t> GetMethodIDs( const std::vector< std::shared_ptr<Transport> >& transports ) const noexcept;
+
+};
+
+
+//Moving template BP1Writer::GetDataType template specializations outside of the class
+template< > inline std::int8_t BP1::GetDataType<char>( ) const noexcept { return type_byte; }
+template< > inline std::int8_t BP1::GetDataType<short>( ) const noexcept{ return type_short; }
+template< > inline std::int8_t BP1::GetDataType<int>( ) const noexcept{ return type_integer; }
+template< > inline std::int8_t BP1::GetDataType<long int>( ) const noexcept{ return type_long; }
+
+template< > inline std::int8_t BP1::GetDataType<unsigned char>( ) const noexcept { return type_unsigned_byte; }
+template< > inline std::int8_t BP1::GetDataType<unsigned short>( ) const noexcept{ return type_unsigned_short; }
+template< > inline std::int8_t BP1::GetDataType<unsigned int>( ) const noexcept{ return type_unsigned_integer; }
+template< > inline std::int8_t BP1::GetDataType<unsigned long int>( ) const noexcept{ return type_unsigned_long; }
+
+template< > inline std::int8_t BP1::GetDataType<float>( ) const noexcept{ return type_real; }
+template< > inline std::int8_t BP1::GetDataType<double>( ) const noexcept{ return type_double; }
+template< > inline std::int8_t BP1::GetDataType<long double>( ) const noexcept{ return type_long_double; }
+
+
+
+} //end namespace format
+} //end namespace adios
+
+
+
+#endif /* BP1_H_ */
diff --git a/include/format/BP1Aggregator.h b/include/format/BP1Aggregator.h
new file mode 100644
index 0000000000000000000000000000000000000000..60f1a8efafeb5024ce807dbd5f32dd07e889cc01
--- /dev/null
+++ b/include/format/BP1Aggregator.h
@@ -0,0 +1,63 @@
+/*
+ * BP1Aggregator.h
+ *
+ *  Created on: Mar 1, 2017
+ *      Author: wfg
+ */
+
+#ifndef BP1AGGREGATOR_H_
+#define BP1AGGREGATOR_H_
+
+
+
+#ifdef ADIOS_NOMPI
+  #include "mpidummy.h"
+#else
+  #include <mpi.h>
+#endif
+
+
+namespace adios
+{
+namespace format
+{
+
+/**
+ * Does all MPI related spatial aggregation tasks
+ */
+class BP1Aggregator
+{
+
+public:
+
+    MPI_Comm m_MPIComm = MPI_COMM_SELF; ///< MPI communicator from Engine
+    int m_RankMPI = 0; ///< current MPI rank process
+    int m_SizeMPI = 1; ///< current MPI processes size
+
+    /**
+     * Unique constructor
+     * @param mpiComm coming from engine
+     */
+    BP1Aggregator( MPI_Comm mpiComm, const bool debugMode = false );
+
+    ~BP1Aggregator( );
+
+
+    /**
+     * Function that aggregates and writes (from rank = 0) profiling.log in python dictionary format
+     * @param rankLog contain rank profiling info to be aggregated
+     */
+    void WriteProfilingLog( const std::string fileName, const std::string& rankLog );
+
+private:
+
+    const bool m_DebugMode = false;
+
+
+};
+
+
+} //end namespace format
+} //end namespace adios
+
+#endif /* BP1AGGREGATOR_H_ */
diff --git a/include/format/BP1Writer.h b/include/format/BP1Writer.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e68f083f1e6a9ec2d62b146a6b8ef7a0a3f6f8c
--- /dev/null
+++ b/include/format/BP1Writer.h
@@ -0,0 +1,449 @@
+/*
+ * BP1.h
+ *
+ *  Created on: Jan 24, 2017
+ *      Author: wfg
+ */
+
+#ifndef BP1WRITER_H_
+#define BP1WRITER_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <algorithm> //std::count, std::copy, std::for_each
+#include <cstring> //std::memcpy
+#include <cmath>   //std::ceil
+/// \endcond
+
+#include "BP1.h"
+#include "core/Variable.h"
+#include "core/Capsule.h"
+#include "core/Profiler.h"
+#include "capsule/heap/STLVector.h"
+#include "functions/adiosTemplates.h"
+#include "functions/adiosFunctions.h"
+
+
+namespace adios
+{
+namespace format
+{
+
+
+class BP1Writer : public BP1
+{
+
+public:
+
+    unsigned int m_Threads = 1;  ///< number of threads for thread operations in large array (min,max)
+    unsigned int m_Verbosity = 0; ///< statistics verbosity, can change if redefined in Engine method.
+    float m_GrowthFactor = 1.5; ///< memory growth factor, can change if redefined in Engine method.
+    const std::uint8_t m_Version = 3; ///< BP format version
+
+    /**
+     * Calculates the Process Index size in bytes according to the BP format, including list of method with no parameters (for now)
+     * @param name
+     * @param timeStepName
+     * @param numberOfTransports
+     * @return size of pg index
+     */
+    std::size_t GetProcessGroupIndexSize( const std::string name, const std::string timeStepName,
+                                          const std::size_t numberOfTransports ) const noexcept;
+
+    /**
+     * Writes a process group index PGIndex and list of methods (from transports), done at Open or aggregation of new time step
+     * Version that operates on a single heap buffer and metadataset.
+     * @param isFortran
+     * @param name
+     * @param processID
+     * @param transports
+     * @param buffer
+     * @param metadataSet
+     */
+    void WriteProcessGroupIndex( const bool isFortran, const std::string name, const std::uint32_t processID,
+                                 const std::vector< std::shared_ptr<Transport> >& transports,
+                                 capsule::STLVector& heap, BP1MetadataSet& metadataSet ) const noexcept;
+
+    /**
+     * Returns the estimated variable index size
+     * @param group
+     * @param variableName
+     * @param variable
+     * @param verbosity
+     * @return variable index size
+     */
+    template< class T >
+    size_t GetVariableIndexSize( const Variable<T>& variable ) const noexcept
+    {
+        //size_t indexSize = varEntryLength + memberID + lengthGroupName + groupName + lengthVariableName + lengthOfPath + path + datatype
+        size_t indexSize = 23; //without characteristics
+        indexSize += variable.m_Name.size();
+
+        // characteristics 3 and 4, check variable number of dimensions
+        const std::size_t dimensions = variable.DimensionsSize(); //number of commas in CSV + 1
+        indexSize += 28 * dimensions; //28 bytes per dimension
+        indexSize += 1; //id
+
+        //characteristics, offset + payload offset in data
+        indexSize += 2*(1+8);
+        //characteristic 0, if scalar add value, for now only allowing string
+        if( dimensions == 1 )
+        {
+            indexSize += sizeof(T);
+            indexSize += 1; //id
+            //must have an if here
+            indexSize += 2 + variable.m_Name.size();
+            indexSize += 1; //id
+        }
+
+        //characteristic statistics
+        if( m_Verbosity == 0 ) //default, only min and max
+        {
+            indexSize += 2 * ( sizeof(T) + 1 );
+            indexSize += 1 + 1; //id
+        }
+
+        return indexSize + 12; ///extra 12 bytes in case of attributes
+        //need to add transform characteristics
+    }
+
+    /**
+     * Version for primitive types (except std::complex<T>)
+     * @param variable
+     * @param heap
+     * @param metadataSet
+     */
+    template<class T> inline
+    void WriteVariableMetadata( const Variable<T>& variable, capsule::STLVector& heap, BP1MetadataSet& metadataSet ) const noexcept
+    {
+    	Stats<T> stats = GetStats( variable );
+    	WriteVariableMetadataCommon( variable, stats, heap, metadataSet );
+    }
+
+    /**
+     * Overloaded version for std::complex<T> variables
+     * @param variable
+     * @param heap
+     * @param metadataSet
+     */
+    template<class T>
+    void WriteVariableMetadata( const Variable<std::complex<T>>& variable, capsule::STLVector& heap, BP1MetadataSet& metadataSet ) const noexcept
+    {
+    	Stats<T> stats = GetStats( variable );
+    	WriteVariableMetadataCommon( variable, stats, heap, metadataSet );
+    }
+
+
+    /**
+     * Expensive part this is only for heap buffers need to adapt to vector of capsules
+     * @param variable
+     * @param buffer
+     */
+    template< class T >
+    void WriteVariablePayload( const Variable<T>& variable, capsule::STLVector& heap, const unsigned int nthreads = 1 ) const noexcept
+    {
+        //EXPENSIVE part, might want to use threads if large, serial for now
+        CopyToBuffer( heap.m_Data, variable.m_AppValues, variable.TotalSize() );
+        heap.m_DataAbsolutePosition += variable.PayLoadSize();
+    }
+
+
+    void Advance( BP1MetadataSet& metadataSet, capsule::STLVector& buffer );
+
+    /**
+     * Function that sets metadata (if first close) and writes to a single transport
+     * @param metadataSet current rank metadata set
+     * @param heap contains data buffer
+     * @param transport does a write after data and metadata is setup
+     * @param isFirstClose true: metadata has been set and aggregated
+     * @param doAggregation true: for N-to-M, false: for N-to-N
+     */
+    void Close( BP1MetadataSet& metadataSet, capsule::STLVector& heap, Transport& transport, bool& isFirstClose,
+                const bool doAggregation ) const noexcept;
+
+
+    /**
+     * Writes the ADIOS log information (buffering, open, write and close) for a rank process
+     * @param rank current rank
+     * @param metadataSet contains Profile info for buffering
+     * @param transports  contains Profile info for transport open, writes and close
+     * @return string for this rank that will be aggregated into profiling.log
+     */
+    std::string GetRankProfilingLog( const int rank, const BP1MetadataSet& metadataSet,
+                                     const std::vector< std::shared_ptr<Transport> >& transports ) const noexcept;
+
+private:
+
+    template< class T, class U >
+    void WriteVariableMetadataCommon( const Variable<T>& variable, Stats<U>& stats,
+    		                          capsule::STLVector& heap, BP1MetadataSet& metadataSet ) const noexcept
+	{
+        stats.TimeIndex = metadataSet.TimeStep;
+
+        //Get new Index or point to existing index
+        bool isNew = true; //flag to check if variable is new
+    	BP1Index& varIndex = GetBP1Index( variable.m_Name, metadataSet.VarsIndices, isNew );
+    	stats.MemberID = varIndex.MemberID;
+
+    	//write metadata header in data and extract offsets
+    	stats.Offset = heap.m_DataAbsolutePosition;
+    	WriteVariableMetadataInData( variable, stats, heap );
+    	stats.PayloadOffset = heap.m_DataAbsolutePosition;
+
+    	//write to metadata  index
+    	WriteVariableMetadataInIndex( variable, stats, isNew, varIndex );
+
+    	++metadataSet.DataPGVarsCount;
+	}
+
+
+    template< class T, class U >
+    void WriteVariableMetadataInData( const Variable<T>& variable, const Stats<U>& stats,
+    								  capsule::STLVector& heap ) const noexcept
+    {
+        auto& buffer = heap.m_Data;
+
+        const std::size_t varLengthPosition = buffer.size(); //capture initial position for variable length
+        buffer.insert( buffer.end(), 8, 0 ); //skip var length (8)
+        CopyToBuffer( buffer, &stats.MemberID ); //memberID
+        WriteNameRecord( variable.m_Name, buffer ); //variable name
+        buffer.insert( buffer.end(), 2, 0 ); //skip path
+        const std::uint8_t dataType = GetDataType<T>(); //dataType
+        CopyToBuffer( buffer, &dataType );
+        constexpr char no = 'n';  //isDimension
+        CopyToBuffer( buffer, &no );
+
+        //write variable dimensions
+        const std::uint8_t dimensions = variable.m_Dimensions.size();
+        CopyToBuffer( buffer, &dimensions ); //count
+        std::uint16_t dimensionsLength = 27 * dimensions; //27 is from 9 bytes for each: var y/n + local, var y/n + global dimension, var y/n + global offset, changed for characteristic
+        CopyToBuffer( buffer, &dimensionsLength ); //length
+        WriteDimensionsRecord( buffer, variable.m_Dimensions, variable.m_GlobalDimensions, variable.m_GlobalOffsets, 18, true );
+
+        //CHARACTERISTICS
+        WriteVariableCharacteristics( variable, stats, buffer, true );
+
+        //Back to varLength including payload size
+        const std::uint64_t varLength = buffer.size() - varLengthPosition + variable.PayLoadSize() - 8; //remove its own size
+        CopyToBuffer( buffer, varLengthPosition, &varLength ); //length
+
+        heap.m_DataAbsolutePosition += buffer.size() - varLengthPosition; // update absolute position to be used as payload position
+    }
+
+
+    template< class T, class U>
+    void WriteVariableMetadataInIndex( const Variable<T>& variable, const Stats<U>& stats,
+                                       const bool isNew, BP1Index& index ) const noexcept
+    {
+        auto& buffer = index.Buffer;
+
+        if( isNew == true ) //write variable header (might be shared with attributes index)
+        {
+            buffer.insert( buffer.end(), 4, 0 ); //skip var length (4)
+            CopyToBuffer( buffer, &stats.MemberID );
+            buffer.insert( buffer.end(), 2, 0 ); //skip group name
+            WriteNameRecord( variable.m_Name, buffer );
+            buffer.insert( buffer.end(), 2, 0 ); //skip path
+
+            const std::uint8_t dataType = GetDataType<T>();
+            CopyToBuffer( buffer, &dataType );
+
+            //Characteristics Sets Count in Metadata
+            index.Count = 1;
+            CopyToBuffer( buffer, &index.Count );
+        }
+        else //update characteristics sets count
+        {
+            const std::size_t characteristicsSetsCountPosition = 15 + variable.m_Name.size();
+            ++index.Count;
+            CopyToBuffer( buffer, characteristicsSetsCountPosition, &index.Count ); //test
+        }
+
+        WriteVariableCharacteristics( variable, stats, buffer );
+    }
+
+
+    template<class T, class U>
+    void WriteVariableCharacteristics( const Variable<T>& variable, const Stats<U>& stats, std::vector<char>& buffer,
+                                       const bool addLength = false ) const noexcept
+    {
+        const std::size_t characteristicsCountPosition = buffer.size(); //very important to track as writer is going back to this position
+        buffer.insert( buffer.end(), 5, 0 ); //skip characteristics count(1) + length (4)
+        std::uint8_t characteristicsCounter = 0;
+
+        //DIMENSIONS
+        std::uint8_t characteristicID = characteristic_dimensions;
+        CopyToBuffer( buffer, &characteristicID );
+        const std::uint8_t dimensions = variable.m_Dimensions.size();
+
+        if( addLength == true )
+        {
+            const std::int16_t lengthOfDimensionsCharacteristic = 24 * dimensions + 3; // 24 = 3 local, global, global offset x 8 bytes/each
+            CopyToBuffer( buffer, &lengthOfDimensionsCharacteristic );
+        }
+
+        CopyToBuffer( buffer, &dimensions ); //count
+        const std::uint16_t dimensionsLength = 24 * dimensions;
+        CopyToBuffer( buffer, &dimensionsLength ); //length
+        WriteDimensionsRecord( buffer, variable.m_Dimensions, variable.m_GlobalDimensions, variable.m_GlobalOffsets, 16, addLength );
+        ++characteristicsCounter;
+
+        //VALUE for SCALAR or STAT min, max for ARRAY
+        WriteBoundsRecord( variable.m_IsScalar, stats, buffer, characteristicsCounter, addLength );
+        //TIME INDEX
+        WriteCharacteristicRecord( characteristic_time_index, stats.TimeIndex, buffer, characteristicsCounter, addLength );
+
+        if( addLength == false )//only in metadata offset and payload offset
+        {
+            WriteCharacteristicRecord( characteristic_offset, stats.Offset, buffer, characteristicsCounter );
+            WriteCharacteristicRecord( characteristic_payload_offset, stats.PayloadOffset, buffer, characteristicsCounter );
+        }
+        //END OF CHARACTERISTICS
+
+        //Back to characteristics count and length
+        CopyToBuffer( buffer, characteristicsCountPosition, &characteristicsCounter ); //count (1)
+        const std::uint32_t characteristicsLength = buffer.size() - characteristicsCountPosition - 4 - 1; //remove its own length (4 bytes) + characteristic counter ( 1 byte )
+        CopyToBuffer( buffer, characteristicsCountPosition+1, &characteristicsLength ); //length
+    }
+
+    /**
+     * Writes from &buffer[position]:  [2 bytes:string.length()][string.length(): string.c_str()]
+     * @param name
+     * @param buffer
+     * @param position
+     */
+    void WriteNameRecord( const std::string name, std::vector<char>& buffer ) const noexcept;
+
+
+    /**
+     * Write a dimension record for a global variable used by WriteVariableCommon
+     * @param buffer
+     * @param position
+     * @param localDimensions
+     * @param globalDimensions
+     * @param globalOffsets
+     * @param addType true: for data buffers, false: for metadata buffer and data characteristic
+     */
+    void WriteDimensionsRecord( std::vector<char>& buffer,
+                                const std::vector<std::size_t>& localDimensions,
+                                const std::vector<std::size_t>& globalDimensions,
+                                const std::vector<std::size_t>& globalOffsets,
+							    const unsigned int skip,
+                                const bool addType = false ) const noexcept;
+
+    /**
+     * GetStats for primitive types except std::complex<T> types
+     * @param variable
+     * @return stats
+     */
+    template<class T>
+	Stats<T> GetStats( const Variable<T>& variable ) const noexcept
+	{
+		Stats<T> stats;
+		const std::size_t valuesSize = variable.TotalSize();
+
+		if( m_Verbosity == 0 )
+		{
+			if( valuesSize >= 10000000 ) //ten million? this needs actual results //here we can make decisions for threads based on valuesSize
+				GetMinMax( variable.m_AppValues, valuesSize, stats.Min, stats.Max, m_Threads ); //here we can add cores from constructor
+			else
+				GetMinMax( variable.m_AppValues, valuesSize, stats.Min, stats.Max );
+		}
+		return stats;
+	}
+
+    /**
+     * GetStats for std::complex<T> types
+     * @param variable
+     * @return stats
+     */
+    template<class T>
+	Stats<T> GetStats( const Variable<std::complex<T>>& variable ) const noexcept
+	{
+		Stats<T> stats;
+		const std::size_t valuesSize = variable.TotalSize();
+
+		if( m_Verbosity == 0 )
+		{
+			if( valuesSize >= 10000000 ) //ten million? this needs actual results //here we can make decisions for threads based on valuesSize
+				GetMinMax( variable.m_AppValues, valuesSize, stats.Min, stats.Max, m_Threads ); //here we can add cores from constructor
+			else
+				GetMinMax( variable.m_AppValues, valuesSize, stats.Min, stats.Max );
+		}
+		return stats;
+	}
+
+    template< class T >
+    void WriteBoundsRecord( const bool isScalar, const Stats<T>& stats, std::vector<char>& buffer,
+    		                std::uint8_t& characteristicsCounter, const bool addLength ) const noexcept
+    {
+    	if( isScalar == true )
+    	{
+    	    WriteCharacteristicRecord( characteristic_value, stats.Min, buffer, characteristicsCounter, addLength ); //stats.min = stats.max = value
+    		return;
+    	}
+
+    	if( m_Verbosity == 0 ) //default verbose
+        {
+    	    WriteCharacteristicRecord( characteristic_min, stats.Min, buffer, characteristicsCounter, addLength );
+    	    WriteCharacteristicRecord( characteristic_max, stats.Max, buffer, characteristicsCounter, addLength );
+        }
+    }
+
+    /**
+     * Write a characteristic value record to buffer
+     * @param id
+     * @param value
+     * @param buffers
+     * @param positions
+     * @param characvteristicsCounter to be updated by 1
+     * @param addLength true for data, false for metadata
+     */
+    template<class T>
+    void WriteCharacteristicRecord( const std::uint8_t characteristicID, const T& value,
+                                    std::vector<char>& buffer, std::uint8_t& characteristicsCounter,
+                                    const bool addLength = false ) const noexcept
+    {
+        const std::uint8_t id = characteristicID;
+    	CopyToBuffer( buffer, &id );
+
+        if( addLength == true )
+        {
+            const std::uint16_t lengthOfCharacteristic = sizeof( T ); //id
+            CopyToBuffer( buffer, &lengthOfCharacteristic );
+        }
+
+        CopyToBuffer( buffer, &value );
+        ++characteristicsCounter;
+    }
+
+    /**
+     * Returns corresponding index of type BP1Index, if doesn't exists creates a new one.
+     * Used for variables and attributes
+     * @param name variable or attribute name to look for index
+     * @param indices look up hash table of indices
+     * @param isNew true: index is newly created, false: index already exists in indices
+     * @return reference to BP1Index in indices
+     */
+    BP1Index& GetBP1Index( const std::string name, std::unordered_map<std::string, BP1Index>& indices, bool& isNew ) const noexcept;
+
+    /**
+     * Flattens the data and fills the pg length, vars count, vars length and attributes
+     * @param metadataSet
+     * @param buffer
+     */
+    void FlattenData( BP1MetadataSet& metadataSet, capsule::STLVector& buffer ) const noexcept;
+
+    /**
+     * Flattens the metadata indices into a single metadata buffer in capsule
+     * @param metadataSet
+     * @param buffer
+     */
+    void FlattenMetadata( BP1MetadataSet& metadataSet, capsule::STLVector& buffer ) const noexcept; ///< sets the metadata buffer in capsule with indices and minifooter
+
+};
+
+
+} //end namespace format
+} //end namespace adios
+
+#endif /* BP1WRITER_H_ */
diff --git a/include/functions/adiosFunctions.h b/include/functions/adiosFunctions.h
new file mode 100644
index 0000000000000000000000000000000000000000..46598ff855d57abf6cd24d428697a217e126db23
--- /dev/null
+++ b/include/functions/adiosFunctions.h
@@ -0,0 +1,195 @@
+/*
+ * adiosFunctions.h Long helper functions used by ADIOS class
+ *
+ *  Created on: Oct 10, 2016
+ *      Author: wfg
+ */
+
+#ifndef ADIOSFUNCTIONS_H_
+#define ADIOSFUNCTIONS_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+#include <vector>
+#include <map>
+#include <cstring> //std::size_t
+#include <memory> //std::shared_ptr
+/// \endcond
+
+#ifdef ADIOS_NOMPI
+  #include "mpidummy.h"
+#else
+  #include <mpi.h>
+#endif
+
+#include "core/Transform.h"
+
+namespace adios
+{
+
+/**
+ * Opens and checks for file and dumps contents to a single string
+ * @param fileName file to be opened
+ * @param fileContents output contains the entire file
+ */
+void DumpFileToString( const std::string fileName, std::string& fileContents );
+
+
+/**
+ * Extracts a substring between two tags from content
+ * @param initialTag
+ * @param finalTag
+ * @param content full string
+ * @param subString if found return substring between initialTag and finalTag, otherwise returns empty
+ * @param currentPosition to start the search, moved forward to finalTag position
+ */
+void GetSubString ( const std::string initialTag, const std::string finalTag, const std::string content, std::string& subString,
+                    std::string::size_type& currentPosition );
+
+/**
+ * Extracts the value inside quotes in a string currentTag ( Example: currentTag --> field1="value1" field2="value2" )
+ * @param quote double " or single '
+ * @param quotePosition position of the opening quote in currentTag
+ * @param currentTag initial tag value, modified by cutting the first found " " portion, currentTag --> field2="value2"
+ * @param value value1 in the example above
+ */
+void GetQuotedValue( const char quote, const std::string::size_type& quotePosition,
+                     std::string& currentTag, std::string& value );
+
+
+/**
+ * Get attributes field1="value1" field2="value2" by looping through a single XML tag
+ * @param tag field0="value0" field1="value1" in a single string
+ * @param pairs pairs[0].first=field0 pairs[0].second=value0 pairs[1].first=field1 pairs[1].second=value1
+ */
+void GetPairs( const std::string tag, std::vector< std::pair<const std::string, const std::string> >& pairs ) noexcept;
+
+
+/**
+ * Determine tag type and call GetPairs to populate pairs
+ * @param fileContent file Content in a single string
+ * @param tag field0="value0" field1="value1" in a single string
+ * @param pairs pairs[0].first=field0 pairs[0].second=value0 pairs[1].first=field1 pairs[1].second=value1
+ */
+void GetPairsFromTag( const std::string& fileContent, const std::string tag,
+                      std::vector< std::pair<const std::string, const std::string> >& pairs );
+
+
+/**
+ * Set members m_Groups and m_HostLanguage from XML file content, called within Init functions
+ * @param fileContent file Content in a single string
+ * @param mpiComm MPI Communicator passed from application passed to Transport method if required
+ * @param hostLanguage return the host language from fileContent
+ * @param transforms return the modified transforms vector if there are variables with transformations
+ * @param groups passed returns the map of groups defined in fileContent
+ */
+//void SetMembers( const std::string& fileContent, const MPI_Comm mpiComm,
+//                 std::string& hostLanguage, std::vector< std::shared_ptr<Transform> >& transforms,
+//                 std::map< std::string, Group >& groups );
+
+
+/**
+ * Called inside the ADIOS XML constructors to get contents from file, broadcast and set hostLanguage and groups from ADIOS class
+ * @param xmlConfigFile xml config file name
+ * @param mpiComm communicator used from broadcasting
+ * @param debugMode from ADIOS m_DebugMode passed to CGroup in groups
+ * @param hostLanguage set from host-language in xml file
+ * @param transforms return the modified transforms vector if there are variables with transformations
+ * @param groups passed returns the map of groups defined in fileContent
+ */
+//void InitXML( const std::string xmlConfigFile, const MPI_Comm mpiComm, const bool debugMode,
+//              std::string& hostLanguage, std::vector< std::shared_ptr<Transform> >& transforms,
+//              std::map< std::string, Group >& groups );
+
+
+/**
+ * Loops through a vector containing dimensions and returns the product of all elements
+ * @param dimensions input containing size on each dimension {Nx, Ny, Nz}
+ * @return product of all dimensions Nx * Ny * Nz
+ */
+std::size_t GetTotalSize( const std::vector<size_t>& dimensions );
+
+
+/**
+ * Might need to add exceptions for debug mode
+ * Creates a chain of directories using POSIX systems calls (stat, mkdir),
+ * Verifies if directory exists before creating a new one. Permissions are 777 for now
+ * @param fullPath /full/path/for/directory
+ */
+void CreateDirectory( const std::string fullPath ) noexcept;
+
+
+/**
+ * Identifies, verifies the corresponding transform method and adds it the transforms container if neccesary.
+ * This functions must be updated as new transform methods are supported.
+ * @param variableTransforms methods to be added to transforms with format "method:compressionLevel", or  "method" with compressionLevel=0 (default)
+ * @param transforms container of existing transform methods, owned by ADIOS class
+ * @param debugMode if true will do more checks, exceptions, warnings, expect slower code
+ * @param transformIndices returns the corresponding indices in ADIOS m_Transforms for a single variable
+ * @param parameters returns the corresponding parameters understood by a collection of transform="method:parameter"
+ */
+void SetTransformsHelper( const std::vector<std::string>& transformNames, std::vector< std::shared_ptr<Transform> >& transforms,
+                          const bool debugMode, std::vector<short>& transformIndices, std::vector<short>& parameters );
+
+
+/**
+ * Transforms a vector
+ * @param parameters vector of parameters with format "field=value"
+ * @param debugMode true=check parameters format, false=no checks
+ * @return a map with unique key=field, value=corresponding value
+ */
+std::map<std::string, std::string> BuildParametersMap( const std::vector<std::string>& parameters, const bool debugMode );
+
+
+/**
+ * Single call that extract data buffers information from Capsule. That way virtual Capsule functions are called a few times
+ * @param capsules input
+ * @param dataBuffers from Capsule.GetData()
+ * @param positions
+ * @param absolutePositions
+ */
+//void GetDataBuffers( const std::vector<Capsule*>& capsules, std::vector<char*>& dataBuffers, std::vector<std::size_t>& positions,
+//                     std::vector<std::size_t>& absolutePositions );
+
+/**
+ * Converts comma-separated values to a vector of integers
+ * @param csv "1,2,3"
+ * @return vector<int> = { 1, 2, 3 }
+ */
+std::vector<int> CSVToVectorInt( const std::string csv );
+
+
+/**
+ * Common strategy to check for heap buffer allocation for data and metadata typically calculated in Write
+ * @param newSize new data size
+ * @param growthFactor user provided growth factor for index and data memory buffers ( default = 1.5 )
+ * @param maxBufferSize user provided maximum buffer size
+ * @param buffer to be reallocated
+ * @return true: must do a transport flush, false: buffer sizes are enough to contain incoming data, no need for transport flush
+ */
+bool CheckBufferAllocation( const std::size_t newSize, const float growthFactor, const std::size_t maxBufferSize,
+                            std::vector<char>& buffer );
+
+/**
+ * Grows a buffer by a factor of  n . growthFactor . currentCapacity to accommodate for incomingDataSize
+ * @param incomingDataSize size of new data required to be stored in buffer
+ * @param growthFactor buffer grows in multiples of the growth buffer
+ * @param buffer to be resized
+ * @return -1: failed to allocate (bad_alloc), 0: didn't have to allocate (enough space), 1: successful allocation
+ */
+int GrowBuffer( const std::size_t incomingDataSize, const float growthFactor,
+                std::vector<char>& buffer );
+
+
+/**
+ * Check if system is little endian
+ * @return true: little endian, false: big endian
+ */
+bool IsLittleEndian( ) noexcept;
+
+
+} //end namespace
+
+
+
+#endif /* ADIOSFUNCTIONS_H_ */
diff --git a/include/functions/adiosTemplates.h b/include/functions/adiosTemplates.h
new file mode 100644
index 0000000000000000000000000000000000000000..8d373033679a98521e05f8fd6908a788e044240d
--- /dev/null
+++ b/include/functions/adiosTemplates.h
@@ -0,0 +1,238 @@
+/*
+ * adiosTemplates.h
+ *
+ *  Created on: Jan 26, 2017
+ *      Author: wfg
+ */
+
+#ifndef ADIOSTEMPLATES_H_
+#define ADIOSTEMPLATES_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <cstring> //std::memcpy
+#include <vector>
+#include <thread>
+#include <set>
+#include <complex>
+#include <cmath> //std::sqrt
+#include <iostream>
+/// \endcond
+
+
+namespace adios
+{
+/**
+ * Get the primitive type in a string from a template
+ * @return if T is a char, returns string = "char"
+ */
+template<class T> inline std::string GetType( ) noexcept { return "compound"; }
+template<> inline std::string GetType<void>() noexcept { return "unknown"; }
+template<> inline std::string GetType<char>() noexcept { return "char"; }
+template<> inline std::string GetType<unsigned char>() noexcept { return "unsigned char"; }
+template<> inline std::string GetType<short>() noexcept { return "short"; }
+template<> inline std::string GetType<unsigned short>() noexcept { return "unsigned short"; }
+template<> inline std::string GetType<int>() noexcept { return "int"; }
+template<> inline std::string GetType<unsigned int>() noexcept { return "unsigned int"; }
+template<> inline std::string GetType<long int>() noexcept { return "long int"; }
+template<> inline std::string GetType<unsigned long int>() noexcept { return "unsigned long int"; }
+template<> inline std::string GetType<long long int>() noexcept { return "long long int"; }
+template<> inline std::string GetType<unsigned long long int>() noexcept { return "unsigned long long int"; }
+template<> inline std::string GetType<float>() noexcept { return "float"; }
+template<> inline std::string GetType<double>() noexcept { return "double"; }
+template<> inline std::string GetType<long double>() noexcept { return "long double"; }
+template<> inline std::string GetType<std::complex<float>>() noexcept { return "float complex"; }
+template<> inline std::string GetType<std::complex<double>>() noexcept { return "double complex"; }
+template<> inline std::string GetType<std::complex<long double>>() noexcept { return "long double complex"; }
+
+
+
+/**
+ * Check in types set if "type" is one of the aliases for a certain type,
+ * (e.g. if type = integer is an accepted alias for "int", returning true)
+ * @param type input to be compared with an alias
+ * @param aliases set containing aliases to a certain type, typically Support::DatatypesAliases from Support.h
+ * @return true: is an alias, false: is not
+ */
+template<class T>
+bool IsTypeAlias( const std::string type,
+		          const std::map<std::string, std::set<std::string>>& aliases ) noexcept
+{
+	if( type == GetType<T>() ) //most of the time we will pass the same type, which is a key in aliases
+		return true;
+
+	bool isAlias = false;
+	if( aliases.at( GetType<T>() ).count( type ) == 1 )
+	    isAlias = true;
+
+	return isAlias;
+}
+
+
+/**
+ * Get the minimum and maximum values in one loop
+ * @param values array of primitives
+ * @param size of the values array
+ * @param min from values
+ * @param max from values
+ * @param nthreads threaded version not yet implemented
+ */
+template<class T> inline
+void GetMinMax( const T* values, const std::size_t size, T& min, T& max, const unsigned int nthreads = 1 ) noexcept
+{
+    min = values[0];
+    max = min;
+
+    for( std::size_t i = 1; i < size; ++i )
+    {
+        if( values[i] < min )
+        {
+            min = values[i];
+            continue;
+        }
+
+        if( values[i] > max  )
+            max = values[i];
+    }
+}
+
+/**
+ * Overloaded version for complex types, gets the "doughnut" range between min and max modulus
+ * @param values array of complex numbers
+ * @param size of the values array
+ * @param min modulus from values
+ * @param max modulus from values
+ * @param nthreads
+ */
+template<class T> inline
+void GetMinMax( const std::complex<T>* values, const std::size_t size, T& min, T& max, const unsigned int nthreads = 1 ) noexcept
+{
+
+    min = std::norm( values[0] );
+    max = min;
+
+    for( std::size_t i = 1; i < size; ++i )
+    {
+        T norm = std::norm( values[i] );
+
+        if( norm < min )
+        {
+            min = norm;
+            continue;
+        }
+
+        if( norm > max )
+        {
+            max = norm;
+        }
+    }
+
+    min = std::sqrt( min );
+    max = std::sqrt( max );
+}
+
+/**
+ * threaded version of std::memcpy
+ * @param dest
+ * @param source
+ * @param count total number of bytes (as in memcpy)
+ * @param nthreads
+ */
+template<class T, class U>
+void MemcpyThreads( T* destination, const U* source, std::size_t count, const unsigned int nthreads = 1 )
+{
+    // do not decompose tasks to less than 4MB pieces
+    const std::size_t minBlockSize = 4194304;
+    const std::size_t maxNThreads = std::max( (std::size_t)nthreads, count / minBlockSize );
+
+    if( maxNThreads == 1)
+    {
+        std::memcpy( destination, source, count );
+        return;
+    }
+
+    const std::size_t stride =  count/maxNThreads;
+    const std::size_t remainder = count % maxNThreads;
+    const std::size_t last = stride + remainder;
+
+    std::vector<std::thread> memcpyThreads;
+    memcpyThreads.reserve( maxNThreads );
+
+    for( unsigned int t = 0; t < maxNThreads; ++t )
+    {
+        const size_t initialDestination = stride * t / sizeof(T);
+        const size_t initialSource = stride * t / sizeof(U);
+
+        if( t == maxNThreads-1 )
+            memcpyThreads.push_back( std::thread( std::memcpy, &destination[initialDestination], &source[initialSource], last ) );
+        else
+            memcpyThreads.push_back( std::thread( std::memcpy, &destination[initialDestination], &source[initialSource], stride ) );
+    }
+    //Now join the threads (is this really needed?)
+    for( auto& thread : memcpyThreads )
+        thread.join( );
+}
+
+
+template< class T >
+void MemcpyToBuffer( std::vector<char>& raw, std::size_t& position, const T* source, std::size_t size ) noexcept
+{
+    std::memcpy( &raw[position], source, size );
+    position += size;
+}
+
+
+
+/**
+ * Version that pushed to the end of the buffer, updates vec.size() automatically
+ * @param raw
+ * @param source using pointer notation
+ * @param elements
+ */
+template<class T>
+void CopyToBuffer( std::vector<char>& buffer, const T* source, const std::size_t elements = 1 ) noexcept
+{
+    const char* src = reinterpret_cast<const char*>( source );
+    buffer.insert( buffer.end(), src, src + elements*sizeof(T) );
+}
+
+/**
+ * Overloaded version to copies data to a specific location in the buffer, doesn't update vec.size()
+ * @param raw
+ * @param position
+ * @param source
+ * @param elements
+ */
+template<class T>
+void CopyToBuffer( std::vector<char>& buffer, const std::size_t position, const T* source, const std::size_t elements = 1 ) noexcept
+{
+    const char* src = reinterpret_cast<const char*>( source );
+    std::copy( src, src + elements*sizeof(T), buffer.begin() + position );
+}
+
+
+template<class T>
+void CopyFromBuffer( T* destination, std::size_t elements, const std::vector<char>& raw, std::size_t& position ) noexcept
+{
+    std::copy( raw.begin() + position, raw.begin() + position + sizeof(T)*elements, reinterpret_cast<char*>(destination) );
+    position += elements*sizeof(T);
+}
+
+
+template< class T >
+void PrintValues( const std::string name, const char* buffer, const std::size_t position, const std::size_t elements )
+{
+    std::vector<T> values( elements );
+    std::memcpy( values.data(), &buffer[position], elements * sizeof(T) );
+
+    std::cout << "Read " << name << "\n";
+    for( const auto value : values )
+        std::cout << value << " ";
+
+    std::cout << "\n";
+}
+
+
+} //end namespace
+
+
+#endif /* ADIOSTEMPLATES_H_ */
diff --git a/include/functions/capsuleTemplates.h b/include/functions/capsuleTemplates.h
new file mode 100644
index 0000000000000000000000000000000000000000..8262ebedcfbe5589b5a3710299ff400827a9a933
--- /dev/null
+++ b/include/functions/capsuleTemplates.h
@@ -0,0 +1,112 @@
+/*
+ * capsuleTemplates.h
+ *
+ *  Created on: Nov 18, 2016
+ *      Author: wfg
+ */
+
+#ifndef CAPSULETEMPLATES_H_
+#define CAPSULETEMPLATES_H_
+
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <cstring> //std::memcpy
+#include <vector>
+#include <thread>
+/// \endcond
+
+
+#include "core/Transport.h"
+
+
+namespace adios
+{
+
+
+
+
+/**
+ *
+ * @param data
+ * @param size
+ * @param transportIndex
+ * @param transports
+ * @param maxBufferSize
+ * @param buffer
+ */
+//template<class T>
+//void WriteToBuffer( const T* data, const size_t size,
+//                    std::vector< std::shared_ptr<Transport> >& transports,
+//                    const size_t maxBufferSize, std::vector<char>& buffer )
+//{
+//    auto lf_TransportsWrite = []( const int transportIndex, std::vector< std::shared_ptr<Transport> >& transports,
+//                                  std::vector<char>& buffer )
+//    {
+//        if( transportIndex == -1 ) // all transports
+//        {
+//            for( auto& transport : transports )
+//                transport->Write( buffer );
+//        }
+//        else
+//            transports[ transportIndex ]->Write( buffer );
+//    };
+//
+//    //FUNCTION starts here
+//    const size_t dataBytes = size * sizeof( T ); //size of data in bytes
+//
+//    //check for DataMan transport
+//    if( transportIndex == -1 ) // all transports
+//    {
+//        for( auto& transport : transports )
+//        {
+//            if( transport->m_Method == "DataMan" ) //DataMan needs all the information
+//                buffer.resize( dataBytes ); //resize buffer to fit all data
+//        }
+//    }
+//    else //just one transport
+//    {
+//        if( transports[transportIndex]->m_Method == "DataMan" )
+//            buffer.resize( dataBytes ); //resize buffer to fit all data
+//    }
+//
+//    if( dataBytes <= buffer.size() ) // dataBytes < buffer.size()
+//    {
+//        buffer.resize( dataBytes ); //this resize shouldn't change capacity or call realloc
+//        MemcpyThreads( &buffer[0], data, dataBytes, 1 ); //copy memory in threaded fashion, need to test with size, serial for now
+//        lf_TransportsWrite( transportIndex, transports, buffer );
+//        return;
+//    }
+//
+//    if( buffer.size() < dataBytes && dataBytes <= maxBufferSize ) //  buffer.size() < dataBytes <  maxBufferSize
+//    {
+//        buffer.resize( dataBytes );
+//        MemcpyThreads( &buffer[0], data, dataBytes, 1 ); //copy memory in threaded fashion, need to test with size, serial for now
+//        lf_TransportsWrite( transportIndex, transports, buffer );
+//        return;
+//    }
+//
+//    // dataBytes > maxBufferSize == buffer.size() split the variable in buffer buckets
+//    buffer.resize( maxBufferSize ); //resize to maxBufferSize, this might call realloc
+//    const size_t buckets =  dataBytes / maxBufferSize + 1;
+//    const size_t remainder = dataBytes % maxBufferSize;
+//
+//    for( unsigned int bucket = 0; buckets < buckets; ++bucket )
+//    {
+//        const size_t dataOffset = bucket * maxBufferSize / sizeof( T );
+//
+//        if( bucket == buckets-1 )
+//            MemcpyThreads( &buffer[0], data[dataOffset], remainder, 1 );
+//        else
+//            MemcpyThreads( &buffer[0], data[dataOffset], maxBufferSize, 1 );
+//
+//        lf_TransportsWrite( transportIndex, transports, buffer );
+//    }
+//}
+
+
+
+} //end namespace
+
+
+
+#endif /* CAPSULETEMPLATES_H_ */
diff --git a/include/mpidummy.h b/include/mpidummy.h
new file mode 100644
index 0000000000000000000000000000000000000000..865320755eb511d564c3968f7be7ce3e1f4f3c30
--- /dev/null
+++ b/include/mpidummy.h
@@ -0,0 +1,117 @@
+/*
+ * ADIOS is freely available under the terms of the BSD license described
+ * in the COPYING file in the top level directory of this source distribution.
+ *
+ * Copyright (c) 2008 - 2009.  UT-BATTELLE, LLC. All rights reserved.
+ */
+
+#ifndef __MPI_DUMMY_H__
+#define __MPI_DUMMY_H__
+
+/*
+   A dummy MPI 'implementation' for the BP READ API, to have an MPI-free version of the API
+*/
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+/// \endcond
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+namespace adios
+{
+
+
+typedef int MPI_Comm;
+typedef uint64_t MPI_Status;
+typedef uint64_t MPI_Request;
+typedef int MPI_File;
+typedef int MPI_Info;
+typedef int MPI_Datatype;  /* Store the byte size of a type in such vars */
+typedef uint64_t MPI_Offset;
+typedef int MPI_Fint;
+
+#define MPI_SUCCESS                 0
+#define MPI_ERR_BUFFER              1      /* Invalid buffer pointer */
+#define MPI_ERR_COUNT               2      /* Invalid count argument */
+#define MPI_ERR_TYPE                3      /* Invalid datatype argument */
+#define MPI_ERR_TAG                 4      /* Invalid tag argument */
+#define MPI_ERR_COMM                5      /* Invalid communicator */
+#define MPI_MAX_ERROR_STRING        512
+#define MPI_MODE_RDONLY             O_RDONLY
+#define MPI_SEEK_SET                SEEK_SET
+#define MPI_SEEK_CUR                SEEK_CUR
+#define MPI_SEEK_END                SEEK_END
+#define MPI_BYTE                    1          /* I need the size of the type here */
+#define MPI_INFO_NULL               0
+
+#define MPI_COMM_NULL               0
+#define MPI_COMM_WORLD              1
+#define MPI_COMM_SELF               2
+
+#define MPI_INT                     1
+#define MPI_CHAR                    2
+#define MPI_DOUBLE                  3
+
+#define MPI_ANY_SOURCE              0
+#define MPI_ANY_TAG                 0
+
+#define MPI_SUM                     0
+
+#define MPI_MAX_PROCESSOR_NAME      32
+int MPI_Init(int *argc, char ***argv);
+int MPI_Finalize();
+int MPI_Initialized( int* flag ) ;
+
+int MPI_Barrier(MPI_Comm comm);
+int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm);
+
+int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm);
+int MPI_Comm_rank(MPI_Comm comm, int *rank);
+int MPI_Comm_size(MPI_Comm comm, int *size);
+int MPI_Comm_free(MPI_Comm *comm);
+MPI_Comm MPI_Comm_f2c(MPI_Fint comm);
+
+int MPI_Gather(void *sendbuf, int sendcnt, MPI_Datatype sendtype, void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm) ;
+int MPI_Gatherv(void *sendbuf, int sendcnt, MPI_Datatype sendtype, void *recvbuf, int *recvcnts, int *displs, MPI_Datatype recvtype, int root, MPI_Comm comm);
+int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
+                  void *recvbuf, int recvcount, MPI_Datatype recvtype,
+                  MPI_Comm comm);
+
+int MPI_Scatter(void *sendbuf, int sendcnt, MPI_Datatype sendtype, void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);
+int MPI_Scatterv(void *sendbuf, int *sendcnts, int *displs, MPI_Datatype sendtype, void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);
+
+int MPI_Recv( void *recvbuffer, int count, MPI_Datatype type, int source, int tag, MPI_Comm comm, MPI_Status* status );
+int MPI_Irecv( void *recvbuffer, int count, MPI_Datatype type, int source, int tag, MPI_Comm comm, MPI_Request* request );
+int MPI_Send( void *sendbuffer, int count, MPI_Datatype type, int destination, int tag, MPI_Comm comm );
+int MPI_Isend( void *recvbuffer, int count, MPI_Datatype type, int source, int tag, MPI_Comm comm, MPI_Request* request );
+
+int MPI_Wait( MPI_Request* request, MPI_Status* status );
+
+int MPI_File_open(MPI_Comm comm, char *filename, int amode, MPI_Info info, MPI_File *fh);
+int MPI_File_close(MPI_File *fh);
+int MPI_File_get_size(MPI_File fh, MPI_Offset *size);
+int MPI_File_read(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status);
+int MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence);
+
+int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count);
+int MPI_Error_string(int errorcode, char *string, int *resultlen);
+int MPI_Comm_split ( MPI_Comm comm, int color, int key, MPI_Comm *comm_out );
+
+int MPI_Get_processor_name (char *name, int *resultlen);
+
+double MPI_Wtime();
+
+} //end namespace
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/transform/BZip2.h b/include/transform/BZip2.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f2daffc5fb5e28b73b98d9c45427e8a1c4481f6
--- /dev/null
+++ b/include/transform/BZip2.h
@@ -0,0 +1,46 @@
+/*
+ * BZip2.h
+ *
+ *  Created on: Oct 17, 2016
+ *      Author: wfg
+ */
+
+#ifndef BZIP2_H_
+#define BZIP2_H_
+
+
+#include "core/Transform.h"
+
+
+namespace adios
+{
+namespace transform
+{
+
+
+class BZIP2 : public Transform
+{
+
+public:
+
+    /**
+     * Initialize parent method
+     * @param compressionLevel
+     * @param variable
+     */
+    BZIP2( );
+
+    ~BZIP2( );
+
+    void Compress( const std::vector<char>& bufferIn, std::vector<char>& bufferOut );
+
+    void Decompress( const std::vector<char>& bufferIn, std::vector<char>& bufferOut );
+};
+
+
+} //end namespace transform
+} //end namespace adios
+
+
+
+#endif /* BZIP2_H_ */
diff --git a/include/transport/file/FStream.h b/include/transport/file/FStream.h
new file mode 100644
index 0000000000000000000000000000000000000000..fed11ac1fa1a63221e57b4e8930bc0688a33ff56
--- /dev/null
+++ b/include/transport/file/FStream.h
@@ -0,0 +1,58 @@
+/*
+ * FStream.h
+ *
+ *  Created on: Oct 18, 2016
+ *      Author: wfg
+ */
+
+#ifndef FSTREAM_H_
+#define FSTREAM_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <fstream>
+/// \endcond
+
+#include "core/Transport.h"
+
+
+namespace adios
+{
+namespace transport
+{
+
+/**
+ * File stream transport using C++ fstream
+ */
+class FStream : public Transport
+{
+
+public:
+
+    FStream( MPI_Comm mpiComm, const bool debugMode );
+
+    ~FStream( );
+
+    void Open( const std::string name, const std::string accessMode );
+
+    void SetBuffer( char* buffer, std::size_t size );
+
+    void Write( const char* buffer, std::size_t size );
+
+    void Flush( );
+
+    void Close( );
+
+
+private:
+
+    std::fstream m_FStream; ///< file stream under name.bp.dir/name.bp.rank
+
+};
+
+
+} //end namespace transport
+} //end namespace
+
+
+
+#endif /* FSTREAM_H_ */
diff --git a/include/transport/file/FileDescriptor.h b/include/transport/file/FileDescriptor.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e199659c9861b16861deda4387d657a49d4b0ae
--- /dev/null
+++ b/include/transport/file/FileDescriptor.h
@@ -0,0 +1,48 @@
+/*
+ * FileDescriptor.h uses POSIX as the underlying library
+ *
+ *  Created on: Oct 6, 2016
+ *      Author: wfg
+ */
+
+#ifndef FILEDESCRIPTOR_H_
+#define FILEDESCRIPTOR_H_
+
+
+#include "core/Transport.h"
+
+
+namespace adios
+{
+namespace transport
+{
+
+/**
+ * File descriptor transport using the POSIX library
+ */
+class FileDescriptor : public Transport
+{
+
+public:
+
+    FileDescriptor( MPI_Comm mpiComm, const bool debugMode );
+
+    ~FileDescriptor( );
+
+    void Open( const std::string name, const std::string accessMode );
+
+    void Write( const char* buffer, std::size_t size );
+
+    void Close( );
+
+private:
+
+    int m_FileDescriptor = -1; ///< file descriptor returned by POSIX open
+
+};
+
+
+
+} //end namespace transport
+} //end namespace
+#endif /* FILEDESCRIPTOR_H_ */
diff --git a/include/transport/file/FilePointer.h b/include/transport/file/FilePointer.h
new file mode 100644
index 0000000000000000000000000000000000000000..cbe11ef60e03fd7e3036704082fbd5710a4a2155
--- /dev/null
+++ b/include/transport/file/FilePointer.h
@@ -0,0 +1,59 @@
+/*
+ * FilePointer.h
+ *
+ *  Created on: Jan 6, 2017
+ *      Author: wfg
+ */
+
+#ifndef FILEPOINTER_H_
+#define FILEPOINTER_H_
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <stdio.h> // FILE*
+/// \endcond
+
+#include "core/Transport.h"
+
+
+namespace adios
+{
+namespace transport
+{
+
+/**
+ * Class that defines a transport method using C file pointer (FP) to streams FILE*
+ */
+class FilePointer : public Transport
+{
+
+public:
+
+    FilePointer( MPI_Comm mpiComm, const bool debugMode );
+
+    ~FilePointer( );
+
+    void Open( const std::string name, const std::string accessMode );
+
+    void SetBuffer( char* buffer, std::size_t size );
+
+    void Write( const char* buffer, std::size_t size );
+
+    void Flush( );
+
+    void Close( );
+
+
+private:
+
+    FILE* m_File = NULL; ///< C file pointer
+
+};
+
+
+} //end namespace transport
+} //end namespace
+
+
+
+
+#endif /* FILEPOINTER_H_ */
diff --git a/include/transport/file/MPI_File.h b/include/transport/file/MPI_File.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e5d1892a4ff44eb81584deadacaa7f92b1ca7f7
--- /dev/null
+++ b/include/transport/file/MPI_File.h
@@ -0,0 +1,60 @@
+/*
+ * MPIFile.h
+ *
+ *  Created on: Jan 5, 2017
+ *      Author: wfg
+ */
+
+#ifndef MPI_FILE_H_
+#define MPI_FILE_H_
+
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <mpi.h>
+/// \endcond
+
+
+namespace adios
+{
+namespace transport
+{
+
+/**
+ * Class that defines a transport method using C++ file streams
+ */
+class MPI_File : public Transport
+{
+
+public:
+
+    MPI_File( MPI_Comm mpiComm, const bool debugMode );
+
+    ~MPI_File( );
+
+    void Open( const std::string streamName, const std::string accessMode );
+
+    void SetBuffer( char* buffer, std::size_t size );
+
+    void Write( const char* buffer, std::size_t size );
+
+    void Flush( );
+
+    void Close( );
+
+
+private:
+
+    MPI_File m_MPIFile; ///< MPI File
+
+};
+
+
+
+} //end namespace transport
+} //end namespace
+
+
+
+
+
+#endif /* MPI_FILE_H_ */
diff --git a/include/transport/wan/MdtmMan.h b/include/transport/wan/MdtmMan.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0fed7848cdaea502b49fe21953965a8bf71f681
--- /dev/null
+++ b/include/transport/wan/MdtmMan.h
@@ -0,0 +1,137 @@
+/*
+ * MdtmMan.h
+ *
+ *  Created on: Jan 18, 2017
+ *      Author: wfg
+ */
+
+#ifndef MDTMMAN_H_
+#define MDTMMAN_H_
+
+
+#include "external/json.hpp"
+#include "core/Transport.h"
+
+#include "DataMan.h"  //here comes your DataMan header
+
+namespace adios
+{
+namespace transport
+{
+
+class MdtmMan : public Transport
+{
+
+public:
+
+
+    /**
+     *
+     * @param localIP
+     * @param remoteIP
+     * @param mode
+     * @param prefix
+     * @param numberOfPipes
+     * @param tolerances
+     * @param priorities
+     * @param mpiComm
+     * @param debugMode
+     */
+	MdtmMan( const std::string localIP, const std::string remoteIP, const std::string mode, const std::string prefix,
+             const int numberOfPipes, const std::vector<int> tolerances, const std::vector<int> priorities,
+             MPI_Comm mpiComm, const bool debugMode );
+
+
+    ~MdtmMan( );
+
+
+    void Open( const std::string name, const std::string accessMode );
+
+    void SetBuffer( char* buffer, std::size_t size );
+
+    /**
+     * We can always overload this function in the base class and accept other types of data pointers, e.g. Write( json* );
+     * I'm sticking with char* as it's more general (only C++ libraries, e.g. boost understand std::std::vector, MPI, POSIX, Infiniband use pointer*)
+     * @param buffer
+     * @param size
+     */
+    void Write( const char* buffer, std::size_t size );
+
+    void Flush( ); ///< not sure if this one is needed...
+
+    void Close( );
+
+
+private:
+
+    std::string m_LocalIP; ///< local ip address, can change over time
+    std::string m_RemoteIP; ///<  remote ip address, can change over time
+    std::string m_Mode; ///< send/write, receive/read
+    std::string m_Prefix; ///< prefix given to message
+    int m_NumberOfPipes = -1; ///< should it be unsigned int?
+    std::vector<int> m_Tolerances;
+    std::vector<int> m_Priorities;
+
+    /**
+     * Should we change data to char* ?
+     * @param data
+     * @param doid
+     * @param variable
+     * @param dType
+     * @param putShape
+     * @param varShape
+     * @param offset
+     * @param timestep
+     * @param tolerance
+     * @param priority
+     * @return
+     */
+    int Put( const void* data, const std::string doid, const std::string variable, const std::string dType,
+             const std::vector<std::uint64_t>& putShape, const std::vector<uint64_t>& varShape, const std::vector<uint64_t>& offset,
+             const std::uint64_t timestep, const int tolerance, const int priority );
+
+    /**
+     *
+     * @param data
+     * @param doid
+     * @param variable
+     * @param dType
+     * @param putShape
+     * @param varShape
+     * @param offset
+     * @param timestep
+     * @param tolerance
+     * @param priority
+     * @return
+     */
+    int Get( void* data, const std::string doid, const std::string variable, const std::string dType,
+             const std::vector<std::uint64_t>& putShape, const std::vector<uint64_t>& varShape, const std::vector<uint64_t>& offset,
+             const std::uint64_t timestep, const int tolerance, const int priority );
+
+    /**
+     *
+     * @param data
+     * @param doid
+     * @param variable
+     * @param dType
+     * @param varShape
+     * @param timestep
+     * @return
+     */
+    int Get( void *data, const std::string doid, const std::string variable, const std::string dType,
+             std::vector<std::uint64_t>& varShape, const std::uint64_t timestep );
+
+    /**
+     *
+     * @param jData
+     */
+    void OnReceive( nlohmann::json& jData );
+};
+
+
+} //end namespace transport
+} //end namespace
+
+
+
+#endif /* MDTMMAN_H_ */
diff --git a/src/ADIOS.cpp b/src/ADIOS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc9889d992732ef7bb2d5c31b792f4234f07ee7a
--- /dev/null
+++ b/src/ADIOS.cpp
@@ -0,0 +1,317 @@
+/*
+ * ADIOS.cpp
+ *
+ *  Created on: Sep 29, 2016
+ *      Author: William F Godoy
+ */
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <utility>
+/// \endcond
+
+#include "ADIOS.h"
+#include "functions/adiosFunctions.h"
+
+//Engines
+#include "engine/bp/BPFileWriter.h"
+#include "engine/bp/BPFileReader.h"
+
+#ifdef HAVE_DATAMAN  //external dependencies
+#include "engine/dataman/DataManWriter.h"
+#include "engine/dataman/DataManReader.h"
+#endif
+
+
+#ifdef HAVE_ADIOS1  //external dependencies
+#include "engine/adios1/ADIOS1Writer.h"
+#include "engine/adios1/ADIOS1Reader.h"
+#endif
+
+namespace adios
+{
+
+
+ADIOS::ADIOS( const Verbose verbose, const bool debugMode ):
+    m_DebugMode{ debugMode }
+{
+    InitMPI( );
+}
+
+
+ADIOS::ADIOS( const std::string configFileName, const Verbose verbose, const bool debugMode ):
+    m_ConfigFile{ configFileName },
+    m_DebugMode{ debugMode }
+{
+   InitMPI( );
+    // InitXML( m_ConfigFile, m_MPIComm, m_DebugMode, m_Transforms );
+}
+
+
+
+ADIOS::ADIOS( const std::string xmlConfigFile, MPI_Comm mpiComm, const Verbose verbose, const bool debugMode  ):
+    m_MPIComm{ mpiComm },
+    m_ConfigFile{ xmlConfigFile },
+	m_DebugMode{ debugMode }
+{
+    InitMPI( );
+    //InitXML( m_XMLConfigFile, m_MPIComm, m_DebugMode, m_HostLanguage, m_Transforms, m_Groups );
+}
+
+
+ADIOS::ADIOS( MPI_Comm mpiComm, const Verbose verbose, const bool debugMode ):
+    m_MPIComm{ mpiComm },
+    m_DebugMode{ debugMode }
+{
+    InitMPI( );
+}
+
+
+ADIOS::~ADIOS( )
+{ }
+
+
+void ADIOS::InitMPI( )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_MPIComm == MPI_COMM_NULL )
+            throw std::ios_base::failure( "ERROR: engine communicator is MPI_COMM_NULL,"
+                                          " in call to ADIOS Open or Constructor\n" );
+    }
+
+    MPI_Comm_rank( m_MPIComm, &m_RankMPI );
+    MPI_Comm_size( m_MPIComm, &m_SizeMPI );
+}
+
+
+Method& ADIOS::DeclareMethod( const std::string methodName )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_Methods.count( methodName ) == 1 )
+            throw std::invalid_argument( "ERROR: method " + methodName + " already declared, from DeclareMethod\n" );
+    }
+    m_Methods.emplace( methodName, Method( methodName, m_DebugMode ) );
+    return m_Methods.at( methodName );
+}
+
+
+std::shared_ptr<Engine> ADIOS::Open( const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                                     const Method& method, const IOMode iomode, const float timeout_sec )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_EngineNames.count( name ) == 1 ) //Check if Engine already exists
+            throw std::invalid_argument( "ERROR: engine name " + name + " already created by Open, in call from Open.\n" );
+    }
+
+    m_EngineNames.insert( name );
+
+    const std::string type( method.m_Type );
+
+    const bool isDefaultWriter = ( accessMode == "w" || accessMode == "write" ||
+                                   accessMode == "a" || accessMode == "append" ) && type.empty() ? true : false;
+
+    const bool isDefaultReader = ( accessMode == "r" || accessMode == "read" ) && type.empty() ? true : false;
+
+    if( isDefaultWriter || type == "BPFileWriter" || type == "bpfilewriter" )
+    {
+        return std::make_shared<BPFileWriter>( *this, name, accessMode, mpiComm, method, iomode, timeout_sec, m_DebugMode, method.m_nThreads );
+    }
+    else if( isDefaultReader || type == "BPReader" || type == "bpreader" )
+    {
+        return std::make_shared<BPFileReader>( *this, name, accessMode, mpiComm, method, iomode, timeout_sec, m_DebugMode, method.m_nThreads );
+    }
+    else if( type == "SIRIUS" || type == "sirius" || type == "Sirius" )
+    {
+        //not yet supported
+        //return std::make_shared<engine::DataMan>( *this, name, accessMode, mpiComm, method, iomode, timeout_sec, m_DebugMode, method.m_nThreads );
+    }
+    else if( type == "DataManWriter" )
+    {
+        #ifdef HAVE_DATAMAN
+        return std::make_shared<DataManWriter>( *this, name, accessMode, mpiComm, method, iomode, timeout_sec, m_DebugMode, method.m_nThreads );
+        #else
+        throw std::invalid_argument( "ERROR: this version didn't compile with Dataman library, can't Open DataManWriter\n" );
+        #endif
+
+    }
+    else if( type == "DataManReader" )
+    {
+        #ifdef HAVE_DATAMAN
+        return std::make_shared<DataManReader>( *this, name, accessMode, mpiComm, method, iomode, timeout_sec, m_DebugMode, method.m_nThreads );
+        #else
+        throw std::invalid_argument( "ERROR: this version didn't compile with Dataman library, can't Open DataManReader\n" );
+        #endif
+    }
+    else if( type == "ADIOS1Writer" )
+    {
+        #ifdef HAVE_ADIOS1
+        return std::make_shared<ADIOS1Writer>( *this, name, accessMode, mpiComm, method, iomode, timeout_sec, m_DebugMode, method.m_nThreads );
+        #else
+        throw std::invalid_argument( "ERROR: this version didn't compile with ADIOS 1.x library, can't Open ADIOS1Writer\n" );
+        #endif
+    }
+    else if( type == "Vis" )
+    {
+        //return std::make_shared<Vis>( *this, name, accessMode, mpiComm, method, iomode, timeout_sec, m_DebugMode, method.m_nThreads );
+    }
+    else
+    {
+        if( m_DebugMode == true )
+            throw std::invalid_argument( "ERROR: method type " + type + " not supported for " + name + ", in call to Open\n" );
+    }
+
+    return nullptr; // if debug mode is off
+}
+
+
+std::shared_ptr<Engine> ADIOS::Open( const std::string streamName, const std::string accessMode,
+                                     const Method& method, const IOMode iomode, const float timeout_sec )
+{
+    return Open( streamName, accessMode, m_MPIComm, method, iomode, timeout_sec );
+}
+
+
+std::shared_ptr<Engine> ADIOS::Open( const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                                     const std::string methodName, const IOMode iomode, const float timeout_sec )
+{
+    auto itMethod = m_Methods.find( methodName );
+
+    if( m_DebugMode == true )
+    {
+        CheckMethod( itMethod, methodName, " in call to Open\n" );
+    }
+
+    return Open( name, accessMode, mpiComm, itMethod->second, iomode, timeout_sec );
+}
+
+
+std::shared_ptr<Engine> ADIOS::Open( const std::string name, const std::string accessMode,
+                                     const std::string methodName, const IOMode iomode, const float timeout_sec )
+{
+    return Open( name, accessMode, m_MPIComm, methodName, iomode, timeout_sec );
+}
+
+std::shared_ptr<Engine> ADIOS::OpenFileReader( const std::string name, MPI_Comm mpiComm,
+                                         const Method& method, const IOMode iomode )
+{
+    return Open( name, "r", m_MPIComm, method, iomode );
+}
+
+std::shared_ptr<Engine> ADIOS::OpenFileReader( const std::string name, MPI_Comm mpiComm,
+                                               const std::string methodName, const IOMode iomode )
+{
+    auto itMethod = m_Methods.find( methodName );
+
+    if( m_DebugMode == true )
+    {
+        CheckMethod( itMethod, methodName, " in call to Open\n" );
+    }
+
+    return Open( name, "r", m_MPIComm, itMethod->second, iomode );
+}
+
+VariableCompound& ADIOS::GetVariableCompound( const std::string name )
+{
+    return m_Compound.at( GetVariableIndex<void>(name) );
+}
+
+
+void ADIOS::MonitorVariables( std::ostream& logStream )
+{
+    logStream << "\tVariable \t Type\n";
+
+    for( auto& variablePair : m_Variables )
+    {
+        const std::string name( variablePair.first );
+        const std::string type( variablePair.second.first );
+
+        if( type == GetType<char>() )
+            GetVariable<char>( name ).Monitor( logStream );
+
+        else if( type == GetType<unsigned char>() )
+            GetVariable<unsigned char>( name ).Monitor( logStream );
+
+        else if( type == GetType<short>() )
+            GetVariable<short>( name ).Monitor( logStream );
+
+        else if( type == GetType<unsigned short>() )
+            GetVariable<unsigned short>( name ).Monitor( logStream );
+
+        else if( type == GetType<int>() )
+            GetVariable<int>( name ).Monitor( logStream );
+
+        else if( type == GetType<unsigned int>() )
+            GetVariable<unsigned int>( name ).Monitor( logStream );
+
+        else if( type == GetType<long int>() )
+            GetVariable<long int>( name ).Monitor( logStream );
+
+        else if( type == GetType<unsigned long int>() )
+            GetVariable<unsigned long int>( name ).Monitor( logStream );
+
+        else if( type == GetType<long long int>() )
+            GetVariable<long long int>( name ).Monitor( logStream );
+
+        else if( type == GetType<unsigned long long int>() )
+            GetVariable<unsigned long long int>( name ).Monitor( logStream );
+
+        else if( type == GetType<float>() )
+            GetVariable<float>( name ).Monitor( logStream );
+
+        else if( type == GetType<double>() )
+            GetVariable<double>( name ).Monitor( logStream );
+
+        else if( type == GetType<long double>() )
+            GetVariable<long double>( name ).Monitor( logStream );
+
+        else if( type == GetType<std::complex<float>>() )
+            GetVariable<std::complex<float>>( name ).Monitor( logStream );
+
+        else if( type == GetType<std::complex<double>>() )
+            GetVariable<std::complex<double>>( name ).Monitor( logStream );
+
+        else if( type == GetType<std::complex<long double>>() )
+            GetVariable<std::complex<long double>>( name ).Monitor( logStream );
+    }
+}
+
+
+//PRIVATE FUNCTIONS BELOW
+void ADIOS::CheckVariableInput( const std::string name, const Dims& dimensions ) const
+{
+    if( m_DebugMode == true )
+    {
+        if( m_Variables.count( name ) == 1 )
+            throw std::invalid_argument( "ERROR: variable " + name + " already exists, in call to DefineVariable\n" );
+
+        if( dimensions.empty() == true )
+            throw std::invalid_argument( "ERROR: variable " + name + " dimensions can't be empty, in call to DefineVariable\n" );
+    }
+}
+
+
+void ADIOS::CheckVariableName( std::map< std::string, std::pair< std::string, unsigned int > >::const_iterator itVariable,
+                               const std::string name, const std::string hint ) const
+{
+    if( m_DebugMode == true )
+    {
+        if( itVariable == m_Variables.end() )
+            throw std::invalid_argument( "ERROR: variable " + name + " does not exist " + hint + "\n" );
+    }
+}
+
+
+void ADIOS::CheckMethod( std::map< std::string, Method >::const_iterator itMethod,
+                         const std::string methodName, const std::string hint ) const
+{
+    if( itMethod == m_Methods.end() )
+        throw std::invalid_argument( "ERROR: method " + methodName + " not found " + hint + "\n" );
+}
+
+
+} //end namespace
diff --git a/src/ADIOS_C.cpp b/src/ADIOS_C.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b8e738014d15ff9eea129f572f777e0c049ac858
--- /dev/null
+++ b/src/ADIOS_C.cpp
@@ -0,0 +1,246 @@
+/*
+ * ADIOS_C.cpp
+ *
+ *  Created on: Oct 31, 2016
+ *      Author: wfg
+ */
+
+
+
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <cstring>
+
+#include "ADIOS.h"
+#include "ADIOS_C.h"
+
+
+adios::ADIOS* adios;
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void adios_init( const char* xmlConfigFile, const MPI_Comm mpiComm )
+{
+
+    int rank;
+    MPI_Comm_rank( mpiComm, &rank );
+
+    try
+    {
+        adios = new adios::ADIOS( std::string( xmlConfigFile ), mpiComm );
+    }
+    catch( std::bad_alloc& e )
+    {
+        if( rank == 0 )
+            std::cout << "Bad allocation exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+            std::cout << "Exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+
+//    return ( ADIOS* ) ( adios );
+}
+
+
+ADIOS* adios_init_debug( const char* xmlConfigFile, const MPI_Comm mpiComm )
+{
+    adios::ADIOS* adios;
+    int rank;
+    MPI_Comm_rank( mpiComm, &rank );
+
+    try
+    {
+        adios = new adios::ADIOS( std::string( xmlConfigFile ), mpiComm, true );
+    }
+    catch( std::bad_alloc& e )
+    {
+        if( rank == 0 )
+            std::cout << "Bad allocation exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+            std::cout << "Exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+
+    return ( ADIOS* ) ( adios );
+}
+
+
+void adios_open( const ADIOS* adiosC, const char* groupName, const char* fileName, const char* accessMode )
+{
+    adios::ADIOS* adios = ( adios::ADIOS* ) adiosC;
+    int rank;
+    MPI_Comm_rank( adios->m_MPIComm, &rank );
+
+    try
+    {
+        adios::ADIOS* adios = ( adios::ADIOS * ) adiosC;
+        adios->Open( std::string( groupName ), std::string( fileName ), std::string( accessMode ) );
+    }
+    catch( std::bad_alloc& e )
+    {
+        if( rank == 0 )
+            std::cout << "Bad allocation exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+            std::cout << "Exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+}
+
+
+void adios_write( const ADIOS* adiosC, const char* groupName, const char* variableName, const void* values  )
+{
+    adios::ADIOS* adios = ( adios::ADIOS* ) adiosC;
+    int rank;
+    MPI_Comm_rank( adios->m_MPIComm, &rank );
+
+    try
+    {
+        adios->Write( const std::string( groupName ), const std::string( variableName ), values );
+    }
+    catch( std::bad_alloc& e )
+    {
+        if( rank == 0 )
+            std::cout << "Bad allocation exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+            std::cout << "Exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+}
+
+
+void adios_close( const ADIOS* adiosC, const char* groupName )
+{
+    adios::ADIOS* adios = ( adios::ADIOS * ) adiosC;
+    int rank;
+    MPI_Comm_rank( adios->m_MPIComm, &rank );
+
+    try
+    {
+        adios->Close( std::string( groupName ) );
+    }
+    catch( std::bad_alloc& e )
+    {
+        if( rank == 0 )
+            std::cout << "Bad allocation exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+            std::cout << "Exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+}
+
+
+void adios_free( const ADIOS* adiosC )
+{
+    adios::ADIOS* adios = ( adios::ADIOS* ) adiosC;
+    delete adios;
+}
+
+
+void adios_monitor_groups( const ADIOS* adiosC )
+{
+    adios::ADIOS* adios = ( adios::ADIOS* ) adiosC;
+    int rank;
+    MPI_Comm_rank( adios->m_MPIComm, &rank );
+
+    try
+    {
+        adios->MonitorGroups( std::cout );
+    }
+    catch( std::bad_alloc& e )
+    {
+        if( rank == 0 )
+            std::cout << "Bad allocation exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+            std::cout << "Exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+}
+
+
+void adios_monitor_groups_file( const ADIOS* adiosC, const char* fileName, const char* mode )
+{
+    adios::ADIOS* adios = ( adios::ADIOS * ) adiosC;
+    int rank;
+    MPI_Comm_rank( adios->m_MPIComm, &rank );
+
+    try
+    {
+        std::ofstream fileStream;
+
+        if( strcmp( mode, "a" ) == 0 || strcmp( mode, "append" ) == 0 )
+            fileStream.open( fileName, std::ostream::app );
+        else if( strcmp( mode, "w" ) == 0 || strcmp( mode, "write" ) == 0 )
+            fileStream.open( fileName );
+
+        adios->MonitorGroups( fileStream );
+
+    }
+    catch( std::bad_alloc& e )
+    {
+        if( rank == 0 )
+            std::cout << "Bad allocation exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::invalid_argument& e )
+    {
+        if( rank == 0 )
+            std::cout << "Invalid argument exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+    catch( std::exception& e )
+    {
+        if( rank == 0 )
+            std::cout << "Exception, STOPPING PROGRAM\n" << e.what() << "\n";
+    }
+}
+
+
+#ifdef __cplusplus
+} //end extern C
+#endif
diff --git a/src/capsule/heap/STLVector.cpp b/src/capsule/heap/STLVector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dafae7a7b4adba29c3b2995534b73b8058cbd0ae
--- /dev/null
+++ b/src/capsule/heap/STLVector.cpp
@@ -0,0 +1,87 @@
+/*
+ * Heap.cpp
+ *
+ *  Created on: Dec 22, 2016
+ *      Author: wfg
+ */
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <new> //std::bad_alloc
+#include <stdexcept> //std::runtime_error
+/// \endcond
+
+#include "capsule/heap/STLVector.h"
+
+
+namespace adios
+{
+namespace capsule
+{
+
+
+STLVector::STLVector( const std::string accessMode, const int rankMPI, const bool debugMode ):
+    Capsule( "Heap", accessMode, rankMPI, debugMode )
+{
+    m_Data.reserve( 16777216 );
+}
+
+
+STLVector::~STLVector( )
+{ }
+
+
+char* STLVector::GetData( )
+{
+    return m_Data.data( );
+}
+
+
+char* STLVector::GetMetadata( )
+{
+    return m_Metadata.data( );
+}
+
+
+std::size_t STLVector::GetDataSize( ) const
+{
+    return m_Data.size( );
+}
+
+
+std::size_t STLVector::GetMetadataSize( ) const
+{
+    return m_Metadata.size( );
+}
+
+
+void STLVector::ResizeData( const std::size_t size )
+{
+    if( m_DebugMode == true )
+    {
+        try { m_Data.resize( size ); }
+        catch( std::bad_alloc& e ){ throw std::runtime_error( "ERROR: bad_alloc detected when resizing data buffer with size " +
+                                                               std::to_string( size ) + "\n" ); }
+    }
+    else
+    {
+        m_Data.resize( size );
+    }
+}
+
+void STLVector::ResizeMetadata( const std::size_t size )
+{
+    if( m_DebugMode == true )
+    {
+        try { m_Metadata.resize( size ); }
+        catch( std::bad_alloc& e ){ throw std::runtime_error( "ERROR: bad_alloc detected when resizing metadata buffer with size " +
+                                                               std::to_string( size ) + "\n" ); }
+    }
+    else
+    {
+        m_Metadata.resize( size );
+    }
+}
+
+
+}  //end namespace heap
+}  //end namespace
diff --git a/src/capsule/shmem/ShmSystemV.cpp b/src/capsule/shmem/ShmSystemV.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8d3d508ac8894ed68dbbdf9b8216ae5071c94104
--- /dev/null
+++ b/src/capsule/shmem/ShmSystemV.cpp
@@ -0,0 +1,96 @@
+/*
+ * ShmSystemV.cpp
+ *
+ *  Created on: Dec 22, 2016
+ *      Author: wfg
+ */
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <sys/shm.h>
+#include <ios> //std::ios_base::failure
+/// \endcond
+
+
+#include "capsule/shmem/ShmSystemV.h"
+
+
+namespace adios
+{
+
+
+ShmSystemV::ShmSystemV( const std::string accessMode, const int rankMPI, const std::string pathName,
+                        const size_t dataSize, const size_t metadataSize, const bool debugMode ):
+    Capsule( "ShmSystemV", accessMode, rankMPI, debugMode ),
+    m_DataSize{ dataSize },
+    m_MetadataSize{ metadataSize }
+{
+    // Data Shared memory sector
+    const std::string dataPath( pathName + "/adios.shm.data." + std::to_string( m_RankMPI ) );
+    m_DataKey = ftok( dataPath.c_str(), m_RankMPI+1 );
+    m_DataShmID = shmget( m_DataKey, m_DataSize, IPC_CREAT | 0666 );
+    m_Data = (char*)shmat( m_DataShmID, NULL, 0 );
+
+
+    // Metadata Shared memory sector
+    const std::string metadataPath( pathName + "/adios.shm.metadata." + std::to_string( m_RankMPI ) );
+    m_MetadataKey = ftok( metadataPath.c_str(), m_RankMPI+1 ); //2nd field must be greater than zero and unique
+    m_MetadataShmID = shmget( m_MetadataKey, m_MetadataSize, IPC_CREAT | 0666 );
+    m_Metadata = (char*)shmat( m_MetadataShmID, NULL, 0 );
+
+    if( m_DebugMode == true )
+        CheckShm( );
+}
+
+
+ShmSystemV::~ShmSystemV( )
+{ }
+
+
+char* ShmSystemV::GetData( )
+{
+    return m_Data;
+}
+
+
+char* ShmSystemV::GetMetadata( )
+{
+    return m_Metadata;
+}
+
+
+std::size_t ShmSystemV::GetDataSize( ) const
+{
+    return m_DataSize;
+}
+
+
+std::size_t ShmSystemV::GetMetadataSize( ) const
+{
+    return m_MetadataSize;
+}
+
+
+void ShmSystemV::CheckShm( ) const
+{
+    if( m_DataShmID < 0)
+        throw std::ios_base::failure( "ERROR: Failed to create data shm segment of size " + std::to_string( m_DataSize ) +
+                                      " from call to ShmSystemV constructor\n" );
+
+    if( m_Data == nullptr )
+        throw std::ios_base::failure( "ERROR: Failed to attach to data shm segment of size " + std::to_string( m_DataSize ) +
+                                      " and id " + std::to_string( m_DataShmID ) +
+                                      ", from call to ShmSystemV constructor\n" );
+
+    if( m_DataShmID < 0)
+        throw std::ios_base::failure( "ERROR: Failed to create metadata shm segment of size " + std::to_string( m_MetadataSize ) +
+                                      " from call to ShmSystemV constructor\n" );
+
+
+    if( m_Metadata == nullptr )
+        throw std::ios_base::failure( "ERROR: Failed to attach to metadata shm segment of size " + std::to_string( m_MetadataSize ) +
+                                      " and id " + std::to_string( m_MetadataShmID ) +
+                                      " from call to ShmSystemV constructor\n" );
+}
+
+
+
+} //end namespace
diff --git a/src/core/Capsule.cpp b/src/core/Capsule.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..98c933ca74e595adaa2898b39a23284d690b7e51
--- /dev/null
+++ b/src/core/Capsule.cpp
@@ -0,0 +1,37 @@
+/*
+ * Capsule.cpp
+ *
+ *  Created on: Nov 11, 2016
+ *      Author: wfg
+ */
+
+
+#include "core/Capsule.h"
+
+
+namespace adios
+{
+
+
+Capsule::Capsule( const std::string type, const std::string accessMode, const int rankMPI,
+                  const bool debugMode ):
+    m_Type{ type },
+    m_AccessMode{ accessMode },
+    m_RankMPI{ rankMPI },
+    m_DebugMode{ debugMode }
+{ }
+
+
+Capsule::~Capsule( )
+{ }
+
+
+void Capsule::ResizeData( const std::size_t size )
+{ }
+
+
+void Capsule::ResizeMetadata( const std::size_t size )
+{ }
+
+
+} //end namespace
diff --git a/src/core/Engine.cpp b/src/core/Engine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..db6002cf5a3af17fa1ad5b222ec97e4a9bcf8116
--- /dev/null
+++ b/src/core/Engine.cpp
@@ -0,0 +1,185 @@
+/*
+ * Engine.cpp
+ *
+ *  Created on: Dec 19, 2016
+ *      Author: wfg
+ */
+
+
+#include "core/Engine.h"
+#include "core/Support.h"
+#include "functions/adiosFunctions.h"
+
+
+namespace adios
+{
+
+
+Engine::Engine( ADIOS& adios, const std::string engineType, const std::string name, const std::string accessMode,
+                MPI_Comm mpiComm, const Method& method, const bool debugMode, const unsigned int nthreads,
+                const std::string endMessage ):
+    m_MPIComm{ mpiComm },
+    m_EngineType{ engineType },
+    m_Name{ name },
+    m_AccessMode{ accessMode },
+    m_Method{ method },
+    m_ADIOS{ adios },
+    m_DebugMode{ debugMode },
+    m_nThreads{ nthreads },
+    m_EndMessage( endMessage )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_MPIComm == MPI_COMM_NULL )
+            throw std::ios_base::failure( "ERROR: engine communicator is MPI_COMM_NULL,"
+                                          " in call to ADIOS Open or Constructor\n" );
+    }
+
+    MPI_Comm_rank( m_MPIComm, &m_RankMPI );
+    MPI_Comm_size( m_MPIComm, &m_SizeMPI );
+}
+
+
+Engine::~Engine( )
+{ }
+
+void Engine::SetCallBack( std::function<void( const void*, std::string, std::string, std::string, Dims )> callback ){ }
+
+//should these functions throw an exception?
+void Engine::Write( Variable<char>& variable,                      const char* values ){ }
+void Engine::Write( Variable<unsigned char>& variable,             const unsigned char* values ){ }
+void Engine::Write( Variable<short>& variable,                     const short* values ){ }
+void Engine::Write( Variable<unsigned short>& variable,            const unsigned short* values ){ }
+void Engine::Write( Variable<int>& variable,                       const int* values ){ }
+void Engine::Write( Variable<unsigned int>& variable,              const unsigned int* values ){ }
+void Engine::Write( Variable<long int>& variable,                  const long int* values ){ }
+void Engine::Write( Variable<unsigned long int>& variable,         const unsigned long int* values ){ }
+void Engine::Write( Variable<long long int>& variable,             const long long int* values ){ }
+void Engine::Write( Variable<unsigned long long int>& variable,    const unsigned long long int* values ){ }
+void Engine::Write( Variable<float>& variable,                     const float* values ){ }
+void Engine::Write( Variable<double>& variable,                    const double* values ){ }
+void Engine::Write( Variable<long double>& variable,               const long double* values ){ }
+void Engine::Write( Variable<std::complex<float>>& variable,       const std::complex<float>* values ){ }
+void Engine::Write( Variable<std::complex<double>>& variable,      const std::complex<double>* values ){ }
+void Engine::Write( Variable<std::complex<long double>>& variable, const std::complex<long double>* values ){ }
+void Engine::Write( VariableCompound& variable,                    const void* values ){ }
+
+void Engine::Write( const std::string variableName, const char* values ){ }
+void Engine::Write( const std::string variableName, const unsigned char* values ){ }
+void Engine::Write( const std::string variableName, const short* values ){ }
+void Engine::Write( const std::string variableName, const unsigned short* values ){ }
+void Engine::Write( const std::string variableName, const int* values ){ }
+void Engine::Write( const std::string variableName, const unsigned int* values ){ }
+void Engine::Write( const std::string variableName, const long int* values ){ }
+void Engine::Write( const std::string variableName, const unsigned long int* values ){ }
+void Engine::Write( const std::string variableName, const long long int* values ){ }
+void Engine::Write( const std::string variableName, const unsigned long long int* values ){ }
+void Engine::Write( const std::string variableName, const float* values ){ }
+void Engine::Write( const std::string variableName, const double* values ){ }
+void Engine::Write( const std::string variableName, const long double* values ){ }
+void Engine::Write( const std::string variableName, const std::complex<float>* values ){ }
+void Engine::Write( const std::string variableName, const std::complex<double>* values ){ }
+void Engine::Write( const std::string variableName, const std::complex<long double>* values ){ }
+void Engine::Write( const std::string variableName, const void* values ){ }
+
+void Engine::Advance( float timeout_sec ){ }
+void Engine::Advance( AdvanceMode mode, float timeout_sec ){ }
+void Engine::AdvanceAsync ( AdvanceMode mode, std::function<void( std::shared_ptr<adios::Engine> )> callback ){ }
+
+
+void Engine::Close( const int transportIndex ){ }
+
+//READ
+Variable<void>* Engine::InquireVariable( const std::string name, const bool readIn ){ return nullptr; }
+Variable<char>* Engine::InquireVariableChar( const std::string name, const bool readIn ){ return nullptr; }
+Variable<unsigned char>* Engine::InquireVariableUChar( const std::string name, const bool readIn ){ return nullptr; }
+Variable<short>* Engine::InquireVariableShort( const std::string name, const bool readIn ){ return nullptr; }
+Variable<unsigned short>* Engine::InquireVariableUShort( const std::string name, const bool readIn ){ return nullptr; }
+Variable<int>* Engine::InquireVariableInt( const std::string name, const bool readIn ){ return nullptr; }
+Variable<unsigned int>* Engine::InquireVariableUInt( const std::string name, const bool readIn ){ return nullptr; }
+Variable<long int>* Engine::InquireVariableLInt( const std::string name, const bool readIn ){ return nullptr; }
+Variable<unsigned long int>* Engine::InquireVariableULInt( const std::string name, const bool readIn ){ return nullptr; }
+Variable<long long int>* Engine::InquireVariableLLInt( const std::string name, const bool readIn ){ return nullptr; }
+Variable<unsigned long long int>* Engine::InquireVariableULLInt( const std::string name, const bool readIn ){ return nullptr; }
+Variable<float>* Engine::InquireVariableFloat( const std::string name, const bool readIn ){ return nullptr; }
+Variable<double>* Engine::InquireVariableDouble( const std::string name, const bool readIn ){ return nullptr; }
+Variable<long double>* Engine::InquireVariableLDouble( const std::string name, const bool readIn ){ return nullptr; }
+Variable<std::complex<float>>* Engine::InquireVariableCFloat( const std::string name, const bool readIn ){ return nullptr; }
+Variable<std::complex<double>>* Engine::InquireVariableCDouble( const std::string name, const bool readIn ){ return nullptr; }
+Variable<std::complex<long double>>* Engine::InquireVariableCLDouble( const std::string name, const bool readIn ){ return nullptr; }
+VariableCompound* Engine::InquireVariableCompound( const std::string name, const bool readIn ){ return nullptr;  }
+
+void Engine::Read( Variable<double>& variable,                    const double* values ){ }
+void Engine::ScheduleRead( Variable<double>& variable,                    const double* values ){ }
+void Engine::Release( ){ }
+
+//PROTECTED
+void Engine::Init( )
+{ }
+
+void Engine::InitParameters( )
+{ }
+
+void Engine::InitTransports( )
+{ }
+
+
+void Engine::CheckParameter( const std::map<std::string, std::string>::const_iterator itParam,
+                             const std::map<std::string, std::string>& parameters,
+                             const std::string parameterName, const std::string hint ) const
+{
+    if( itParam == parameters.end() )
+        throw std::invalid_argument( "ERROR: parameter name " + parameterName + " not found " + hint );
+}
+
+
+bool Engine::TransportNamesUniqueness( ) const
+{
+    auto lf_CheckTransportsType = [&]( const std::set<std::string>& specificType ) -> bool
+    {
+        std::set<std::string> transportNames;
+
+        for( const auto& parameters : m_Method.m_TransportParameters )
+        {
+            auto itTransport = parameters.find( "transport" );
+            if( m_DebugMode == true )
+            {
+                if( itTransport == parameters.end() )
+                    throw std::invalid_argument( "ERROR: transport not defined in Method input to Engine " + m_Name );
+            }
+
+            const std::string type( itTransport->second );
+            if( specificType.count( type ) == 1   ) //file transports type
+            {
+                std::string name( m_Name );
+                auto itName = parameters.find("name");
+                if( itName != parameters.end() )
+                    name = itName->second;
+
+                if( transportNames.count( name ) == 0 )
+                    transportNames.insert( name );
+                else
+                    return false;
+            }
+        }
+        return true;
+    };
+
+    return lf_CheckTransportsType( Support::FileTransports );
+}
+
+
+void Engine::CheckTransportIndex( const int transportIndex )
+{
+    if( m_DebugMode == true )
+    {
+        if( transportIndex >= static_cast<int>( m_Transports.size() ) || transportIndex < -1 )
+        {
+            throw std::invalid_argument( "ERROR: transport index " + std::to_string( transportIndex ) +
+                                         " is out of range, in call to " + m_Name + "Close \n");
+        }
+    }
+}
+
+
+} //end namespace
diff --git a/src/core/Method.cpp b/src/core/Method.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..08660e78229d1b41fed19c8fee89a512b153e863
--- /dev/null
+++ b/src/core/Method.cpp
@@ -0,0 +1,73 @@
+/*
+ * Method.cpp
+ *
+ *  Created on: Jan 6, 2017
+ *      Author: wfg
+ */
+
+
+#include "core/Method.h"
+#include "functions/adiosFunctions.h"
+
+
+namespace adios
+{
+
+
+Method::Method( const std::string name, const bool debugMode ):
+    m_Name{ name },
+    m_DebugMode{ debugMode }
+{
+    // m_Type can stay empty (forcing the choice of the default engine)
+    m_nThreads = 1;
+}
+
+
+Method::~Method( )
+{ }
+
+bool Method::isUserDefined()
+{
+    return false; //TODO: check if XML has the method defined
+}
+
+void Method::SetEngine( const std::string type )
+{
+    m_Type = type;
+}
+
+void Method::AllowThreads( const int nThreads )
+{
+    if (nThreads > 1)
+        m_nThreads = nThreads;
+    else
+        m_nThreads = 1;
+}
+
+
+//PRIVATE Functions
+void Method::AddTransportParameters( const std::string type, const std::vector<std::string>& parameters )
+{
+    if( m_DebugMode == true )
+    {
+        if( type.empty() || type.find("=") != type.npos )
+            throw std::invalid_argument( "ERROR: first argument in AddTransport must be a single word for transport\n" );
+    }
+
+    std::map<std::string, std::string> mapParameters = BuildParametersMap( parameters, m_DebugMode );
+    if( m_DebugMode == true )
+    {
+        if( mapParameters.count("transport") == 1 )
+            std::invalid_argument( "ERROR: transport can't be redefined with \"transport=type\", "
+                                   "type must be the first argument\n" );
+    }
+
+    mapParameters["transport"] = type;
+    m_TransportParameters.push_back( mapParameters );
+}
+
+
+
+} //end namespace
+
+
diff --git a/src/core/Support.cpp b/src/core/Support.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..670838cda448e5208dbe372f88afea56095c9935
--- /dev/null
+++ b/src/core/Support.cpp
@@ -0,0 +1,115 @@
+/*
+ * Support.cpp
+ *
+ *  Created on: Oct 18, 2016
+ *      Author: wfg
+ */
+
+
+#include "core/Support.h"
+#include "functions/adiosTemplates.h"
+
+
+namespace adios
+{
+
+
+const std::string Support::Version{ "2.00" };
+
+
+const std::set<std::string> Support::HostLanguages{
+    { "C++", "C", "Fortran" }
+};
+
+
+const std::set<std::string> Support::Transports{
+    { "NULL", "POSIX", "FStream", "MdtmMan" } // "MPI", "MPI_LUSTRE", "MPI_AGGREGATE", "DATASPACES", "DIMES", "FLEXPATH", "PHDF5", "NC4", "ICEE" }
+};
+
+
+const std::set<std::string> Support::Transforms{
+    { "none", "identity", "bzip2", "isobar", "szip" , "zlib" }
+};
+
+
+const std::map<std::string, std::set<std::string> > Support::Datatypes
+{
+    { "C++",
+        {
+            "char", "std::string", "string",
+            "unsigned char",
+            "short",
+            "unsigned short",
+            "int", "integer",
+            "unsigned int",
+            "long int", "long",
+            "unsigned long int", "unsigned long",
+            "long long int", "long long",
+            "unsigned long long int", "unsigned long long",
+            "float",
+            "float complex",
+            "double",
+            "long double",
+            "double complex", "std::complex<double>", "complex<double>"
+        }
+    },
+    { "C",
+        {
+            "char",
+            "unsigned char",
+            "short",
+            "unsigned short",
+            "int", "integer"
+            "unsigned int", "unsigned integer",
+            "long int", "long", "long integer",
+            "unsigned long int", "unsigned long", "unsigned long integer",
+            "long long int", "long long", "long long integer",
+            "unsigned long long int", "unsigned long long", "unsigned long long integer",
+            "float",
+            "float complex"
+            "double",
+            "long double",
+            "double complex"
+        }
+    },
+    { "Fortran",
+        {
+            "character",
+            "integer*2",
+            "integer", "real*2",
+            "real", "real*4",
+            "double precision", "real*8",
+            "complex",
+            "double complex"
+        }
+    }
+};
+
+
+const std::map<std::string, std::set<std::string> > Support::DatatypesAliases
+{
+    { GetType<char>(),         { GetType<char>(), "character" }  },
+    { GetType<unsigned char>(),  { GetType<unsigned char>(), "unsigned character" }  },
+    { GetType<short>(),          { GetType<short>(), "integer*2" } },
+    { GetType<unsigned short>(), { GetType<unsigned short>() }  },
+    { GetType<int>(),            { GetType<int>(), "integer" } },
+    { GetType<unsigned int>(),   { GetType<unsigned int>(), "unsigned integer" } },
+    { GetType<long int>(),       { GetType<long int>(), "long", "long integer" } },
+    { GetType<unsigned long int>(), { GetType<unsigned long int>(), "unsigned long", "unsigned long integer" } },
+    { GetType<long long int>(),  { GetType<long long int>(), "long long", "long long integer" } },
+    { GetType<unsigned long long int>(), { GetType<unsigned long long int>(), "unsigned long long", "unsigned long long integer" } },
+    { GetType<float>(),                  { GetType<float>(), "real", "real*4" } },
+    { GetType<double>(),      { GetType<double>(), "double precision", "real*8" } },
+    { GetType<long double>(), { GetType<long double>(), "long double precision", "real*16" } }
+};
+
+
+const std::set<std::string> Support::FileTransports{
+    { "POSIX", "File", "FStream", "MPIFile" }
+};
+
+
+
+
+} //end namespace
+
diff --git a/src/core/Transform.cpp b/src/core/Transform.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..89b882e55abde71434afe0aef61f6264a47d8020
--- /dev/null
+++ b/src/core/Transform.cpp
@@ -0,0 +1,32 @@
+/*
+ * Transform.cpp
+ *
+ *  Created on: Dec 5, 2016
+ *      Author: wfg
+ */
+
+#include "core/Transform.h"
+
+
+namespace adios
+{
+
+
+Transform::Transform( const std::string method ):
+    m_Method( method )
+{ }
+
+
+Transform::~Transform( )
+{ }
+
+
+void Transform::Compress( const std::vector<char>& bufferIn, std::vector<char>& bufferOut )
+{ }
+
+
+void Transform::Decompress( const std::vector<char>& bufferIn, std::vector<char>& bufferOut )
+{ }
+
+
+} //end namespace
diff --git a/src/core/Transport.cpp b/src/core/Transport.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4bbc1f7439e6f2db0e09859f16b0aecae7697bcb
--- /dev/null
+++ b/src/core/Transport.cpp
@@ -0,0 +1,62 @@
+/*
+ * Transport.cpp
+ *
+ *  Created on: Dec 5, 2016
+ *      Author: wfg
+ */
+
+#include "core/Transport.h"
+
+
+namespace adios
+{
+
+Transport::Transport( const std::string type, MPI_Comm mpiComm, const bool debugMode ):
+    m_Type{ type },
+    m_MPIComm{ mpiComm },
+    m_DebugMode{ debugMode }
+{
+    MPI_Comm_rank( m_MPIComm, &m_RankMPI );
+    MPI_Comm_size( m_MPIComm, &m_SizeMPI );
+}
+
+
+Transport::~Transport( )
+{ }
+
+
+void Transport::SetBuffer( char* buffer, size_t size )
+{ }
+
+
+void Transport::Flush( )
+{ }
+
+
+void Transport::Close( )
+{ }
+
+
+void Transport::InitProfiler( const std::string accessMode, const Support::Resolutions resolution )
+{
+    m_Profiler.m_Timers.emplace_back( "open", Support::Resolutions::mus );
+
+    if( accessMode == "w" || accessMode == "write" )
+        m_Profiler.m_Timers.emplace_back( "write", resolution );
+
+    else if( accessMode == "a" || accessMode == "append" )
+        m_Profiler.m_Timers.emplace_back( "append", resolution );
+
+    else if( accessMode == "r" || accessMode == "read" )
+        m_Profiler.m_Timers.emplace_back( "read", resolution );
+
+    m_Profiler.m_Timers.emplace_back( "close", Support::Resolutions::mus );
+
+    m_Profiler.m_TotalBytes.push_back( 0 );
+    m_Profiler.m_IsActive = true;
+}
+
+
+
+} //end namespace
+
diff --git a/src/engine/adios1/ADIOS1Reader.cpp b/src/engine/adios1/ADIOS1Reader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..edff32aad4f43e7ee05f42d7b8d2512630798c77
--- /dev/null
+++ b/src/engine/adios1/ADIOS1Reader.cpp
@@ -0,0 +1,178 @@
+/*
+ * BPFileReader.cpp
+ *
+ *  Created on: Feb 27, 2017
+ *      Author: wfg
+ */
+
+
+
+#include "engine/bp/BPFileReader.h"
+
+#include "transport/file/FileDescriptor.h" // uses POSIX
+#include "transport/file/FilePointer.h" // uses C FILE*
+#include "core/Support.h"
+#include "functions/adiosFunctions.h" //CSVToVector
+
+//supported transports
+#include "transport/file/FStream.h" // uses C++ fstream
+
+
+namespace adios
+{
+
+BPFileReader::BPFileReader( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                    const Method& method, const IOMode iomode, const float timeout_sec,
+                    const bool debugMode, const unsigned int nthreads ):
+    Engine( adios, "BPFileReader", name, accessMode, mpiComm, method, debugMode, nthreads, " BPFileReader constructor (or call to ADIOS Open).\n" ),
+    m_Buffer( accessMode, m_RankMPI, m_DebugMode )
+{
+    Init( );
+}
+
+BPFileReader::~BPFileReader( )
+{ }
+
+
+Variable<void>* BPFileReader::InquireVariable( const std::string name, const bool readIn ) //not yet implemented
+{ return nullptr; }
+
+Variable<char>* BPFileReader::InquireVariableChar( const std::string name, const bool readIn )
+{ return InquireVariableCommon<char>( name, readIn ); }
+
+Variable<unsigned char>* BPFileReader::InquireVariableUChar( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned char>( name, readIn ); }
+
+Variable<short>* BPFileReader::InquireVariableShort( const std::string name, const bool readIn )
+{ return InquireVariableCommon<short>( name, readIn ); }
+
+Variable<unsigned short>* BPFileReader::InquireVariableUShort( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned short>( name, readIn ); }
+
+Variable<int>* BPFileReader::InquireVariableInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<int>( name, readIn ); }
+
+Variable<unsigned int>* BPFileReader::InquireVariableUInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned int>( name, readIn ); }
+
+Variable<long int>* BPFileReader::InquireVariableLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long int>( name, readIn ); }
+
+Variable<unsigned long int>* BPFileReader::InquireVariableULInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned long int>( name, readIn ); }
+
+Variable<long long int>* BPFileReader::InquireVariableLLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long long int>( name, readIn ); }
+
+Variable<unsigned long long int>* BPFileReader::InquireVariableULLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned long long int>( name, readIn ); }
+
+Variable<float>* BPFileReader::InquireVariableFloat( const std::string name, const bool readIn )
+{ return InquireVariableCommon<float>( name, readIn ); }
+
+Variable<double>* BPFileReader::InquireVariableDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<double>( name, readIn ); }
+
+Variable<long double>* BPFileReader::InquireVariableLDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long double>( name, readIn ); }
+
+Variable<std::complex<float>>* BPFileReader::InquireVariableCFloat( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<float>>( name, readIn ); }
+
+Variable<std::complex<double>>* BPFileReader::InquireVariableCDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<double>>( name, readIn ); }
+
+Variable<std::complex<long double>>* BPFileReader::InquireVariableCLDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<long double>>( name, readIn ); }
+
+VariableCompound* BPFileReader::InquireVariableCompound( const std::string name, const bool readIn )
+{ return nullptr; }
+
+
+void BPFileReader::Close( const int transportIndex )
+{
+
+}
+
+
+//PRIVATE
+void BPFileReader::Init( )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_AccessMode != "r" && m_AccessMode != "read" )
+            throw std::invalid_argument( "ERROR: BPFileReader doesn't support access mode " + m_AccessMode +
+                                         ", in call to ADIOS Open or BPFileReader constructor\n"  );
+    }
+
+    InitCapsules( );
+    InitTransports( );
+}
+
+
+void BPFileReader::InitCapsules( )
+{
+    //here init memory capsules
+}
+
+
+void BPFileReader::InitTransports( ) //maybe move this?
+{
+    if( m_DebugMode == true )
+    {
+        if( TransportNamesUniqueness( ) == false )
+        {
+            throw std::invalid_argument( "ERROR: two transports of the same kind (e.g file IO) "
+                                         "can't have the same name, modify with name= in Method AddTransport\n" );
+        }
+    }
+
+    for( const auto& parameters : m_Method.m_TransportParameters )
+    {
+        auto itTransport = parameters.find( "transport" );
+        if( itTransport->second == "file" || itTransport->second == "File" )
+        {
+            auto itLibrary = parameters.find( "library" );
+            if( itLibrary == parameters.end() || itLibrary->second == "POSIX" ) //use default POSIX
+            {
+                auto file = std::make_shared<transport::FileDescriptor>( m_MPIComm, m_DebugMode );
+                //m_BP1Reader.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+            }
+            else if( itLibrary->second == "FILE*" || itLibrary->second == "stdio.h" )
+            {
+                auto file = std::make_shared<transport::FilePointer>( m_MPIComm, m_DebugMode );
+                //m_BP1Reader.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+
+            }
+            else if( itLibrary->second == "fstream" || itLibrary->second == "std::fstream" )
+            {
+                auto file = std::make_shared<transport::FStream>( m_MPIComm, m_DebugMode );
+                //m_BP1Reader.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+            }
+            else if( itLibrary->second == "MPI-IO" )
+            {
+
+            }
+            else
+            {
+                if( m_DebugMode == true )
+                    throw std::invalid_argument( "ERROR: file transport library " + itLibrary->second + " not supported, in " +
+                            m_Name + m_EndMessage );
+            }
+        }
+        else
+        {
+            if( m_DebugMode == true )
+                throw std::invalid_argument( "ERROR: transport " + itTransport->second + " (you mean File?) not supported, in " +
+                        m_Name + m_EndMessage );
+        }
+    }
+}
+
+
+} //end namespace
+
+
diff --git a/src/engine/adios1/ADIOS1Writer.cpp b/src/engine/adios1/ADIOS1Writer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0adc032e68a2efe389e0be129512b4efc11f1a2b
--- /dev/null
+++ b/src/engine/adios1/ADIOS1Writer.cpp
@@ -0,0 +1,369 @@
+/*
+ * ADIOS1Writer.cpp
+ * Class to write files using old adios 1.x library.
+ * It requires adios 1.x installed
+ *
+ *  Created on: Mar 27, 2017
+ *      Author: pnb
+ */
+
+#include "engine/adios1/ADIOS1Writer.h"
+#include "ADIOS.h"
+
+extern int adios_verbose_level;
+extern int adios_errno;
+
+namespace adios
+{
+
+
+ADIOS1Writer::ADIOS1Writer( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                            const Method& method, const IOMode iomode, const float timeout_sec,
+                            const bool debugMode, const unsigned int nthreads ):
+    Engine( adios, "ADIOS1Writer", name, accessMode, mpiComm, method, debugMode, nthreads, " ADIOS1Writer constructor (or call to ADIOS Open).\n" ),
+    m_groupname{method.m_Name.c_str()},
+    m_filename{name.c_str()},
+    m_comm{mpiComm}
+{
+    Init( );
+    adios_open( &m_adios_file, m_groupname, m_filename, accessMode.c_str(), m_comm );
+    if( adios_errno == err_no_error )
+    {
+        m_IsFileOpen = true;
+    }
+}
+
+
+ADIOS1Writer::~ADIOS1Writer( )
+{
+    if (m_IsFileOpen )
+    {
+        adios_close( m_adios_file );
+        m_IsFileOpen = false;
+    }
+}
+
+
+void ADIOS1Writer::Init( )
+{
+    if( !m_initialized )
+    {
+        adios_init_noxml( m_comm );
+        m_initialized = true;
+    }
+    adios_declare_group( &m_adios_group, m_groupname, "", adios_stat_default );
+
+    InitParameters( );
+    InitTransports( );
+}
+
+bool ADIOS1Writer::ReOpenAsNeeded( )
+{
+    if( !m_IsFileOpen )
+    {
+        adios_open( &m_adios_file, m_groupname, m_filename, "a", m_comm );
+        if( adios_errno == err_no_error )
+        {
+            m_IsFileOpen = true;
+            adios_delete_vardefs( m_adios_group );
+        }
+    }
+    return m_IsFileOpen;
+}
+
+void ADIOS1Writer::DefineVariable ( std::string name, bool isScalar, enum ADIOS_DATATYPES vartype,
+                                     std::string ldims, std::string gdims, std::string offs )
+{
+    if( isScalar )
+    {
+        adios_define_var( m_adios_group, name.c_str(), "", vartype, "", "", "" );
+    }
+    else
+    {
+        adios_define_var( m_adios_group, name.c_str(), "", vartype, ldims.c_str(), gdims.c_str(), offs.c_str());
+    }
+}
+
+void ADIOS1Writer::WriteVariable ( std::string name, bool isScalar, enum ADIOS_DATATYPES vartype,
+                                   std::string ldims, std::string gdims, std::string offs, const void * values )
+{
+    if( ReOpenAsNeeded() )
+    {
+        DefineVariable( name, isScalar, vartype, ldims, gdims, offs );
+        adios_write( m_adios_file, name.c_str(), values );
+    }
+}
+
+
+void ADIOS1Writer::Write( Variable<char>& variable, const char* values )
+{
+   WriteVariable( variable.m_Name, variable.m_IsScalar, adios_byte,
+                  variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                  values);
+}
+
+void ADIOS1Writer::Write( Variable<unsigned char>& variable, const unsigned char* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_unsigned_byte,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<short>& variable, const short* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_short,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<unsigned short>& variable, const unsigned short* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_unsigned_short,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<int>& variable, const int* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_integer,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<unsigned int>& variable, const unsigned int* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_unsigned_integer,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<long int>& variable, const long int* values )
+{
+    enum ADIOS_DATATYPES type = adios_integer; // long int is usually 4 bytes which is adios_integer
+    if( sizeof(long int) == 8 )
+    {
+        type = adios_long;
+    }
+    WriteVariable( variable.m_Name, variable.m_IsScalar, type,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<unsigned long int>& variable, const unsigned long int* values )
+{
+    enum ADIOS_DATATYPES type = adios_unsigned_integer; // long int is usually 4 bytes
+    if( sizeof(long int) == 8 )
+    {
+        type = adios_unsigned_long;
+    }
+    WriteVariable( variable.m_Name, variable.m_IsScalar, type,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<long long int>& variable, const long long int* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_long,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<unsigned long long int>& variable, const unsigned long long int* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_unsigned_long,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<float>& variable, const float* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_real,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<double>& variable, const double* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_double,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<long double>& variable, const long double* values )
+{
+    /* TODO: This is faulty: adios_long_double expects 16 bytes per elements, but long double is compiler dependent */
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_long_double,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<std::complex<float>>& variable, const std::complex<float>* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_complex,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<std::complex<double>>& variable, const std::complex<double>* values )
+{
+    WriteVariable( variable.m_Name, variable.m_IsScalar, adios_double_complex,
+                   variable.GetDimensionAsString(), variable.GetGlobalDimensionAsString(), variable.GetOffsetsAsString(),
+                   values);
+}
+
+void ADIOS1Writer::Write( Variable<std::complex<long double>>& variable, const std::complex<long double>* values )
+{
+    throw std::invalid_argument( "ERROR: Adios 1.x does not support complex<long double> type, so it cannot write variable " +
+            variable.m_Name + "\n");
+}
+
+void ADIOS1Writer::Write( VariableCompound& variable, const void* values )
+{
+    throw std::invalid_argument( "ERROR: Adios 1.x does not support compound types, so it cannot write variable " +
+            variable.m_Name + "\n");
+}
+
+//String version
+void ADIOS1Writer::Write( const std::string variableName, const char* values )
+{ Write( m_ADIOS.GetVariable<char>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const unsigned char* values )
+{ Write( m_ADIOS.GetVariable<unsigned char>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const short* values )
+{ Write( m_ADIOS.GetVariable<short>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const unsigned short* values )
+{ Write( m_ADIOS.GetVariable<unsigned short>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const int* values )
+{ Write( m_ADIOS.GetVariable<int>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const unsigned int* values )
+{ Write( m_ADIOS.GetVariable<unsigned int>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const long int* values )
+{ Write( m_ADIOS.GetVariable<long int>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const unsigned long int* values )
+{ Write( m_ADIOS.GetVariable<unsigned long int>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const long long int* values )
+{ Write( m_ADIOS.GetVariable<long long int>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const unsigned long long int* values )
+{ Write( m_ADIOS.GetVariable<unsigned long long int>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const float* values )
+{ Write( m_ADIOS.GetVariable<float>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const double* values )
+{ Write( m_ADIOS.GetVariable<double>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const long double* values )
+{ Write( m_ADIOS.GetVariable<long double>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const std::complex<float>* values )
+{ Write( m_ADIOS.GetVariable<std::complex<float>>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const std::complex<double>* values )
+{ Write( m_ADIOS.GetVariable<std::complex<double>>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const std::complex<long double>* values )
+{ Write( m_ADIOS.GetVariable<std::complex<long double>>( variableName ), values ); }
+
+void ADIOS1Writer::Write( const std::string variableName, const void* values ) //Compound type
+{
+    throw std::invalid_argument( "ERROR: Adios 1.x does not support compound types, so it cannot write variable " +
+            variableName + "\n");
+}
+
+
+void ADIOS1Writer::Advance( )
+{
+    if (m_IsFileOpen )
+    {
+        adios_close( m_adios_file );
+        m_IsFileOpen = false;
+    }
+}
+
+
+void ADIOS1Writer::Close( const int transportIndex )
+{
+    if (m_IsFileOpen )
+    {
+        adios_close( m_adios_file );
+        m_IsFileOpen = false;
+    }
+}
+
+
+//PRIVATE FUNCTIONS
+void ADIOS1Writer::InitParameters( )
+{
+    auto itMaxBufferSize = m_Method.m_Parameters.find( "max_size_MB" );
+    if( itMaxBufferSize != m_Method.m_Parameters.end() )
+    {
+        adios_set_max_buffer_size( std::stoul( itMaxBufferSize->second ) );
+    }
+
+    auto itVerbosity = m_Method.m_Parameters.find( "verbose" );
+    if( itVerbosity != m_Method.m_Parameters.end() )
+    {
+        int verbosity = std::stoi( itVerbosity->second );
+        if( m_DebugMode == true )
+        {
+            if( verbosity < 0 || verbosity > 5 )
+                throw std::invalid_argument( "ERROR: Method verbose argument must be an integer in the range [0,5], in call to Open or Engine constructor\n" );
+        }
+        adios_verbose_level = verbosity;
+    }
+}
+
+
+void ADIOS1Writer::InitTransports( )
+{
+    if( m_DebugMode == true )
+    {
+        if( TransportNamesUniqueness( ) == false )
+        {
+            throw std::invalid_argument( "ERROR: two transports of the same kind (e.g file IO) "
+                                         "can't have the same name, modify with name= in Method AddTransport\n" );
+        }
+    }
+
+    for( const auto& parameters : m_Method.m_TransportParameters )
+    {
+        auto itTransport = parameters.find( "transport" );
+
+        if( itTransport->second == "file" || itTransport->second == "File" )
+        {
+            auto itLibrary = parameters.find( "library" );
+            if( itLibrary == parameters.end() || itLibrary->second == "POSIX" ) //use default POSIX
+            {
+                adios_select_method( m_adios_group, "POSIX", "", "" );
+            }
+            else if( itLibrary->second == "MPI_File" || itLibrary->second == "MPI-IO" )
+            {
+                adios_select_method( m_adios_group, "MPI", "", "" );
+            }
+            else
+            {
+                if( m_DebugMode == true )
+                    throw std::invalid_argument( "ERROR: file transport library " + itLibrary->second + " not supported, in " +
+                                                  m_Name + m_EndMessage );
+            }
+        }
+        else
+        {
+            if( m_DebugMode == true )
+                throw std::invalid_argument( "ERROR: transport " + itTransport->second + " (you mean File?) not supported, in " +
+                                              m_Name + m_EndMessage );
+        }
+    }
+}
+
+
+
+} //end namespace adios
diff --git a/src/engine/bp/BPFileReader.cpp b/src/engine/bp/BPFileReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..edff32aad4f43e7ee05f42d7b8d2512630798c77
--- /dev/null
+++ b/src/engine/bp/BPFileReader.cpp
@@ -0,0 +1,178 @@
+/*
+ * BPFileReader.cpp
+ *
+ *  Created on: Feb 27, 2017
+ *      Author: wfg
+ */
+
+
+
+#include "engine/bp/BPFileReader.h"
+
+#include "transport/file/FileDescriptor.h" // uses POSIX
+#include "transport/file/FilePointer.h" // uses C FILE*
+#include "core/Support.h"
+#include "functions/adiosFunctions.h" //CSVToVector
+
+//supported transports
+#include "transport/file/FStream.h" // uses C++ fstream
+
+
+namespace adios
+{
+
+BPFileReader::BPFileReader( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                    const Method& method, const IOMode iomode, const float timeout_sec,
+                    const bool debugMode, const unsigned int nthreads ):
+    Engine( adios, "BPFileReader", name, accessMode, mpiComm, method, debugMode, nthreads, " BPFileReader constructor (or call to ADIOS Open).\n" ),
+    m_Buffer( accessMode, m_RankMPI, m_DebugMode )
+{
+    Init( );
+}
+
+BPFileReader::~BPFileReader( )
+{ }
+
+
+Variable<void>* BPFileReader::InquireVariable( const std::string name, const bool readIn ) //not yet implemented
+{ return nullptr; }
+
+Variable<char>* BPFileReader::InquireVariableChar( const std::string name, const bool readIn )
+{ return InquireVariableCommon<char>( name, readIn ); }
+
+Variable<unsigned char>* BPFileReader::InquireVariableUChar( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned char>( name, readIn ); }
+
+Variable<short>* BPFileReader::InquireVariableShort( const std::string name, const bool readIn )
+{ return InquireVariableCommon<short>( name, readIn ); }
+
+Variable<unsigned short>* BPFileReader::InquireVariableUShort( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned short>( name, readIn ); }
+
+Variable<int>* BPFileReader::InquireVariableInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<int>( name, readIn ); }
+
+Variable<unsigned int>* BPFileReader::InquireVariableUInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned int>( name, readIn ); }
+
+Variable<long int>* BPFileReader::InquireVariableLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long int>( name, readIn ); }
+
+Variable<unsigned long int>* BPFileReader::InquireVariableULInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned long int>( name, readIn ); }
+
+Variable<long long int>* BPFileReader::InquireVariableLLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long long int>( name, readIn ); }
+
+Variable<unsigned long long int>* BPFileReader::InquireVariableULLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned long long int>( name, readIn ); }
+
+Variable<float>* BPFileReader::InquireVariableFloat( const std::string name, const bool readIn )
+{ return InquireVariableCommon<float>( name, readIn ); }
+
+Variable<double>* BPFileReader::InquireVariableDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<double>( name, readIn ); }
+
+Variable<long double>* BPFileReader::InquireVariableLDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long double>( name, readIn ); }
+
+Variable<std::complex<float>>* BPFileReader::InquireVariableCFloat( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<float>>( name, readIn ); }
+
+Variable<std::complex<double>>* BPFileReader::InquireVariableCDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<double>>( name, readIn ); }
+
+Variable<std::complex<long double>>* BPFileReader::InquireVariableCLDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<long double>>( name, readIn ); }
+
+VariableCompound* BPFileReader::InquireVariableCompound( const std::string name, const bool readIn )
+{ return nullptr; }
+
+
+void BPFileReader::Close( const int transportIndex )
+{
+
+}
+
+
+//PRIVATE
+void BPFileReader::Init( )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_AccessMode != "r" && m_AccessMode != "read" )
+            throw std::invalid_argument( "ERROR: BPFileReader doesn't support access mode " + m_AccessMode +
+                                         ", in call to ADIOS Open or BPFileReader constructor\n"  );
+    }
+
+    InitCapsules( );
+    InitTransports( );
+}
+
+
+void BPFileReader::InitCapsules( )
+{
+    //here init memory capsules
+}
+
+
+void BPFileReader::InitTransports( ) //maybe move this?
+{
+    if( m_DebugMode == true )
+    {
+        if( TransportNamesUniqueness( ) == false )
+        {
+            throw std::invalid_argument( "ERROR: two transports of the same kind (e.g file IO) "
+                                         "can't have the same name, modify with name= in Method AddTransport\n" );
+        }
+    }
+
+    for( const auto& parameters : m_Method.m_TransportParameters )
+    {
+        auto itTransport = parameters.find( "transport" );
+        if( itTransport->second == "file" || itTransport->second == "File" )
+        {
+            auto itLibrary = parameters.find( "library" );
+            if( itLibrary == parameters.end() || itLibrary->second == "POSIX" ) //use default POSIX
+            {
+                auto file = std::make_shared<transport::FileDescriptor>( m_MPIComm, m_DebugMode );
+                //m_BP1Reader.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+            }
+            else if( itLibrary->second == "FILE*" || itLibrary->second == "stdio.h" )
+            {
+                auto file = std::make_shared<transport::FilePointer>( m_MPIComm, m_DebugMode );
+                //m_BP1Reader.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+
+            }
+            else if( itLibrary->second == "fstream" || itLibrary->second == "std::fstream" )
+            {
+                auto file = std::make_shared<transport::FStream>( m_MPIComm, m_DebugMode );
+                //m_BP1Reader.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+            }
+            else if( itLibrary->second == "MPI-IO" )
+            {
+
+            }
+            else
+            {
+                if( m_DebugMode == true )
+                    throw std::invalid_argument( "ERROR: file transport library " + itLibrary->second + " not supported, in " +
+                            m_Name + m_EndMessage );
+            }
+        }
+        else
+        {
+            if( m_DebugMode == true )
+                throw std::invalid_argument( "ERROR: transport " + itTransport->second + " (you mean File?) not supported, in " +
+                        m_Name + m_EndMessage );
+        }
+    }
+}
+
+
+} //end namespace
+
+
diff --git a/src/engine/bp/BPFileWriter.cpp b/src/engine/bp/BPFileWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..775fbe44a91d9f679a770b091d12c243dcbdb7d5
--- /dev/null
+++ b/src/engine/bp/BPFileWriter.cpp
@@ -0,0 +1,397 @@
+/*
+ * BPFileWriter.cpp
+ *
+ *  Created on: Dec 19, 2016
+ *      Author: wfg
+ */
+
+#include "engine/bp/BPFileWriter.h"
+#include "ADIOS.h"
+
+//supported transports
+#include "transport/file/FileDescriptor.h"
+#include "transport/file/FilePointer.h"
+#include "transport/file/FStream.h"
+
+namespace adios
+{
+
+
+BPFileWriter::BPFileWriter( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                            const Method& method, const IOMode iomode, const float timeout_sec,
+                            const bool debugMode, const unsigned int nthreads ):
+    Engine( adios, "BPFileWriter", name, accessMode, mpiComm, method, debugMode, nthreads, " BPFileWriter constructor (or call to ADIOS Open).\n" ),
+    m_Buffer{ capsule::STLVector( accessMode, m_RankMPI, m_DebugMode ) },
+    m_BP1Aggregator{ format::BP1Aggregator( m_MPIComm, debugMode ) },
+    m_MaxBufferSize{ m_Buffer.m_Data.max_size() }
+{
+    m_MetadataSet.TimeStep = 1; //starting at one to be compatible with ADIOS1.x
+    Init( );
+}
+
+
+BPFileWriter::~BPFileWriter( )
+{ }
+
+
+void BPFileWriter::Init( )
+{
+    InitParameters( );
+    InitTransports( );
+    InitProcessGroup( );
+}
+
+
+void BPFileWriter::Write( Variable<char>& variable, const char* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<unsigned char>& variable, const unsigned char* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<short>& variable, const short* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<unsigned short>& variable, const unsigned short* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<int>& variable, const int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<unsigned int>& variable, const unsigned int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<long int>& variable, const long int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<unsigned long int>& variable, const unsigned long int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<long long int>& variable, const long long int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<unsigned long long int>& variable, const unsigned long long int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<float>& variable, const float* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<double>& variable, const double* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<long double>& variable, const long double* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<std::complex<float>>& variable, const std::complex<float>* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<std::complex<double>>& variable, const std::complex<double>* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( Variable<std::complex<long double>>& variable, const std::complex<long double>* values )
+{ WriteVariableCommon( variable, values ); }
+
+void BPFileWriter::Write( VariableCompound& variable, const void* values )
+{ }
+
+//String version
+void BPFileWriter::Write( const std::string variableName, const char* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<char>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const unsigned char* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned char>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const short* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<short>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const unsigned short* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned short>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<int>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const unsigned int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned int>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const long int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<long int>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const unsigned long int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned long int>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const long long int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<long long int>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const unsigned long long int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned long long int>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const float* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<float>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const double* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<double>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const long double* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<long double>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const std::complex<float>* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<std::complex<float>>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const std::complex<double>* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<std::complex<double>>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const std::complex<long double>* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<std::complex<long double>>( variableName ), values ); }
+
+void BPFileWriter::Write( const std::string variableName, const void* values ) //Compound type
+{ }
+
+
+void BPFileWriter::Advance( float timeout_sec )
+{
+    m_BP1Writer.Advance( m_MetadataSet, m_Buffer );
+}
+
+
+void BPFileWriter::Close( const int transportIndex )
+{
+    CheckTransportIndex( transportIndex );
+    if( transportIndex == -1 )
+    {
+        for( auto& transport : m_Transports ) //by reference or value or it doesn't matter?
+            m_BP1Writer.Close( m_MetadataSet, m_Buffer, *transport, m_IsFirstClose, false ); //false: not using aggregation for now
+    }
+    else
+    {
+        m_BP1Writer.Close( m_MetadataSet, m_Buffer, *m_Transports[transportIndex], m_IsFirstClose, false ); //false: not using aggregation for now
+    }
+
+    if( m_MetadataSet.Log.m_IsActive == true )
+    {
+        bool allClose = true;
+        for( auto& transport : m_Transports )
+        {
+            if( transport->m_IsOpen == true )
+            {
+                allClose = false;
+                break;
+            }
+        }
+        if( allClose == true ) //aggregate and write profiling.log
+        {
+            const std::string rankLog = m_BP1Writer.GetRankProfilingLog( m_RankMPI, m_MetadataSet, m_Transports );
+
+            const std::string fileName( m_BP1Writer.GetDirectoryName(m_Name) + "/profiling.log" );
+            m_BP1Aggregator.WriteProfilingLog( fileName, rankLog );
+        }
+    }
+
+}
+
+
+//PRIVATE FUNCTIONS
+void BPFileWriter::InitParameters( )
+{
+    auto itGrowthFactor = m_Method.m_Parameters.find( "buffer_growth" );
+    if( itGrowthFactor != m_Method.m_Parameters.end() )
+    {
+        const float growthFactor = std::stof( itGrowthFactor->second );
+        if( m_DebugMode == true )
+        {
+            if( growthFactor == 1.f )
+                throw std::invalid_argument( "ERROR: buffer_growth argument can't be less of equal than 1, in " + m_EndMessage + "\n" );
+        }
+
+        m_BP1Writer.m_GrowthFactor = growthFactor;
+        m_GrowthFactor = growthFactor; //float
+    }
+
+    auto itMaxBufferSize = m_Method.m_Parameters.find( "max_size_MB" );
+    if( itMaxBufferSize != m_Method.m_Parameters.end() )
+    {
+        if( m_DebugMode == true )
+        {
+            if( m_GrowthFactor <= 1.f )
+                throw std::invalid_argument( "ERROR: Method buffer_growth argument can't be less of equal than 1, in " + m_EndMessage + "\n" );
+        }
+
+        m_MaxBufferSize = std::stoul( itMaxBufferSize->second ) * 1048576; //convert from MB to bytes
+    }
+
+    auto itVerbosity = m_Method.m_Parameters.find( "verbose" );
+    if( itVerbosity != m_Method.m_Parameters.end() )
+    {
+        int verbosity = std::stoi( itVerbosity->second );
+        if( m_DebugMode == true )
+        {
+            if( verbosity < 0 || verbosity > 5 )
+                throw std::invalid_argument( "ERROR: Method verbose argument must be an integer in the range [0,5], in call to Open or Engine constructor\n" );
+        }
+        m_BP1Writer.m_Verbosity = verbosity;
+    }
+
+    auto itProfile = m_Method.m_Parameters.find( "profile_units" );
+    if( itProfile != m_Method.m_Parameters.end() )
+    {
+        auto& profiler = m_MetadataSet.Log;
+
+        if( itProfile->second == "mus" || itProfile->second == "microseconds" )
+            profiler.m_Timers.emplace_back( "buffering", Support::Resolutions::mus );
+
+        else if( itProfile->second == "ms" || itProfile->second == "milliseconds" )
+            profiler.m_Timers.emplace_back( "buffering", Support::Resolutions::ms );
+
+        else if( itProfile->second == "s" || itProfile->second == "seconds" )
+            profiler.m_Timers.emplace_back( "buffering", Support::Resolutions::s );
+
+        else if( itProfile->second == "min" || itProfile->second == "minutes" )
+            profiler.m_Timers.emplace_back( "buffering", Support::Resolutions::m );
+
+        else if( itProfile->second == "h" || itProfile->second == "hours" )
+            profiler.m_Timers.emplace_back( "buffering", Support::Resolutions::h );
+        else
+        {
+            if( m_DebugMode == true )
+                throw std::invalid_argument( "ERROR: Method profile_buffering_units argument must be mus, ms, s, min or h, in call to Open or Engine constructor\n" );
+        }
+
+        profiler.m_IsActive = true;
+    }
+}
+
+
+void BPFileWriter::InitTransports( )
+{
+    if( m_DebugMode == true )
+    {
+        if( TransportNamesUniqueness( ) == false )
+        {
+            throw std::invalid_argument( "ERROR: two transports of the same kind (e.g file IO) "
+                                         "can't have the same name, modify with name= in Method AddTransport\n" );
+        }
+    }
+
+    for( const auto& parameters : m_Method.m_TransportParameters )
+    {
+        auto itProfile = parameters.find( "profile_units" );
+        bool doProfiling = false;
+        Support::Resolutions resolution = Support::Resolutions::s; //default is seconds
+        if( itProfile != parameters.end() )
+        {
+            if( itProfile->second == "mus" || itProfile->second == "microseconds" )
+                resolution = Support::Resolutions::mus;
+
+            else if( itProfile->second == "ms" || itProfile->second == "milliseconds" )
+                resolution = Support::Resolutions::ms;
+
+            else if( itProfile->second == "s" || itProfile->second == "seconds" )
+                resolution = Support::Resolutions::s;
+
+            else if( itProfile->second == "min" || itProfile->second == "minutes" )
+                resolution = Support::Resolutions::m;
+
+            else if( itProfile->second == "h" || itProfile->second == "hours" )
+                resolution = Support::Resolutions::h;
+
+            else
+            {
+                if( m_DebugMode == true )
+                    throw std::invalid_argument( "ERROR: Transport profile_units argument must be mus, ms, s, min or h " + m_EndMessage );
+            }
+            doProfiling = true;
+        }
+
+        auto itTransport = parameters.find( "transport" );
+
+        if( itTransport->second == "file" || itTransport->second == "File" )
+        {
+            auto itLibrary = parameters.find( "library" );
+            if( itLibrary == parameters.end() || itLibrary->second == "POSIX" ) //use default POSIX
+            {
+                auto file = std::make_shared<transport::FileDescriptor>( m_MPIComm, m_DebugMode );
+                if( doProfiling == true )
+                    file->InitProfiler( m_AccessMode, resolution );
+
+                m_BP1Writer.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+
+            }
+            else if( itLibrary->second == "FILE*" || itLibrary->second == "stdio" )
+            {
+                auto file = std::make_shared<transport::FilePointer>( m_MPIComm, m_DebugMode );
+                if( doProfiling == true )
+                    file->InitProfiler( m_AccessMode, resolution );
+
+                m_BP1Writer.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+            }
+            else if( itLibrary->second == "fstream" || itLibrary->second == "std::fstream" )
+            {
+                auto file = std::make_shared<transport::FStream>( m_MPIComm, m_DebugMode );
+
+                if( doProfiling == true )
+                    file->InitProfiler( m_AccessMode, resolution );
+
+                m_BP1Writer.OpenRankFiles( m_Name, m_AccessMode, *file );
+                m_Transports.push_back( std::move( file ) );
+            }
+            else if( itLibrary->second == "MPI_File" || itLibrary->second == "MPI-IO" )
+            {
+
+            }
+            else
+            {
+                if( m_DebugMode == true )
+                    throw std::invalid_argument( "ERROR: file transport library " + itLibrary->second + " not supported, in " +
+                                                  m_Name + m_EndMessage );
+            }
+        }
+        else
+        {
+            if( m_DebugMode == true )
+                throw std::invalid_argument( "ERROR: transport " + itTransport->second + " (you mean File?) not supported, in " +
+                                              m_Name + m_EndMessage );
+        }
+    }
+}
+
+
+void BPFileWriter::InitProcessGroup( )
+{
+    if( m_MetadataSet.Log.m_IsActive == true )
+        m_MetadataSet.Log.m_Timers[0].SetInitialTime();
+
+    if( m_AccessMode == "a" )
+    {
+        //Get last pg timestep and update timestep counter in format::BP1MetadataSet
+    }
+
+    WriteProcessGroupIndex( );
+
+    if( m_MetadataSet.Log.m_IsActive == true )
+        m_MetadataSet.Log.m_Timers[0].SetTime();
+}
+
+
+
+void BPFileWriter::WriteProcessGroupIndex( )
+{
+    //pg = process group
+//    const std::size_t pgIndexSize = m_BP1Writer.GetProcessGroupIndexSize( std::to_string( m_RankMPI ),
+//                                                                          std::to_string( m_MetadataSet.TimeStep ),
+//                                                                          m_Transports.size() );
+    //metadata
+    //GrowBuffer( pgIndexSize, m_GrowthFactor, m_MetadataSet.PGIndex );
+
+    //data? Need to be careful, maybe add some trailing tolerance in variable ????
+    //GrowBuffer( pgIndexSize, m_GrowthFactor, m_Buffer.m_Data );
+
+    const bool isFortran = ( m_HostLanguage == "Fortran" ) ? true : false;
+
+    m_BP1Writer.WriteProcessGroupIndex( isFortran, std::to_string( m_RankMPI ), static_cast<std::uint32_t>( m_RankMPI ),
+                                        m_Transports, m_Buffer, m_MetadataSet );
+
+}
+
+
+
+} //end namespace adios
diff --git a/src/engine/dataman/DataManReader.cpp b/src/engine/dataman/DataManReader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..062bfaa50b684ec3484651364c09fb247bd6b67c
--- /dev/null
+++ b/src/engine/dataman/DataManReader.cpp
@@ -0,0 +1,253 @@
+/*
+ * DataManReader.cpp
+ *
+ *  Created on: Feb 21, 2017
+ *      Author: wfg
+ */
+
+
+#include "engine/dataman/DataManReader.h"
+
+#include "core/Support.h"
+#include "functions/adiosFunctions.h" //CSVToVector
+
+//supported transports
+#include "transport/file/FStream.h" // uses C++ fstream
+#include "transport/wan/MdtmMan.h" //uses Mdtm library
+
+#include "DataMan.h"  //here comes your DataMan header from external dataman library
+#include "../../../include/transport/file/FileDescriptor.h" // uses POSIX
+#include "../../../include/transport/file/FilePointer.h" // uses C FILE*
+
+namespace adios
+{
+
+DataManReader::DataManReader( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                              const Method& method, const IOMode iomode, const float timeout_sec,
+                              const bool debugMode, const unsigned int nthreads ):
+    Engine( adios, "DataManReader", name, accessMode, mpiComm, method, debugMode, nthreads, " DataManReader constructor (or call to ADIOS Open).\n" ),
+    m_Buffer( accessMode, m_RankMPI, m_DebugMode )
+{
+    Init( );
+}
+
+DataManReader::~DataManReader( )
+{ }
+
+void DataManReader::SetCallBack( std::function<void( const void*, std::string, std::string, std::string, Dims )> callback )
+{
+    m_CallBack = callback;
+    m_Man.reg_callback(callback);
+}
+
+Variable<void>* DataManReader::InquireVariable( const std::string name, const bool readIn ) //not yet implemented
+{ return nullptr; }
+
+Variable<char>* DataManReader::InquireVariableChar( const std::string name, const bool readIn )
+{ return InquireVariableCommon<char>( name, readIn ); }
+
+Variable<unsigned char>* DataManReader::InquireVariableUChar( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned char>( name, readIn ); }
+
+Variable<short>* DataManReader::InquireVariableShort( const std::string name, const bool readIn )
+{ return InquireVariableCommon<short>( name, readIn ); }
+
+Variable<unsigned short>* DataManReader::InquireVariableUShort( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned short>( name, readIn ); }
+
+Variable<int>* DataManReader::InquireVariableInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<int>( name, readIn ); }
+
+Variable<unsigned int>* DataManReader::InquireVariableUInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned int>( name, readIn ); }
+
+Variable<long int>* DataManReader::InquireVariableLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long int>( name, readIn ); }
+
+Variable<unsigned long int>* DataManReader::InquireVariableULInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned long int>( name, readIn ); }
+
+Variable<long long int>* DataManReader::InquireVariableLLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long long int>( name, readIn ); }
+
+Variable<unsigned long long int>* DataManReader::InquireVariableULLInt( const std::string name, const bool readIn )
+{ return InquireVariableCommon<unsigned long long int>( name, readIn ); }
+
+Variable<float>* DataManReader::InquireVariableFloat( const std::string name, const bool readIn )
+{ return InquireVariableCommon<float>( name, readIn ); }
+
+Variable<double>* DataManReader::InquireVariableDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<double>( name, readIn ); }
+
+Variable<long double>* DataManReader::InquireVariableLDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<long double>( name, readIn ); }
+
+Variable<std::complex<float>>* DataManReader::InquireVariableCFloat( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<float>>( name, readIn ); }
+
+Variable<std::complex<double>>* DataManReader::InquireVariableCDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<double>>( name, readIn ); }
+
+Variable<std::complex<long double>>* DataManReader::InquireVariableCLDouble( const std::string name, const bool readIn )
+{ return InquireVariableCommon<std::complex<long double>>( name, readIn ); }
+
+VariableCompound* DataManReader::InquireVariableCompound( const std::string name, const bool readIn )
+{ return nullptr; }
+
+
+void DataManReader::Close( const int transportIndex )
+{
+
+}
+
+
+//PRIVATE
+void DataManReader::Init( )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_AccessMode != "r" && m_AccessMode != "read" )
+            throw std::invalid_argument( "ERROR: DataManReader doesn't support access mode " + m_AccessMode +
+                                         ", in call to ADIOS Open or DataManReader constructor\n"  );
+    }
+
+    auto itRealTime = m_Method.m_Parameters.find( "real_time" );
+    if( itRealTime != m_Method.m_Parameters.end() )
+    {
+        if( itRealTime->second == "yes" || itRealTime->second == "true" )
+            m_DoRealTime = true;
+    }
+
+    if(m_DoRealTime)
+    {
+        /**
+         * Lambda function that assigns a parameter in m_Method to a localVariable of type std::string
+         */
+        auto lf_AssignString = [this]( const std::string parameter, std::string& localVariable )
+        {
+            auto it = m_Method.m_Parameters.find( parameter );
+            if( it != m_Method.m_Parameters.end() )
+            {
+                localVariable = it->second;
+            }
+        };
+
+        /**
+         * Lambda function that assigns a parameter in m_Method to a localVariable of type int
+         */
+        auto lf_AssignInt = [this]( const std::string parameter, int& localVariable )
+        {
+            auto it = m_Method.m_Parameters.find( parameter );
+            if( it != m_Method.m_Parameters.end() )
+            {
+                localVariable = std::stoi( it->second );
+            }
+        };
+
+        auto is_number = [] (const std::string& s)
+        {
+            return !s.empty() && std::find_if(s.begin(), s.end(), [](char c) { return !std::isdigit(c);  }) == s.end();
+        };
+
+        json jmsg;
+        for(auto &i : m_Method.m_Parameters){
+            if( is_number(i.second) ){
+                jmsg[i.first] = std::stoi(i.second);
+            }
+            else{
+                jmsg[i.first] = i.second;
+            }
+        }
+        jmsg["stream_mode"] = "receiver";
+        m_Man.add_stream(jmsg);
+
+        std::string method_type;
+        int num_channels=0;
+        lf_AssignString( "method_type", method_type );
+        lf_AssignInt( "num_channels", num_channels );
+    }
+    else
+    {
+        InitCapsules( );
+        InitTransports( );
+    }
+}
+
+
+void DataManReader::InitCapsules( )
+{
+    //here init memory capsules
+}
+
+
+void DataManReader::InitTransports( ) //maybe move this?
+{
+    TransportNamesUniqueness( );
+
+    for( const auto& parameters : m_Method.m_TransportParameters )
+    {
+        auto itTransport = parameters.find( "transport" );
+
+        if( itTransport->second == "Mdtm" || itTransport->second == "MdtmMan" )
+        {
+            const std::string localIP( GetMdtmParameter( "localIP", parameters ) ); //mandatory
+            const std::string remoteIP( GetMdtmParameter( "remoteIP", parameters ) ); //mandatory
+            const std::string prefix( GetMdtmParameter( "prefix", parameters ) );
+            const int numberOfPipes = std::stoi( GetMdtmParameter( "pipes", parameters ) );
+            const std::vector<int> tolerances = CSVToVectorInt( GetMdtmParameter( "tolerances", parameters ) );
+            const std::vector<int> priorities = CSVToVectorInt( GetMdtmParameter( "priorities", parameters ) );
+
+            m_Transports.push_back( std::make_shared<transport::MdtmMan>( localIP, remoteIP, m_AccessMode, prefix, numberOfPipes,
+                                                                          tolerances, priorities, m_MPIComm, m_DebugMode ) );
+        }
+        else if( itTransport->second == "Zmq" )
+        {
+
+        }
+        else
+        {
+            if( m_DebugMode == true )
+                throw std::invalid_argument( "ERROR: transport + " + itTransport->second + " not supported, in " +
+                                              m_Name + m_EndMessage );
+        }
+    }
+}
+
+
+std::string DataManReader::GetMdtmParameter( const std::string parameter, const std::map<std::string,std::string>& mdtmParameters )
+{
+    auto itParam = mdtmParameters.find( parameter );
+    if( itParam != mdtmParameters.end() ) //found
+    {
+        return itParam->second; //return value
+    }
+    // if not found
+    //mandatory ones
+    if( parameter == "localIP" || parameter == "remoteIP" )
+    {
+        if( m_DebugMode == true )
+            throw std::invalid_argument( "ERROR: " + parameter + " parameter not found in Method, in call to DataManWriter constructor\n" );
+    }
+    else if( parameter == "prefix" )
+    {
+        return "";
+    }
+    else if( parameter == "pipes" )
+    {
+        return "0"; // or 1?
+    }
+    else if( parameter == "tolerances" ) //so far empty string
+    {
+
+    }
+    else if( parameter == "priority" )
+    {
+
+    }
+
+    return ""; //return empty string
+}
+
+
+
+}
diff --git a/src/engine/dataman/DataManWriter.cpp b/src/engine/dataman/DataManWriter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c4b431ee72fd0d526e56f154c39448f7ce8b53da
--- /dev/null
+++ b/src/engine/dataman/DataManWriter.cpp
@@ -0,0 +1,304 @@
+/*
+ * DataMan.cpp
+ *
+ *  Created on: Jan 10, 2017
+ *      Author: wfg
+ */
+
+#include <iostream> //needs to go away, this is just for demo purposes
+
+#include "engine/dataman/DataManWriter.h"
+
+#include "core/Support.h"
+#include "functions/adiosFunctions.h" //CSVToVector
+
+//supported transports
+#include "transport/file/FStream.h" // uses C++ fstream
+#include "transport/wan/MdtmMan.h" //uses Mdtm library
+
+
+
+namespace adios
+{
+
+
+DataManWriter::DataManWriter( ADIOS& adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm,
+                              const Method& method, const IOMode iomode, const float timeout_sec,
+                              const bool debugMode, const unsigned int nthreads ):
+    Engine( adios, "DataManWriter", name, accessMode, mpiComm, method, debugMode, nthreads, " DataManWriter constructor (or call to ADIOS Open).\n" ),
+    m_Buffer( accessMode, m_RankMPI, m_DebugMode )
+{
+    Init( );
+}
+
+
+DataManWriter::~DataManWriter( )
+{ }
+
+void DataManWriter::SetCallBack( std::function<void( const void*, std::string, std::string, std::string, Dims )> callback )
+{
+    m_CallBack = callback;
+    m_Man.reg_callback(callback);
+}
+
+void DataManWriter::Write( Variable<char>& variable, const char* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<unsigned char>& variable, const unsigned char* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<short>& variable, const short* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<unsigned short>& variable, const unsigned short* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<int>& variable, const int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<unsigned int>& variable, const unsigned int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<long int>& variable, const long int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<unsigned long int>& variable, const unsigned long int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<long long int>& variable, const long long int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<unsigned long long int>& variable, const unsigned long long int* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<float>& variable, const float* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<double>& variable, const double* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<long double>& variable, const long double* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<std::complex<float>>& variable, const std::complex<float>* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<std::complex<double>>& variable, const std::complex<double>* values )
+{ WriteVariableCommon( variable, values ); }
+
+void DataManWriter::Write( Variable<std::complex<long double>>& variable, const std::complex<long double>* values )
+{ WriteVariableCommon( variable, values ); }
+
+//String version
+void DataManWriter::Write( const std::string variableName, const char* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<char>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const unsigned char* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned char>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const short* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<short>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const unsigned short* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned short>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<int>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const unsigned int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned int>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const long int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<long int>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const unsigned long int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned long int>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const long long int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<long long int>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const unsigned long long int* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<unsigned long long int>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const float* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<float>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const double* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<double>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const long double* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<long double>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const std::complex<float>* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<std::complex<float>>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const std::complex<double>* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<std::complex<double>>( variableName ), values ); }
+
+void DataManWriter::Write( const std::string variableName, const std::complex<long double>* values )
+{ WriteVariableCommon( m_ADIOS.GetVariable<std::complex<long double>>( variableName ), values ); }
+
+
+void DataManWriter::Close( const int transportIndex )
+{
+    m_Man.flush();
+    //here close IPs and deallocate or free/close resources (if using STL no need for memory deallocation)
+}
+
+
+
+//PRIVATE functions below
+void DataManWriter::Init( )
+{
+    if( m_DebugMode == true )
+    {
+        if( m_AccessMode != "w" && m_AccessMode != "write" && m_AccessMode != "a" && m_AccessMode != "append" )
+            throw std::invalid_argument( "ERROR: DataManWriter doesn't support access mode " + m_AccessMode +
+                                         ", in call to ADIOS Open or DataManWriter constructor\n"  );
+    }
+
+    auto itRealTime = m_Method.m_Parameters.find( "real_time" );
+    if( itRealTime != m_Method.m_Parameters.end() )
+    {
+        if( itRealTime->second == "yes" || itRealTime->second == "true" )
+            m_DoRealTime = true;
+    }
+
+    itRealTime = m_Method.m_Parameters.find( "monitoring" );
+    if( itRealTime != m_Method.m_Parameters.end() )
+    {
+        if( itRealTime->second == "yes" || itRealTime->second == "true" )
+            m_DoMonitor = true;
+    }
+
+    if(m_DoRealTime)
+    {
+        /**
+         * Lambda function that assigns a parameter in m_Method to a localVariable of type std::string
+         */
+        auto lf_AssignString = [this]( const std::string parameter, std::string& localVariable )
+        {
+            auto it = m_Method.m_Parameters.find( parameter );
+            if( it != m_Method.m_Parameters.end() )
+            {
+                localVariable = it->second;
+            }
+        };
+
+        /**
+         * Lambda function that assigns a parameter in m_Method to a localVariable of type int
+         */
+        auto lf_AssignInt = [this]( const std::string parameter, int& localVariable )
+        {
+            auto it = m_Method.m_Parameters.find( parameter );
+            if( it != m_Method.m_Parameters.end() )
+            {
+                localVariable = std::stoi( it->second );
+            }
+        };
+
+        auto is_number = [] (const std::string& s)
+        {
+            return !s.empty() && std::find_if(s.begin(), s.end(), [](char c) { return !std::isdigit(c);  }) == s.end();
+        };
+
+        json jmsg;
+        for(auto &i : m_Method.m_Parameters){
+            if( is_number(i.second) ){
+                jmsg[i.first] = std::stoi(i.second);
+            }
+            else{
+                jmsg[i.first] = i.second;
+            }
+        }
+        jmsg["stream_mode"] = "sender";
+        m_Man.add_stream(jmsg);
+
+        std::string method_type;
+        int num_channels=0;
+        lf_AssignString( "method_type", method_type );
+        lf_AssignInt( "num_channels", num_channels );
+    }
+    else
+    {
+        InitCapsules( );
+        InitTransports( );
+    }
+}
+
+void DataManWriter::InitCapsules( )
+{
+    //here init memory capsules
+}
+
+
+void DataManWriter::InitTransports( ) //maybe move this?
+{
+    TransportNamesUniqueness( );
+
+    for( const auto& parameters : m_Method.m_TransportParameters )
+    {
+        auto itTransport = parameters.find( "transport" );
+
+        if( itTransport->second == "Mdtm" || itTransport->second == "MdtmMan" )
+        {
+            const std::string localIP( GetMdtmParameter( "localIP", parameters ) ); //mandatory
+            const std::string remoteIP( GetMdtmParameter( "remoteIP", parameters ) ); //mandatory
+            const std::string prefix( GetMdtmParameter( "prefix", parameters ) );
+            const int numberOfPipes = std::stoi( GetMdtmParameter( "pipes", parameters ) );
+            const std::vector<int> tolerances = CSVToVectorInt( GetMdtmParameter( "tolerances", parameters ) );
+            const std::vector<int> priorities = CSVToVectorInt( GetMdtmParameter( "priorities", parameters ) );
+
+            m_Transports.push_back( std::make_shared<transport::MdtmMan>( localIP, remoteIP, m_AccessMode, prefix, numberOfPipes,
+                                                                          tolerances, priorities, m_MPIComm, m_DebugMode ) );
+        }
+        else if( itTransport->second == "Zmq" )
+        {
+
+        }
+        else
+        {
+            if( m_DebugMode == true )
+                throw std::invalid_argument( "ERROR: transport + " + itTransport->second + " not supported, in " +
+                                              m_Name + m_EndMessage );
+        }
+    }
+}
+
+
+std::string DataManWriter::GetMdtmParameter( const std::string parameter, const std::map<std::string,std::string>& mdtmParameters )
+{
+    auto itParam = mdtmParameters.find( parameter );
+    if( itParam != mdtmParameters.end() ) //found
+    {
+        return itParam->second; //return value
+    }
+    // if not found
+    //mandatory ones
+    if( parameter == "localIP" || parameter == "remoteIP" )
+    {
+        if( m_DebugMode == true )
+            throw std::invalid_argument( "ERROR: " + parameter + " parameter not found in Method, in call to DataManWriter constructor\n" );
+    }
+    else if( parameter == "prefix" )
+    {
+        return "";
+    }
+    else if( parameter == "pipes" )
+    {
+        return "0"; // or 1?
+    }
+    else if( parameter == "tolerances" ) //so far empty string
+    {
+
+    }
+    else if( parameter == "priority" )
+    {
+
+    }
+
+    return ""; //return empty string
+}
+
+
+} //end namespace adios
diff --git a/src/format/BP1.cpp b/src/format/BP1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eb70ff6d22c286db96107dcb3c04fd17f31bd0fd
--- /dev/null
+++ b/src/format/BP1.cpp
@@ -0,0 +1,67 @@
+/*
+ * BP1.cpp
+ *
+ *  Created on: Feb 7, 2017
+ *      Author: wfg
+ */
+
+
+#include "format/BP1.h"
+#include "functions/adiosFunctions.h"
+
+
+namespace adios
+{
+namespace format
+{
+
+
+std::string BP1::GetDirectoryName( const std::string name ) const noexcept
+{
+    std::string directory;
+
+    if( name.find(".bp") == name.size()-3 )
+        directory = name;
+    else
+        directory = name + ".bp";
+
+    return directory;
+}
+
+
+void BP1::OpenRankFiles( const std::string name, const std::string accessMode, Transport& file ) const
+{
+    const std::string directory = GetDirectoryName( name );
+    CreateDirectory( directory ); //creates a directory and sub-directories recursively
+
+    std::string fileName( directory + "/" + directory + "." + std::to_string( file.m_RankMPI ) );
+    file.Open( fileName, accessMode );  // opens a file transport under name.bp.dir/name.bp.rank reserve that location fro writing
+}
+
+
+std::vector<std::uint8_t> BP1::GetMethodIDs( const std::vector< std::shared_ptr<Transport> >& transports ) const noexcept
+{
+    auto lf_GetMethodID = []( const std::string method ) -> std::uint8_t
+    {
+        int id = METHOD_UNKNOWN;
+        if( method == "NULL" ) id = METHOD_NULL;
+        else if( method == "POSIX" ) id = METHOD_POSIX;
+        else if( method == "FStream" ) id = METHOD_FSTREAM;
+        else if( method == "File" ) id = METHOD_FILE;
+        else if( method == "MPI" ) id = METHOD_MPI;
+
+        return id;
+    };
+
+    std::vector<std::uint8_t> methodIDs;
+    methodIDs.reserve( transports.size() );
+
+    for( const auto& transport : transports )
+        methodIDs.push_back( lf_GetMethodID( transport->m_Type ) );
+
+    return methodIDs;
+}
+
+
+} //end namespace format
+} //end namespace adios
diff --git a/src/format/BP1Aggregator.cpp b/src/format/BP1Aggregator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..89a067e7a648f7738e9ef202777ae179a4a1996a
--- /dev/null
+++ b/src/format/BP1Aggregator.cpp
@@ -0,0 +1,97 @@
+/*
+ * BP1Aggregator.cpp
+ *
+ *  Created on: Mar 21, 2017
+ *      Author: wfg
+ */
+
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <vector>
+#include <fstream>
+/// \endcond
+
+#include "format/BP1Aggregator.h"
+
+
+namespace adios
+{
+namespace format
+{
+
+
+BP1Aggregator::BP1Aggregator( MPI_Comm mpiComm, const bool debugMode ):
+    m_MPIComm{ mpiComm },
+    m_DebugMode{ debugMode }
+{
+    MPI_Comm_rank( m_MPIComm, &m_RankMPI );
+    MPI_Comm_size( m_MPIComm, &m_SizeMPI );
+}
+
+
+BP1Aggregator::~BP1Aggregator( )
+{ }
+
+
+void BP1Aggregator::WriteProfilingLog( const std::string fileName, const std::string& rankLog )
+{
+    if( m_RankMPI == 0 )
+    {
+        unsigned int sizeMPI = static_cast<unsigned int>( m_SizeMPI );
+        std::vector< std::vector<char> > rankLogs( sizeMPI - 1 ); //rankLogs from other processes
+        std::vector< int > rankLogsSizes( sizeMPI-1, -1 ); //init with -1
+        std::vector<MPI_Request> requests( sizeMPI );
+        std::vector<MPI_Status> statuses( sizeMPI );
+
+        //first receive sizes
+        for( unsigned int i = 1; i < sizeMPI; ++i )
+            MPI_Irecv( &rankLogsSizes[i-1], 1, MPI_INT, i, 0, m_MPIComm, &requests[i] );
+
+        for( unsigned int i = 1; i < sizeMPI; ++i )
+        {
+            MPI_Wait( &requests[i], &statuses[i] );
+            if( m_DebugMode == true )
+            {
+                if( rankLogsSizes[i-1] == -1 )
+                    throw std::runtime_error( "ERROR: couldn't get size from rank " + std::to_string(i) + ", in ADIOS aggregator for Profiling.log\n" );
+            }
+            rankLogs[i-1].resize( rankLogsSizes[i-1] ); //allocate with zeros
+        }
+
+        //receive rankLog from other ranks
+        for( unsigned int i = 1; i < sizeMPI; ++i )
+            MPI_Irecv( rankLogs[i-1].data(), rankLogsSizes[i-1], MPI_CHAR, i, 1, m_MPIComm, &requests[i] );
+
+        for( unsigned int i = 1; i < sizeMPI; ++i )
+            MPI_Wait( &requests[i], &statuses[i] );
+
+        //write file
+        std::string logFile( "log = { \n" );
+        logFile += rankLog + "\n";
+        for( unsigned int i = 1; i < sizeMPI; ++i )
+        {
+            const std::string rankLogStr( rankLogs[i-1].data(), rankLogs[i-1].size() );
+            logFile += rankLogStr + "\n";
+        }
+        logFile += " }\n";
+
+        std::ofstream logStream( fileName );
+        logStream.write( logFile.c_str(), logFile.size() );
+        logStream.close();
+    }
+    else
+    {
+        int rankLogSize = static_cast<int>( rankLog.size() );
+        MPI_Request requestSize;
+        MPI_Isend( &rankLogSize, 1, MPI_INT, 0, 0, m_MPIComm, &requestSize );
+
+        MPI_Request requestRankLog;
+        MPI_Isend( const_cast<char*>( rankLog.c_str() ), rankLogSize, MPI_CHAR, 0, 1, m_MPIComm, &requestRankLog );
+    }
+}
+
+
+
+} //end namespace format
+} //end namespace adios
+
diff --git a/src/format/BP1Writer.cpp b/src/format/BP1Writer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a441e6392535913885223b1f615abf1dbfe1a7fa
--- /dev/null
+++ b/src/format/BP1Writer.cpp
@@ -0,0 +1,379 @@
+/*
+ * BP1Writer.cpp
+ *
+ *  Created on: Feb 1, 2017
+ *      Author: wfg
+ */
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <string>
+/// \endcond
+
+#include "format/BP1Writer.h"
+#include "core/Profiler.h"
+
+
+
+
+namespace adios
+{
+namespace format
+{
+
+
+std::size_t BP1Writer::GetProcessGroupIndexSize( const std::string name, const std::string timeStepName,
+                                                 const std::size_t numberOfTransports ) const noexcept
+{
+    //pgIndex + list of methods (transports)
+    return ( name.length() + timeStepName.length() + 23 ) + ( 3 + numberOfTransports ); //should be sufficient for data and metadata pgindices
+}
+
+
+void BP1Writer::WriteProcessGroupIndex( const bool isFortran, const std::string name, const std::uint32_t processID,
+                                        const std::vector< std::shared_ptr<Transport> >& transports,
+                                        capsule::STLVector& heap, BP1MetadataSet& metadataSet ) const noexcept
+{
+    std::vector<char>& metadataBuffer = metadataSet.PGIndex.Buffer;
+    std::vector<char>& dataBuffer = heap.m_Data;
+
+    metadataSet.DataPGLengthPosition = dataBuffer.size();
+    dataBuffer.insert( dataBuffer.end(), 8, 0 ); //skip pg length (8)
+
+    const std::size_t metadataPGLengthPosition = metadataBuffer.size();
+    metadataBuffer.insert( metadataBuffer.end(), 2, 0 ); //skip pg length (2)
+
+    //write name to metadata
+    WriteNameRecord( name, metadataBuffer );
+    //write if host language Fortran in metadata and data
+    const char hostFortran = ( isFortran ) ? 'y' : 'n'; //if host language is fortran
+    CopyToBuffer( metadataBuffer, &hostFortran );
+    CopyToBuffer( dataBuffer, &hostFortran );
+    //write name in data
+    WriteNameRecord( name, dataBuffer );
+
+    //processID in metadata,
+    CopyToBuffer( metadataBuffer, &processID );
+    //skip coordination var in data ....what is coordination var?
+    dataBuffer.insert( dataBuffer.end(), 4, 0 );
+
+    //time step name to metadata and data
+    const std::string timeStepName( std::to_string( metadataSet.TimeStep ) );
+    WriteNameRecord( timeStepName, metadataBuffer );
+    WriteNameRecord( timeStepName, dataBuffer );
+
+    //time step to metadata and data
+    CopyToBuffer( metadataBuffer, &metadataSet.TimeStep );
+    CopyToBuffer( dataBuffer, &metadataSet.TimeStep );
+
+    //offset to pg in data in metadata which is the current absolute position
+    CopyToBuffer( metadataBuffer, reinterpret_cast<std::uint64_t*>( &heap.m_DataAbsolutePosition ) );
+
+    //Back to writing metadata pg index length (length of group)
+    const std::uint16_t metadataPGIndexLength = metadataBuffer.size() - metadataPGLengthPosition - 2; //without length of group record
+    CopyToBuffer( metadataBuffer, metadataPGLengthPosition, &metadataPGIndexLength );
+    //DONE With metadataBuffer
+
+    //here write method in data
+    const std::vector<std::uint8_t> methodIDs = GetMethodIDs( transports );
+    const std::uint8_t methodsCount = methodIDs.size();
+    CopyToBuffer( dataBuffer, &methodsCount ); //count
+    const std::uint16_t methodsLength = methodIDs.size() * 3; //methodID (1) + method params length(2), no parameters for now
+    CopyToBuffer( dataBuffer, &methodsLength );//length
+
+    for( const auto methodID : methodIDs )
+    {
+        CopyToBuffer( dataBuffer, &methodID ); //method ID,
+        dataBuffer.insert( dataBuffer.end(), 2, 0 ); //skip method params length = 0 (2 bytes) for now
+    }
+
+    //update absolute position
+    heap.m_DataAbsolutePosition += dataBuffer.size() - metadataSet.DataPGLengthPosition;
+    //pg vars count and position
+    metadataSet.DataPGVarsCount = 0;
+    metadataSet.DataPGVarsCountPosition = dataBuffer.size();
+    //add vars count and length
+    dataBuffer.insert( dataBuffer.end(), 12, 0 );
+    heap.m_DataAbsolutePosition += 12; //add vars count and length
+
+    ++metadataSet.DataPGCount;
+    metadataSet.DataPGIsOpen = true;
+}
+
+
+
+void BP1Writer::Advance( BP1MetadataSet& metadataSet, capsule::STLVector& buffer )
+{
+    FlattenData( metadataSet, buffer );
+}
+
+
+
+void BP1Writer::Close( BP1MetadataSet& metadataSet, capsule::STLVector& heap, Transport& transport, bool& isFirstClose,
+                       const bool doAggregation ) const noexcept
+{
+    if( metadataSet.Log.m_IsActive == true )
+        metadataSet.Log.m_Timers[0].SetInitialTime();
+
+    if( isFirstClose == true )
+    {
+        if( metadataSet.DataPGIsOpen == true )
+            FlattenData( metadataSet, heap );
+
+        FlattenMetadata( metadataSet, heap );
+
+        if( metadataSet.Log.m_IsActive == true )
+            metadataSet.Log.m_Timers[0].SetInitialTime();
+
+        if( doAggregation == true ) //N-to-M  where 1 <= M <= N-1, might need a new Log metadataSet.Log.m_Timers just for aggregation
+        {
+            //here call aggregator
+        }
+        isFirstClose = false;
+    }
+
+    if( doAggregation == true ) //N-to-M  where 1 <= M <= N-1
+    {
+        //here call aggregator to select transports for Write and Close
+    }
+    else // N-to-N
+    {
+        transport.Write( heap.m_Data.data(), heap.m_Data.size() ); //single write
+        transport.Close();
+    }
+}
+
+
+std::string BP1Writer::GetRankProfilingLog( const int rank, const BP1MetadataSet& metadataSet,
+                                            const std::vector< std::shared_ptr<Transport> >& transports ) const noexcept
+{
+    auto lf_WriterTimer = []( std::string& rankLog, const Timer& timer )
+    {
+        rankLog += "'" + timer.Process + "_" + timer.GetUnits() + "': " + std::to_string( timer.ProcessTime ) + ", ";
+    };
+
+    //prepare string dictionary per rank
+    std::string rankLog( "'rank_" + std::to_string( rank ) + "': { " );
+
+    auto& profiler = metadataSet.Log;
+    rankLog += "'bytes': " + std::to_string( profiler.m_TotalBytes[0] ) + ", ";
+    lf_WriterTimer( rankLog, profiler.m_Timers[0] );
+
+    for( unsigned int t = 0; t < transports.size(); ++t )
+    {
+        auto& timers = transports[t]->m_Profiler.m_Timers;
+
+        rankLog += "'transport_" + std::to_string(t) + "': { ";
+        rankLog += "'lib': " + transports[t]->m_Type + ", ";
+
+        for( unsigned int i = 0; i < 3; ++i )
+            lf_WriterTimer( rankLog, timers[i] );
+
+        rankLog += "}, ";
+    }
+    rankLog += "}, ";
+
+    return rankLog;
+}
+
+
+
+//PRIVATE FUNCTIONS
+void BP1Writer::WriteDimensionsRecord( std::vector<char>& buffer,
+                                       const std::vector<std::size_t>& localDimensions,
+                                       const std::vector<std::size_t>& globalDimensions,
+                                       const std::vector<std::size_t>& globalOffsets,
+									   const unsigned int skip,
+                                       const bool addType ) const noexcept
+{
+    auto lf_WriteFlaggedDim = []( std::vector<char>& buffer, const char no,
+    		                      const std::size_t dimension )
+    {
+    	CopyToBuffer( buffer, &no );
+        CopyToBuffer( buffer, reinterpret_cast<const std::uint64_t*>( &dimension ) );
+    };
+
+    //BODY Starts here
+    if( globalDimensions.empty() )
+    {
+        if( addType == true )
+        {
+        	constexpr char no = 'n'; //dimension format unsigned int value (not using memberID for now)
+        	for( const auto& localDimension : localDimensions )
+        	{
+        		lf_WriteFlaggedDim( buffer, no, localDimension );
+        		buffer.insert( buffer.end(), skip, 0 );
+        	}
+        }
+        else
+        {
+        	for( const auto& localDimension : localDimensions )
+        	{
+        		CopyToBuffer( buffer, reinterpret_cast<const std::uint64_t*>( &localDimension ) );
+        		buffer.insert( buffer.end(), skip, 0 );
+        	}
+        }
+    }
+    else
+    {
+    	if( addType == true )
+    	{
+    		constexpr char no = 'n'; //dimension format unsigned int value for now
+    		for( unsigned int d = 0; d < localDimensions.size(); ++d )
+    		{
+    			lf_WriteFlaggedDim( buffer, no, localDimensions[d] );
+    			lf_WriteFlaggedDim( buffer, no, globalDimensions[d] );
+    			lf_WriteFlaggedDim( buffer, no, globalOffsets[d] );
+    		}
+    	}
+    	else
+    	{
+    		for( unsigned int d = 0; d < localDimensions.size(); ++d )
+    		{
+    			CopyToBuffer( buffer, reinterpret_cast<const std::uint64_t*>( &localDimensions[d] ) );
+    			CopyToBuffer( buffer, reinterpret_cast<const std::uint64_t*>( &globalDimensions[d] ) );
+    			CopyToBuffer( buffer, reinterpret_cast<const std::uint64_t*>( &globalOffsets[d] ) );
+    		}
+    	}
+    }
+}
+
+
+void BP1Writer::WriteNameRecord( const std::string name, std::vector<char>& buffer ) const noexcept
+{
+    const std::uint16_t length = name.length( );
+    CopyToBuffer( buffer, &length );
+    CopyToBuffer( buffer, name.c_str(), length );
+}
+
+
+
+BP1Index& BP1Writer::GetBP1Index( const std::string name, std::unordered_map<std::string, BP1Index>& indices,
+                                  bool& isNew ) const noexcept
+{
+	auto itName = indices.find( name );
+    if( itName == indices.end() )
+    {
+    	indices.emplace( name, BP1Index( indices.size() ) );
+    	isNew = true;
+    	return indices.at( name );
+    }
+
+    isNew = false;
+    return itName->second;
+}
+
+
+void BP1Writer::FlattenData( BP1MetadataSet& metadataSet, capsule::STLVector& heap ) const noexcept
+{
+    auto& buffer = heap.m_Data;
+    //vars count and Length (only for PG)
+    CopyToBuffer( buffer, metadataSet.DataPGVarsCountPosition, &metadataSet.DataPGVarsCount );
+    const std::uint64_t varsLength = buffer.size() - metadataSet.DataPGVarsCountPosition - 8 - 4; //without record itself and vars count
+    CopyToBuffer( buffer, metadataSet.DataPGVarsCountPosition + 4, &varsLength );
+
+    //attributes (empty for now) count (4) and length (8) are zero by moving positions in time step zero
+    buffer.insert( buffer.end(), 12, 0 );
+    heap.m_DataAbsolutePosition += 12;
+
+    //Finish writing pg group length
+    const std::uint64_t dataPGLength = buffer.size() - metadataSet.DataPGLengthPosition - 8; //without record itself, 12 due to empty attributes
+    CopyToBuffer( buffer, metadataSet.DataPGLengthPosition, &dataPGLength );
+
+    ++metadataSet.TimeStep;
+    metadataSet.DataPGIsOpen = false;
+}
+
+
+void BP1Writer::FlattenMetadata( BP1MetadataSet& metadataSet, capsule::STLVector& heap ) const noexcept
+{
+    auto lf_IndexCountLength = []( std::unordered_map<std::string, BP1Index>& indices,
+                                   std::uint32_t& count, std::uint64_t& length )
+    {
+        count = indices.size();
+        length = 0;
+        for( auto& indexPair : indices ) //set each index length
+        {
+            auto& indexBuffer = indexPair.second.Buffer;
+            const std::uint32_t indexLength = indexBuffer.size()-4;
+            CopyToBuffer( indexBuffer, 0, &indexLength );
+
+            length += indexBuffer.size(); //overall length
+        }
+    };
+
+    auto lf_FlattenIndices = []( const std::uint32_t count, const std::uint64_t length,
+                                 const std::unordered_map<std::string, BP1Index>& indices,
+                                 std::vector<char>& buffer )
+    {
+        CopyToBuffer( buffer, &count );
+        CopyToBuffer( buffer, &length );
+
+        for( const auto& indexPair : indices ) //set each index length
+        {
+            const auto& indexBuffer = indexPair.second.Buffer;
+            CopyToBuffer( buffer, indexBuffer.data(), indexBuffer.size() );
+        }
+    };
+
+
+    //Finish writing metadata counts and lengths
+    //PG Index
+    const std::uint64_t pgCount = metadataSet.DataPGCount;
+    const std::uint64_t pgLength = metadataSet.PGIndex.Buffer.size();
+
+    //var index count and length (total), and each index length
+    std::uint32_t varsCount;
+    std::uint64_t varsLength;
+    lf_IndexCountLength( metadataSet.VarsIndices, varsCount, varsLength );
+    //attribute index count and length, and each index length
+    std::uint32_t attributesCount;
+    std::uint64_t attributesLength;
+    lf_IndexCountLength( metadataSet.AttributesIndices, attributesCount, attributesLength );
+
+    const std::size_t footerSize = (pgLength+16) + (varsLength+12) + (attributesLength+12) + metadataSet.MiniFooterSize;
+    auto& buffer = heap.m_Data;
+    buffer.reserve( buffer.size() + footerSize ); //reserve data to fit metadata, must replace with growth buffer strategy
+
+    //write pg index
+    CopyToBuffer( buffer, &pgCount );
+    CopyToBuffer( buffer, &pgLength );
+    CopyToBuffer( buffer, metadataSet.PGIndex.Buffer.data(), pgLength );
+    //Vars indices
+    lf_FlattenIndices( varsCount, varsLength, metadataSet.VarsIndices, buffer );
+    //Attribute indices
+    lf_FlattenIndices( attributesCount, attributesLength, metadataSet.AttributesIndices, buffer );
+
+    //getting absolute offsets, minifooter is 28 bytes for now
+    const std::uint64_t offsetPGIndex = heap.m_DataAbsolutePosition;
+    const std::uint64_t offsetVarsIndex = offsetPGIndex + (pgLength+16);
+    const std::uint64_t offsetAttributeIndex = offsetVarsIndex + (varsLength+12);
+
+    CopyToBuffer( buffer, &offsetPGIndex );
+    CopyToBuffer( buffer, &offsetVarsIndex );
+    CopyToBuffer( buffer, &offsetAttributeIndex );
+
+    //version
+    if( IsLittleEndian( ) )
+    {
+    	const std::uint8_t endian = 0;
+    	CopyToBuffer( buffer, &endian );
+    	buffer.insert( buffer.end(), 2, 0 );
+    	CopyToBuffer( buffer, &m_Version );
+    }
+    else
+    {
+
+    }
+
+    heap.m_DataAbsolutePosition += footerSize;
+
+    if( metadataSet.Log.m_IsActive == true )
+        metadataSet.Log.m_TotalBytes.push_back( heap.m_DataAbsolutePosition );
+
+}
+
+
+
+
+} //end namespace format
+} //end namespace adios
diff --git a/src/functions/adiosFunctions.cpp b/src/functions/adiosFunctions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..11e92b07b87f945524194f45a1c7a0190a66c76b
--- /dev/null
+++ b/src/functions/adiosFunctions.cpp
@@ -0,0 +1,595 @@
+/*
+ * adiosFunctions.cpp
+ *
+ *  Created on: Oct 10, 2016
+ *      Author: wfg
+ */
+
+/// \cond EXCLUDED_FROM_DOXYGEN
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+#include <ios>  //std::ios_base::failure
+#include <thread>  //std::thread
+#include <cstring> //std::memcpy
+#include <algorithm> //std::count
+#include <cmath> // std::ceil, std::pow, std::log
+
+#include <sys/types.h> //CreateDirectory
+#include <sys/stat.h> //stat
+#include <unistd.h> //CreateDirectory
+/// \endcond
+
+#include "functions/adiosFunctions.h"
+#include "core/Support.h"
+
+#ifdef HAVE_BZIP2
+#include "transform/BZIP2.h"
+#endif
+
+
+namespace adios
+{
+
+
+void DumpFileToString( const std::string fileName, std::string& fileContent )
+{
+    std::ifstream fileStream( fileName );
+
+    if( fileStream.good() == false ) //check file
+        throw std::ios_base::failure( "ERROR: file " + fileName +
+                                      " could not be opened. Check permissions or file existence\n" );
+
+    std::ostringstream fileSS;
+    fileSS << fileStream.rdbuf();
+    fileStream.close();
+    fileContent = fileSS.str(); //convert to string and check
+
+    if( fileContent.empty()  )
+        throw std::invalid_argument( "ERROR: file " + fileName + " is empty\n" );
+}
+
+
+void GetSubString( const std::string initialTag, const std::string finalTag, const std::string content,
+                   std::string& subString, std::string::size_type& currentPosition )
+{
+    auto lf_Wipe = []( std::string& subString, std::string::size_type& currentPosition )
+    {
+        subString.clear();
+        currentPosition = std::string::npos;
+    };
+
+    auto lf_SetPositions = []( const char quote, const std::string::size_type quotePosition, const std::string& content,
+                               std::string::size_type& currentPosition, std::string::size_type& closingQuotePosition )
+    {
+        currentPosition = quotePosition;
+        closingQuotePosition = content.find( quote, currentPosition+1 );
+    };
+
+
+    //BODY OF FUNCTION STARTS HERE
+    std::string::size_type start( content.find( initialTag, currentPosition ) );
+    if( start == content.npos )
+    {
+        lf_Wipe( subString, currentPosition );
+        return;
+    }
+    currentPosition = start;
+
+    std::string::size_type end( content.find( finalTag, currentPosition ) );
+    if( end == content.npos )
+    {
+        lf_Wipe( subString, currentPosition );
+        return;
+    }
+
+    //here make sure the finalTag is not a value surrounded by " " or ' ', if so find next
+    bool isValue = true;
+
+    while( isValue == true )
+    {
+        std::string::size_type singleQuotePosition = content.find( '\'', currentPosition );
+        std::string::size_type doubleQuotePosition = content.find( '\"', currentPosition );
+
+        if( ( singleQuotePosition == content.npos && doubleQuotePosition == content.npos ) ||
+            ( singleQuotePosition == content.npos && end < doubleQuotePosition  ) ||
+            ( doubleQuotePosition == content.npos && end < singleQuotePosition  ) ||
+            ( end < singleQuotePosition && end < doubleQuotePosition )
+          ) break;
+
+        //find the closing corresponding quote
+        std::string::size_type closingQuotePosition;
+
+        if( singleQuotePosition == content.npos ) //no ' anywhere
+            lf_SetPositions( '\"', doubleQuotePosition, content, currentPosition, closingQuotePosition );
+        else if( doubleQuotePosition == content.npos ) //no " anywhere
+            lf_SetPositions( '\'', singleQuotePosition, content, currentPosition, closingQuotePosition );
+        else
+        {
+            if( singleQuotePosition < doubleQuotePosition )
+                lf_SetPositions( '\'', singleQuotePosition, content, currentPosition, closingQuotePosition );
+            else //find the closing "
+                lf_SetPositions( '\"', doubleQuotePosition, content, currentPosition, closingQuotePosition );
+        }
+
+        if( closingQuotePosition == content.npos ) //if can't find closing it's open until the end
+        {
+            lf_Wipe( subString, currentPosition );
+            return;
+        }
+
+        currentPosition = closingQuotePosition+1;
+
+        if( closingQuotePosition < end )
+            continue;
+
+        //if this point is reached it means it's a value inside " " or ' ', move to the next end
+        end = content.find( finalTag, currentPosition );
+    }
+
+    subString = content.substr( start, end-start+finalTag.size() );
+    currentPosition = end;
+}
+
+
+void GetQuotedValue( const char quote, const std::string::size_type& quotePosition,
+                     std::string& currentTag, std::string& value )
+{
+    currentTag = currentTag.substr( quotePosition + 1 );
+    auto nextQuotePosition = currentTag.find( quote );
+
+    if( nextQuotePosition == currentTag.npos )
+        throw std::invalid_argument( "ERROR: Invalid attribute in..." + currentTag + "...check XML file\n");
+
+    value = currentTag.substr( 0, nextQuotePosition );
+    currentTag = currentTag.substr( nextQuotePosition+1 );
+}
+
+
+void GetPairs( const std::string tag, std::vector< std::pair<const std::string, const std::string> >& pairs ) noexcept
+{
+    std::string currentTag( tag.substr( tag.find_first_of(" \t\n") ) ); //initialize current tag
+
+    while( currentTag.find('=') != currentTag.npos ) //equalPosition
+    {
+        currentTag = currentTag.substr( currentTag.find_first_not_of(" \t\n") );
+        auto equalPosition = currentTag.find('=');
+        const std::string field( currentTag.substr( 0, equalPosition) );  //get field
+        std::string value;
+
+        const char quote = currentTag[equalPosition+1];
+        if( quote == '\'' || quote == '"') //single quotes
+        {
+            GetQuotedValue( quote, equalPosition+1, currentTag, value );
+        }
+
+        pairs.push_back( std::pair<const std::string, const std::string>( field, value ) );
+    }
+}
+
+
+void GetPairsFromTag( const std::string& fileContent, const std::string tag,
+                      std::vector< std::pair<const std::string, const std::string> >& pairs )
+{
+    if( tag.back() == '/' ) //last char is / --> "XML empty tag"
+    {
+        GetPairs( tag, pairs );
+    }
+    else if( tag[0] == '/' ) // first char is / ---> closing tag
+    { }
+    else // opening tag
+    {
+        const std::string tagName( tag.substr( 0, tag.find_first_of(" \t\n\r") ) );
+        const std::string closingTagName( "</" + tagName + ">" ); //check for closing tagName
+
+        if( fileContent.find( closingTagName ) == fileContent.npos )
+            throw std::invalid_argument( "ERROR: closing tag " + closingTagName + " missing, check XML file\n");
+
+        GetPairs( tag, pairs );
+    }
+}
+
+
+//void SetMembers( const std::string& fileContent, const MPI_Comm mpiComm, const bool debugMode,
+//                 std::string& hostLanguage, std::vector< std::shared_ptr<Transform> >& transforms,
+//                 std::map< std::string, Group >& groups )
+//{
+//    //adios-config
+//    std::string currentContent;
+//    std::string::size_type currentPosition( 0 );
+//    GetSubString( "<adios-config ", "</adios-config>", fileContent, currentContent, currentPosition );
+//
+//    //remove comment sections
+//    std::string::size_type startComment ( currentContent.find( "<!--" ) );
+//
+//    while( startComment != currentContent.npos )
+//    {
+//        std::string::size_type endComment( currentContent.find( "-->") );
+//        currentContent.erase( startComment, endComment-startComment+3 );
+//        startComment = currentContent.find( "<!--" );
+//    }
+//
+//    //Tag <adios-config
+//    currentPosition = 0;
+//
+//    std::string tag; //use for < > tags
+//    GetSubString( "<adios-config", ">", currentContent, tag, currentPosition );
+//    tag = tag.substr( 1, tag.size() - 2 ); //eliminate < >
+//
+//    std::vector< std::pair<const std::string, const std::string> > pairs; // pairs in tag
+//    GetPairsFromTag( currentContent, tag, pairs );
+//
+//    for( auto& pair : pairs )
+//        if( pair.first == "host-language" )
+//            hostLanguage = pair.second;
+//
+//    if( debugMode == true )
+//    {
+//        if( Support::HostLanguages.count( hostLanguage ) == 0 )
+//            throw std::invalid_argument("ERROR: host language " + hostLanguage + " not supported.\n" );
+//
+//        if( hostLanguage.empty() == true )
+//            throw std::invalid_argument("ERROR: host language is empty.\n" );
+//    }
+//
+//    //adios-group
+//    currentPosition = 0;
+//
+//    while( currentPosition != std::string::npos )
+//    {
+//        std::string xmlGroup;
+//        GetSubString("<adios-group ", "</adios-group>", currentContent, xmlGroup, currentPosition ); //Get all group contents
+//
+//        if( xmlGroup.empty() ) //no more groups to find
+//            break;
+//
+//        //get group name
+//        std::string::size_type groupPosition( 0 );
+//        GetSubString( "<adios-group ", ">", xmlGroup, tag, groupPosition );
+//        if( debugMode == true )
+//        {
+//            if( tag.size() < 2 )
+//                throw std::invalid_argument( "ERROR: wrong tag " + tag + " in adios-group\n" ); //check < or <=
+//        }
+//
+//        tag = tag.substr( 1, tag.size() - 2 ); //eliminate < >
+//        GetPairsFromTag( xmlGroup, tag, pairs );
+//        std::string groupName;
+//
+//        for( auto& pair : pairs )
+//        {
+//            if( pair.first == "name")
+//                groupName = pair.second;
+//        }
+//
+//        if( debugMode == true )
+//        {
+//            if( groupName.empty() )
+//                throw std::invalid_argument( "ERROR: group name not found. \n" );
+//
+//            if( groups.count( groupName ) == 1 ) //group exists
+//                throw std::invalid_argument( "ERROR: group " + groupName + " defined twice.\n" );
+//        }
+//
+//        groups.emplace( groupName, Group( groupName, xmlGroup, transforms, debugMode ) );
+//
+//        currentContent.erase( currentContent.find( xmlGroup ), xmlGroup.size() );
+//        currentPosition = 0;
+//    }
+//
+//    //transport
+//    //lambda function to check priority and iteration casting to unsigned int
+//    auto lf_UIntCheck = []( const std::string method, const std::string fieldStr, const std::string fieldName,
+//                            const bool debugMode, int& field )
+//    {
+//        field = 0;
+//        if( fieldStr.empty() == false )
+//        {
+//            field = std::stoi( fieldStr ); //throws invalid_argument
+//
+//            if( debugMode == true )
+//            {
+//                if( field < 0 )
+//                    throw std::invalid_argument("ERROR: " + fieldName + " in transport " + method + " can't be negative\n" );
+//            }
+//        }
+//    };
+//
+//    //this section will have to change, doing nothing for now
+//    currentPosition = 0;
+//    while( currentPosition != std::string::npos )
+//    {
+//        GetSubString( "<transport ", ">", currentContent, tag, currentPosition );
+//        if( tag.empty() ) break;
+//        tag = tag.substr( 1, tag.size() - 2 ); //eliminate < >
+//        pairs.clear();
+//        GetPairsFromTag( currentContent, tag, pairs );
+//
+//        std::string groupName, method, priorityStr, iterationStr;
+//        for( auto& pair : pairs )
+//        {
+//            if( pair.first == "group" )  groupName = pair.second;
+//            else if( pair.first == "method" ) method = pair.second;
+//            else if( pair.first == "priority" ) priorityStr = pair.second;
+//            else if( pair.first == "iteration" ) iterationStr = pair.second;
+//        }
+//
+//        auto itGroup = groups.find( groupName );
+//        if( debugMode == true )
+//        {
+//            if( itGroup == groups.end() ) //not found
+//                throw std::invalid_argument( "ERROR: in transport " + method + " group " + groupName + " not found.\n" );
+//        }
+//
+//        int priority, iteration;
+//        lf_UIntCheck( method, priorityStr, "priority", debugMode, priority );
+//        lf_UIntCheck( method, iterationStr, "iteration", debugMode, iteration );
+//        //here do something with the capsule
+//    }
+//}
+
+
+//void InitXML( const std::string xmlConfigFile, const MPI_Comm mpiComm, const bool debugMode,
+//              std::string& hostLanguage, std::vector< std::shared_ptr<Transform> >& transforms,
+//              std::map< std::string, Group >& groups )
+//{
+//    int xmlFileContentSize;
+//    std::string xmlFileContent;
+//
+//    int rank;
+//    MPI_Comm_rank( mpiComm, &rank );
+//
+//    if( rank == 0 ) //serial part
+//    {
+//        DumpFileToString( xmlConfigFile, xmlFileContent ); //in ADIOSFunctions.h dumps all XML Config File to xmlFileContent
+//        xmlFileContentSize = xmlFileContent.size( ) + 1; // add one for the null character
+//
+//        MPI_Bcast( &xmlFileContentSize, 1, MPI_INT, 0, mpiComm ); //broadcast size for allocation
+//        MPI_Bcast( (char*)xmlFileContent.c_str(), xmlFileContentSize, MPI_CHAR, 0, mpiComm ); //broadcast contents
+//    }
+//    else
+//    {
+//        MPI_Bcast( &xmlFileContentSize, 1, MPI_INT, 0, mpiComm  ); //receive size
+//
+//        char* xmlFileContentMPI = new char[ xmlFileContentSize ]; //allocate xml C-char
+//        MPI_Bcast( xmlFileContentMPI, xmlFileContentSize, MPI_CHAR, 0, mpiComm ); //receive xml C-char
+//        xmlFileContent.assign( xmlFileContentMPI ); //copy to a string
+//
+//        delete []( xmlFileContentMPI ); //delete char* needed for MPI, might add size is moving to C++14 for optimization, avoid memory leak
+//    }
+//
+//    SetMembers( xmlFileContent,  mpiComm, debugMode, hostLanguage, transforms, groups );
+//}
+
+
+std::size_t GetTotalSize( const std::vector<std::size_t>& dimensions )
+{
+    std::size_t product = 1;
+
+    for( const auto dimension : dimensions )
+        product *= dimension;
+
+    return product;
+}
+
+
+void CreateDirectory( const std::string fullPath ) noexcept
+{
+    auto lf_Mkdir = []( const std::string directory, struct stat& st )
+    {
+        if ( stat( directory.c_str(), &st ) == -1 )
+            mkdir( directory.c_str(), 0777 );
+    };
+
+    auto directoryPosition = fullPath.find( "/" );
+
+    if( fullPath[0] == '/' || fullPath[0] == '.' ) //find the second '/'
+        directoryPosition = fullPath.find( "/", directoryPosition+1 );
+
+    struct stat st = {0};
+    if( directoryPosition == fullPath.npos ) //no subdirectories
+    {
+        lf_Mkdir( fullPath.c_str(), st );
+        return;
+    }
+
+    std::string directory( fullPath.substr( 0, directoryPosition ) );
+    lf_Mkdir( directory.c_str(), st );
+
+    while( directoryPosition != fullPath.npos )
+    {
+        directoryPosition = fullPath.find( "/", directoryPosition+1 );
+        directory = fullPath.substr( 0, directoryPosition );
+        lf_Mkdir( directory.c_str(), st );
+    }
+}
+
+
+void SetTransformsHelper( const std::vector<std::string>& transformNames, std::vector< std::shared_ptr<Transform> >& transforms,
+                         const bool debugMode, std::vector<short>& transformIndices, std::vector<short>& parameters )
+{
+    //function to get a parameter from "method:parameter"
+    auto lf_GetParameter = []( const std::string transformName, std::string& transformMethod, const bool debugMode ) -> short
+    {
+        short parameter = -1;
+        auto colonPosition = transformName.find( ":" );
+
+        if( colonPosition != transformName.npos )
+        {
+            if( debugMode == true )
+            {
+                if( colonPosition == transformName.size() - 1 )
+                    throw std::invalid_argument( "ERROR: wrong format for transform " + transformName + ", in call to SetTransform\n" );
+            }
+
+            transformMethod = transformName.substr( 0, colonPosition );
+            parameter = std::stoi( transformName.substr( colonPosition+1 ) ); //need to test
+        }
+        return parameter;
+    };
+
+    //Get transform index from transforms, if not found return -1
+    auto lf_GetTransformIndex = []( const std::string transformMethod, const std::vector< std::shared_ptr<Transform> >& transforms )
+            -> short
+    {
+        short transformIndex = -1;
+        for( unsigned int i = 0; i < transforms.size(); ++i )
+        {
+            if( transforms[i]->m_Method == transformMethod )
+            {
+                transformIndex = i;
+                break;
+            }
+        }
+        return transformIndex;
+    };
+
+    //BODY of FUNCTION STARTS HERE
+    for( const std::string transformName : transformNames )
+    {
+        std::string transformMethod( transformName );
+        short parameter = lf_GetParameter( transformName, transformMethod, debugMode ); // from transform = "method:parameter"
+        short transformIndex = lf_GetTransformIndex( transformMethod, transforms );
+
+        if( transformIndex == -1 ) //not found, then create a new transform
+        {
+            if( transformMethod == "bzip2" )
+            {
+                #ifdef HAVE_BZIP2
+                transforms.push_back( std::make_shared<CBZIP2>( ) );
+                #endif
+            }
+
+            transformIndex = static_cast<short>( transforms.size() - 1 );
+        }
+        transformIndices.push_back( transformIndex );
+        parameters.push_back( parameter );
+    }
+}
+
+
+
+std::map<std::string, std::string> BuildParametersMap( const std::vector<std::string>& parameters,
+                                                       const bool debugMode )
+{
+    auto lf_GetFieldValue = []( const std::string parameter, std::string& field, std::string& value, const bool debugMode )
+    {
+        auto equalPosition = parameter.find( "=" );
+
+        if( debugMode == true )
+        {
+            if( equalPosition == parameter.npos )
+                throw std::invalid_argument( "ERROR: wrong format for parameter " + parameter + ", format must be field=value \n" );
+
+            if( equalPosition == parameter.size()-1 )
+                throw std::invalid_argument( "ERROR: empty value in parameter " + parameter + ", format must be field=value \n" );
+        }
+
+        field = parameter.substr( 0, equalPosition );
+        value = parameter.substr( equalPosition+1 ); //need to test
+    };
+
+    //BODY OF FUNCTION STARTS HERE
+    std::map<std::string, std::string> parametersOutput;
+
+    for( const auto parameter : parameters )
+    {
+        std::string field, value;
+        lf_GetFieldValue( parameter, field, value, debugMode );
+
+        if( debugMode == true )
+        {
+            if( parametersOutput.count( field ) == 1 )
+                throw std::invalid_argument( "ERROR: parameter " + field + " already exists, must be unique\n" );
+        }
+
+        parametersOutput[field] = value;
+    }
+
+    return parametersOutput;
+}
+
+
+std::vector<int> CSVToVectorInt( const std::string csv )
+{
+    std::vector<int> numbers;
+    if( csv.empty() )
+        return numbers;
+
+    if( csv.find(",") == csv.npos ) //check if no commas, one int
+    {
+        numbers.push_back( std::stoi( csv ) ); //might need to be checked
+    }
+    else
+    {
+        int count = std::count( csv.begin(), csv.end(), ',' );
+        numbers.reserve( count );
+
+        std::istringstream csvSS( csv );
+        std::string value;
+        while( std::getline( csvSS, value, ',' ) ) //need to test
+        {
+            numbers.push_back( std::stoi( csv ) );
+        }
+    }
+
+    return numbers;
+}
+
+
+bool CheckBufferAllocation( const std::size_t newSize, const float growthFactor, const std::size_t maxBufferSize,
+                            std::vector<char>& buffer )
+{
+    //Check if data in buffer needs to be reallocated
+    const std::size_t requiredDataSize = buffer.size() + newSize + 100; //adding some bytes for tolerance
+    // might need to write payload in batches
+    bool doTransportsFlush = ( requiredDataSize > maxBufferSize )? true : false;
+
+    if( GrowBuffer( requiredDataSize, growthFactor, buffer ) == -1 )
+        doTransportsFlush = true;
+
+    return doTransportsFlush;
+}
+
+
+
+int GrowBuffer( const std::size_t incomingDataSize, const float growthFactor,
+                std::vector<char>& buffer )
+{
+    const std::size_t currentCapacity = buffer.capacity();
+    const std::size_t availableSpace = currentCapacity - buffer.size();
+    const double gf = static_cast<double>( growthFactor );
+
+    if( incomingDataSize > availableSpace )
+    {
+        const std::size_t neededCapacity = incomingDataSize + buffer.size();
+        const double numerator = std::log( static_cast<double>( neededCapacity ) / static_cast<double>( currentCapacity ) );
+        const double denominator = std::log( gf );
+
+        double n = std::ceil( numerator / denominator );
+        const std::size_t newSize = static_cast<std::size_t>( std::ceil(  std::pow( gf, n ) * currentCapacity ) );
+
+        try
+        {
+            buffer.reserve( newSize );
+        }
+        catch( std::bad_alloc& e )
+        {
+            return -1;
+        }
+
+        return 1;
+    }
+    return 0;
+}
+
+
+
+bool IsLittleEndian( ) noexcept
+{
+    std::uint16_t hexa = 0x1234;
+    return *reinterpret_cast<std::uint8_t*>(&hexa) != 0x12;
+}
+
+
+} //end namespace
diff --git a/src/mpidummy.cpp b/src/mpidummy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e58e1b817cdf2756be130428857f0c844079f0f4
--- /dev/null
+++ b/src/mpidummy.cpp
@@ -0,0 +1,256 @@
+/*
+ * ADIOS is freely available under the terms of the BSD license described
+ * in the COPYING file in the top level directory of this source distribution.
+ *
+ * Copyright (c) 2008 - 2009.  UT-BATTELLE, LLC. All rights reserved.
+ */
+
+/*
+   A dummy MPI implementation for the BP READ API, to have an MPI-free version of the API
+*/
+/// \cond EXCLUDE_FROM_DOXYGEN
+#define __STDC_FORMAT_MACROS
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <cstdint>
+//#define _LARGEFILE64_SOURCE
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+/// \endcond
+
+#include "mpidummy.h"
+
+
+
+#if defined(__APPLE__) || defined(__WIN32__) || defined(__CYGWIN__)
+#    define lseek64 lseek
+#    define open64  open
+#endif
+
+
+namespace adios
+{
+
+static char mpierrmsg[MPI_MAX_ERROR_STRING];
+
+int MPI_Init(int *argc, char ***argv)
+{
+    mpierrmsg[0] = '\0';
+    return MPI_SUCCESS;
+}
+
+int MPI_Finalize()
+{
+    mpierrmsg[0] = '\0';
+    return MPI_SUCCESS;
+}
+
+int MPI_Initialized( int* flag )
+{
+  *flag = 1 ;
+  return MPI_SUCCESS;
+}
+
+int MPI_Comm_split ( MPI_Comm comm, int color, int key, MPI_Comm *comm_out ) {return MPI_SUCCESS;}
+
+int MPI_Barrier(MPI_Comm comm) { return MPI_SUCCESS; }
+int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) { return MPI_SUCCESS; }
+
+int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm) { *newcomm = comm; return MPI_SUCCESS; }
+int MPI_Comm_rank(MPI_Comm comm, int *rank) { *rank = 0; return MPI_SUCCESS; }
+int MPI_Comm_size(MPI_Comm comm, int *size) { *size = 1; return MPI_SUCCESS; }
+int MPI_Comm_free(MPI_Comm *comm) { *comm = 0; return MPI_SUCCESS; }
+MPI_Comm MPI_Comm_f2c(MPI_Fint comm) { return comm; }
+
+int MPI_Gather(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
+               void *recvbuf, int recvcnt, MPI_Datatype recvtype,
+               int root, MPI_Comm comm)
+{
+  int ier = MPI_SUCCESS;
+  size_t n=0, nsent=0, nrecv=0 ;
+  if( !sendbuf || !recvbuf )        ier = MPI_ERR_BUFFER ;
+  if( comm==MPI_COMM_NULL || root ) ier = MPI_ERR_COMM ;
+
+  switch( sendtype )
+  {
+    case MPI_INT : n = sizeof( int );
+                   break;
+    default      : return MPI_ERR_TYPE ;
+  }
+  nsent = n * sendcnt ;
+
+  switch( recvtype )
+  {
+    case MPI_INT : nrecv = sizeof( int ) ;
+                   break;
+    default      : return MPI_ERR_TYPE ;
+  }
+  nrecv = n * recvcnt ;
+
+  if( nrecv!=nsent ) ier = MPI_ERR_COUNT ;
+
+  if( ier == MPI_SUCCESS ) memcpy( recvbuf, sendbuf, nsent );
+  else snprintf(mpierrmsg, ier, "could not gather data\n" );
+
+  return ier ;
+}
+
+int MPI_Gatherv(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
+                void *recvbuf, int *recvcnts, int *displs,
+                MPI_Datatype recvtype, int root, MPI_Comm comm)
+{
+  int ier = MPI_SUCCESS;
+  if( !recvcnts || !displs ) ier = MPI_ERR_BUFFER ;
+
+  if( ier == MPI_SUCCESS )
+    ier = MPI_Gather(sendbuf, sendcnt, sendtype, recvbuf, recvcnts[0], recvtype, root, comm ) ;
+
+  return ier ;
+}
+
+int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
+                  void *recvbuf, int recvcount, MPI_Datatype recvtype,
+                  MPI_Comm comm)
+{
+    return MPI_Gather (sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, 0, comm);
+}
+
+int MPI_Scatter(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
+               void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root,
+               MPI_Comm comm)
+{
+  int ier = MPI_SUCCESS;
+  size_t n=0, nsent=0, nrecv=0 ;
+  if( !sendbuf || !recvbuf )        ier = MPI_ERR_BUFFER ;
+  if( comm==MPI_COMM_NULL || root ) ier = MPI_ERR_COMM ;
+
+  switch( sendtype )
+  {
+    case MPI_INT : n = sizeof( int ) ;
+                   break;
+    default      : return MPI_ERR_TYPE ;
+  }
+  nsent = n * sendcnt ;
+
+  switch( recvtype )
+  {
+    case MPI_INT : nrecv = sizeof( int ) ;
+                   break;
+    default      : return MPI_ERR_TYPE ;
+  }
+  nrecv = n * recvcnt ;
+
+  if( nrecv!=nsent ) ier = MPI_ERR_COUNT ;
+
+  if( ier == MPI_SUCCESS ) memcpy( sendbuf, recvbuf, nsent );
+  else snprintf(mpierrmsg, ier, "could not scatter data\n" );
+
+  return ier ;
+}
+
+int MPI_Scatterv( void *sendbuf, int *sendcnts, int *displs,
+                 MPI_Datatype sendtype, void *recvbuf, int recvcnt,
+                 MPI_Datatype recvtype,
+                 int root, MPI_Comm comm)
+{
+  int ier = MPI_SUCCESS;
+  if( !sendcnts || !displs ) ier = MPI_ERR_BUFFER ;
+
+  if( ier == MPI_SUCCESS )
+    ier = MPI_Scatter(sendbuf, sendcnts[0], sendtype, recvbuf, recvcnt, recvtype, root, comm ) ;
+
+  return ier ;
+}
+
+int MPI_Recv( void *recvbuffer, int count, MPI_Datatype type, int source, int tag, MPI_Comm comm, MPI_Status* status )
+{ return 0; }
+
+int MPI_Irecv( void *recvbuffer, int count, MPI_Datatype type, int source, int tag, MPI_Comm comm, MPI_Request* request )
+{ return 0; }
+
+int MPI_Send( void *sendbuffer, int count, MPI_Datatype type, int destination, int tag, MPI_Comm comm )
+{ return 0; }
+
+int MPI_Isend( void *recvbuffer, int count, MPI_Datatype type, int source, int tag, MPI_Comm comm, MPI_Request* request )
+{ return 0; }
+
+int MPI_Wait( MPI_Request* request, MPI_Status* status )
+{ return 0; }
+
+int MPI_File_open(MPI_Comm comm, char *filename, int amode, MPI_Info info, MPI_File *fh)
+{
+    *fh = open64 (filename, amode);
+    if (*fh == -1) {
+        snprintf(mpierrmsg, MPI_MAX_ERROR_STRING, "File not found: %s", filename);
+        return -1;
+    }
+    return MPI_SUCCESS;
+}
+
+int MPI_File_close(MPI_File *fh) { return close(*fh); }
+
+int MPI_File_get_size(MPI_File fh, MPI_Offset *size) {
+    uint64_t curpos = lseek64(fh, 0, SEEK_CUR); // get the current seek pos
+    uint64_t endpos = lseek64(fh, 0, SEEK_END); // go to end, returned is the size in bytes
+    lseek64(fh, curpos, SEEK_SET);             // go back where we were
+    *size = (MPI_Offset) endpos;
+    //printf("MPI_File_get_size: fh=%d, size=%lld\n", fh, *size);
+    return MPI_SUCCESS;
+}
+
+int MPI_File_read(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status)
+{
+    // FIXME: int count can read only 2GB (*datatype size) array at max
+    std::uint64_t bytes_to_read = count * datatype;  // datatype should hold the size of the type, not an id
+    std::uint64_t bytes_read;
+    bytes_read = read (fh, buf, bytes_to_read);
+    if (bytes_read != bytes_to_read) {
+        snprintf(mpierrmsg, MPI_MAX_ERROR_STRING, "could not read %" PRId64 " bytes. read only: %" PRId64 "\n", bytes_to_read, bytes_read);
+        return -2;
+    }
+    *status = bytes_read;
+    //printf("MPI_File_read: fh=%d, count=%d, typesize=%d, bytes read=%lld\n", fh, count, datatype, *status);
+    return MPI_SUCCESS;
+}
+
+int MPI_File_seek(MPI_File fh, MPI_Offset offset, int whence)
+{
+    uint64_t off = (uint64_t) offset;
+    lseek64 (fh, off, whence);
+    //printf("MPI_File_seek: fh=%d, offset=%lld, whence=%d\n", fh, off, whence);
+    return MPI_SUCCESS;
+}
+
+int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count)
+{
+    *count = (int) *status;
+    return MPI_SUCCESS;
+}
+
+int MPI_Error_string(int errorcode, char *string, int *resultlen)
+{
+    //sprintf(string, "Dummy lib does not know error strings. Code=%d\n",errorcode);
+    strcpy(string, mpierrmsg);
+    *resultlen = strlen(string);
+    return MPI_SUCCESS;
+}
+
+double MPI_Wtime()
+{
+    // Implementation not tested
+    struct timeval tv;
+    gettimeofday (&tv, NULL);
+    return (double)(tv.tv_sec) + (double)(tv.tv_usec) / 1000000;
+}
+
+int MPI_Get_processor_name (char *name, int *resultlen)
+{
+    sprintf(name, "0");
+    *resultlen = 1;
+    return 0;
+}
+
+}//end namespace
diff --git a/src/transform/BZip2.cpp b/src/transform/BZip2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..36c3bde0b9b7380ba2464da5b3bda3cda830f3d0
--- /dev/null
+++ b/src/transform/BZip2.cpp
@@ -0,0 +1,45 @@
+/*
+ * BZIP2.cpp
+ *
+ *  Created on: Oct 19, 2016
+ *      Author: wfg
+ */
+
+
+
+#include "../../include/transform/BZip2.h"
+
+
+
+namespace adios
+{
+namespace transform
+{
+
+
+BZIP2::BZIP2( ):
+    Transform( "bzip2" )
+{ }
+
+
+BZIP2::~BZIP2( )
+{ }
+
+
+
+void BZIP2::Compress( const std::vector<char>& bufferIn, std::vector<char>& bufferOut )
+{
+
+}
+
+
+void BZIP2::Decompress( const std::vector<char>& bufferIn, std::vector<char>& bufferOut )
+{
+
+}
+
+
+} //end namespace transform
+} //end namespace adios
+
+
diff --git a/src/transport/file/FStream.cpp b/src/transport/file/FStream.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9d571ebaf1b146cef2a6ae87224d083904d06d2a
--- /dev/null
+++ b/src/transport/file/FStream.cpp
@@ -0,0 +1,84 @@
+/*
+ * CFStream.cpp
+ *
+ *  Created on: Oct 24, 2016
+ *      Author: wfg
+ */
+
+/// \cond EXCLUDED_FROM_DOXYGEN
+#include <stdexcept>
+/// \endcond
+
+#include "transport/file/FStream.h"
+
+
+namespace adios
+{
+namespace transport
+{
+
+
+FStream::FStream( MPI_Comm mpiComm, const bool debugMode ):
+    Transport( "fstream", mpiComm, debugMode )
+{ }
+
+
+FStream::~FStream( )
+{ }
+
+
+void FStream::Open( const std::string name, const std::string accessMode )
+{
+    m_Name = name;
+    m_AccessMode = accessMode;
+
+    if( accessMode == "w" || accessMode == "write" )
+        m_FStream.open( name, std::fstream::out );
+
+    else if( accessMode == "a" || accessMode == "append" )
+        m_FStream.open( name, std::fstream::out | std::fstream::app );
+
+    else if( accessMode == "r" || accessMode == "read" )
+        m_FStream.open( name, std::fstream::in );
+
+    if( m_DebugMode == true )
+    {
+        if( !m_FStream )
+            throw std::ios_base::failure( "ERROR: couldn't open file " + name + ", in call to Open from FStream transport\n" );
+    }
+}
+
+
+void FStream::SetBuffer( char* buffer, std::size_t size )
+{
+    m_FStream.rdbuf()->pubsetbuf( buffer, size );
+}
+
+
+void FStream::Write( const char* buffer, std::size_t size )
+{
+    m_FStream.write( buffer, size );
+
+    if( m_DebugMode == true )
+    {
+        if( !m_FStream )
+            throw std::ios_base::failure( "ERROR: couldn't write to file " + m_Name + ", in call to FStream write\n"   );
+    }
+}
+
+
+void FStream::Flush( )
+{
+    m_FStream.flush( );
+}
+
+
+void FStream::Close( )
+{
+    m_FStream.close();
+}
+
+
+} //end namespace transport
+} //end namespace
+
diff --git a/src/transport/file/FileDescriptor.cpp b/src/transport/file/FileDescriptor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dabb4e2a2c94691a8a1eacf33d365b2549c32074
--- /dev/null
+++ b/src/transport/file/FileDescriptor.cpp
@@ -0,0 +1,135 @@
+/*
+ * FileDescriptor.cpp file descriptor
+ *
+ *  Created on: Oct 6, 2016
+ *      Author: wfg
+ */
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <fcntl.h>  //open
+#include <sys/types.h> //open
+#include <sys/stat.h> //open
+#include <stddef.h> // write output
+#include <unistd.h> // write, close
+#include <ios> //std::ios_base::failure
+/// \endcond
+
+
+
+#include "transport/file/FileDescriptor.h"
+
+
+namespace adios
+{
+namespace transport
+{
+
+FileDescriptor::FileDescriptor( MPI_Comm mpiComm, const bool debugMode ):
+    Transport( "POSIX_IO", mpiComm, debugMode )
+{ }
+
+
+FileDescriptor::~FileDescriptor( )
+{
+    if( m_FileDescriptor != -1 )
+    {
+        close( m_FileDescriptor );
+    }
+}
+
+
+void FileDescriptor::Open( const std::string name, const std::string accessMode )
+{
+    m_Name = name;
+    m_AccessMode = accessMode;
+
+    if( accessMode == "w" || accessMode == "write" )
+    {
+        if( m_Profiler.m_IsActive == true )
+            m_Profiler.m_Timers[0].SetInitialTime();
+
+        m_FileDescriptor = open( m_Name.c_str(), O_WRONLY | O_CREAT, 0777 );
+
+        if( m_Profiler.m_IsActive == true )
+            m_Profiler.m_Timers[0].SetTime();
+
+    }
+    else if( accessMode == "a" || accessMode == "append" )
+    {
+        if( m_Profiler.m_IsActive == true )
+            m_Profiler.m_Timers[0].SetInitialTime();
+
+        m_FileDescriptor = open( m_Name.c_str(),  O_WRONLY | O_APPEND ); //we need to change this
+
+        if( m_Profiler.m_IsActive == true )
+            m_Profiler.m_Timers[0].SetTime();
+    }
+    else if( accessMode == "r" || accessMode == "read" )
+    {
+        if( m_Profiler.m_IsActive == true )
+            m_Profiler.m_Timers[0].SetInitialTime();
+
+        m_FileDescriptor = open( m_Name.c_str(), O_RDONLY );
+
+        if( m_Profiler.m_IsActive == true )
+            m_Profiler.m_Timers[0].SetTime();
+    }
+
+    if( m_DebugMode == true )
+    {
+        if( m_FileDescriptor == -1 )
+            throw std::ios_base::failure( "ERROR: couldn't open file " + m_Name +
+                                          ", from call to Open in FD transport using POSIX open. Does file exists?\n" );
+    }
+}
+
+
+void FileDescriptor::Write( const char* buffer, std::size_t size )
+{
+    if( m_Profiler.m_IsActive == true )
+        m_Profiler.m_Timers[1].SetInitialTime();
+
+    auto writtenSize = write( m_FileDescriptor, buffer, size );
+
+    if( m_Profiler.m_IsActive == true )
+        m_Profiler.m_Timers[1].SetTime();
+
+    if( m_DebugMode == true )
+    {
+        if( writtenSize == -1 )
+            throw std::ios_base::failure( "ERROR: couldn't write to file " + m_Name +
+                                          ", in call to POSIX write\n"   );
+
+        if( static_cast<std::size_t>( writtenSize ) != size )
+            throw std::ios_base::failure( "ERROR: written size + " + std::to_string( writtenSize ) +
+                                          " is not equal to intended size " +
+                                          std::to_string( size ) + " in file " + m_Name +
+                                          ", in call to POSIX write\n"   );
+    }
+}
+
+
+void FileDescriptor::Close( )
+{
+    if( m_Profiler.m_IsActive == true )
+        m_Profiler.m_Timers[2].SetInitialTime();
+
+    int status = close( m_FileDescriptor );
+
+    if( m_Profiler.m_IsActive == true )
+        m_Profiler.m_Timers[2].SetTime();
+
+    if( m_DebugMode == true )
+    {
+        if( status == -1 )
+            throw std::ios_base::failure( "ERROR: couldn't close file " + m_Name +
+                                          ", in call to POSIX write\n"   );
+    }
+
+    m_IsOpen = false;
+}
+
+
+
+} //end namespace transport
+}//end namespace
diff --git a/src/transport/file/FilePointer.cpp b/src/transport/file/FilePointer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..181af76a93e81ac46699f0f7ed19a886870c6bac
--- /dev/null
+++ b/src/transport/file/FilePointer.cpp
@@ -0,0 +1,98 @@
+/*
+ * FP.cpp
+ *
+ *  Created on: Jan 6, 2017
+ *      Author: wfg
+ */
+
+/// \cond EXCLUDE_FROM_DOXYGEN
+#include <ios> //std::ios_base::failure
+/// \endcond
+
+
+#include "transport/file/FilePointer.h"
+
+
+namespace adios
+{
+namespace transport
+{
+
+
+FilePointer::FilePointer( MPI_Comm mpiComm, const bool debugMode ):
+    Transport( "FILE*", mpiComm, debugMode )
+{ }
+
+
+FilePointer::~FilePointer( )
+{
+    if( m_File != NULL )
+        fclose( m_File );
+}
+
+
+void FilePointer::Open( const std::string name, const std::string accessMode )
+{
+    m_Name = name;
+    m_AccessMode = accessMode;
+
+    if( accessMode == "w" || accessMode == "write" )
+        m_File = fopen( name.c_str(), "w" );
+
+    else if( accessMode == "a" || accessMode == "append" )
+        m_File = fopen( name.c_str(), "a" );
+
+    else if( accessMode == "r" || accessMode == "read" )
+        m_File = fopen( name.c_str(), "r" );
+
+    if( m_DebugMode == true )
+    {
+        if( m_File == NULL )
+            throw std::ios_base::failure( "ERROR: couldn't open file " + name + ", "
+                                          "in call to Open from File* transport\n" );
+    }
+}
+
+
+void FilePointer::SetBuffer( char* buffer, std::size_t size )
+{
+    int status = setvbuf( m_File, buffer, _IOFBF, size );
+
+    if( m_DebugMode == true )
+    {
+        if( status == 1 )
+            throw std::ios_base::failure( "ERROR: could not set buffer in rank "
+                                           + std::to_string( m_RankMPI ) + "\n" );
+    }
+}
+
+
+void FilePointer::Write( const char* buffer, std::size_t size )
+{
+    fwrite( buffer, sizeof(char), size, m_File );
+
+    if( m_DebugMode == true )
+    {
+        if( ferror( m_File ) )
+            throw std::ios_base::failure( "ERROR: couldn't write to file " + m_Name +
+                                          ", in call to File* write\n"   );
+    }
+}
+
+
+void FilePointer::Flush( )
+{
+    fflush( m_File );
+}
+
+
+void FilePointer::Close( )
+{
+    fclose( m_File );
+
+    m_IsOpen = false;
+}
+
+
+} //end namespace transport
+} //end namespace
diff --git a/src/transport/wan/MdtmMan.cpp b/src/transport/wan/MdtmMan.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6df6b1951c763519db378426a6b2a2a8f8f030ea
--- /dev/null
+++ b/src/transport/wan/MdtmMan.cpp
@@ -0,0 +1,96 @@
+/*
+ * MdtmMan.cpp
+ *
+ *  Created on: Jan 22, 2017
+ *      Author: wfg
+ */
+
+
+
+#include "transport/wan/MdtmMan.h"
+
+
+
+namespace adios
+{
+namespace transport
+{
+
+MdtmMan::MdtmMan( const std::string localIP, const std::string remoteIP, const std::string mode, const std::string prefix,
+                  const int numberOfPipes, const std::vector<int> tolerances, const std::vector<int> priorities,
+                  MPI_Comm mpiComm, const bool debugMode ):
+    Transport( "File", mpiComm, debugMode ),
+	m_LocalIP { localIP },
+	m_RemoteIP{ remoteIP },
+	m_Mode{ mode },
+	m_Prefix { prefix },
+	m_NumberOfPipes{ numberOfPipes },
+	m_Tolerances{ tolerances },
+	m_Priorities{ priorities }
+{ }
+
+MdtmMan::~MdtmMan( )
+{ }
+
+
+void MdtmMan::Open( const std::string name, const std::string accessMode )
+{ }
+
+
+void MdtmMan::SetBuffer( char* buffer, std::size_t size )
+{ }
+
+
+void MdtmMan::Write( const char* buffer, std::size_t size )
+{ }
+
+
+void MdtmMan::Flush( )
+{ }
+
+
+void MdtmMan::Close( )
+{
+
+    m_NumberOfPipes = -1;
+}
+
+
+//PRIVATE Functions
+int MdtmMan::Put( const void* data, const std::string doid, const std::string variable, const std::string dType,
+                  const std::vector<std::uint64_t>& putShape, const std::vector<uint64_t>& varShape, const std::vector<uint64_t>& offset,
+                  const std::uint64_t timestep, const int tolerance, const int priority )
+{
+
+
+    return 0;
+}
+
+
+int MdtmMan::Get( void* data, const std::string doid, const std::string variable, const std::string dType,
+                  const std::vector<std::uint64_t>& putShape, const std::vector<uint64_t>& varShape, const std::vector<uint64_t>& offset,
+                  const std::uint64_t timestep, const int tolerance, const int priority )
+{
+
+	return 0;
+}
+
+
+int MdtmMan::Get( void *data, const std::string doid, const std::string variable, const std::string dType,
+                  std::vector<std::uint64_t>& varShape, const std::uint64_t timestep )
+{
+
+	return 0;
+}
+
+
+
+void MdtmMan::OnReceive( nlohmann::json& jData )
+{
+
+}
+
+
+
+} //end namespace transport
+} //end namespace