Index: XmlTools2/trunk/XmlTools/Makefile
===================================================================
--- XmlTools2/trunk/XmlTools/Makefile	(revision 905)
+++ XmlTools2/trunk/XmlTools/Makefile	(revision 905)
@@ -0,0 +1,147 @@
+#############################################################################
+# Makefile for building: XmlTools
+# Generated by qmake (2.01a) (Qt 4.8.1) on: sex 10. Jan 22:50:58 2014
+# Project:  XmlTools.pro
+# Template: app
+# Command: c:\qtsdk\desktop\qt\4.8.1\mingw\bin\qmake.exe -spec ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\win32-g++ CONFIG+=declarative_debug -o Makefile XmlTools.pro
+#############################################################################
+
+first: debug
+install: debug-install
+uninstall: debug-uninstall
+MAKEFILE      = Makefile
+QMAKE         = c:\qtsdk\desktop\qt\4.8.1\mingw\bin\qmake.exe
+DEL_FILE      = del
+CHK_DIR_EXISTS= if not exist
+MKDIR         = mkdir
+COPY          = copy /y
+COPY_FILE     = $(COPY)
+COPY_DIR      = xcopy /s /q /y /i
+INSTALL_FILE  = $(COPY_FILE)
+INSTALL_PROGRAM = $(COPY_FILE)
+INSTALL_DIR   = $(COPY_DIR)
+DEL_FILE      = del
+SYMLINK       = 
+DEL_DIR       = rmdir
+MOVE          = move
+CHK_DIR_EXISTS= if not exist
+MKDIR         = mkdir
+SUBTARGETS    =  \
+		debug \
+		release
+
+debug: $(MAKEFILE).Debug FORCE
+	$(MAKE) -f $(MAKEFILE).Debug
+debug-make_default: $(MAKEFILE).Debug FORCE
+	$(MAKE) -f $(MAKEFILE).Debug 
+debug-make_first: $(MAKEFILE).Debug FORCE
+	$(MAKE) -f $(MAKEFILE).Debug first
+debug-all: $(MAKEFILE).Debug FORCE
+	$(MAKE) -f $(MAKEFILE).Debug all
+debug-clean: $(MAKEFILE).Debug FORCE
+	$(MAKE) -f $(MAKEFILE).Debug clean
+debug-distclean: $(MAKEFILE).Debug FORCE
+	$(MAKE) -f $(MAKEFILE).Debug distclean
+debug-install: $(MAKEFILE).Debug FORCE
+	$(MAKE) -f $(MAKEFILE).Debug install
+debug-uninstall: $(MAKEFILE).Debug FORCE
+	$(MAKE) -f $(MAKEFILE).Debug uninstall
+release: $(MAKEFILE).Release FORCE
+	$(MAKE) -f $(MAKEFILE).Release
+release-make_default: $(MAKEFILE).Release FORCE
+	$(MAKE) -f $(MAKEFILE).Release 
+release-make_first: $(MAKEFILE).Release FORCE
+	$(MAKE) -f $(MAKEFILE).Release first
+release-all: $(MAKEFILE).Release FORCE
+	$(MAKE) -f $(MAKEFILE).Release all
+release-clean: $(MAKEFILE).Release FORCE
+	$(MAKE) -f $(MAKEFILE).Release clean
+release-distclean: $(MAKEFILE).Release FORCE
+	$(MAKE) -f $(MAKEFILE).Release distclean
+release-install: $(MAKEFILE).Release FORCE
+	$(MAKE) -f $(MAKEFILE).Release install
+release-uninstall: $(MAKEFILE).Release FORCE
+	$(MAKE) -f $(MAKEFILE).Release uninstall
+
+Makefile: XmlTools.pro  ../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/win32-g++/qmake.conf ../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/qconfig.pri \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/modules/qt_webkit_version.pri \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/qt_functions.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/qt_config.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/exclusive_builds.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/default_pre.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/win32/default_pre.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/debug.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/debug_and_release.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/default_post.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/win32/default_post.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/win32/console.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/declarative_debug.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/win32/rtti.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/win32/exceptions.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/win32/stl.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/shared.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/warn_on.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/qt.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/win32/thread.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/moc.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/resources.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/uic.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/yacc.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/lex.prf \
+		../../../../QtSDK/Desktop/Qt/4.8.1/mingw/mkspecs/features/include_source_dir.prf
+	$(QMAKE) -spec ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\win32-g++ CONFIG+=declarative_debug -o Makefile XmlTools.pro
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\qconfig.pri:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\modules\qt_webkit_version.pri:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt_functions.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt_config.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\exclusive_builds.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\default_pre.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\default_pre.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\debug.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\debug_and_release.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\default_post.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\default_post.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\console.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\declarative_debug.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\rtti.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\exceptions.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\stl.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\shared.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\warn_on.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\thread.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\moc.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\resources.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\uic.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\yacc.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\lex.prf:
+..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\include_source_dir.prf:
+qmake: qmake_all FORCE
+	@$(QMAKE) -spec ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\win32-g++ CONFIG+=declarative_debug -o Makefile XmlTools.pro
+
+qmake_all: FORCE
+
+make_default: debug-make_default release-make_default FORCE
+make_first: debug-make_first release-make_first FORCE
+all: debug-all release-all FORCE
+clean: debug-clean release-clean FORCE
+distclean: debug-distclean release-distclean FORCE
+	-$(DEL_FILE) Makefile
+
+check: first
+
+debug-mocclean: $(MAKEFILE).Debug
+	$(MAKE) -f $(MAKEFILE).Debug mocclean
+release-mocclean: $(MAKEFILE).Release
+	$(MAKE) -f $(MAKEFILE).Release mocclean
+mocclean: debug-mocclean release-mocclean
+
+debug-mocables: $(MAKEFILE).Debug
+	$(MAKE) -f $(MAKEFILE).Debug mocables
+release-mocables: $(MAKEFILE).Release
+	$(MAKE) -f $(MAKEFILE).Release mocables
+mocables: debug-mocables release-mocables
+FORCE:
+
+$(MAKEFILE).Debug: Makefile
+$(MAKEFILE).Release: Makefile
Index: XmlTools2/trunk/XmlTools/Makefile.Debug
===================================================================
--- XmlTools2/trunk/XmlTools/Makefile.Debug	(revision 905)
+++ XmlTools2/trunk/XmlTools/Makefile.Debug	(revision 905)
@@ -0,0 +1,161 @@
+#############################################################################
+# Makefile for building: XmlTools
+# Generated by qmake (2.01a) (Qt 4.8.1) on: sex 10. Jan 22:50:58 2014
+# Project:  XmlTools.pro
+# Template: app
+#############################################################################
+
+####### Compiler, tools and options
+
+CC            = gcc
+CXX           = g++
+DEFINES       = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_SCRIPT_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT
+CFLAGS        = -g -Wall $(DEFINES)
+CXXFLAGS      = -g -frtti -fexceptions -mthreads -Wall $(DEFINES)
+INCPATH       = -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include\QtCore" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include\QtGui" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include\QtScript" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include" -I"libs" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include\ActiveQt" -I"debug" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\win32-g++"
+LINK        =        g++
+LFLAGS        =        -Wl,-subsystem,console -mthreads
+LIBS        =        -L"c:\QtSDK\Desktop\Qt\4.8.1\mingw\lib" -lQtScriptd4 -lQtGuid4 -lQtCored4 
+QMAKE         = c:\qtsdk\desktop\qt\4.8.1\mingw\bin\qmake.exe
+IDC           = c:\QtSDK\Desktop\Qt\4.8.1\mingw\bin\idc.exe
+IDL           = midl
+ZIP           = zip -r -9
+DEF_FILE      = 
+RES_FILE      = 
+COPY          = copy /y
+SED           = 
+COPY_FILE     = $(COPY)
+COPY_DIR      = xcopy /s /q /y /i
+DEL_FILE      = del
+DEL_DIR       = rmdir
+MOVE          = move
+CHK_DIR_EXISTS= if not exist
+MKDIR         = mkdir
+INSTALL_FILE    = $(COPY_FILE)
+INSTALL_PROGRAM = $(COPY_FILE)
+INSTALL_DIR     = $(COPY_DIR)
+
+####### Output directory
+
+OBJECTS_DIR   = debug
+
+####### Files
+
+SOURCES       = main.cpp \
+		libs\pugixml.cpp \
+		xmltools.cpp \
+		util.cpp debug\qrc_resources.cpp
+OBJECTS       = debug/main.o \
+		debug/pugixml.o \
+		debug/xmltools.o \
+		debug/util.o \
+		debug/qrc_resources.o
+DIST          = 
+QMAKE_TARGET  = XmlTools
+DESTDIR        = debug\ #avoid trailing-slash linebreak
+TARGET         = XmlTools.exe
+DESTDIR_TARGET = debug\XmlTools.exe
+
+####### Implicit rules
+
+.SUFFIXES: .cpp .cc .cxx .c
+
+.cpp.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cc.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cxx.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+
+####### Build rules
+
+first: all
+all: Makefile.Debug  $(DESTDIR_TARGET)
+
+$(DESTDIR_TARGET):  $(OBJECTS) 
+	$(LINK) $(LFLAGS) -o $(DESTDIR_TARGET) $(OBJECTS)  $(LIBS)
+
+qmake:  FORCE
+	@$(QMAKE) -spec ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\win32-g++ CONFIG+=declarative_debug -o Makefile.Debug XmlTools.pro
+
+dist:
+	$(ZIP) XmlTools.zip $(SOURCES) $(DIST) XmlTools.pro ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\qconfig.pri ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\modules\qt_webkit_version.pri ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt_functions.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt_config.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\exclusive_builds.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\default_pre.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\default_pre.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\debug.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\debug_and_release.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\default_post.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\default_post.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\build_pass.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\console.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\declarative_debug.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\rtti.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\exceptions.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\stl.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\shared.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\warn_on.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\thread.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\moc.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\resources.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\uic.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\yacc.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\lex.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\include_source_dir.prf  HEADERS RESOURCES IMAGES SOURCES OBJECTIVE_SOURCES FORMS YACCSOURCES YACCSOURCES LEXSOURCES 
+
+clean: compiler_clean 
+	-$(DEL_FILE) debug\main.o debug\pugixml.o debug\xmltools.o debug\util.o debug\qrc_resources.o
+
+distclean: clean
+	-$(DEL_FILE) $(DESTDIR_TARGET)
+	-$(DEL_FILE) Makefile.Debug
+
+check: first
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+compiler_moc_header_make_all:
+compiler_moc_header_clean:
+compiler_rcc_make_all: debug/qrc_resources.cpp
+compiler_rcc_clean:
+	-$(DEL_FILE) debug\qrc_resources.cpp
+debug/qrc_resources.cpp: resources.qrc \
+		libs/jsxml.js \
+		libs/rexml.js
+	c:\QtSDK\Desktop\Qt\4.8.1\mingw\bin\rcc.exe -name resources resources.qrc -o debug\qrc_resources.cpp
+
+compiler_image_collection_make_all: qmake_image_collection.cpp
+compiler_image_collection_clean:
+	-$(DEL_FILE) qmake_image_collection.cpp
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all:
+compiler_uic_clean:
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_rcc_clean 
+
+
+
+####### Compile
+
+debug/main.o: main.cpp main.h \
+		xmltools.h \
+		libs/pugixml.hpp \
+		libs/pugiconfig.hpp \
+		util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\main.o main.cpp
+
+debug/pugixml.o: libs/pugixml.cpp libs/pugixml.hpp \
+		libs/pugiconfig.hpp
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\pugixml.o libs\pugixml.cpp
+
+debug/xmltools.o: xmltools.cpp xmltools.h \
+		libs/pugixml.hpp \
+		libs/pugiconfig.hpp \
+		util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\xmltools.o xmltools.cpp
+
+debug/util.o: util.cpp util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\util.o util.cpp
+
+debug/qrc_resources.o: debug/qrc_resources.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o debug\qrc_resources.o debug\qrc_resources.cpp
+
+####### Install
+
+install:   FORCE
+
+uninstall:   FORCE
+
+FORCE:
+
Index: XmlTools2/trunk/XmlTools/Makefile.Release
===================================================================
--- XmlTools2/trunk/XmlTools/Makefile.Release	(revision 905)
+++ XmlTools2/trunk/XmlTools/Makefile.Release	(revision 905)
@@ -0,0 +1,161 @@
+#############################################################################
+# Makefile for building: XmlTools
+# Generated by qmake (2.01a) (Qt 4.8.1) on: sex 10. Jan 22:50:58 2014
+# Project:  XmlTools.pro
+# Template: app
+#############################################################################
+
+####### Compiler, tools and options
+
+CC            = gcc
+CXX           = g++
+DEFINES       = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_SCRIPT_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT
+CFLAGS        = -O2 -Wall $(DEFINES)
+CXXFLAGS      = -O2 -frtti -fexceptions -mthreads -Wall $(DEFINES)
+INCPATH       = -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include\QtCore" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include\QtGui" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include\QtScript" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include" -I"libs" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\include\ActiveQt" -I"release" -I"..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\win32-g++"
+LINK        =        g++
+LFLAGS        =        -Wl,-s -Wl,-subsystem,console -mthreads
+LIBS        =        -L"c:\QtSDK\Desktop\Qt\4.8.1\mingw\lib" -lQtScript4 -lQtGui4 -lQtCore4 
+QMAKE         = c:\qtsdk\desktop\qt\4.8.1\mingw\bin\qmake.exe
+IDC           = c:\QtSDK\Desktop\Qt\4.8.1\mingw\bin\idc.exe
+IDL           = midl
+ZIP           = zip -r -9
+DEF_FILE      = 
+RES_FILE      = 
+COPY          = copy /y
+SED           = 
+COPY_FILE     = $(COPY)
+COPY_DIR      = xcopy /s /q /y /i
+DEL_FILE      = del
+DEL_DIR       = rmdir
+MOVE          = move
+CHK_DIR_EXISTS= if not exist
+MKDIR         = mkdir
+INSTALL_FILE    = $(COPY_FILE)
+INSTALL_PROGRAM = $(COPY_FILE)
+INSTALL_DIR     = $(COPY_DIR)
+
+####### Output directory
+
+OBJECTS_DIR   = release
+
+####### Files
+
+SOURCES       = main.cpp \
+		libs\pugixml.cpp \
+		xmltools.cpp \
+		util.cpp release\qrc_resources.cpp
+OBJECTS       = release/main.o \
+		release/pugixml.o \
+		release/xmltools.o \
+		release/util.o \
+		release/qrc_resources.o
+DIST          = 
+QMAKE_TARGET  = XmlTools
+DESTDIR        = release\ #avoid trailing-slash linebreak
+TARGET         = XmlTools.exe
+DESTDIR_TARGET = release\XmlTools.exe
+
+####### Implicit rules
+
+.SUFFIXES: .cpp .cc .cxx .c
+
+.cpp.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cc.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cxx.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+
+####### Build rules
+
+first: all
+all: Makefile.Release  $(DESTDIR_TARGET)
+
+$(DESTDIR_TARGET):  $(OBJECTS) 
+	$(LINK) $(LFLAGS) -o $(DESTDIR_TARGET) $(OBJECTS)  $(LIBS)
+
+qmake:  FORCE
+	@$(QMAKE) -spec ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\win32-g++ CONFIG+=declarative_debug -o Makefile.Release XmlTools.pro
+
+dist:
+	$(ZIP) XmlTools.zip $(SOURCES) $(DIST) XmlTools.pro ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\qconfig.pri ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\modules\qt_webkit_version.pri ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt_functions.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt_config.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\exclusive_builds.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\default_pre.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\default_pre.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\release.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\debug_and_release.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\default_post.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\default_post.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\build_pass.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\console.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\declarative_debug.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\rtti.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\exceptions.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\stl.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\shared.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\warn_on.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\qt.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\win32\thread.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\moc.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\resources.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\uic.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\yacc.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\lex.prf ..\..\..\..\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\features\include_source_dir.prf  HEADERS RESOURCES IMAGES SOURCES OBJECTIVE_SOURCES FORMS YACCSOURCES YACCSOURCES LEXSOURCES 
+
+clean: compiler_clean 
+	-$(DEL_FILE) release\main.o release\pugixml.o release\xmltools.o release\util.o release\qrc_resources.o
+
+distclean: clean
+	-$(DEL_FILE) $(DESTDIR_TARGET)
+	-$(DEL_FILE) Makefile.Release
+
+check: first
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+compiler_moc_header_make_all:
+compiler_moc_header_clean:
+compiler_rcc_make_all: release/qrc_resources.cpp
+compiler_rcc_clean:
+	-$(DEL_FILE) release\qrc_resources.cpp
+release/qrc_resources.cpp: resources.qrc \
+		libs/jsxml.js \
+		libs/rexml.js
+	c:\QtSDK\Desktop\Qt\4.8.1\mingw\bin\rcc.exe -name resources resources.qrc -o release\qrc_resources.cpp
+
+compiler_image_collection_make_all: qmake_image_collection.cpp
+compiler_image_collection_clean:
+	-$(DEL_FILE) qmake_image_collection.cpp
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all:
+compiler_uic_clean:
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_rcc_clean 
+
+
+
+####### Compile
+
+release/main.o: main.cpp main.h \
+		xmltools.h \
+		libs/pugixml.hpp \
+		libs/pugiconfig.hpp \
+		util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\main.o main.cpp
+
+release/pugixml.o: libs/pugixml.cpp libs/pugixml.hpp \
+		libs/pugiconfig.hpp
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\pugixml.o libs\pugixml.cpp
+
+release/xmltools.o: xmltools.cpp xmltools.h \
+		libs/pugixml.hpp \
+		libs/pugiconfig.hpp \
+		util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\xmltools.o xmltools.cpp
+
+release/util.o: util.cpp util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\util.o util.cpp
+
+release/qrc_resources.o: release/qrc_resources.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\qrc_resources.o release\qrc_resources.cpp
+
+####### Install
+
+install:   FORCE
+
+uninstall:   FORCE
+
+FORCE:
+
Index: XmlTools2/trunk/XmlTools/XmlTools.pro
===================================================================
--- XmlTools2/trunk/XmlTools/XmlTools.pro	(revision 905)
+++ XmlTools2/trunk/XmlTools/XmlTools.pro	(revision 905)
@@ -0,0 +1,38 @@
+TEMPLATE = app
+CONFIG += console
+QT       += core
+QT       -= gui # not needed
+#CONFIG -= qt
+#QT += qml #for use new google v8 qtscript engine
+QT += script #for use old qtscript engine
+
+macx {
+CONFIG -= app_bundle # We only want the binary on mac os not a bundle
+}
+
+
+INCLUDEPATH += ./libs
+
+SOURCES += main.cpp \
+    libs/pugixml.cpp \
+    xmltools.cpp \
+    util.cpp \
+    xmlpatch.cpp \
+    multidimvar.cpp \
+    utilxmltools.cpp \
+    xmlfilter.cpp
+
+HEADERS += main.h \
+    libs/pugiconfig.hpp \
+    libs/pugixml.hpp \
+    util.h \
+    xmltools.h \
+    xmlpatch.h \
+    multidimvar.h \
+    utilxmltools.h \
+    xmlfilter.h
+
+OTHER_FILES +=
+
+RESOURCES += \
+    resources.qrc
Index: XmlTools2/trunk/XmlTools/XmlTools.pro.user
===================================================================
--- XmlTools2/trunk/XmlTools/XmlTools.pro.user	(revision 905)
+++ XmlTools2/trunk/XmlTools/XmlTools.pro.user	(revision 905)
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QtCreatorProject>
+<!-- Written by QtCreator 3.0.0, 2014-02-01T11:10:30. -->
+<qtcreator>
+ <data>
+  <variable>ProjectExplorer.Project.ActiveTarget</variable>
+  <value type="int">0</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.EditorSettings</variable>
+  <valuemap type="QVariantMap">
+   <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
+   <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
+   <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
+    <value type="QString" key="language">Cpp</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
+    </valuemap>
+   </valuemap>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
+    <value type="QString" key="language">QmlJS</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
+    </valuemap>
+   </valuemap>
+   <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
+   <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
+   <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
+   <value type="int" key="EditorConfiguration.IndentSize">4</value>
+   <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
+   <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
+   <value type="int" key="EditorConfiguration.PaddingMode">1</value>
+   <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
+   <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
+   <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
+   <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
+   <value type="int" key="EditorConfiguration.TabSize">8</value>
+   <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
+   <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
+   <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
+   <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
+   <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
+   <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.PluginSettings</variable>
+  <valuemap type="QVariantMap"/>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.0</variable>
+  <valuemap type="QVariantMap">
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.2.0 MinGW 32bit</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.2.0 MinGW 32bit</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.520.win32_mingw48.essentials_kit</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/home/qtWorkspace/build-XmlTools-Desktop_Qt_5_2_0_MinGW_32bit-Debug</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/home/qtWorkspace/build-XmlTools-Desktop_Qt_5_2_0_MinGW_32bit-Release</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+    <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
+    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+    <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
+    <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
+    <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
+    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+     <value type="int">0</value>
+     <value type="int">1</value>
+     <value type="int">2</value>
+     <value type="int">3</value>
+     <value type="int">4</value>
+     <value type="int">5</value>
+     <value type="int">6</value>
+     <value type="int">7</value>
+     <value type="int">8</value>
+     <value type="int">9</value>
+     <value type="int">10</value>
+     <value type="int">11</value>
+     <value type="int">12</value>
+     <value type="int">13</value>
+     <value type="int">14</value>
+    </valuelist>
+    <value type="int" key="PE.EnvironmentAspect.Base">2</value>
+    <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">XmlTools</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:C:/Users/home/qtWorkspace/XmlTools/XmlTools.pro</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments">-p &quot;*&quot;</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">XmlTools.pro</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">true</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory">C:/Users/home/qtWorkspace/build-XmlTools-Desktop_Qt_5_2_0_MinGW_32bit-Release/release</value>
+    <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
+    <value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
+    <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
+    <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebugger">true</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.TargetCount</variable>
+  <value type="int">1</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
+  <value type="QByteArray">{6edaa77c-4000-4dbd-8c05-9d321f2dbdf6}</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
+  <value type="int">15</value>
+ </data>
+</qtcreator>
Index: XmlTools2/trunk/XmlTools/XmlTools.pro.user.2.5pre1
===================================================================
--- XmlTools2/trunk/XmlTools/XmlTools.pro.user.2.5pre1	(revision 905)
+++ XmlTools2/trunk/XmlTools/XmlTools.pro.user.2.5pre1	(revision 905)
@@ -0,0 +1,365 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QtCreatorProject>
+<!-- Written by Qt Creator 2.4.1, 2014-01-11T19:44:50. -->
+<qtcreator>
+ <data>
+  <variable>ProjectExplorer.Project.ActiveTarget</variable>
+  <value type="int">0</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.EditorSettings</variable>
+  <valuemap type="QVariantMap">
+   <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
+   <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
+    <value type="QString" key="language">Cpp</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QString" key="CurrentPreferences">CppGlobal</value>
+    </valuemap>
+   </valuemap>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
+    <value type="QString" key="language">QmlJS</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QString" key="CurrentPreferences">QmlJSGlobal</value>
+    </valuemap>
+   </valuemap>
+   <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
+   <value type="QByteArray" key="EditorConfiguration.Codec">System</value>
+   <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
+   <value type="int" key="EditorConfiguration.IndentSize">4</value>
+   <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
+   <value type="int" key="EditorConfiguration.PaddingMode">1</value>
+   <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
+   <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
+   <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
+   <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
+   <value type="int" key="EditorConfiguration.TabSize">8</value>
+   <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
+   <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
+   <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
+   <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
+   <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
+   <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.PluginSettings</variable>
+  <valuemap type="QVariantMap"/>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.0</variable>
+  <valuemap type="QVariantMap">
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Target.DesktopTarget</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
+    <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Mingw:C:/QtSDK/mingw/bin/mingw32-g++.exe.x86-windows-msys-pe-32bit.C:/QtSDK/pythongdb/python_2.7based/gdb-i686-pc-mingw32.exe</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.1 for Desktop - MinGW (Qt SDK) Debug</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">C:/Users/home/qtWorkspace/XmlTools</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">5</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
+    <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Mingw:C:/QtSDK/mingw/bin/mingw32-g++.exe.x86-windows-msys-pe-32bit.C:/QtSDK/pythongdb/python_2.7based/gdb-i686-pc-mingw32.exe</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.1 for Desktop - MinGW (Qt SDK) Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">C:/Users/home/qtWorkspace/XmlTools</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">5</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
+    <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Mingw:C:/QtSDK/mingw/bin/mingw32-g++.exe.x86-windows-msys-pe-32bit.C:/QtSDK/pythongdb/python_2.7based/gdb-i686-pc-mingw32.exe</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.7.4 for Desktop - MinGW 4.4 (Qt SDK) Debug</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">C:/Users/home/qtWorkspace/XmlTools</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">6</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3">
+    <value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Mingw:C:/QtSDK/mingw/bin/mingw32-g++.exe.x86-windows-msys-pe-32bit.C:/QtSDK/pythongdb/python_2.7based/gdb-i686-pc-mingw32.exe</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.7.4 for Desktop - MinGW 4.4 (Qt SDK) Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">C:/Users/home/qtWorkspace/XmlTools</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">6</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">4</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">No deployment</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
+    <value type="bool" key="Analyzer.Project.UseGlobal">true</value>
+    <value type="bool" key="Analyzer.Project.UseGlobal">true</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+     <value type="int">0</value>
+     <value type="int">1</value>
+     <value type="int">2</value>
+     <value type="int">3</value>
+     <value type="int">4</value>
+     <value type="int">5</value>
+     <value type="int">6</value>
+     <value type="int">7</value>
+     <value type="int">8</value>
+     <value type="int">9</value>
+     <value type="int">10</value>
+     <value type="int">11</value>
+     <value type="int">12</value>
+     <value type="int">13</value>
+     <value type="int">14</value>
+    </valuelist>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+     <value type="int">0</value>
+     <value type="int">1</value>
+     <value type="int">2</value>
+     <value type="int">3</value>
+     <value type="int">4</value>
+     <value type="int">5</value>
+     <value type="int">6</value>
+     <value type="int">7</value>
+     <value type="int">8</value>
+     <value type="int">9</value>
+     <value type="int">10</value>
+     <value type="int">11</value>
+     <value type="int">12</value>
+     <value type="int">13</value>
+     <value type="int">14</value>
+    </valuelist>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">XmlTools</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase">2</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">XmlTools.pro</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">true</value>
+    <valuelist type="QVariantList" key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
+    <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
+    <value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.TargetCount</variable>
+  <value type="int">1</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
+  <value type="QString">{d1d804e5-7180-479f-b853-a9ffac018cf5}</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
+  <value type="int">10</value>
+ </data>
+</qtcreator>
Index: XmlTools2/trunk/XmlTools/XmlTools.pro.user.d1d804e
===================================================================
--- XmlTools2/trunk/XmlTools/XmlTools.pro.user.d1d804e	(revision 905)
+++ XmlTools2/trunk/XmlTools/XmlTools.pro.user.d1d804e	(revision 905)
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QtCreatorProject>
+<!-- Written by QtCreator 3.0.0, 2014-01-27T13:11:47. -->
+<qtcreator>
+ <data>
+  <variable>ProjectExplorer.Project.ActiveTarget</variable>
+  <value type="int">0</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.EditorSettings</variable>
+  <valuemap type="QVariantMap">
+   <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
+   <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
+   <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
+    <value type="QString" key="language">Cpp</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
+    </valuemap>
+   </valuemap>
+   <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
+    <value type="QString" key="language">QmlJS</value>
+    <valuemap type="QVariantMap" key="value">
+     <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
+    </valuemap>
+   </valuemap>
+   <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
+   <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
+   <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
+   <value type="int" key="EditorConfiguration.IndentSize">4</value>
+   <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
+   <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
+   <value type="int" key="EditorConfiguration.PaddingMode">1</value>
+   <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
+   <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
+   <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
+   <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
+   <value type="int" key="EditorConfiguration.TabSize">8</value>
+   <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
+   <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
+   <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
+   <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
+   <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
+   <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.PluginSettings</variable>
+  <valuemap type="QVariantMap"/>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.0</variable>
+  <valuemap type="QVariantMap">
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.2.0 MinGW 32bit</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.2.0 MinGW 32bit</value>
+   <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.520.win32_mingw48.essentials_kit</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
+   <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/home/qtWorkspace/build-XmlTools-Desktop_Qt_5_2_0_MinGW_32bit-Debug</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
+   </valuemap>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
+    <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/home/qtWorkspace/build-XmlTools-Desktop_Qt_5_2_0_MinGW_32bit-Release</value>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
+      <value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
+      <value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
+     </valuemap>
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+    </valuemap>
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
+     <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+      <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+      <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
+      <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
+      <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+     </valuemap>
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
+    <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+    <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">2</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
+    <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+     <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
+    </valuemap>
+    <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
+   <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+    <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+    <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+    <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+    <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
+    <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+    <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
+    <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
+    <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
+    <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+    <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+    <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+     <value type="int">0</value>
+     <value type="int">1</value>
+     <value type="int">2</value>
+     <value type="int">3</value>
+     <value type="int">4</value>
+     <value type="int">5</value>
+     <value type="int">6</value>
+     <value type="int">7</value>
+     <value type="int">8</value>
+     <value type="int">9</value>
+     <value type="int">10</value>
+     <value type="int">11</value>
+     <value type="int">12</value>
+     <value type="int">13</value>
+     <value type="int">14</value>
+    </valuelist>
+    <value type="int" key="PE.EnvironmentAspect.Base">2</value>
+    <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">XmlTools</value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:C:/Users/home/qtWorkspace/XmlTools/XmlTools.pro</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">XmlTools.pro</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
+    <value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">true</value>
+    <value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory">C:/Users/home/qtWorkspace/build-XmlTools-Desktop_Qt_5_2_0_MinGW_32bit-Release/release</value>
+    <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
+    <value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
+    <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">false</value>
+    <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebugger">true</value>
+    <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
+   </valuemap>
+   <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.TargetCount</variable>
+  <value type="int">1</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
+  <value type="QByteArray">{d1d804e5-7180-479f-b853-a9ffac018cf5}</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
+  <value type="int">15</value>
+ </data>
+</qtcreator>
Index: XmlTools2/trunk/XmlTools/libs/TinyJS.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS.cpp	(revision 905)
@@ -0,0 +1,6071 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored / Changed By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+#ifdef _DEBUG
+#	ifndef _MSC_VER
+#		define DEBUG_MEMORY 1
+#	endif
+#endif
+#include <sstream>
+
+#include "TinyJS.h"
+
+#ifndef ASSERT
+#	define ASSERT(X) assert(X)
+#endif
+
+#ifndef NO_REGEXP 
+#	if defined HAVE_TR1_REGEX
+#		include <tr1/regex>
+		using namespace std::tr1;
+#	elif defined HAVE_BOOST_REGEX
+#		include <boost/regex.hpp>
+		using namespace boost;
+#	else
+#		include <regex>
+#	endif
+#endif
+#include <stdio.h>      /* printf, scanf, NULL */
+#include <stdlib.h>
+#include <cstring>
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <iterator>
+#include "TinyJS_Functions.h"
+
+using namespace std;
+
+// ----------------------------------------------------------------------------------- 
+//////////////////////////////////////////////////////////////////////////
+/// Memory Debug
+//////////////////////////////////////////////////////////////////////////
+
+//#define DEBUG_MEMORY 1
+
+#if DEBUG_MEMORY
+
+vector<CScriptVar*> allocatedVars;
+vector<CScriptVarLink*> allocatedLinks;
+
+void mark_allocated(CScriptVar *v) {
+	allocatedVars.push_back(v);
+}
+
+void mark_deallocated(CScriptVar *v) {
+	for (size_t i=0;i<allocatedVars.size();i++) {
+		if (allocatedVars[i] == v) {
+			allocatedVars.erase(allocatedVars.begin()+i);
+			break;
+		}
+	}
+}
+
+void mark_allocated(CScriptVarLink *v) {
+	allocatedLinks.push_back(v);
+}
+
+void mark_deallocated(CScriptVarLink *v) {
+	for (size_t i=0;i<allocatedLinks.size();i++) {
+		if (allocatedLinks[i] == v) {
+			allocatedLinks.erase(allocatedLinks.begin()+i);
+			break;
+		}
+	}
+}
+
+void show_allocated() {
+	for (size_t i=0;i<allocatedVars.size();i++) {
+		printf("ALLOCATED, %d refs\n", allocatedVars[i]->getRefs());
+		allocatedVars[i]->trace("  ");
+	}
+	for (size_t i=0;i<allocatedLinks.size();i++) {
+		printf("ALLOCATED LINK %s, allocated[%d] to \n", allocatedLinks[i]->getName().c_str(), allocatedLinks[i]->getVarPtr()->getRefs());
+		allocatedLinks[i]->getVarPtr()->trace("  ");
+	}
+	allocatedVars.clear();
+	allocatedLinks.clear();
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////
+/// Utils
+//////////////////////////////////////////////////////////////////////////
+
+inline bool isWhitespace(char ch) {
+	return (ch==' ') || (ch=='\t') || (ch=='\n') || (ch=='\r');
+}
+
+inline bool isNumeric(char ch) {
+	return (ch>='0') && (ch<='9');
+}
+uint32_t isArrayIndex(const string &str) {
+	if(str.size()==0 || !isNumeric(str[0]) || (str.size()>1 && str[0]=='0') ) return -1; // empty or (more as 1 digit and beginning with '0')
+	CNumber idx;
+	const char *endptr;
+	idx.parseInt(str.c_str(), 10, &endptr);
+	if(*endptr || idx>uint32_t(0xFFFFFFFFUL)) return -1;
+	return idx.toUInt32();
+}
+inline bool isHexadecimal(char ch) {
+	return ((ch>='0') && (ch<='9')) || ((ch>='a') && (ch<='f')) || ((ch>='A') && (ch<='F'));
+}
+inline bool isOctal(char ch) {
+	return ((ch>='0') && (ch<='7'));
+}
+inline bool isAlpha(char ch) {
+	return ((ch>='a') && (ch<='z')) || ((ch>='A') && (ch<='Z')) || ch=='_' || ch=='$';
+}
+
+bool isIDString(const char *s) {
+	if (!isAlpha(*s))
+		return false;
+	while (*s) {
+		if (!(isAlpha(*s) || isNumeric(*s)))
+			return false;
+		s++;
+	}
+	return true;
+}
+
+void replace(string &str, char textFrom, const char *textTo) {
+	int sLen = strlen(textTo);
+	size_t p = str.find(textFrom);
+	while (p != string::npos) {
+		str = str.substr(0, p) + textTo + str.substr(p+1);
+		p = str.find(textFrom, p+sLen);
+	}
+}
+string int2string(int32_t intData) {
+	ostringstream str;
+	str << intData;
+	return str.str();
+}
+string int2string(uint32_t intData) {
+	ostringstream str;
+	str << intData;
+	return str.str();
+}
+string float2string(const double &floatData) {
+	ostringstream str;
+	str.unsetf(ios::floatfield);
+#if (defined(_MSC_VER) && _MSC_VER >= 1600) || __cplusplus >= 201103L
+	str.precision(numeric_limits<double>::max_digits10);
+#else
+	str.precision(numeric_limits<double>::digits10+2);
+#endif
+	str << floatData;
+	return str.str();
+}
+/// convert the given string into a quoted string suitable for javascript
+string getJSString(const string &str) {
+	char buffer[5] = "\\x00";
+	string nStr; nStr.reserve(str.length());
+	nStr.push_back('\"');
+	for (string::const_iterator i=str.begin();i!=str.end();i++) {
+		const char *replaceWith = 0;
+		switch (*i) {
+			case '\\': replaceWith = "\\\\"; break;
+			case '\n': replaceWith = "\\n"; break;
+			case '\r': replaceWith = "\\r"; break;
+			case '\a': replaceWith = "\\a"; break;
+			case '\b': replaceWith = "\\b"; break;
+			case '\f': replaceWith = "\\f"; break;
+			case '\t': replaceWith = "\\t"; break;
+			case '\v': replaceWith = "\\v"; break;
+			case '"': replaceWith = "\\\""; break;
+			default: {
+					int nCh = ((unsigned char)*i) & 0xff;
+					if(nCh<32 || nCh>127) {
+						static char hex[] = "0123456789ABCDEF";
+						buffer[2] = hex[(nCh>>4)&0x0f];
+						buffer[3] = hex[nCh&0x0f];
+						replaceWith = buffer;
+					};
+				}
+		}
+		if (replaceWith)
+			nStr.append(replaceWith);
+		else
+			nStr.push_back(*i);
+	}
+	nStr.push_back('\"');
+	return nStr;
+}
+
+static inline string getIDString(const string& str) {
+	if(isIDString(str.c_str()) && CScriptToken::isReservedWord(str)==LEX_ID)
+		return str;
+	return getJSString(str);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptException
+//////////////////////////////////////////////////////////////////////////
+
+string CScriptException::toString() {
+	ostringstream msg;
+	msg << ERROR_NAME[errorType] << ": " << message;
+	if(lineNumber >= 0) msg << " at Line:" << lineNumber+1;
+	if(column >=0) msg << " Column:" << column+1;
+	if(fileName.length()) msg << " in " << fileName;
+	return msg.str();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptLex
+//////////////////////////////////////////////////////////////////////////
+
+CScriptLex::CScriptLex(const char *Code, const string &File, int Line, int Column) : data(Code) {
+	currentFile = File;
+	pos.currentLineStart = pos.tokenStart = data;
+	pos.currentLine = Line;
+	reset(pos);
+}
+
+void CScriptLex::reset(const POS &toPos) { ///< Reset this lex so we can start again
+	dataPos = toPos.tokenStart;
+	tk = last_tk = 0;
+	tkStr = "";
+	pos = toPos;
+	lineBreakBeforeToken = false;
+	currCh = nextCh = 0;
+	getNextCh(); // currCh
+	getNextCh(); // nextCh
+	getNextToken();
+}
+
+void CScriptLex::check(int expected_tk, int alternate_tk/*=-1*/) {
+	if (expected_tk==';' && tk==LEX_EOF) return; // ignore last missing ';'
+	if (tk!=expected_tk && tk!=alternate_tk) {
+		ostringstream errorString;
+		if(expected_tk == LEX_EOF)
+			errorString << "Got unexpected " << CScriptToken::getTokenStr(tk);
+		else
+			errorString << "Got '" << CScriptToken::getTokenStr(tk) << "' expected '" << CScriptToken::getTokenStr(expected_tk) << "'";
+		if(alternate_tk!=-1) errorString << " or '" << CScriptToken::getTokenStr(alternate_tk) << "'";
+		throw new CScriptException(SyntaxError, errorString.str(), currentFile, pos.currentLine, currentColumn());
+	}
+}
+void CScriptLex::match(int expected_tk1, int alternate_tk/*=-1*/) {
+	check(expected_tk1, alternate_tk);
+	int line = pos.currentLine;
+	getNextToken();
+	lineBreakBeforeToken = line != pos.currentLine;
+}
+
+void CScriptLex::getNextCh() {
+	if(currCh == '\n') { // Windows or Linux
+		pos.currentLine++;
+		pos.tokenStart = pos.currentLineStart = dataPos - (nextCh == LEX_EOF ?  0 : 1);
+	}
+	currCh = nextCh;
+	if ( (nextCh = *dataPos) != LEX_EOF ) dataPos++; // stay on EOF
+	if(currCh == '\r') { // Windows or Mac
+		if(nextCh == '\n')
+			getNextCh(); // Windows '\r\n\' --> skip '\r'
+		else
+			currCh = '\n'; // Mac (only '\r') --> convert '\r' to '\n'
+	}
+}
+
+static uint16_t not_allowed_tokens_befor_regexp[] = {LEX_ID, LEX_INT, LEX_FLOAT, LEX_STR, LEX_R_TRUE, LEX_R_FALSE, LEX_R_NULL, ']', ')', '.', LEX_EOF};
+void CScriptLex::getNextToken() {
+	while (currCh && isWhitespace(currCh)) getNextCh();
+	// newline comments
+	if (currCh=='/' && nextCh=='/') {
+			while (currCh && currCh!='\n') getNextCh();
+			getNextCh();
+			getNextToken();
+			return;
+	}
+	// block comments
+	if (currCh=='/' && nextCh=='*') {
+			while (currCh && (currCh!='*' || nextCh!='/')) getNextCh();
+			getNextCh();
+			getNextCh();
+			getNextToken();
+			return;
+	}
+	last_tk = tk;
+	tk = LEX_EOF;
+	tkStr.clear();
+	// record beginning of this token
+	pos.tokenStart = dataPos - (nextCh == LEX_EOF ? (currCh == LEX_EOF ? 0 : 1) : 2);
+	// tokens
+	if (isAlpha(currCh)) { //  IDs
+		while (isAlpha(currCh) || isNumeric(currCh)) {
+			tkStr += currCh;
+			getNextCh();
+		}
+		tk = CScriptToken::isReservedWord(tkStr);
+	} else if (isNumeric(currCh) || (currCh=='.' && isNumeric(nextCh))) { // Numbers
+		if(currCh=='.') tkStr+='0';
+		bool isHex = false, isOct=false;
+		if (currCh=='0') { 
+			tkStr += currCh; getNextCh();
+			if(isOctal(currCh)) isOct = true;
+		}
+		if (currCh=='x' || currCh=='X') {
+			isHex = true;
+			tkStr += currCh; getNextCh();
+		}
+		tk = LEX_INT;
+		while (isOctal(currCh) || (!isOct && isNumeric(currCh)) || (isHex && isHexadecimal(currCh))) {
+			tkStr += currCh;
+			getNextCh();
+		}
+		if (!isHex && !isOct && currCh=='.') {
+			tk = LEX_FLOAT;
+			tkStr += '.';
+			getNextCh();
+			while (isNumeric(currCh)) {
+				tkStr += currCh;
+				getNextCh();
+			}
+		}
+		// do fancy e-style floating point
+		if (!isHex && !isOct && (currCh=='e' || currCh=='E')) {
+			tk = LEX_FLOAT;
+			tkStr += currCh; getNextCh();
+			if (currCh=='-') { tkStr += currCh; getNextCh(); }
+			while (isNumeric(currCh)) {
+				tkStr += currCh; getNextCh();
+			}
+		}
+	} else if (currCh=='"' || currCh=='\'') {	// strings...
+		char endCh = currCh;
+		getNextCh();
+		while (currCh && currCh!=endCh && currCh!='\n') {
+			if (currCh == '\\') {
+				getNextCh();
+				switch (currCh) {
+					case '\n' : break; // ignore newline after '\'
+					case 'n': tkStr += '\n'; break;
+					case 'r': tkStr += '\r'; break;
+					case 'a': tkStr += '\a'; break;
+					case 'b': tkStr += '\b'; break;
+					case 'f': tkStr += '\f'; break;
+					case 't': tkStr += '\t'; break;
+					case 'v': tkStr += '\v'; break;
+					case 'x': { // hex digits
+						getNextCh();
+						if(isHexadecimal(currCh)) {
+							char buf[3]="\0\0";
+							buf[0] = currCh;
+							for(int i=0; i<2 && isHexadecimal(nextCh); i++) {
+								getNextCh(); buf[i] = currCh;
+							}
+							tkStr += (char)strtol(buf, 0, 16);
+						} else
+							throw new CScriptException(SyntaxError, "malformed hexadezimal character escape sequence", currentFile, pos.currentLine, currentColumn());	
+					}
+					default: {
+						if(isOctal(currCh)) {
+							char buf[4]="\0\0\0";
+							buf[0] = currCh;
+							for(int i=1; i<3 && isOctal(nextCh); i++) {
+								getNextCh(); buf[i] = currCh;
+							}
+							tkStr += (char)strtol(buf, 0, 8);
+						}
+						else tkStr += currCh;
+					}
+				}
+			} else {
+				tkStr += currCh;
+			}
+			getNextCh();
+		}
+		if(currCh != endCh)
+			throw new CScriptException(SyntaxError, "unterminated string literal", currentFile, pos.currentLine, currentColumn());
+		getNextCh();
+		tk = LEX_STR;
+	} else {
+		// single chars
+		tk = currCh;
+		if (currCh) getNextCh();
+		if (tk=='=' && currCh=='=') { // ==
+			tk = LEX_EQUAL;
+			getNextCh();
+			if (currCh=='=') { // ===
+				tk = LEX_TYPEEQUAL;
+				getNextCh();
+			}
+		} else if (tk=='!' && currCh=='=') { // !=
+			tk = LEX_NEQUAL;
+			getNextCh();
+			if (currCh=='=') { // !==
+				tk = LEX_NTYPEEQUAL;
+				getNextCh();
+			}
+		} else if (tk=='<') {
+			if (currCh=='=') {	// <=
+				tk = LEX_LEQUAL;
+				getNextCh();
+			} else if (currCh=='<') {	// <<
+				tk = LEX_LSHIFT;
+				getNextCh();
+				if (currCh=='=') { // <<=
+					tk = LEX_LSHIFTEQUAL;
+					getNextCh();
+				}
+			}
+		} else if (tk=='>') {
+			if (currCh=='=') {	// >=
+				tk = LEX_GEQUAL;
+				getNextCh();
+			} else if (currCh=='>') {	// >>
+				tk = LEX_RSHIFT;
+				getNextCh();
+				if (currCh=='=') { // >>=
+					tk = LEX_RSHIFTEQUAL;
+					getNextCh();
+				} else if (currCh=='>') { // >>>
+					tk = LEX_RSHIFTU;
+					getNextCh();
+					if (currCh=='=') { // >>>=
+						tk = LEX_RSHIFTUEQUAL;
+						getNextCh();
+					}				
+				}
+			}
+		}  else if (tk=='+') {
+			if (currCh=='=') {	// +=
+				tk = LEX_PLUSEQUAL;
+				getNextCh();
+			}  else if (currCh=='+') {	// ++
+				tk = LEX_PLUSPLUS;
+				getNextCh();
+			}
+		}  else if (tk=='-') {
+			if (currCh=='=') {	// -=
+				tk = LEX_MINUSEQUAL;
+				getNextCh();
+			}  else if (currCh=='-') {	// --
+				tk = LEX_MINUSMINUS;
+				getNextCh();
+			}
+		} else if (tk=='&') {
+			if (currCh=='=') {			// &=
+				tk = LEX_ANDEQUAL;
+				getNextCh();
+			} else if (currCh=='&') {	// &&
+				tk = LEX_ANDAND;
+				getNextCh();
+			}
+		} else if (tk=='|') {
+			if (currCh=='=') {			// |=
+				tk = LEX_OREQUAL;
+				getNextCh();
+			} else if (currCh=='|') {	// ||
+				tk = LEX_OROR;
+				getNextCh();
+			}
+		} else if (tk=='^' && currCh=='=') {
+			tk = LEX_XOREQUAL;
+			getNextCh();
+		} else if (tk=='*' && currCh=='=') {
+			tk = LEX_ASTERISKEQUAL;
+			getNextCh();
+		} else if (tk=='/') {
+			// check if it's a RegExp-Literal
+			tk = LEX_REGEXP;
+			for(uint16_t *p = not_allowed_tokens_befor_regexp; *p; p++) {
+				if(*p==last_tk) { tk = '/'; break; }
+			}
+			if(tk == LEX_REGEXP) {
+#ifdef NO_REGEXP
+				throw new CScriptException(Error, "42TinyJS was built without support for regular expressions", currentFile, pos.currentLine, currentColumn());
+#endif
+				tkStr = "/";
+				while (currCh && currCh!='/' && currCh!='\n') {
+					if (currCh == '\\' && nextCh == '/') {
+						tkStr.append(1, currCh);
+						getNextCh();
+					}
+					tkStr.append(1, currCh);
+					getNextCh();
+				}
+				if(currCh == '/') {
+#ifndef NO_REGEXP
+					try { regex(tkStr.substr(1), regex_constants::ECMAScript); } catch(regex_error e) {
+						throw new CScriptException(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()), currentFile, pos.currentLine, currentColumn());
+					}
+#endif /* NO_REGEXP */
+					do {
+						tkStr.append(1, currCh);
+						getNextCh();
+					} while (currCh=='g' || currCh=='i' || currCh=='m' || currCh=='y');
+				} else
+					throw new CScriptException(SyntaxError, "unterminated regular expression literal", currentFile, pos.currentLine, currentColumn());
+			} else if(currCh=='=') {
+				tk = LEX_SLASHEQUAL;
+				getNextCh();
+			}
+		} else if (tk=='%' && currCh=='=') {
+			tk = LEX_PERCENTEQUAL;
+			getNextCh();
+		}
+	}
+	/* This isn't quite right yet */
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// CScriptTokenDataForwards
+//////////////////////////////////////////////////////////////////////////
+
+bool CScriptTokenDataForwards::compare_fnc_token_by_name::operator()(const CScriptToken& lhs, const CScriptToken& rhs) const {
+	return lhs.Fnc().name < rhs.Fnc().name;
+}
+bool CScriptTokenDataForwards::checkRedefinition(const string &Str, bool checkVarsInLetScope) {
+	STRING_SET_it it = varNames[LETS].find(Str);
+	if(it!=varNames[LETS].end()) return false;
+	else if(checkVarsInLetScope) {
+		STRING_SET_it it = vars_in_letscope.find(Str);
+		if(it!=vars_in_letscope.end()) return false;
+	}
+	return true;
+}
+
+void CScriptTokenDataForwards::addVars( STRING_VECTOR_t &Vars ) {
+	varNames[VARS].insert(Vars.begin(), Vars.end());
+}
+void CScriptTokenDataForwards::addConsts( STRING_VECTOR_t &Vars ) {
+	varNames[CONSTS].insert(Vars.begin(), Vars.end());
+}
+std::string CScriptTokenDataForwards::addVarsInLetscope( STRING_VECTOR_t &Vars )
+{
+	for(STRING_VECTOR_it it=Vars.begin(); it!=Vars.end(); ++it) {
+		if(!checkRedefinition(*it, false)) return *it;
+		vars_in_letscope.insert(*it);
+	}
+	return "";
+}
+
+std::string CScriptTokenDataForwards::addLets( STRING_VECTOR_t &Lets )
+{
+	for(STRING_VECTOR_it it=Lets.begin(); it!=Lets.end(); ++it) {
+		if(!checkRedefinition(*it, true)) return *it;
+		varNames[LETS].insert(*it);
+	}
+	return "";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// CScriptTokenDataLoop
+//////////////////////////////////////////////////////////////////////////
+
+std::string CScriptTokenDataLoop::getParsableString(const string &IndentString/*=""*/, const string &Indent/*=""*/ ) {
+	static const char *heads[] = {"for each(", "for(", "for(", "for(", "while(", "do "};
+	static const char *ops[] = {" in ", " in ", " of ", "; "};
+	string out = heads[type];
+	if(init.size() && type==FOR)out.append(CScriptToken::getParsableString(init));
+	if(type<=WHILE) out.append(CScriptToken::getParsableString(condition.begin(), condition.end()-(type>=FOR ? 0 : 7)));
+	if(type<=FOR) out.append(ops[type]);
+	if(iter.size()) out.append(CScriptToken::getParsableString(iter));
+	out.append(")");
+	out.append(CScriptToken::getParsableString(body));
+	if(type==DO)out.append(" while(").append(CScriptToken::getParsableString(condition)).append(");");
+	return out;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// CScriptTokenDataTry
+//////////////////////////////////////////////////////////////////////////
+
+std::string CScriptTokenDataTry::getParsableString( const string &IndentString/*=""*/, const string &Indent/*=""*/ ) {
+	string out = "try ";
+	string nl = Indent.size() ? "\n"+IndentString : " ";
+
+	out.append(CScriptToken::getParsableString(tryBlock, IndentString, Indent));
+	for(CScriptTokenDataTry::CatchBlock_it catchBlock = catchBlocks.begin(); catchBlock!=catchBlocks.end(); catchBlock++) {
+		out.append(nl).append("catch(").append(catchBlock->indentifiers->getParsableString());
+		if(catchBlock->condition.size()>1) {
+			out.append(" if ").append(CScriptToken::getParsableString(catchBlock->condition.begin()+1, catchBlock->condition.end()));
+		}
+		out.append(") ").append(CScriptToken::getParsableString(catchBlock->block, IndentString, Indent));
+	}
+	if(finallyBlock.size())
+		out.append(nl).append("finally ").append(CScriptToken::getParsableString(finallyBlock, IndentString, Indent));
+	return out;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// CScriptTokenDataFnc
+//////////////////////////////////////////////////////////////////////////
+
+string CScriptTokenDataFnc::getArgumentsString()
+{
+	ostringstream destination;
+	destination << "(";
+	if(arguments.size()) {
+		const char *comma = "";
+		for(TOKEN_VECT_it argument=arguments.begin(); argument!=arguments.end(); ++argument, comma=", ") {
+			if(argument->token == LEX_ID)
+				destination << comma << argument->String();
+			else {
+				vector<bool> isObject(1, false);
+				for(DESTRUCTURING_VARS_it it=argument->DestructuringVar().vars.begin(); it!=argument->DestructuringVar().vars.end(); ++it) {
+					if(it->second == "}" || it->second == "]") {
+						destination << it->second;
+						isObject.pop_back();
+					} else {
+						destination << comma;
+						if(it->second == "[" || it->second == "{") {
+							comma = "";
+							if(isObject.back() && it->first.length())
+								destination << getIDString(it->first) << ":";
+							destination << it->second;
+							isObject.push_back(it->second == "{");
+						} else {
+							comma = ", ";
+							if(it->second.empty())
+								continue; // skip empty entries
+							if(isObject.back() && it->first!=it->second)
+								destination << getIDString(it->first) << ":";
+							destination << it->second;
+						}
+					}
+				}
+			}
+		}
+	}
+	destination << ") ";
+	return destination.str();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// CScriptTokenDataDestructuringVar
+//////////////////////////////////////////////////////////////////////////
+
+void CScriptTokenDataDestructuringVar::getVarNames(STRING_VECTOR_t Names) {
+	for(DESTRUCTURING_VARS_it it = vars.begin(); it != vars.end(); ++it) {
+		if(it->second.size() && it->second.find_first_of("{[]}") == string::npos)
+			Names.push_back(it->second);
+	}
+}
+
+std::string CScriptTokenDataDestructuringVar::getParsableString()
+{
+	string out;
+	const char *comma = "";
+	vector<bool> isObject(1, false);
+	for(DESTRUCTURING_VARS_it it=vars.begin(); it!=vars.end(); ++it) {
+		if(it->second == "}" || it->second == "]") {
+			out.append(it->second);
+			isObject.pop_back();
+		} else {
+			out.append(comma);
+			if(it->second == "[" || it->second == "{") {
+				comma = "";
+				if(isObject.back() && it->first.length())
+					out.append(getIDString(it->first)).append(":");
+				out.append(it->second);
+				isObject.push_back(it->second == "{");
+			} else {
+				comma = ", ";
+				if(it->second.empty())
+					continue; // skip empty entries
+				if(isObject.back() && it->first!=it->second)
+					out.append(getIDString(it->first)).append(":");
+				out.append(it->second);
+			}
+		}
+	}
+	return out;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// CScriptTokenDataObjectLiteral
+//////////////////////////////////////////////////////////////////////////
+
+void CScriptTokenDataObjectLiteral::setMode(bool Destructuring) {
+	structuring = !(destructuring = Destructuring);
+	for(vector<ELEMENT>::iterator it=elements.begin(); it!=elements.end(); ++it) {
+		if(it->value.size() && it->value.front().token == LEX_T_OBJECT_LITERAL) { 
+			CScriptTokenDataObjectLiteral& e = it->value.front().Object();
+			if(e.destructuring && e.structuring)
+				e.setMode(Destructuring);
+		}
+	}
+}
+
+string CScriptTokenDataObjectLiteral::getParsableString()
+{
+	string out = type == OBJECT ? "{ " : "[ ";
+	const char *comma = "";
+	for(vector<ELEMENT>::iterator it=elements.begin(); it!=elements.end(); ++it) {
+		out.append(comma); comma=", ";
+		if(it->value.empty()) continue;
+		if(type == OBJECT)
+			out.append(getIDString(it->id)).append(" : ");
+		out.append(CScriptToken::getParsableString(it->value));
+	}
+	out.append(type == OBJECT ? " }" : " ]");
+	return out;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// CScriptToken
+//////////////////////////////////////////////////////////////////////////
+
+typedef struct { int id; const char *str; bool need_space; } token2str_t;
+static token2str_t reserved_words_begin[] ={
+	// reserved words
+	{ LEX_R_IF,						"if",							true  },
+	{ LEX_R_ELSE,					"else",						true  },
+	{ LEX_R_DO,						"do",							true  },
+	{ LEX_R_WHILE,					"while",						true  },
+	{ LEX_R_FOR,					"for",						true  },
+	{ LEX_R_IN,						"in",							true  },
+	{ LEX_R_BREAK,					"break",						true  },
+	{ LEX_R_CONTINUE,				"continue",					true  },
+	{ LEX_R_FUNCTION,				"function",					true  },
+	{ LEX_R_RETURN,				"return",					true  },
+	{ LEX_R_VAR,					"var",						true  },
+	{ LEX_R_LET,					"let",						true  },
+	{ LEX_R_CONST,					"const",						true  },
+	{ LEX_R_WITH,					"with",						true  },
+	{ LEX_R_TRUE,					"true",						true  },
+	{ LEX_R_FALSE,					"false",						true  },
+	{ LEX_R_NULL,					"null",						true  },
+	{ LEX_R_NEW,					"new",						true  },
+	{ LEX_R_TRY,					"try",						true  },
+	{ LEX_R_CATCH,					"catch",						true  },
+	{ LEX_R_FINALLY,				"finally",					true  },
+	{ LEX_R_THROW,					"throw",						true  },
+	{ LEX_R_TYPEOF,				"typeof",					true  },
+	{ LEX_R_VOID,					"void",						true  },
+	{ LEX_R_DELETE,				"delete",					true  },
+	{ LEX_R_INSTANCEOF,			"instanceof",				true  },
+	{ LEX_R_SWITCH,				"switch",					true  },
+	{ LEX_R_CASE,					"case",						true  },
+	{ LEX_R_DEFAULT,				"default",					true  },
+};
+#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
+#define ARRAY_END(array) (&array[ARRAY_LENGTH(array)])
+static token2str_t *reserved_words_end = ARRAY_END(reserved_words_begin);//&reserved_words_begin[ARRAY_LENGTH(reserved_words_begin)];
+static token2str_t *str2reserved_begin[sizeof(reserved_words_begin)/sizeof(reserved_words_begin[0])];
+static token2str_t **str2reserved_end = &str2reserved_begin[sizeof(str2reserved_begin)/sizeof(str2reserved_begin[0])];
+static token2str_t tokens2str_begin[] = {
+	{ LEX_EOF,						"EOF",						false },
+	{ LEX_ID,						"ID",							true  },
+	{ LEX_INT,						"INT",						true  },
+	{ LEX_FLOAT,					"FLOAT",						true  },
+	{ LEX_STR,						"STRING",					true  },
+	{ LEX_REGEXP,					"REGEXP",					true  },
+	{ LEX_EQUAL,					"==",							false },
+	{ LEX_TYPEEQUAL,				"===",						false },
+	{ LEX_NEQUAL,					"!=",							false },
+	{ LEX_NTYPEEQUAL,				"!==",						false },
+	{ LEX_LEQUAL,					"<=",							false },
+	{ LEX_LSHIFT,					"<<",							false },
+	{ LEX_LSHIFTEQUAL,			"<<=",						false },
+	{ LEX_GEQUAL,					">=",							false },
+	{ LEX_RSHIFT,					">>",							false },
+	{ LEX_RSHIFTEQUAL,			">>=",						false },
+	{ LEX_RSHIFTU,					">>>",						false },
+	{ LEX_RSHIFTUEQUAL,			">>>=",						false },
+	{ LEX_PLUSEQUAL,				"+=",							false },
+	{ LEX_MINUSEQUAL,				"-=",							false },
+	{ LEX_PLUSPLUS,				"++",							false },
+	{ LEX_MINUSMINUS,				"--",							false },
+	{ LEX_ANDEQUAL,				"&=",							false },
+	{ LEX_ANDAND,					"&&",							false },
+	{ LEX_OREQUAL,					"|=",							false },
+	{ LEX_OROR,						"||",							false },
+	{ LEX_XOREQUAL,				"^=",							false },
+	{ LEX_ASTERISKEQUAL,			"*=",							false },
+	{ LEX_SLASHEQUAL,				"/=",							false },
+	{ LEX_PERCENTEQUAL,			"%=",							false },
+	// special tokens
+	{ LEX_T_OF,						"of",							true  },
+	{ LEX_T_FUNCTION_OPERATOR,	"function",					true  },
+	{ LEX_T_GET,					"get",						true  },
+	{ LEX_T_SET,					"set",						true  },
+	{ LEX_T_EXCEPTION_VAR,		"LEX_T_EXCEPTION_VAR",	false  },
+	{ LEX_T_SKIP,					"LEX_SKIP",					false  },
+	{ LEX_T_DUMMY_LABEL,			"LABEL",						true  },
+	{ LEX_T_LABEL,					"LABEL",						true  },
+	{ LEX_T_LOOP,					"LEX_LOOP",					true  },
+	{ LEX_T_FOR_IN,				"LEX_FOR_IN",				true  },
+	{ LEX_T_FORWARD,				"LEX_T_FORWARD",			false  },
+	{ LEX_T_OBJECT_LITERAL,		"LEX_OBJECT_LITERAL",	false  },
+	{ LEX_T_DESTRUCTURING_VAR,	"Destructuring Var",		false  },
+};
+static token2str_t *tokens2str_end = &tokens2str_begin[sizeof(tokens2str_begin)/sizeof(tokens2str_begin[0])];
+struct token2str_cmp_t {
+	bool operator()(const token2str_t &lhs, const token2str_t &rhs) {
+		return lhs.id < rhs.id;
+	}
+	bool operator()(const token2str_t &lhs, int rhs) {
+		return lhs.id < rhs;
+	}
+	bool operator()(const token2str_t *lhs, const token2str_t *rhs) {
+		return strcmp(lhs->str, rhs->str)<0;
+	}
+	bool operator()(const token2str_t *lhs, const char *rhs) {
+		return strcmp(lhs->str, rhs)<0;
+	}
+};
+static bool tokens2str_sort() {
+//	printf("tokens2str_sort called\n");
+	sort(tokens2str_begin, tokens2str_end, token2str_cmp_t());
+	sort(reserved_words_begin, reserved_words_end, token2str_cmp_t());
+	for(unsigned int i=0; i<ARRAY_LENGTH(str2reserved_begin); i++)
+		str2reserved_begin[i] = &reserved_words_begin[i];
+	sort(str2reserved_begin, str2reserved_end, token2str_cmp_t());
+	return true;
+}
+static bool tokens2str_sorted = tokens2str_sort();
+
+CScriptToken::CScriptToken(CScriptLex *l, int Match, int Alternate) : line(l->currentLine()), column(l->currentColumn()), token(l->tk), intData(0)
+{
+	if(token == LEX_INT || LEX_TOKEN_DATA_FLOAT(token)) {
+		CNumber number(l->tkStr);
+		if(number.isInfinity())
+			token=LEX_ID, (tokenData=new CScriptTokenDataString("Infinity"))->ref();
+		else if(number.isInt32())
+			token=LEX_INT, intData=number.toInt32();
+		else
+			token=LEX_FLOAT, floatData=new double(number.toDouble());
+	} else if(LEX_TOKEN_DATA_STRING(token))
+		(tokenData = new CScriptTokenDataString(l->tkStr))->ref();
+	else if(LEX_TOKEN_DATA_FUNCTION(token))
+		(tokenData = new CScriptTokenDataFnc)->ref();
+	else if (LEX_TOKEN_DATA_LOOP(token))
+		(tokenData = new CScriptTokenDataLoop)->ref();
+	else if (LEX_TOKEN_DATA_TRY(token))
+		(tokenData = new CScriptTokenDataTry)->ref();
+	if(Match>=0)
+		l->match(Match, Alternate);
+	else
+		l->match(l->tk); 
+#ifdef _DEBUG
+	token_str = getTokenStr(token);
+#endif
+}
+CScriptToken::CScriptToken(uint16_t Tk, int IntData) : line(0), column(0), token(Tk), intData(0) {
+	if (LEX_TOKEN_DATA_SIMPLE(token))
+		intData = IntData;
+	else if (LEX_TOKEN_DATA_FUNCTION(token))
+		(tokenData = new CScriptTokenDataFnc)->ref();
+	else if (LEX_TOKEN_DATA_DESTRUCTURING_VAR(token))
+		(tokenData = new CScriptTokenDataDestructuringVar)->ref();
+	else if (LEX_TOKEN_DATA_OBJECT_LITERAL(token))
+		(tokenData = new CScriptTokenDataObjectLiteral)->ref();
+	else if (LEX_TOKEN_DATA_LOOP(token))
+		(tokenData = new CScriptTokenDataLoop)->ref();
+	else if (LEX_TOKEN_DATA_TRY(token))
+		(tokenData = new CScriptTokenDataTry)->ref();
+	else if (LEX_TOKEN_DATA_FORWARDER(token))
+		(tokenData = new CScriptTokenDataForwards)->ref();
+	else 
+		ASSERT(0);
+#ifdef _DEBUG
+	token_str = getTokenStr(token);
+#endif
+}
+
+CScriptToken::CScriptToken(uint16_t Tk, const string &TkStr) : line(0), column(0), token(Tk), intData(0) {
+	ASSERT(LEX_TOKEN_DATA_STRING(token));
+	(tokenData = new CScriptTokenDataString(TkStr))->ref();
+#ifdef _DEBUG
+	token_str = getTokenStr(token);
+#endif
+}
+
+CScriptToken &CScriptToken::operator =(const CScriptToken &Copy)
+{
+	if(this == &Copy) return *this;
+	clear();
+#ifdef _DEBUG
+	token_str	= Copy.token_str;
+#endif
+	line			= Copy.line;
+	column		= Copy.column; 
+	token			= Copy.token;
+	if(LEX_TOKEN_DATA_FLOAT(token))
+		floatData = new double(*Copy.floatData);
+	else if(!LEX_TOKEN_DATA_SIMPLE(token))
+		(tokenData = Copy.tokenData)->ref();
+	else
+		intData	= Copy.intData;
+	return *this;
+}
+string CScriptToken::getParsableString(TOKEN_VECT &Tokens, const string &IndentString, const string &Indent) {
+	return getParsableString(Tokens.begin(), Tokens.end(), IndentString, Indent);
+}
+string CScriptToken::getParsableString(TOKEN_VECT_it Begin, TOKEN_VECT_it End, const string &IndentString, const string &Indent) {
+	ostringstream destination;
+	string nl = Indent.size() ? "\n" : " ";
+	string my_indentString = IndentString;
+	bool add_nl=false, block_start=false, need_space=false;
+	int skip_collon = 0;
+
+	for(TOKEN_VECT_it it=Begin; it != End; ++it) {
+		string OutString;
+		if(add_nl) OutString.append(nl).append(my_indentString);
+		bool old_block_start = block_start;
+		bool old_need_space = need_space;
+		add_nl = block_start = need_space =false;
+		if(it->token == LEX_STR)
+			OutString.append(getJSString(it->String())), need_space=true;
+		else if(LEX_TOKEN_DATA_STRING(it->token))
+			OutString.append(it->String()), need_space=true;
+		else if(LEX_TOKEN_DATA_FLOAT(it->token))
+			OutString.append(CNumber(it->Float()).toString()), need_space=true;
+		else if(it->token == LEX_INT)
+			OutString.append(CNumber(it->Int()).toString()), need_space=true;
+		else if(LEX_TOKEN_DATA_FUNCTION(it->token)) {
+			OutString.append("function ");
+			if(it->Fnc().name.size() )
+				OutString.append(it->Fnc().name);
+			OutString.append(it->Fnc().getArgumentsString());
+			OutString.append(getParsableString(it->Fnc().body, my_indentString, Indent));
+			if(it->Fnc().body.front().token != '{') {
+				OutString.append(";");
+			}
+		} else if(LEX_TOKEN_DATA_LOOP(it->token)) {
+			OutString.append(it->Loop().getParsableString(my_indentString, Indent));
+		} else if(LEX_TOKEN_DATA_TRY(it->token)) {
+			OutString.append(it->Try().getParsableString(my_indentString, Indent));
+		} else if(LEX_TOKEN_DATA_DESTRUCTURING_VAR(it->token)) {
+			OutString.append(it->DestructuringVar().getParsableString());
+		} else if(LEX_TOKEN_DATA_OBJECT_LITERAL(it->token)) {
+			OutString.append(it->Object().getParsableString());
+		} else if(it->token == '{') {
+			OutString.append("{");
+			my_indentString.append(Indent);
+			add_nl = block_start = true;
+		} else if(it->token == '}') {
+			my_indentString.resize(my_indentString.size() - min(my_indentString.size(),Indent.size()));
+			if(old_block_start) 
+				OutString =  "}";
+			else
+				OutString = nl + my_indentString + "}";
+			add_nl = true;
+		} else if(it->token == LEX_T_SKIP) {
+			// ignore SKIP-Token
+		} else if(it->token == LEX_T_FORWARD) {
+			// ignore Forwarder-Token
+		} else if(it->token == LEX_R_FOR) {
+			OutString.append(CScriptToken::getTokenStr(it->token));
+			skip_collon=2;
+		} else {
+			OutString.append(CScriptToken::getTokenStr(it->token,&need_space));
+			if(it->token==';') {
+				if(skip_collon) { --skip_collon; }
+				else add_nl=true; 
+			} 
+		}
+		if(need_space && old_need_space) destination << " ";
+		destination << OutString;
+	}
+	return destination.str();
+
+}
+
+void CScriptToken::clear()
+{
+	if(LEX_TOKEN_DATA_FLOAT(token))
+		delete floatData;
+	else if(!LEX_TOKEN_DATA_SIMPLE(token))
+		tokenData->unref();
+	token = 0;
+}
+string CScriptToken::getTokenStr( int token, bool *need_space/*=0*/ )
+{
+	if(!tokens2str_sorted) tokens2str_sorted=tokens2str_sort();
+	token2str_t *found = lower_bound(reserved_words_begin, reserved_words_end, token, token2str_cmp_t());
+	if(found != reserved_words_end && found->id==token) {
+		if(need_space) *need_space=found->need_space;
+		return found->str;
+	}
+	found = lower_bound(tokens2str_begin, tokens2str_end, token, token2str_cmp_t());
+	if(found != tokens2str_end && found->id==token) {
+		if(need_space) *need_space=found->need_space;
+		return found->str;
+	}
+	if(need_space) *need_space=false;
+
+	if (token>32 && token<128) {
+		char buf[2] = " ";
+		buf[0] = (char)token;
+		return buf;
+	}
+
+	ostringstream msg;
+	msg << "?[" << token << "]";
+	return msg.str();
+}
+const char *CScriptToken::isReservedWord(int Token) {
+	if(!tokens2str_sorted) tokens2str_sorted=tokens2str_sort();
+	token2str_t *found = lower_bound(reserved_words_begin, reserved_words_end, Token, token2str_cmp_t());
+	if(found != reserved_words_end && found->id==Token) {
+		return found->str;
+	}
+	return 0;
+}
+int CScriptToken::isReservedWord(const string &Str) {
+	const char *str = Str.c_str();
+	if(!tokens2str_sorted) tokens2str_sorted=tokens2str_sort();
+	token2str_t **found = lower_bound(str2reserved_begin, str2reserved_end, str, token2str_cmp_t());
+	if(found != str2reserved_end && strcmp((*found)->str, str)==0) {
+		return (*found)->id;
+	}
+	return LEX_ID;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptTokenizer
+//////////////////////////////////////////////////////////////////////////
+
+CScriptTokenizer::CScriptTokenizer() : l(0), prevPos(&tokens) {
+}
+CScriptTokenizer::CScriptTokenizer(CScriptLex &Lexer) : l(0), prevPos(&tokens) {
+	tokenizeCode(Lexer);
+}
+CScriptTokenizer::CScriptTokenizer(const char *Code, const string &File, int Line, int Column) : l(0), prevPos(&tokens) {
+	CScriptLex lexer(Code, File, Line, Column);
+	tokenizeCode(lexer);
+}
+void CScriptTokenizer::tokenizeCode(CScriptLex &Lexer) {
+	try {
+		l=&Lexer;
+		tokens.clear();
+		tokenScopeStack.clear();
+		ScriptTokenState state;
+		pushForwarder(state);
+		if(l->tk == '§') { // special-Token at Start means the code begins not at Statement-Level
+			l->match('§');
+			tokenizeLiteral(state, 0);
+		} else do {
+			tokenizeStatement(state, 0);
+		} while (l->tk!=LEX_EOF);
+		pushToken(state.Tokens, LEX_EOF); // add LEX_EOF-Token
+		removeEmptyForwarder(state);
+//		TOKEN_VECT(tokens).swap(tokens);//	tokens.shrink_to_fit();
+		tokens.swap(state.Tokens);
+		pushTokenScope(tokens);
+		currentFile = l->currentFile;
+		tk = getToken().token;
+	} catch (...) {
+		l=0;
+		throw;
+	}
+}
+
+void CScriptTokenizer::getNextToken() {
+	prevPos = tokenScopeStack.back();
+	if(getToken().token == LEX_EOF) 
+		return;
+	ScriptTokenPosition &_TokenPos = tokenScopeStack.back();
+	_TokenPos.pos++;
+	if(_TokenPos.pos == _TokenPos.tokens->end())
+		tokenScopeStack.pop_back();
+//	ScriptTokenPosition &TokenPos = tokenScopeStack.back();
+	tk = getToken().token;
+}
+
+
+
+void CScriptTokenizer::match(int ExpectedToken, int AlternateToken/*=-1*/) {
+	if(check(ExpectedToken, AlternateToken))
+		getNextToken();
+}
+bool CScriptTokenizer::check(int ExpectedToken, int AlternateToken/*=-1*/) {
+	int currentToken = getToken().token;
+	if (ExpectedToken==';' && (currentToken==LEX_EOF || currentToken=='}')) return false; // ignore last missing ';'
+	if (currentToken!=ExpectedToken && currentToken!=AlternateToken) {
+		ostringstream errorString;
+		if(ExpectedToken == LEX_EOF)
+			errorString << "Got unexpected " << CScriptToken::getTokenStr(currentToken);
+		else {
+			errorString << "Got '" << CScriptToken::getTokenStr(currentToken) << "' expected '" << CScriptToken::getTokenStr(ExpectedToken) << "'";
+			if(AlternateToken!=-1) errorString << " or '" << CScriptToken::getTokenStr(AlternateToken) << "'";
+		}
+		throw new CScriptException(SyntaxError, errorString.str(), currentFile, currentLine(), currentColumn());
+	}
+	return true;
+}
+void CScriptTokenizer::pushTokenScope(TOKEN_VECT &Tokens) {
+	tokenScopeStack.push_back(ScriptTokenPosition(&Tokens));
+	tk = getToken().token;
+}
+
+void CScriptTokenizer::setPos(ScriptTokenPosition &TokenPos) {
+	ASSERT( TokenPos.tokens == tokenScopeStack.back().tokens);
+	tokenScopeStack.back().pos = TokenPos.pos;
+	tk = getToken().token;
+}
+void CScriptTokenizer::skip(int Tokens) {
+	ASSERT(tokenScopeStack.back().tokens->end()-tokenScopeStack.back().pos-Tokens>=0);
+	tokenScopeStack.back().pos+=Tokens-1;
+	getNextToken();
+}
+
+static inline void setTokenSkip(CScriptTokenizer::ScriptTokenState &State) {
+	int tokenBeginIdx = State.Marks.back();
+	State.Marks.pop_back();
+	State.Tokens[tokenBeginIdx].Int() = State.Tokens.size()-tokenBeginIdx;
+}
+
+enum {
+	TOKENIZE_FLAGS_canLabel			= 1<<0,
+	TOKENIZE_FLAGS_canBreak			= 1<<1,
+	TOKENIZE_FLAGS_canContinue		= 1<<2,
+	TOKENIZE_FLAGS_canReturn		= 1<<3,
+	TOKENIZE_FLAGS_asStatement		= 1<<4,
+	TOKENIZE_FLAGS_noIn				= 1<<5,
+	TOKENIZE_FLAGS_isAccessor		= 1<<6,
+	TOKENIZE_FLAGS_callForNew		= 1<<7,
+	TOKENIZE_FLAGS_noBlockStart	= 1<<8,
+	TOKENIZE_FLAGS_nestedObject	= 1<<9,
+};
+void CScriptTokenizer::tokenizeTry(ScriptTokenState &State, int Flags) {
+	l->match(LEX_R_TRY);
+	CScriptToken TryToken(LEX_T_TRY);
+	CScriptTokenDataTry &TryData = TryToken.Try();
+	pushToken(State.Tokens, TryToken);
+
+	TOKEN_VECT mainTokens;
+	State.Tokens.swap(mainTokens);
+
+	// try-block
+	tokenizeBlock(State, Flags);
+	State.Tokens.swap(TryData.tryBlock);
+
+	// catch-blocks
+	l->check(LEX_R_CATCH, LEX_R_FINALLY);
+	bool unconditionalCatch = false;
+	while(l->tk == LEX_R_CATCH) {
+		if(unconditionalCatch) throw new CScriptException(SyntaxError, "catch after unconditional catch", l->currentFile, l->currentLine(), l->currentColumn());
+
+		// vars & condition
+		l->match(LEX_R_CATCH);
+		l->match('(');
+		TryData.catchBlocks.resize(TryData.catchBlocks.size()+1);
+		CScriptTokenDataTry::CatchBlock &catchBlock = TryData.catchBlocks.back();
+		pushForwarder(State, true);
+		STRING_VECTOR_t vars;
+		catchBlock.indentifiers = tokenizeVarIdentifier(&vars).DestructuringVar();
+		State.Forwarders.back()->addLets(vars);
+		if(l->tk == LEX_R_IF) {
+			l->match(LEX_R_IF);
+			tokenizeExpression(State, Flags);
+		} else
+			unconditionalCatch = true;
+		State.Tokens.swap(catchBlock.condition);
+		l->match(')');
+
+		// catch-block
+		tokenizeBlock(State, Flags | TOKENIZE_FLAGS_noBlockStart);
+		State.Tokens.swap(catchBlock.block);
+		State.Forwarders.pop_back();
+	}
+	// finally-block
+	if(l->tk == LEX_R_FINALLY) {
+		l->match(LEX_R_FINALLY);
+		tokenizeBlock(State, Flags);
+		State.Tokens.swap(TryData.finallyBlock);
+	}
+	State.Tokens.swap(mainTokens);
+}
+void CScriptTokenizer::tokenizeSwitch(ScriptTokenState &State, int Flags) {
+
+	State.Marks.push_back(pushToken(State.Tokens)); // push Token & push tokenBeginIdx
+	pushToken(State.Tokens, '(');
+	tokenizeExpression(State, Flags);
+	pushToken(State.Tokens, ')');
+
+	State.Marks.push_back(pushToken(State.Tokens, '{')); // push Token & push blockBeginIdx
+	pushForwarder(State);
+	
+
+	vector<int>::size_type MarksSize = State.Marks.size();
+	Flags |= TOKENIZE_FLAGS_canBreak;
+	for(bool hasDefault=false;;) {
+		if( l->tk == LEX_R_CASE || l->tk == LEX_R_DEFAULT) {
+			if(l->tk == LEX_R_CASE) {
+				State.Marks.push_back(pushToken(State.Tokens)); // push Token & push caseBeginIdx
+				State.Marks.push_back(pushToken(State.Tokens,CScriptToken(LEX_T_SKIP))); //  skipper to skip case-expression
+				tokenizeExpression(State, Flags); 
+				setTokenSkip(State);
+			} else { // default
+				State.Marks.push_back(pushToken(State.Tokens)); // push Token & push caseBeginIdx
+				if(hasDefault) throw new CScriptException(SyntaxError, "more than one switch default", l->currentFile, l->currentLine(), l->currentColumn());
+				hasDefault = true;
+			}
+
+			State.Marks.push_back(pushToken(State.Tokens, ':'));
+			while(l->tk != '}' && l->tk != LEX_R_CASE && l->tk != LEX_R_DEFAULT && l->tk != LEX_EOF )
+				tokenizeStatement(State, Flags); 
+			setTokenSkip(State);
+		} else if(l->tk == '}')
+			break;
+		else
+			throw new CScriptException(SyntaxError, "invalid switch statement", l->currentFile, l->currentLine(), l->currentColumn());
+	}
+	while(MarksSize < State.Marks.size()) setTokenSkip(State);
+	removeEmptyForwarder(State); // remove Forwarder if empty
+	pushToken(State.Tokens, '}');
+	setTokenSkip(State); // switch-block
+	setTokenSkip(State); // switch-statement
+}
+void CScriptTokenizer::tokenizeWith(ScriptTokenState &State, int Flags) {
+	State.Marks.push_back(pushToken(State.Tokens)); // push Token & push tokenBeginIdx
+
+	pushToken(State.Tokens, '(');
+	tokenizeExpression(State, Flags);
+	pushToken(State.Tokens, ')');
+	tokenizeStatementNoLet(State, Flags);
+
+	setTokenSkip(State);
+}
+
+static inline uint32_t GetLoopLabels(CScriptTokenizer::ScriptTokenState &State, CScriptTokenDataLoop &LoopData) {
+	uint32_t label_count = 0;
+	if(State.Tokens.size()>=2) {
+		for(TOKEN_VECT::reverse_iterator it = State.Tokens.rbegin(); it!=State.Tokens.rend(); ++it) {
+			if(it->token == ':' && (++it)->token == LEX_T_LABEL) {
+				++label_count;
+				LoopData.labels.push_back(it->String());
+				State.LoopLabels.push_back(it->String());
+				it->token = LEX_T_DUMMY_LABEL;
+			} else 
+				break;
+		}
+	}
+	return label_count;
+}
+static inline void PopLoopLabels(uint32_t label_count, STRING_VECTOR_t &LoopLabels) {
+	ASSERT(label_count <= LoopLabels.size());
+	LoopLabels.resize(LoopLabels.size()-label_count);
+}
+void CScriptTokenizer::tokenizeWhileAndDo(ScriptTokenState &State, int Flags) {
+	
+	bool do_while = l->tk==LEX_R_DO;
+
+	CScriptToken LoopToken(LEX_T_LOOP);
+	CScriptTokenDataLoop &LoopData = LoopToken.Loop();
+	LoopData.type = do_while ? CScriptTokenDataLoop::DO : CScriptTokenDataLoop::WHILE;
+
+	// get loop-labels
+	uint32_t label_count = GetLoopLabels(State, LoopData);
+
+	l->match(l->tk); // match while or do
+
+	pushToken(State.Tokens, LoopToken);
+	
+	TOKEN_VECT mainTokens;
+	State.Tokens.swap(mainTokens);
+
+	if(!do_while) {
+		l->match('(');
+		tokenizeExpression(State, Flags);
+		State.Tokens.swap(LoopData.condition);
+		l->match(')');
+	}
+	tokenizeStatementNoLet(State, Flags | TOKENIZE_FLAGS_canBreak | TOKENIZE_FLAGS_canContinue);
+	State.Tokens.swap(LoopData.body);
+	if(do_while) {
+		l->match(LEX_R_WHILE);
+		l->match('(');
+		tokenizeExpression(State, Flags);
+		State.Tokens.swap(LoopData.condition);
+		l->match(')');
+		l->match(';');
+	}
+	State.Tokens.swap(mainTokens);
+	PopLoopLabels(label_count, State.LoopLabels);
+}
+
+void CScriptTokenizer::tokenizeIf(ScriptTokenState &State, int Flags) {
+
+	State.Marks.push_back(pushToken(State.Tokens)); // push Token & push tokenBeginIdx
+
+	pushToken(State.Tokens, '(');
+	tokenizeExpression(State, Flags);
+	pushToken(State.Tokens, ')');
+	State.Marks.push_back(pushToken(State.Tokens, CScriptToken(LEX_T_SKIP))); // push skip & skiperBeginIdx
+	tokenizeStatementNoLet(State, Flags);
+
+	setTokenSkip(State);
+
+	if(l->tk == LEX_R_ELSE) {
+		State.Marks.push_back(pushToken(State.Tokens)); // push Token & push tokenBeginIdx
+		tokenizeStatementNoLet(State, Flags);
+		setTokenSkip(State);
+	}
+
+	setTokenSkip(State);
+}
+
+void CScriptTokenizer::tokenizeFor(ScriptTokenState &State, int Flags) {
+	bool for_in=false, for_of=false, for_each_in=false;
+	CScriptToken LoopToken(LEX_T_LOOP);
+	CScriptTokenDataLoop &LoopData = LoopToken.Loop();
+
+	// get loop-labels
+	uint32_t label_count = GetLoopLabels(State, LoopData);
+
+	l->match(LEX_R_FOR);
+	if((for_in = for_each_in = (l->tk == LEX_ID && l->tkStr == "each")))
+		l->match(LEX_ID); // match "each"
+
+	pushToken(State.Tokens, LoopToken);
+
+	l->match('(');
+	TOKEN_VECT mainTokens;
+	State.Tokens.swap(mainTokens);
+
+	bool haveLetScope = false;
+
+	if(l->tk == LEX_R_VAR || l->tk == LEX_R_LET) {
+		if(l->tk == LEX_R_VAR)
+			tokenizeVarNoConst(State, Flags | TOKENIZE_FLAGS_noIn);
+		else { //if(l->tk == LEX_R_LET)
+			haveLetScope = true;
+			pushForwarder(State, true); // no clean up empty tokenizer
+			tokenizeLet(State, Flags | TOKENIZE_FLAGS_noIn | TOKENIZE_FLAGS_asStatement);
+		}
+	} else if(l->tk!=';') {
+		tokenizeExpression(State, Flags | TOKENIZE_FLAGS_noIn);
+	}
+	if((for_in=(l->tk==LEX_R_IN || (l->tk==LEX_ID && l->tkStr=="of")))) {
+		if(!State.LeftHand)
+			throw new CScriptException(ReferenceError, "invalid for/in left-hand side", l->currentFile, l->currentLine(), l->currentColumn());
+		if(l->tk==LEX_ID && l->tkStr=="of") l->tk = LEX_T_OF; // fake token
+		if((for_of = (!for_each_in && l->tk==LEX_T_OF))) {
+			l->match(LEX_T_OF);
+			LoopData.type = CScriptTokenDataLoop::FOR_OF;
+		} else {
+			l->match(LEX_R_IN);
+			LoopData.type = for_each_in ? CScriptTokenDataLoop::FOR_EACH : CScriptTokenDataLoop::FOR_IN;
+		}
+		State.Tokens.swap(LoopData.condition);
+
+		if(LoopData.condition.front().token == LEX_T_FORWARD) {
+			LoopData.init.push_back(LoopData.condition.front());
+			LoopData.condition.erase(LoopData.condition.begin());
+		}
+		mainTokens.back().token = LEX_T_FOR_IN;
+	} else {
+		l->check(';'); // no automatic ;-injection
+		pushToken(State.Tokens, ';');
+		State.Tokens.swap(LoopData.init);
+		if(l->tk != ';') tokenizeExpression(State, Flags);
+		l->check(';'); // no automatic ;-injection
+		l->match(';'); // no automatic ;-injection
+		State.Tokens.swap(LoopData.condition);
+	}
+
+	if(for_in || l->tk != ')') tokenizeExpression(State, Flags); 
+	l->match(')');
+	State.Tokens.swap(LoopData.iter);
+	Flags = TOKENIZE_FLAGS_canBreak | TOKENIZE_FLAGS_canContinue;
+	if(haveLetScope) Flags |= TOKENIZE_FLAGS_noBlockStart;
+	tokenizeStatementNoLet(State, Flags);
+	if(haveLetScope) State.Forwarders.pop_back();
+
+	State.Tokens.swap(LoopData.body);
+	State.Tokens.swap(mainTokens);
+	if(for_in) {
+		LoopData.condition.push_back('=');
+		LoopData.condition.push_back(LEX_T_EXCEPTION_VAR);
+		LoopData.condition.push_back('.');
+		LoopData.condition.push_back(CScriptToken(LEX_ID, "next"));
+		LoopData.condition.push_back('(');
+		LoopData.condition.push_back(')');
+		LoopData.condition.push_back(';');
+	}
+	PopLoopLabels(label_count, State.LoopLabels);
+}
+
+static void tokenizeVarIdentifierDestructuring( CScriptLex *Lexer, DESTRUCTURING_VARS_t &Vars, const std::string &Path, STRING_VECTOR_t *VarNames );
+static void tokenizeVarIdentifierDestructuringObject(CScriptLex *Lexer, DESTRUCTURING_VARS_t &Vars, STRING_VECTOR_t *VarNames) {
+	Lexer->match('{');
+	while(Lexer->tk != '}') {
+		CScriptLex::POS prev_pos = Lexer->pos;
+		string Path = Lexer->tkStr;
+		Lexer->match(LEX_ID, LEX_STR);
+		if(Lexer->tk == ':') {
+			Lexer->match(':');
+			tokenizeVarIdentifierDestructuring(Lexer, Vars, Path, VarNames);
+		} else {
+			Lexer->reset(prev_pos);
+			if(VarNames) VarNames->push_back(Lexer->tkStr);
+			Vars.push_back(DESTRUCTURING_VAR_t(Lexer->tkStr, Lexer->tkStr));
+			Lexer->match(LEX_ID);
+		}
+		if (Lexer->tk!='}') Lexer->match(',', '}'); 
+	}
+	Lexer->match('}');
+}
+static void tokenizeVarIdentifierDestructuringArray(CScriptLex *Lexer, DESTRUCTURING_VARS_t &Vars, STRING_VECTOR_t *VarNames) {
+	int idx = 0;
+	Lexer->match('[');
+	while(Lexer->tk != ']') {
+		if(Lexer->tk == ',')
+			Vars.push_back(DESTRUCTURING_VAR_t("", "")); // empty
+		else
+			tokenizeVarIdentifierDestructuring(Lexer, Vars, int2string(idx), VarNames);
+		++idx;
+		if (Lexer->tk!=']') Lexer->match(',',']'); 
+	}
+	Lexer->match(']');
+}
+static void tokenizeVarIdentifierDestructuring(CScriptLex *Lexer, DESTRUCTURING_VARS_t &Vars, const std::string &Path, STRING_VECTOR_t *VarNames ) {
+	if(Lexer->tk == '[') {
+		Vars.push_back(DESTRUCTURING_VAR_t(Path, "[")); // marks array begin
+		tokenizeVarIdentifierDestructuringArray(Lexer, Vars, VarNames);
+		Vars.push_back(DESTRUCTURING_VAR_t("", "]")); // marks array end
+	} else if(Lexer->tk == '{') {
+		Vars.push_back(DESTRUCTURING_VAR_t(Path, "{")); // marks object begin
+		tokenizeVarIdentifierDestructuringObject(Lexer, Vars, VarNames);
+		Vars.push_back(DESTRUCTURING_VAR_t("", "}")); // marks object end
+	} else {
+		if(VarNames) VarNames->push_back(Lexer->tkStr);
+		Vars.push_back(DESTRUCTURING_VAR_t(Path, Lexer->tkStr));
+		Lexer->match(LEX_ID);
+	}
+}
+CScriptToken CScriptTokenizer::tokenizeVarIdentifier( STRING_VECTOR_t *VarNames/*=0*/, bool *NeedAssignment/*=0*/ ) {
+	CScriptToken token(LEX_T_DESTRUCTURING_VAR);
+	if(NeedAssignment) *NeedAssignment=(l->tk == '[' || l->tk=='{');
+	token.column = l->currentColumn();
+	token.line = l->currentLine();
+	tokenizeVarIdentifierDestructuring(l, token.DestructuringVar().vars, "", VarNames);
+	return token;
+}
+
+void CScriptTokenizer::tokenizeFunction(ScriptTokenState &State, int Flags, bool noLetDef/*=false*/) {
+	bool forward = false;
+	bool Statement = (Flags & TOKENIZE_FLAGS_asStatement) != 0;
+	bool Accessor = (Flags & TOKENIZE_FLAGS_isAccessor) != 0;
+
+	int tk = l->tk;
+	if(Accessor) {
+		tk = State.Tokens.back().String()=="get"?LEX_T_GET:LEX_T_SET;
+		State.Tokens.pop_back();
+	} else {
+		l->match(LEX_R_FUNCTION);
+		if(!Statement) tk = LEX_T_FUNCTION_OPERATOR;
+	}
+	if(tk == LEX_R_FUNCTION) // only forward functions 
+		forward = !noLetDef && State.Forwarders.front() == State.Forwarders.back();
+
+	CScriptToken FncToken(tk);
+	CScriptTokenDataFnc &FncData = FncToken.Fnc();
+
+	if(l->tk == LEX_ID || Accessor) {
+		FncData.name = l->tkStr;
+		l->match(LEX_ID, LEX_STR);
+	} else if(Statement)
+		throw new CScriptException(SyntaxError, "Function statement requires a name.", l->currentFile, l->currentLine(), l->currentColumn());
+	l->match('(');
+	while(l->tk != ')') {
+		FncData.arguments.push_back(tokenizeVarIdentifier());
+		if (l->tk!=')') l->match(',',')'); 
+	}
+	// l->match(')');
+	// to allow regexp at the beginning of a lambda-function fake last token
+	l->tk = '{';
+	l->match('{');
+	FncData.file = l->currentFile;
+	FncData.line = l->currentLine();
+
+	ScriptTokenState functionState;
+	if(l->tk == '{' || tk==LEX_T_GET || tk==LEX_T_SET)
+		tokenizeBlock(functionState, TOKENIZE_FLAGS_canReturn);
+	else {
+		tokenizeExpression(functionState, 0);
+		l->match(';');
+	}
+	functionState.Tokens.swap(FncData.body);
+	if(forward) {
+		State.Forwarders.front()->functions.insert(FncToken);
+		FncToken.token = LEX_T_FUNCTION_PLACEHOLDER;
+	}
+	State.Tokens.push_back(FncToken);
+}
+
+void CScriptTokenizer::tokenizeLet(ScriptTokenState &State, int Flags, bool noLetDef/*=false*/) {
+	bool Definition = (Flags & TOKENIZE_FLAGS_asStatement)!=0; 
+	bool noIN = (Flags & TOKENIZE_FLAGS_noIn)!=0;
+	bool Statement = Definition & !noIN;
+	bool Expression = !Definition;
+	Flags &= ~(TOKENIZE_FLAGS_asStatement);
+	if(!Definition) noIN=false, Flags &= ~TOKENIZE_FLAGS_noIn;
+
+	bool foundIN = false;
+	bool leftHand = true;
+	int currLine = l->currentLine(), currColumn = l->currentColumn();
+
+	State.Marks.push_back(pushToken(State.Tokens)); // push Token & push BeginIdx
+
+	if(l->tk == '(' || !Definition) { // no definition needs statement or expression
+		leftHand = false;
+		Expression = true;
+		pushToken(State.Tokens, '(');
+		pushForwarder(State);
+	} else if(noLetDef)
+		throw new CScriptException(SyntaxError, "let declaration not directly within block", l->currentFile, currLine, currColumn);
+	STRING_VECTOR_t vars;
+	for(;;) {
+		bool needAssignment = false;
+		State.Tokens.push_back(tokenizeVarIdentifier(&vars, &needAssignment));
+		if(noIN && (foundIN=(l->tk==LEX_R_IN || (l->tk==LEX_ID && l->tkStr=="of")))) 
+			break;
+		if(needAssignment || l->tk=='=') {
+			leftHand = false;
+			pushToken(State.Tokens, '=');
+			tokenizeAssignment(State, Flags);
+			if(noIN && (foundIN=(l->tk==LEX_R_IN || (l->tk==LEX_ID && l->tkStr=="of")))) 
+				break;
+		}
+		if(l->tk==',') {
+			leftHand = false;
+			pushToken(State.Tokens);
+		}
+		else
+			break;
+	}
+	if(Expression) {
+		string redeclared = State.Forwarders.back()->addLets(vars);
+		if(redeclared.size())
+			throw new CScriptException(TypeError, "redeclaration of variable '"+redeclared+"'", l->currentFile, currLine, currColumn);
+		if(!foundIN) {
+			pushToken(State.Tokens, ')');
+			if(Statement) { 
+				if(l->tk == '{') // no extra BlockStart by expression
+					tokenizeBlock(State, Flags|=TOKENIZE_FLAGS_noBlockStart);
+				else
+					tokenizeStatementNoLet(State, Flags);
+			} else
+				tokenizeAssignment(State, Flags);
+		}
+		// never remove Forwarder-token here -- popForwarder(Tokens, BlockStart, Marks);
+		State.Forwarders.back()->vars_in_letscope.clear(); // only clear vars_in_letscope
+		State.Marks.pop_back();
+	} else {
+		if(!noIN) pushToken(State.Tokens, ';');
+
+		string redeclared;
+		if(State.Forwarders.size()<=1) {
+			// Currently it is allowed in javascript, to redeclare "let"-declared vars
+			// in root- or function-scopes. In this case, "let" handled like "var"
+			// To prevent redeclaration in root- or function-scopes define PREVENT_REDECLARATION_IN_FUNCTION_SCOPES 
+#ifdef PREVENT_REDECLARATION_IN_FUNCTION_SCOPES
+			redeclared = State.Forwarders.front()->addLets(vars);
+#else
+			State.Forwarders.front()->addVars(vars);
+#endif
+		} else
+			redeclared = State.Forwarders.back()->addLets(vars);
+		if(redeclared.size())
+			throw new CScriptException(TypeError, "redeclaration of variable '"+redeclared+"'", l->currentFile, currLine, currColumn);
+	}
+	setTokenSkip(State);
+	if(leftHand) State.LeftHand = true;
+}
+
+void CScriptTokenizer::tokenizeVarNoConst( ScriptTokenState &State, int Flags) {
+	l->check(LEX_R_VAR);
+	tokenizeVarAndConst(State, Flags);
+}
+void CScriptTokenizer::tokenizeVarAndConst( ScriptTokenState &State, int Flags) {
+	bool noIN = (Flags & TOKENIZE_FLAGS_noIn)!=0;
+	int currLine = l->currentLine(), currColumn = l->currentColumn();
+
+	bool leftHand = true;
+	int tk = l->tk;
+	State.Marks.push_back(pushToken(State.Tokens)); // push Token & push BeginIdx
+
+	STRING_VECTOR_t vars;
+	for(;;) 
+	{
+		bool needAssignment = false;
+		State.Tokens.push_back(tokenizeVarIdentifier(&vars, &needAssignment));
+		if(noIN && (l->tk==LEX_R_IN || (l->tk==LEX_ID && l->tkStr=="of"))) 
+			break;
+		if(needAssignment || l->tk=='=') {
+			leftHand = false;
+			pushToken(State.Tokens, '=');
+			tokenizeAssignment(State, Flags);
+			if(noIN && (l->tk==LEX_R_IN || (l->tk==LEX_ID && l->tkStr=="of"))) 
+				break;
+		}
+		if(l->tk==',') {
+			leftHand = false;
+			pushToken(State.Tokens);
+		}
+		else
+			break;
+	}
+	if(!noIN) pushToken(State.Tokens, ';');
+
+	setTokenSkip(State);
+
+	if(tk==LEX_R_VAR)
+		State.Forwarders.front()->addVars(vars);
+	else
+		State.Forwarders.front()->addConsts(vars);
+	string redeclared;
+	if(State.Forwarders.size()>1) // have let-scope
+		redeclared = State.Forwarders.back()->addVarsInLetscope(vars);
+#ifdef PREVENT_REDECLARATION_IN_FUNCTION_SCOPES
+	else
+		redeclared = State.Forwarders.front()->addVarsInLetscope(vars);
+#endif
+	if(redeclared.size())
+		throw new CScriptException(TypeError, "redeclaration of variable '"+redeclared+"'", l->currentFile, currLine, currColumn);
+	if(leftHand) State.LeftHand = true;
+}
+
+void CScriptTokenizer::_tokenizeLiteralObject(ScriptTokenState &State, int Flags) {
+	bool forFor = (Flags & TOKENIZE_FLAGS_noIn)!=0;
+	bool nestedObject = 	(Flags & TOKENIZE_FLAGS_nestedObject) != 0; 
+	Flags &= ~(TOKENIZE_FLAGS_noIn | TOKENIZE_FLAGS_nestedObject);
+	CScriptToken ObjectToken(LEX_T_OBJECT_LITERAL);
+	CScriptTokenDataObjectLiteral &Objc = ObjectToken.Object();
+
+	Objc.type = CScriptTokenDataObjectLiteral::OBJECT;
+	Objc.destructuring = Objc.structuring = true;
+
+	string msg, msgFile;
+	int msgLine=0, msgColumn=0;
+
+	l->match('{');
+	while (l->tk != '}') {
+		CScriptTokenDataObjectLiteral::ELEMENT element;
+		bool assign = false;
+		if(CScriptToken::isReservedWord(l->tk))
+			l->tk = LEX_ID; // fake reserved-word as member.ID
+		if(l->tk == LEX_ID) {
+			element.id = l->tkStr;
+			CScriptToken Token(l, LEX_ID);
+			if((l->tk==LEX_ID || l->tk==LEX_STR ) && (element.id=="get" || element.id=="set")) {
+				element.id = l->tkStr;
+				element.value.push_back(Token);
+				State.Tokens.swap(element.value);
+				tokenizeFunction(State, Flags|TOKENIZE_FLAGS_isAccessor);
+				State.Tokens.swap(element.value);
+				Objc.destructuring = false;
+			} else {
+				if(Objc.destructuring && (l->tk == ',' || l->tk == '}')) {
+					if(!msg.size()) {
+						Objc.structuring = false;
+						msg.append("Got '").append(CScriptToken::getTokenStr(l->tk)).append("' expected ':'");
+						msgFile = l->currentFile;
+						msgLine = l->currentLine();
+						msgColumn = l->currentColumn();
+						;
+					}
+					element.value.push_back(Token);
+				} else
+					assign = true;
+			}
+		} else if(l->tk == LEX_INT) {
+			element.id = int2string((int32_t)strtol(l->tkStr.c_str(),0,0)); 
+			l->match(LEX_INT);
+			assign = true;
+		} else if(l->tk == LEX_FLOAT) {
+			element.id = float2string(strtod(l->tkStr.c_str(),0)); 
+			l->match(LEX_FLOAT);
+			assign = true;
+		} else if(LEX_TOKEN_DATA_STRING(l->tk) && l->tk != LEX_REGEXP) {
+			element.id = l->tkStr; 
+			l->match(l->tk);
+			assign = true;
+		} else
+			l->match(LEX_ID, LEX_STR);
+		if(assign) {
+			l->match(':');
+			int dFlags = Flags | (l->tk == '{' || l->tk == '[') ? TOKENIZE_FLAGS_nestedObject : 0;
+			State.pushLeftHandState();
+			State.Tokens.swap(element.value);
+			tokenizeAssignment(State, dFlags);
+			State.Tokens.swap(element.value);
+			if(Objc.destructuring) Objc.destructuring = State.LeftHand;
+			State.popLeftHandeState();
+		}
+		
+		if(!Objc.destructuring && msg.size())
+			throw new CScriptException(SyntaxError, msg, msgFile, msgLine, msgColumn);
+		Objc.elements.push_back(element);
+		if (l->tk != '}') l->match(',', '}');
+	}
+	l->match('}');
+	if(Objc.destructuring && Objc.structuring) {
+		if(nestedObject) {
+			if(l->tk!=',' && l->tk!='}' && l->tk!='=')
+				Objc.destructuring = false;
+		}
+		else 
+			Objc.setMode(l->tk=='=' || (forFor && (l->tk==LEX_R_IN ||(l->tk==LEX_ID && l->tkStr=="of"))));
+	} else {
+		if(!Objc.destructuring && msg.size())
+			throw new CScriptException(SyntaxError, msg, msgFile, msgLine, msgColumn);
+		if(!nestedObject) Objc.setMode(Objc.destructuring);
+	}
+
+	if(Objc.destructuring)
+		State.LeftHand = true;
+	State.Tokens.push_back(ObjectToken);
+}
+void CScriptTokenizer::_tokenizeLiteralArray(ScriptTokenState &State, int Flags) {
+	bool forFor = (Flags & TOKENIZE_FLAGS_noIn)!=0;
+	bool nestedObject = 	(Flags & TOKENIZE_FLAGS_nestedObject) != 0; 
+	Flags &= ~(TOKENIZE_FLAGS_noIn | TOKENIZE_FLAGS_nestedObject);
+	CScriptToken ObjectToken(LEX_T_OBJECT_LITERAL);
+	CScriptTokenDataObjectLiteral &Objc = ObjectToken.Object();
+
+	Objc.type = CScriptTokenDataObjectLiteral::ARRAY;
+	Objc.destructuring = Objc.structuring = true;
+	int idx = 0;
+
+	l->match('[');
+	while (l->tk != ']') {
+		CScriptTokenDataObjectLiteral::ELEMENT element;
+		element.id = int2string(idx++);
+		if(l->tk != ',') {
+			int dFlags = Flags | (l->tk == '{' || l->tk == '[') ? TOKENIZE_FLAGS_nestedObject : 0;
+			State.pushLeftHandState();
+			State.Tokens.swap(element.value);
+			tokenizeAssignment(State, dFlags);
+			State.Tokens.swap(element.value);
+			if(Objc.destructuring) Objc.destructuring = State.LeftHand;
+			State.popLeftHandeState();
+		}
+		Objc.elements.push_back(element);
+		if (l->tk != ']') l->match(',', ']');
+	}
+	l->match(']');
+	if(Objc.destructuring && Objc.structuring) {
+		if(nestedObject) {
+			if(l->tk!=',' && l->tk!=']' && l->tk!='=')
+				Objc.destructuring = false;
+		}
+		else 
+			Objc.setMode(l->tk=='=' || (forFor && (l->tk==LEX_R_IN ||(l->tk==LEX_ID && l->tkStr=="of"))));
+	} else 
+		if(!nestedObject) Objc.setMode(Objc.destructuring);
+	if(Objc.destructuring)
+		State.LeftHand = true;
+	State.Tokens.push_back(ObjectToken);
+}
+
+void CScriptTokenizer::tokenizeLiteral(ScriptTokenState &State, int Flags) {
+	State.LeftHand = 0;
+	bool canLabel = Flags & TOKENIZE_FLAGS_canLabel; Flags &= ~TOKENIZE_FLAGS_canLabel;
+	int ObjectLiteralFlags = Flags;
+	Flags &= ~TOKENIZE_FLAGS_noIn;
+	switch(l->tk) {
+	case LEX_ID:
+		{
+			string label = l->tkStr;
+			pushToken(State.Tokens);
+			if(l->tk==':' && canLabel) {
+				if(find(State.Labels.begin(), State.Labels.end(), label) != State.Labels.end()) 
+					throw new CScriptException(SyntaxError, "dublicate label '"+label+"'", l->currentFile, l->currentLine(), l->currentColumn()-label.size());
+				State.Tokens[State.Tokens.size()-1].token = LEX_T_LABEL; // change LEX_ID to LEX_T_LABEL
+				State.Labels.push_back(label);
+			} else if(label=="this") {
+				if( l->tk == '=' || (l->tk >= LEX_ASSIGNMENTS_BEGIN && l->tk <= LEX_ASSIGNMENTS_END) )
+					throw new CScriptException(SyntaxError, "invalid assignment left-hand side", l->currentFile, l->currentLine(), l->currentColumn()-label.size());
+				if( l->tk==LEX_PLUSPLUS || l->tk==LEX_MINUSMINUS )
+					throw new CScriptException(SyntaxError, l->tk==LEX_PLUSPLUS?"invalid increment operand":"invalid decrement operand", l->currentFile, l->currentLine(), l->currentColumn()-label.size());
+			} else
+				State.LeftHand = true;
+		}
+		break;
+	case LEX_INT:
+	case LEX_FLOAT:
+	case LEX_STR:
+	case LEX_REGEXP:
+	case LEX_R_TRUE:
+	case LEX_R_FALSE:
+	case LEX_R_NULL:
+		pushToken(State.Tokens);
+		break;
+	case '{':
+		_tokenizeLiteralObject(State, ObjectLiteralFlags);
+		break;
+	case '[':
+		_tokenizeLiteralArray(State, ObjectLiteralFlags);
+		break;
+	case LEX_R_LET: // let as expression
+		tokenizeLet(State, Flags);
+		break;
+	case LEX_R_FUNCTION:
+		tokenizeFunction(State, Flags);
+		break;
+	case LEX_R_NEW: 
+		State.Marks.push_back(pushToken(State.Tokens)); // push Token & push BeginIdx
+		{
+			tokenizeFunctionCall(State, (Flags | TOKENIZE_FLAGS_callForNew) & ~TOKENIZE_FLAGS_noIn);
+			State.LeftHand = 0;
+		}
+		setTokenSkip(State);
+		break;
+	case '(':
+		State.Marks.push_back(pushToken(State.Tokens)); // push Token & push BeginIdx
+		tokenizeExpression(State, Flags & ~TOKENIZE_FLAGS_noIn);
+		State.LeftHand = 0;
+		pushToken(State.Tokens, ')');
+		setTokenSkip(State);
+		break;
+	default:
+		l->check(LEX_EOF);
+	}
+}
+void CScriptTokenizer::tokenizeMember(ScriptTokenState &State, int Flags) {
+	while(l->tk == '.' || l->tk == '[') {
+		if(l->tk == '.') {
+			pushToken(State.Tokens);
+			if(CScriptToken::isReservedWord(l->tk))
+				l->tk = LEX_ID; // fake reserved-word as member.ID
+			pushToken(State.Tokens , LEX_ID);
+		} else {
+			State.Marks.push_back(pushToken(State.Tokens));
+			State.pushLeftHandState();
+			tokenizeExpression(State, Flags & ~TOKENIZE_FLAGS_noIn);
+			State.popLeftHandeState();
+			pushToken(State.Tokens, ']');
+			setTokenSkip(State);
+		}
+		State.LeftHand = true;
+	}
+}
+void CScriptTokenizer::tokenizeFunctionCall(ScriptTokenState &State, int Flags) {
+	bool for_new = (Flags & TOKENIZE_FLAGS_callForNew)!=0; Flags &= ~TOKENIZE_FLAGS_callForNew;
+	tokenizeLiteral(State, Flags);
+	tokenizeMember(State, Flags);
+	while(l->tk == '(') {
+		State.LeftHand = false;
+		State.Marks.push_back(pushToken(State.Tokens)); // push Token & push BeginIdx
+		State.pushLeftHandState();
+		while(l->tk!=')') {
+			tokenizeAssignment(State, Flags & ~TOKENIZE_FLAGS_noIn);
+			if (l->tk!=')') pushToken(State.Tokens, ',', ')');
+		}
+		State.popLeftHandeState();
+		pushToken(State.Tokens);
+		setTokenSkip(State);
+		if(for_new) break;
+		tokenizeMember(State, Flags);
+	}
+}
+
+void CScriptTokenizer::tokenizeSubExpression(ScriptTokenState &State, int Flags) {
+	static int Left2Right_begin[] = { 
+		/* Precedence 5 */		'*', '/', '%', 
+		/* Precedence 6 */		'+', '-',
+		/* Precedence 7 */		LEX_LSHIFT, LEX_RSHIFT, LEX_RSHIFTU,
+		/* Precedence 8 */		LEX_EQUAL, LEX_NEQUAL, LEX_TYPEEQUAL, LEX_NTYPEEQUAL,
+		/* Precedence 9 */		'<', LEX_LEQUAL, '>', LEX_GEQUAL, LEX_R_IN, LEX_R_INSTANCEOF,
+		/* Precedence 10-12 */	'&', '^', '|', 
+	};
+	static int *Left2Right_end = &Left2Right_begin[sizeof(Left2Right_begin)/sizeof(Left2Right_begin[0])];
+	static bool Left2Right_sorted = false;
+	if(!Left2Right_sorted) Left2Right_sorted = (sort(Left2Right_begin, Left2Right_end), true);
+	bool noLeftHand = false;
+	for(;;) {
+		bool right2left_end = false;
+		while(!right2left_end) {
+			switch(l->tk) {
+			case '-':
+			case '+':
+			case '!':
+			case '~':
+			case LEX_R_TYPEOF:
+			case LEX_R_VOID:
+			case LEX_R_DELETE:
+				Flags &= ~TOKENIZE_FLAGS_canLabel;
+				noLeftHand = true;
+				pushToken(State.Tokens); // Precedence 3
+				break;
+			case LEX_PLUSPLUS: // pre-increment		
+			case LEX_MINUSMINUS: // pre-decrement 	
+				{
+					int tk = l->tk;
+					Flags &= ~TOKENIZE_FLAGS_canLabel;
+					noLeftHand = true;
+					pushToken(State.Tokens); // Precedence 4
+					if(l->tk == LEX_ID && l->tkStr == "this")
+						throw new CScriptException(SyntaxError, tk==LEX_PLUSPLUS?"invalid increment operand":"invalid decrement operand", l->currentFile, l->currentLine(), l->currentColumn());
+				}
+			default:
+				right2left_end = true;
+			}
+		}
+		tokenizeFunctionCall(State, Flags);
+		
+		if (!l->lineBreakBeforeToken && (l->tk==LEX_PLUSPLUS || l->tk==LEX_MINUSMINUS)) { // post-in-/de-crement
+			noLeftHand = true;;
+			pushToken(State.Tokens); // Precedence 4
+		}
+		if(Flags&TOKENIZE_FLAGS_noIn && l->tk==LEX_R_IN)
+			break;
+		int *found = lower_bound(Left2Right_begin, Left2Right_end, l->tk);
+		if(found != Left2Right_end && *found == l->tk) {
+			noLeftHand = true;
+			pushToken(State.Tokens); // Precedence 5-14
+		}
+		else
+			break;
+	}
+	if(noLeftHand) State.LeftHand = false;
+}
+
+void CScriptTokenizer::tokenizeLogic(ScriptTokenState &State, int Flags, int op /*= LEX_OROR*/, int op_n /*= LEX_ANDAND*/) {
+	op_n ? tokenizeLogic(State, Flags, op_n, 0) : tokenizeSubExpression(State, Flags);
+	if(l->tk==op) {
+		unsigned int marks_count = State.Marks.size();
+		while(l->tk==op) {
+			State.Marks.push_back(pushToken(State.Tokens));
+			op_n ? tokenizeLogic(State, Flags, op_n, 0) : tokenizeSubExpression(State, Flags);
+		}
+		while(State.Marks.size()>marks_count) setTokenSkip(State);
+		State.LeftHand = false;
+	}
+}
+
+void CScriptTokenizer::tokenizeCondition(ScriptTokenState &State, int Flags) {
+	tokenizeLogic(State, Flags);
+	if(l->tk == '?') {
+		Flags &= ~TOKENIZE_FLAGS_noIn;
+		State.Marks.push_back(pushToken(State.Tokens));
+		tokenizeCondition(State, Flags);
+		setTokenSkip(State);
+		State.Marks.push_back(pushToken(State.Tokens, ':'));
+		tokenizeCondition(State, Flags);
+		setTokenSkip(State);
+		State.LeftHand = false;
+	}
+}
+void CScriptTokenizer::tokenizeAssignment(ScriptTokenState &State, int Flags) {
+	tokenizeCondition(State, Flags);
+	if (l->tk=='=' || (l->tk>=LEX_ASSIGNMENTS_BEGIN && l->tk<=LEX_ASSIGNMENTS_END) ) {
+		if(!State.LeftHand)
+			throw new CScriptException(ReferenceError, "invalid assignment left-hand side", l->currentFile, l->currentLine(), l->currentColumn());
+		pushToken(State.Tokens);
+		tokenizeAssignment(State, Flags);
+		State.LeftHand = false;
+	}
+}
+void CScriptTokenizer::tokenizeExpression(ScriptTokenState &State, int Flags) {
+	tokenizeAssignment(State, Flags);
+	while(l->tk == ',') {
+		pushToken(State.Tokens);
+		tokenizeAssignment(State, Flags);
+		State.LeftHand = false;
+	}
+}
+void CScriptTokenizer::tokenizeBlock(ScriptTokenState &State, int Flags) {
+	bool addBlockStart = (Flags&TOKENIZE_FLAGS_noBlockStart)==0; 
+	Flags&=~(TOKENIZE_FLAGS_noBlockStart);
+	State.Marks.push_back(pushToken(State.Tokens, '{')); // push Token & push BeginIdx
+	if(addBlockStart) pushForwarder(State);
+
+	while(l->tk != '}' && l->tk != LEX_EOF) 
+		tokenizeStatement(State, Flags);
+	pushToken(State.Tokens, '}');
+
+	if(addBlockStart) removeEmptyForwarder(State); // clean-up BlockStarts
+
+	setTokenSkip(State);
+}
+
+void CScriptTokenizer::tokenizeStatementNoLet(ScriptTokenState &State, int Flags) {
+	if(l->tk == LEX_R_LET)
+		tokenizeLet(State, Flags | TOKENIZE_FLAGS_asStatement, true); 
+	else if(l->tk==LEX_R_FUNCTION)
+		tokenizeFunction(State, Flags | TOKENIZE_FLAGS_asStatement, true);
+	else
+		tokenizeStatement(State, Flags);
+}
+void CScriptTokenizer::tokenizeStatement(ScriptTokenState &State, int Flags) {
+	switch(l->tk)
+	{
+	case '{':				tokenizeBlock(State, Flags); break;
+	case ';':				pushToken(State.Tokens); break;
+	case LEX_R_CONST:
+	case LEX_R_VAR:		tokenizeVarAndConst(State, Flags); break;
+	case LEX_R_LET:		tokenizeLet(State, Flags | TOKENIZE_FLAGS_asStatement); break;
+	case LEX_R_WITH:		tokenizeWith(State, Flags); break;
+	case LEX_R_IF:			tokenizeIf(State, Flags); break;
+	case LEX_R_SWITCH:	tokenizeSwitch(State, Flags); break;
+	case LEX_R_DO:
+	case LEX_R_WHILE:		tokenizeWhileAndDo(State, Flags); break;
+	case LEX_R_FOR:		tokenizeFor(State, Flags); break;
+	case LEX_R_FUNCTION:	tokenizeFunction(State, Flags | TOKENIZE_FLAGS_asStatement); break;
+	case LEX_R_TRY:		tokenizeTry(State, Flags); break;
+	case LEX_R_RETURN:	
+			if( (Flags & TOKENIZE_FLAGS_canReturn)==0) 
+				throw new CScriptException(SyntaxError, "'return' statement, but not in a function.", l->currentFile, l->currentLine(), l->currentColumn());
+	case LEX_R_THROW:	
+		State.Marks.push_back(pushToken(State.Tokens)); // push Token & push BeginIdx
+		if(l->tk != ';' && !l->lineBreakBeforeToken) {
+			tokenizeExpression(State, Flags);
+		}
+		pushToken(State.Tokens, ';'); // push ';'
+		setTokenSkip(State);
+		break;
+	case LEX_R_BREAK:		
+	case LEX_R_CONTINUE:	
+		{
+			bool isBreak = l->tk == LEX_R_BREAK;
+			State.Marks.push_back(pushToken(State.Tokens)); // push Token
+
+			if(l->tk != ';' && !l->lineBreakBeforeToken) {
+				l->check(LEX_ID);
+				STRING_VECTOR_t &L = isBreak ? State.Labels : State.LoopLabels;
+				if(find(L.begin(), L.end(), l->tkStr) == L.end())
+					throw new CScriptException(SyntaxError, "label '"+l->tkStr+"' not found", l->currentFile, l->currentLine(), l->currentColumn());
+				pushToken(State.Tokens); // push 'Label'
+			} else if((Flags & (isBreak ? TOKENIZE_FLAGS_canBreak : TOKENIZE_FLAGS_canContinue) )==0) 
+				throw new CScriptException(SyntaxError, 
+											isBreak ? "'break' must be inside loop, switch or labeled statement" : "'continue' must be inside loop", 
+											l->currentFile, l->currentLine(), l->currentColumn());
+			pushToken(State.Tokens, ';'); // push ';'
+			setTokenSkip(State);
+		}
+		break;
+	case LEX_ID:
+		{
+			State.Marks.push_back(pushToken(State.Tokens, CScriptToken(LEX_T_SKIP))); // push skip & skiperBeginIdx
+			STRING_VECTOR_t::size_type label_count = State.Labels.size();
+			tokenizeExpression(State, Flags | TOKENIZE_FLAGS_canLabel); 
+			if(label_count < State.Labels.size() && l->tk == ':') {
+				State.Tokens.erase(State.Tokens.begin()+State.Marks.back()); // remove skip
+				State.Marks.pop_back();
+				pushToken(State.Tokens); // push ':'
+				tokenizeStatement(State, Flags);
+				State.Labels.pop_back();
+			} else {
+				pushToken(State.Tokens, ';');
+				setTokenSkip(State);
+			}
+		}
+		break;
+	default:
+		State.Marks.push_back(pushToken(State.Tokens, CScriptToken(LEX_T_SKIP))); // push skip & skiperBeginIdx
+		tokenizeExpression(State, Flags); 
+		pushToken(State.Tokens, ';'); 
+		setTokenSkip(State);
+		break;
+	}
+}
+
+int CScriptTokenizer::pushToken(TOKEN_VECT &Tokens, int Match, int Alternate) {
+	if(Match == ';' && l->tk != ';' && (l->lineBreakBeforeToken || l->tk=='}' || l->tk==LEX_EOF))
+		Tokens.push_back(CScriptToken(';')); // inject ';'
+	else
+		Tokens.push_back(CScriptToken(l, Match, Alternate));
+	return Tokens.size()-1;
+}
+int CScriptTokenizer::pushToken(TOKEN_VECT &Tokens, const CScriptToken &Token) {
+	int ret = Tokens.size();
+	Tokens.push_back(Token);
+	return ret;
+}
+void CScriptTokenizer::pushForwarder(TOKEN_VECT &Tokens, FORWARDER_VECTOR_t &Forwarders, vector<int> &Marks) {
+	Marks.push_back(Tokens.size());
+	CScriptToken token(LEX_T_FORWARD);
+	Tokens.push_back(token);
+	Forwarders.push_back(token.Forwarder());
+}
+void CScriptTokenizer::pushForwarder(ScriptTokenState &State, bool noMarks/*=false*/) {
+	if(!noMarks) State.Marks.push_back(State.Tokens.size());
+	CScriptToken token(LEX_T_FORWARD);
+	State.Tokens.push_back(token);
+	State.Forwarders.push_back(token.Forwarder());
+}
+void CScriptTokenizer::removeEmptyForwarder(ScriptTokenState &State)
+{
+	CScriptTokenDataForwardsPtr &forwarder = State.Forwarders.back();
+	forwarder->vars_in_letscope.clear();
+	if(forwarder->empty())
+		State.Tokens.erase(State.Tokens.begin()+State.Marks.back());
+	State.Forwarders.pop_back();
+	State.Marks.pop_back();
+}
+
+void CScriptTokenizer::removeEmptyForwarder( TOKEN_VECT &Tokens, FORWARDER_VECTOR_t &Forwarders, vector<int> &Marks )
+{
+	CScriptTokenDataForwardsPtr &forwarder = Forwarders.back();
+	forwarder->vars_in_letscope.clear();
+	if(forwarder->empty())
+		Tokens.erase(Tokens.begin()+Marks.back());
+	Forwarders.pop_back();
+	Marks.pop_back();
+}
+void CScriptTokenizer::throwTokenNotExpected() {
+	throw new CScriptException(SyntaxError, "'"+CScriptToken::getTokenStr(l->tk)+"' was not expected", l->currentFile, l->currentLine(), l->currentColumn());
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVar
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVar::CScriptVar(CTinyJS *Context, const CScriptVarPtr &Prototype) {
+	extensible = true;
+	context = Context;
+	temporaryID = 0;
+	if(context->first) {
+		next = context->first;
+		next->prev = this;
+	} else {
+		next = 0;
+	}
+	context->first = this;
+	prev = 0;
+	refs = 0;
+	if(Prototype)
+		addChild(TINYJS___PROTO___VAR, Prototype, SCRIPTVARLINK_WRITABLE);
+#if DEBUG_MEMORY
+	mark_allocated(this);
+#endif
+}
+CScriptVar::CScriptVar(const CScriptVar &Copy) {
+	extensible = Copy.extensible;
+	context = Copy.context;
+	temporaryID = 0;
+	if(context->first) {
+		next = context->first;
+		next->prev = this;
+	} else {
+		next = 0;
+	}
+	context->first = this;
+	prev = 0;
+	refs = 0;
+	SCRIPTVAR_CHILDS_cit it;
+	for(it = Copy.Childs.begin(); it!= Copy.Childs.end(); ++it) {
+		addChild((*it)->getName(), (*it)->getVarPtr(), (*it)->getFlags());
+	}
+
+#if DEBUG_MEMORY
+	mark_allocated(this);
+#endif
+}
+CScriptVar::~CScriptVar(void) {
+#if DEBUG_MEMORY
+	mark_deallocated(this);
+#endif
+	for(SCRIPTVAR_CHILDS_it it = Childs.begin(); it != Childs.end(); ++it)
+		(*it)->setOwner(0);
+	removeAllChildren();
+	if(prev)
+		prev->next = next;
+	else
+		context->first = next;
+	if(next)
+		next->prev = prev;
+}
+
+/// Type
+
+bool CScriptVar::isObject()		{return false;}
+bool CScriptVar::isError()			{return false;}
+bool CScriptVar::isArray()			{return false;}
+bool CScriptVar::isRegExp()		{return false;}
+bool CScriptVar::isAccessor()		{return false;}
+bool CScriptVar::isNull()			{return false;}
+bool CScriptVar::isUndefined()	{return false;}
+bool CScriptVar::isNaN()			{return false;}
+bool CScriptVar::isString()		{return false;}
+bool CScriptVar::isInt()			{return false;}
+bool CScriptVar::isBool()			{return false;}
+int CScriptVar::isInfinity()		{ return 0; } ///< +1==POSITIVE_INFINITY, -1==NEGATIVE_INFINITY, 0==is not an InfinityVar
+bool CScriptVar::isDouble()		{return false;}
+bool CScriptVar::isRealNumber()	{return false;}
+bool CScriptVar::isNumber()		{return false;}
+bool CScriptVar::isPrimitive()	{return false;}
+bool CScriptVar::isFunction()		{return false;}
+bool CScriptVar::isNative()		{return false;}
+bool CScriptVar::isBounded()		{return false;}
+bool CScriptVar::isIterator()		{return false;}
+
+//////////////////////////////////////////////////////////////////////////
+/// Value
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarPrimitivePtr CScriptVar::getRawPrimitive() {
+	return CScriptVarPrimitivePtr(); // default NULL-Ptr
+}
+CScriptVarPrimitivePtr CScriptVar::toPrimitive() {
+	return toPrimitive_hintNumber();
+}
+
+CScriptVarPrimitivePtr CScriptVar::toPrimitive(CScriptResult &execute) {
+	return toPrimitive_hintNumber(execute);
+} 
+
+CScriptVarPrimitivePtr CScriptVar::toPrimitive_hintString(int32_t radix) {
+	CScriptResult execute;
+	CScriptVarPrimitivePtr var = toPrimitive_hintString(execute, radix);
+	execute.cThrow();
+	return var;
+}
+CScriptVarPrimitivePtr CScriptVar::toPrimitive_hintString(CScriptResult &execute, int32_t radix) {
+	if(execute) {
+		if(!isPrimitive()) {
+			CScriptVarPtr ret = callJS_toString(execute, radix);
+			if(execute && !ret->isPrimitive()) {
+				ret = callJS_valueOf(execute);
+				if(execute && !ret->isPrimitive())
+					context->throwError(execute, TypeError, "can't convert b to primitive type");
+			}
+			return ret;
+		}
+		return this;
+	}
+	return constScriptVar(Undefined);
+}
+CScriptVarPrimitivePtr CScriptVar::toPrimitive_hintNumber() {
+	CScriptResult execute;
+	CScriptVarPrimitivePtr var = toPrimitive_hintNumber(execute);
+	execute.cThrow();
+	return var;
+}
+CScriptVarPrimitivePtr CScriptVar::toPrimitive_hintNumber(CScriptResult &execute) {
+	if(execute) {
+		if(!isPrimitive()) {
+			CScriptVarPtr ret = callJS_valueOf(execute);
+			if(execute && !ret->isPrimitive()) {
+				ret = callJS_toString(execute);
+				if(execute && !ret->isPrimitive())
+					context->throwError(execute, TypeError, "can't convert to primitive type");
+			}
+			return ret;
+		}
+		return this;
+	}
+	return constScriptVar(Undefined);
+}
+
+CScriptVarPtr CScriptVar::callJS_valueOf(CScriptResult &execute) {
+	if(execute) {
+		CScriptVarPtr FncValueOf = findChildWithPrototypeChain("valueOf").getter(execute);
+		if(FncValueOf != context->objectPrototype_valueOf) { // custom valueOf in JavaScript
+			if(FncValueOf->isFunction()) { // no Error if toString not callable
+				vector<CScriptVarPtr> Params;
+				return context->callFunction(execute, FncValueOf, Params, this);
+			}
+		} else
+			return valueOf_CallBack();
+	}
+	return this;
+}
+CScriptVarPtr CScriptVar::valueOf_CallBack() {
+	return this;
+}
+
+CScriptVarPtr CScriptVar::callJS_toString(CScriptResult &execute, int radix/*=0*/) {
+	if(execute) {
+		CScriptVarPtr FncToString = findChildWithPrototypeChain("toString").getter(execute);
+		if(FncToString != context->objectPrototype_toString) { // custom valueOf in JavaScript
+			if(FncToString->isFunction()) { // no Error if toString not callable
+				vector<CScriptVarPtr> Params;
+				Params.push_back(newScriptVar(radix));
+				return context->callFunction(execute, FncToString, Params, this);
+			}
+		} else
+			return toString_CallBack(execute, radix);
+	}
+	return this;
+}
+CScriptVarPtr CScriptVar::toString_CallBack(CScriptResult &execute, int radix/*=0*/) {
+	return this;
+}
+
+CNumber CScriptVar::toNumber() { return toPrimitive_hintNumber()->toNumber_Callback(); };
+CNumber CScriptVar::toNumber(CScriptResult &execute) { return toPrimitive_hintNumber(execute)->toNumber_Callback(); };
+bool CScriptVar::toBoolean() { return true; }
+string CScriptVar::toString(int32_t radix) { return toPrimitive_hintString(radix)->toCString(radix); }
+string CScriptVar::toString(CScriptResult &execute, int32_t radix) { return toPrimitive_hintString(execute, radix)->toCString(radix); }
+
+int CScriptVar::getInt() { return toNumber().toInt32(); }
+double CScriptVar::getDouble() { return toNumber().toDouble(); } 
+bool CScriptVar::getBool() { return toBoolean(); }
+string CScriptVar::getString() { return toPrimitive_hintString()->toCString(); }
+
+CScriptTokenDataFnc *CScriptVar::getFunctionData() { return 0; }
+
+CScriptVarPtr CScriptVar::toIterator(int Mode/*=3*/) {
+	CScriptResult execute;
+	CScriptVarPtr var = toIterator(execute, Mode);
+	execute.cThrow();
+	return var;
+}
+CScriptVarPtr CScriptVar::toIterator(CScriptResult &execute, int Mode/*=3*/) {
+	if(!execute) return constScriptVar(Undefined);
+	if(isIterator()) return this;
+	CScriptVarFunctionPtr Generator(findChildWithPrototypeChain("__iterator__").getter(execute));
+	vector<CScriptVarPtr> args;
+	if(Generator) return context->callFunction(execute, Generator, args, this);
+	return newScriptVarDefaultIterator(context, this, Mode);
+}
+
+string CScriptVar::getParsableString(const string &indentString, const string &indent, uint32_t uniqueID, bool &hasRecursion) {
+	getParsableStringRecursionsCheck();
+	return toString();
+}
+
+CScriptVarPtr CScriptVar::getNumericVar() { return newScriptVar(toNumber()); }
+
+////// Flags
+
+void CScriptVar::seal() {
+	preventExtensions(); 
+	for(SCRIPTVAR_CHILDS_it it = Childs.begin(); it != Childs.end(); ++it)
+		(*it)->setConfigurable(false);
+}
+bool CScriptVar::isSealed() const {
+	if(isExtensible()) return false; 
+	for(SCRIPTVAR_CHILDS_cit it = Childs.begin(); it != Childs.end(); ++it)
+		if((*it)->isConfigurable()) return false;
+	return true;
+}
+void CScriptVar::freeze() {
+	preventExtensions(); 
+	for(SCRIPTVAR_CHILDS_it it = Childs.begin(); it != Childs.end(); ++it)
+		(*it)->setConfigurable(false), (*it)->setWritable(false);
+}
+bool CScriptVar::isFrozen() const {
+	if(isExtensible()) return false; 
+	for(SCRIPTVAR_CHILDS_cit it = Childs.begin(); it != Childs.end(); ++it)
+		if((*it)->isConfigurable() || (*it)->isWritable()) return false;
+	return true;
+}
+
+////// Childs
+
+CScriptVarPtr CScriptVar::getOwnPropertyDescriptor(const string &Name) {
+	CScriptVarLinkPtr child = findChild(Name);
+	if(!child) {
+		CScriptVarStringPtr strVar = getRawPrimitive();
+		uint32_t Idx;
+		if (strVar && (Idx=isArrayIndex(Name))!=uint32_t(-1) && Idx<strVar->stringLength()) {
+			int Char = strVar->getChar(Idx);
+			CScriptVarPtr ret = newScriptVar(Object);
+			ret->addChild("value", newScriptVar(string(1, (char)Char)));
+			ret->addChild("writable", constScriptVar(false));
+			ret->addChild("enumerable", constScriptVar(true));
+			ret->addChild("configurable", constScriptVar(false));
+			return ret;
+		}
+	}
+
+	if(!child || child->getVarPtr()->isUndefined()) return constScriptVar(Undefined);
+	CScriptVarPtr ret = newScriptVar(Object);
+	if(child->getVarPtr()->isAccessor()) {
+		CScriptVarLinkPtr value = child->getVarPtr()->findChild(TINYJS_ACCESSOR_GET_VAR);
+		ret->addChild("get", value ? value->getVarPtr() : constScriptVar(Undefined));
+		value = child->getVarPtr()->findChild(TINYJS_ACCESSOR_SET_VAR);
+		ret->addChild("set", value ? value->getVarPtr() : constScriptVar(Undefined));
+	} else {
+		ret->addChild("value", child->getVarPtr()->valueOf_CallBack());
+		ret->addChild("writable", constScriptVar(child->isWritable()));
+	}
+	ret->addChild("enumerable", constScriptVar(child->isEnumerable()));
+	ret->addChild("configurable", constScriptVar(child->isConfigurable()));
+	return ret;
+}
+const char *CScriptVar::defineProperty(const string &Name, CScriptVarPtr Attributes) {
+	CScriptVarPtr attr;
+	CScriptVarLinkPtr child = findChildWithStringChars(Name);
+
+	CScriptVarPtr attr_value			= Attributes->findChild("value");
+	CScriptVarPtr attr_writable		= Attributes->findChild("writable");
+	CScriptVarPtr attr_get				= Attributes->findChild("get");
+	CScriptVarPtr attr_set				= Attributes->findChild("set");
+	CScriptVarPtr attr_enumerable		= Attributes->findChild("enumerable");
+	CScriptVarPtr attr_configurable	= Attributes->findChild("configurable");
+	bool attr_isDataDescriptor			= !attr_get && !attr_set;
+	if(!attr_isDataDescriptor && (attr_value || attr_writable)) return "property descriptors must not specify a value or be writable when a getter or setter has been specified";
+	if(attr_isDataDescriptor) {
+		if(attr_get && (!attr_get->isUndefined() || !attr_get->isFunction())) return "property descriptor's getter field is neither undefined nor a function";
+		if(attr_set && (!attr_set->isUndefined() || !attr_set->isFunction())) return "property descriptor's setter field is neither undefined nor a function";
+	}
+	if(!child) {
+		if(!isExtensible()) return "is not extensible";
+		if(attr_isDataDescriptor) {
+			child = addChild(Name, attr_value?attr_value:constScriptVar(Undefined), 0);
+			if(attr_writable) child->setWritable(attr_writable->toBoolean());
+		} else {
+			child = addChild(Name, newScriptVarAccessor(context, attr_get, attr_set), SCRIPTVARLINK_WRITABLE);
+		}
+	} else {
+		if(!child->isConfigurable()) {
+			if(attr_configurable && attr_configurable->toBoolean()) goto cant_redefine;
+			if(attr_enumerable && attr_enumerable->toBoolean() != child->isEnumerable()) goto cant_redefine;
+			if(child->getVarPtr()->isAccessor()) {
+				if(attr_isDataDescriptor) goto cant_redefine;
+				if(attr_get && attr_get != child->getVarPtr()->findChild(TINYJS_ACCESSOR_GET_VAR)) goto cant_redefine;
+				if(attr_set && attr_set != child->getVarPtr()->findChild(TINYJS_ACCESSOR_SET_VAR)) goto cant_redefine;
+			} else if(!attr_isDataDescriptor) goto cant_redefine;
+			else if(!child->isWritable()) {
+				if(attr_writable && attr_writable->toBoolean()) goto cant_redefine;
+				if(attr_value && !attr_value->mathsOp(child, LEX_EQUAL)->toBoolean()) goto cant_redefine;
+			}
+		}
+		if(attr_isDataDescriptor) {
+			if(child->getVarPtr()->isAccessor()) child->setWritable(false);
+			child->setVarPtr(attr_value?attr_value:constScriptVar(Undefined));
+			if(attr_writable) child->setWritable(attr_writable->toBoolean());
+		} else {
+			if(child->getVarPtr()->isAccessor()) {
+				if(!attr_get) attr_get = child->getVarPtr()->findChild(TINYJS_ACCESSOR_GET_VAR);
+				if(!attr_set) attr_set = child->getVarPtr()->findChild(TINYJS_ACCESSOR_SET_VAR);
+			}
+			child->setVarPtr(newScriptVarAccessor(context, attr_get, attr_set));
+			child->setWritable(true);
+		}
+	}
+	if(attr_enumerable) child->setEnumerable(attr_enumerable->toBoolean());
+	if(attr_configurable) child->setConfigurable(attr_configurable->toBoolean());
+	return 0;
+cant_redefine:
+	return "can't redefine non-configurable property";
+}
+
+CScriptVarLinkPtr CScriptVar::findChild(const string &childName) {
+	if(Childs.empty()) return 0;
+	SCRIPTVAR_CHILDS_it it = lower_bound(Childs.begin(), Childs.end(), childName);
+	if(it != Childs.end() && (*it)->getName() == childName)
+		return *it;
+	return 0;
+}
+
+CScriptVarLinkWorkPtr CScriptVar::findChildWithStringChars(const string &childName) {
+	CScriptVarLinkWorkPtr child = findChild(childName);
+	if(child) return child;
+	CScriptVarStringPtr strVar = getRawPrimitive();
+	uint32_t Idx;
+	if (strVar && (Idx=isArrayIndex(childName))!=uint32_t(-1) && Idx<strVar->stringLength()) {
+		int Char = strVar->getChar(Idx);
+		child(newScriptVar(string(1, (char)Char)), childName, SCRIPTVARLINK_ENUMERABLE);
+		child.setReferencedOwner(this); // fake referenced Owner
+		return child;
+	}
+	return 0;
+}
+
+CScriptVarLinkPtr CScriptVar::findChildInPrototypeChain(const string &childName) {
+	unsigned int uniqueID = context->getUniqueID();
+	// Look for links to actual parent classes
+	CScriptVarPtr object = this;
+	CScriptVarLinkPtr __proto__;
+	while( object->getTempraryID() != uniqueID && (__proto__ = object->findChild(TINYJS___PROTO___VAR)) ) {
+		CScriptVarLinkPtr implementation = __proto__->getVarPtr()->findChild(childName);
+		if (implementation) return implementation;
+		object->setTemporaryID(uniqueID); // prevents recursions
+		object = __proto__;
+	}
+	return 0;
+}
+
+CScriptVarLinkWorkPtr CScriptVar::findChildWithPrototypeChain(const string &childName) {
+	CScriptVarLinkWorkPtr child = findChildWithStringChars(childName);
+	if(child) return child;
+	child = findChildInPrototypeChain(childName);
+	if(child) {
+		child(child->getVarPtr(), child->getName(), child->getFlags()); // recreate implementation
+		child.setReferencedOwner(this); // fake referenced Owner
+	}
+	return child;
+}
+CScriptVarLinkPtr CScriptVar::findChildByPath(const string &path) {
+	string::size_type p = path.find('.');
+	CScriptVarLinkPtr child;
+	if (p == string::npos)
+		return findChild(path);
+	if( (child = findChild(path.substr(0,p))) )
+		return child->getVarPtr()->findChildByPath(path.substr(p+1));
+	return 0;
+}
+
+CScriptVarLinkPtr CScriptVar::findChildOrCreate(const string &childName/*, int varFlags*/) {
+	CScriptVarLinkPtr l = findChild(childName);
+	if (l) return l;
+	return addChild(childName, constScriptVar(Undefined));
+	//	return addChild(childName, new CScriptVar(context, TINYJS_BLANK_DATA, varFlags));
+}
+
+CScriptVarLinkPtr CScriptVar::findChildOrCreateByPath(const string &path) {
+	string::size_type p = path.find('.');
+	if (p == string::npos)
+		return findChildOrCreate(path);
+	string childName(path, 0, p);
+	CScriptVarLinkPtr l = findChild(childName);
+	if (!l) l = addChild(childName, newScriptVar(Object));
+	return l->getVarPtr()->findChildOrCreateByPath(path.substr(p+1));
+}
+
+void CScriptVar::keys(set<string> &Keys, bool OnlyEnumerable/*=true*/, uint32_t ID/*=0*/)
+{
+	setTemporaryID(ID);
+	for(SCRIPTVAR_CHILDS_it it = Childs.begin(); it != Childs.end(); ++it) {
+		if(!OnlyEnumerable || (*it)->isEnumerable())
+			Keys.insert((*it)->getName());
+	}
+	CScriptVarStringPtr isStringObj = this->getRawPrimitive();
+	if(isStringObj) {
+		uint32_t length = isStringObj->stringLength();
+		for(uint32_t i=0; i<length; ++i)
+			Keys.insert(int2string(i));
+	}
+	CScriptVarLinkPtr __proto__;
+	if( ID && (__proto__ = findChild(TINYJS___PROTO___VAR)) && __proto__->getVarPtr()->getTempraryID() != ID )
+		__proto__->getVarPtr()->keys(Keys, OnlyEnumerable, ID);
+}
+
+/// add & remove
+CScriptVarLinkPtr CScriptVar::addChild(const string &childName, const CScriptVarPtr &child, int linkFlags /*= SCRIPTVARLINK_DEFAULT*/) {
+	CScriptVarLinkPtr link;
+	SCRIPTVAR_CHILDS_it it = lower_bound(Childs.begin(), Childs.end(), childName);
+	if(it == Childs.end() || (*it)->getName() != childName) {
+		link = CScriptVarLinkPtr(child?child:constScriptVar(Undefined), childName, linkFlags);
+		link->setOwner(this);
+
+		Childs.insert(it, 1, link);
+#ifdef _DEBUG
+	} else {
+		ASSERT(0); // addChild - the child exists 
+#endif
+	}
+	return link;
+}
+CScriptVarLinkPtr CScriptVar::addChildNoDup(const string &childName, const CScriptVarPtr &child, int linkFlags /*= SCRIPTVARLINK_DEFAULT*/) { 
+	return addChildOrReplace(childName, child, linkFlags); 
+}
+CScriptVarLinkPtr CScriptVar::addChildOrReplace(const string &childName, const CScriptVarPtr &child, int linkFlags /*= SCRIPTVARLINK_DEFAULT*/) {
+	SCRIPTVAR_CHILDS_it it = lower_bound(Childs.begin(), Childs.end(), childName);
+	if(it == Childs.end() || (*it)->getName() != childName) {
+		CScriptVarLinkPtr link(child, childName, linkFlags);
+		link->setOwner(this);
+		Childs.insert(it, 1, link);
+		return link;
+	} else {
+		(*it)->setVarPtr(child);
+		return (*it);
+	}
+}
+
+bool CScriptVar::removeLink(CScriptVarLinkPtr &link) {
+	if (!link) return false;
+	SCRIPTVAR_CHILDS_it it = lower_bound(Childs.begin(), Childs.end(), link->getName());
+	if(it != Childs.end() && (*it) == link) {
+		Childs.erase(it);
+#ifdef _DEBUG
+	} else {
+		ASSERT(0); // removeLink - the link is not atached to this var 
+#endif
+	}
+	link.clear();
+	return true;
+}
+void CScriptVar::removeAllChildren() {
+	Childs.clear();
+}
+
+CScriptVarPtr CScriptVar::getArrayIndex(uint32_t idx) {
+	CScriptVarLinkPtr link = findChild(int2string(idx));
+	if (link) return link;
+	else return constScriptVar(Undefined); // undefined
+}
+
+void CScriptVar::setArrayIndex(uint32_t idx, const CScriptVarPtr &value) {
+	string sIdx = int2string(idx);
+	CScriptVarLinkPtr link = findChild(sIdx);
+
+	if (link) {
+		link->setVarPtr(value);
+	} else {
+		addChild(sIdx, value);
+	}
+}
+
+uint32_t CScriptVar::getArrayLength() {
+	if (!isArray() || Childs.size()==0) return 0;
+	return isArrayIndex(Childs.back()->getName())+1; 
+}
+
+CScriptVarPtr CScriptVar::mathsOp(const CScriptVarPtr &b, int op) {
+	CScriptResult execute;
+	return context->mathsOp(execute, this, b, op);
+}
+
+void CScriptVar::trace(const string &name) {
+	string indentStr;
+	uint32_t uniqueID = context->getUniqueID();
+	trace(indentStr, uniqueID, name);
+}
+void CScriptVar::trace(string &indentStr, uint32_t uniqueID, const string &name) {
+	string indent = "  ";
+	const char *extra="";
+	if(temporaryID == uniqueID)
+		extra = " recursion detected";
+	TRACE("%s'%s' = '%s' %s%s\n",
+		indentStr.c_str(),
+		name.c_str(),
+		toString().c_str(),
+		getFlagsAsString().c_str(),
+		extra);
+	if(temporaryID != uniqueID) {
+		temporaryID = uniqueID;
+		indentStr+=indent;
+		for(SCRIPTVAR_CHILDS_it it = Childs.begin(); it != Childs.end(); ++it) {
+			if((*it)->isEnumerable())
+				(*it)->getVarPtr()->trace(indentStr, uniqueID, (*it)->getName());
+		}
+		indentStr = indentStr.substr(0, indentStr.length()-2);
+	}
+}
+
+string CScriptVar::getFlagsAsString() {
+	string flagstr = "";
+	if (isFunction()) flagstr = flagstr + "FUNCTION ";
+	if (isObject()) flagstr = flagstr + "OBJECT ";
+	if (isArray()) flagstr = flagstr + "ARRAY ";
+	if (isNative()) flagstr = flagstr + "NATIVE ";
+	if (isDouble()) flagstr = flagstr + "DOUBLE ";
+	if (isInt()) flagstr = flagstr + "INTEGER ";
+	if (isBool()) flagstr = flagstr + "BOOLEAN ";
+	if (isString()) flagstr = flagstr + "STRING ";
+	if (isRegExp()) flagstr = flagstr + "REGEXP ";
+	if (isNaN()) flagstr = flagstr + "NaN ";
+	if (isInfinity()) flagstr = flagstr + "INFINITY ";
+	return flagstr;
+}
+
+CScriptVar *CScriptVar::ref() {
+	refs++;
+	return this;
+}
+void CScriptVar::unref() {
+	refs--;
+	ASSERT(refs>=0); // printf("OMFG, we have unreffed too far!\n");
+	if (refs==0)
+		delete this;
+}
+
+int CScriptVar::getRefs() {
+	return refs;
+}
+
+void CScriptVar::setTemporaryID_recursive(uint32_t ID) {
+	if(temporaryID != ID) {
+		temporaryID = ID;
+		for(SCRIPTVAR_CHILDS_it it = Childs.begin(); it != Childs.end(); ++it) {
+			(*it)->getVarPtr()->setTemporaryID_recursive(ID);
+		}
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarLink
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarLink::CScriptVarLink(const CScriptVarPtr &Var, const string &Name /*=TINYJS_TEMP_NAME*/, int Flags /*=SCRIPTVARLINK_DEFAULT*/) 
+	: name(Name), owner(0), flags(Flags), refs(0) {
+#if DEBUG_MEMORY
+	mark_allocated(this);
+#endif
+	var = Var;
+}
+
+CScriptVarLink::~CScriptVarLink() {
+#if DEBUG_MEMORY
+	mark_deallocated(this);
+#endif
+}
+
+CScriptVarLink *CScriptVarLink::ref() {
+	refs++;
+	return this;
+}
+void CScriptVarLink::unref() {
+	refs--;
+	ASSERT(refs>=0); // printf("OMFG, we have unreffed too far!\n");
+	if (refs==0)
+		delete this;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarLinkPtr
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarLinkPtr & CScriptVarLinkPtr::operator()( const CScriptVarPtr &var, const std::string &name /*= TINYJS_TEMP_NAME*/, int flags /*= SCRIPTVARLINK_DEFAULT*/ ) {
+	if(link && link->refs == 1) { // the link is only refered by this
+		link->name = name;
+		link->owner = 0;
+		link->flags = flags;
+		link->var = var;
+	} else {
+		if(link) link->unref();
+		link = (new CScriptVarLink(var, name, flags))->ref();
+	} 
+	return *this;
+}
+
+CScriptVarLinkWorkPtr CScriptVarLinkPtr::getter() {
+	return CScriptVarLinkWorkPtr(*this).getter();
+}
+
+CScriptVarLinkWorkPtr CScriptVarLinkPtr::getter( CScriptResult &execute ) {
+	return CScriptVarLinkWorkPtr(*this).getter(execute);
+}
+
+CScriptVarLinkWorkPtr CScriptVarLinkPtr::setter( const CScriptVarPtr &Var ) {
+	return CScriptVarLinkWorkPtr(*this).setter(Var);
+}
+
+CScriptVarLinkWorkPtr CScriptVarLinkPtr::setter( CScriptResult &execute, const CScriptVarPtr &Var ) {
+	return CScriptVarLinkWorkPtr(*this).setter(execute, Var);
+}
+
+bool CScriptVarLinkPtr::operator <(const string &rhs) const {
+	uint32_t lhs_int = isArrayIndex(link->getName());
+	uint32_t rhs_int = isArrayIndex(rhs);
+	if(lhs_int==uint32_t(-1)) {
+		if(rhs_int==uint32_t(-1)) 
+			return link->getName() < rhs;
+		else 
+			return true;
+	} else if(rhs_int==uint32_t(-1)) 
+		return false;
+	return lhs_int < rhs_int;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarLinkWorkPtr
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarLinkWorkPtr CScriptVarLinkWorkPtr::getter() {
+	if(link && link->getVarPtr()) {
+		CScriptResult execute;
+		CScriptVarPtr ret = getter(execute);
+		execute.cThrow();
+		return ret;
+	}
+	return *this;
+}
+CScriptVarLinkWorkPtr CScriptVarLinkWorkPtr::getter(CScriptResult &execute) {
+	if(execute && link && link->getVarPtr() && link->getVarPtr()->isAccessor()) {
+		const CScriptVarPtr &var = link->getVarPtr();
+		CScriptVarLinkPtr getter = var->findChild(TINYJS_ACCESSOR_GET_VAR);
+		if(getter) {
+			vector<CScriptVarPtr> Params;
+			ASSERT(getReferencedOwner());
+			return getter->getVarPtr()->getContext()->callFunction(execute, getter->getVarPtr(), Params, getReferencedOwner());
+		} else
+			return var->constScriptVar(Undefined);
+	} else
+		return *this;
+}
+CScriptVarLinkWorkPtr CScriptVarLinkWorkPtr::setter( const CScriptVarPtr &Var ) {
+	if(link && link->getVarPtr()) {
+		CScriptResult execute;
+		CScriptVarPtr ret = setter(execute, Var);
+		execute.cThrow();
+		return ret;
+	}
+	return *this;
+}
+
+CScriptVarLinkWorkPtr CScriptVarLinkWorkPtr::setter( CScriptResult &execute, const CScriptVarPtr &Var ) {
+	if(execute) {
+		if(link) {
+			if(link->getVarPtr() && link->getVarPtr()->isAccessor()) {
+				const CScriptVarPtr &var = link->getVarPtr();
+				CScriptVarLinkPtr setter = var->findChild(TINYJS_ACCESSOR_SET_VAR);
+				if(setter) {
+					vector<CScriptVarPtr> Params;
+					Params.push_back(Var);
+					ASSERT(getReferencedOwner());
+					setter->getVarPtr()->getContext()->callFunction(execute, setter->getVarPtr(), Params, getReferencedOwner());
+				}
+			} else
+				link->setVarPtr(Var);
+		}
+	}
+	return *this;
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarPrimitive
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarPrimitive::~CScriptVarPrimitive(){}
+
+bool CScriptVarPrimitive::isPrimitive() { return true; }
+CScriptVarPrimitivePtr CScriptVarPrimitive::getRawPrimitive() { return this; }
+bool CScriptVarPrimitive::toBoolean() { return false; }
+CScriptVarPtr CScriptVarPrimitive::toObject() { return this; }
+CScriptVarPtr CScriptVarPrimitive::toString_CallBack( CScriptResult &execute, int radix/*=0*/ ) {
+	return newScriptVar(toCString(radix));
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+// CScriptVarUndefined
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(Undefined);
+CScriptVarUndefined::CScriptVarUndefined(CTinyJS *Context) : CScriptVarPrimitive(Context, Context->objectPrototype) { }
+CScriptVarUndefined::~CScriptVarUndefined() {}
+CScriptVarPtr CScriptVarUndefined::clone() { return new CScriptVarUndefined(*this); }
+bool CScriptVarUndefined::isUndefined() { return true; }
+
+CNumber CScriptVarUndefined::toNumber_Callback() { return NaN; }
+string CScriptVarUndefined::toCString(int radix/*=0*/) { return "undefined"; }
+string CScriptVarUndefined::getVarType() { return "undefined"; }
+
+
+////////////////////////////////////////////////////////////////////////// 
+// CScriptVarNull
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(Null);
+CScriptVarNull::CScriptVarNull(CTinyJS *Context) : CScriptVarPrimitive(Context, Context->objectPrototype) { }
+CScriptVarNull::~CScriptVarNull() {}
+CScriptVarPtr CScriptVarNull::clone() { return new CScriptVarNull(*this); }
+bool CScriptVarNull::isNull() { return true; }
+
+CNumber CScriptVarNull::toNumber_Callback() { return 0; }
+string CScriptVarNull::toCString(int radix/*=0*/) { return "null"; }
+string CScriptVarNull::getVarType() { return "null"; }
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarString
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarString::CScriptVarString(CTinyJS *Context, const string &Data) : CScriptVarPrimitive(Context, Context->stringPrototype), data(Data) {
+	addChild("length", newScriptVar(data.size()), SCRIPTVARLINK_CONSTANT);
+/*
+	CScriptVarLinkPtr acc = addChild("length", newScriptVar(Accessor), 0);
+	CScriptVarFunctionPtr getter(::newScriptVar(Context, this, &CScriptVarString::native_Length, 0));
+	getter->setFunctionData(new CScriptTokenDataFnc);
+	acc->getVarPtr()->addChild(TINYJS_ACCESSOR_GET_VAR, getter, 0);
+*/
+}
+CScriptVarString::~CScriptVarString() {}
+CScriptVarPtr CScriptVarString::clone() { return new CScriptVarString(*this); }
+bool CScriptVarString::isString() { return true; }
+
+bool CScriptVarString::toBoolean() { return data.length()!=0; }
+CNumber CScriptVarString::toNumber_Callback() { return data.c_str(); }
+string CScriptVarString::toCString(int radix/*=0*/) { return data; }
+
+string CScriptVarString::getParsableString(const string &indentString, const string &indent, uint32_t uniqueID, bool &hasRecursion) { return getJSString(data); }
+string CScriptVarString::getVarType() { return "string"; }
+
+CScriptVarPtr CScriptVarString::toObject() { 
+	CScriptVarPtr ret = newScriptVar(CScriptVarPrimitivePtr(this), context->stringPrototype); 
+	ret->addChild("length", newScriptVar(data.size()), SCRIPTVARLINK_CONSTANT);
+	return ret;
+}
+
+CScriptVarPtr CScriptVarString::toString_CallBack( CScriptResult &execute, int radix/*=0*/ ) {
+	return this;
+}
+
+int CScriptVarString::getChar(uint32_t Idx) {
+	if((string::size_type)Idx >= data.length())
+		return -1;
+	else
+		return (unsigned char)data[Idx];
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CNumber
+//////////////////////////////////////////////////////////////////////////
+
+NegativeZero_t NegativeZero;
+declare_dummy_t(NaN);
+Infinity InfinityPositive(1);
+Infinity InfinityNegative(-1);
+#if 1
+static inline bool _isNaN(volatile double *Value1, volatile double *Value2) {
+	return !(*Value1==*Value2);
+}
+
+static inline bool isNaN(double Value) {
+	return _isNaN(&Value, &Value);
+}
+inline bool isNegZero(double d) {
+	double x=-0.0;
+	return memcmp(&d, &x, sizeof(double))==0;
+}
+
+CNumber &CNumber::operator=(double Value) { 
+	double integral;
+	if(isNegZero(Value))
+		type=tnNULL, Int32=0;
+	else if(numeric_limits<double>::has_infinity && Value == numeric_limits<double>::infinity())
+		type=tInfinity, Int32=1; 
+	else if(numeric_limits<double>::has_infinity && Value == -numeric_limits<double>::infinity())
+		type=tInfinity, Int32=-1; 
+	else if(::isNaN(Value) || Value == numeric_limits<double>::quiet_NaN() || Value == std::numeric_limits<double>::signaling_NaN())
+		type=tNaN, Int32=0; 
+	else if(modf(Value, &integral)==0.0 && numeric_limits<int32_t>::min()<=integral && integral<=numeric_limits<int32_t>::max()) 
+		type=tInt32, Int32=int32_t(integral);
+	else 
+		type=tDouble, Double=Value; 
+	return *this; 
+}
+CNumber &CNumber::operator=(const char *str) {
+	
+	while(isWhitespace(*str)) str++;
+	const char *start = str, *endptr;
+	if(*str == '-' || *str == '+') str++;
+	if(*str == '0' && ( str[1]=='x' || str[1]=='X'))
+		parseInt(start, 16, &endptr);
+	else if(*str == '0' && str[1]>='0' && str[1]<='7')
+		parseInt(start, 8, &endptr);
+	else
+		parseFloat(start, &endptr);
+	while(isWhitespace(*endptr)) endptr++;
+	if(*endptr != '\0')
+		type=tNaN, Int32=0;
+	return *this;
+}
+int32_t CNumber::parseInt(const char * str, int32_t radix/*=0*/, const char **endptr/*=0*/) {
+	type=tInt32, Int32=0;
+	if(endptr) *endptr = str;
+	bool stripPrefix = false; //< is true if radix==0 or radix==16
+	if(radix == 0) {
+		radix=10;
+		stripPrefix = true;
+	} else if(radix < 2 || radix > 36) {
+		type = tNaN;
+		return 0;
+	} else
+		stripPrefix = radix == 16;
+	while(isWhitespace(*str)) str++;
+	int sign=1;
+	if(*str=='-') sign=-1,str++;
+	else if(*str=='+') str++;
+	if(stripPrefix && *str=='0' && (str[1]=='x' || str[1]=='X')) str+=2, radix=16;
+	else if(stripPrefix && *str=='0' && str[1]>='0' && str[1]<='7') str+=1, radix=8;
+	int32_t max = 0x7fffffff/radix;
+	const char *start = str;
+	for( ; *str; str++) {
+		if(*str >= '0' && *str <= '0'-1+radix) Int32 = Int32*radix+*str-'0';
+		else if(*str>='a' && *str<='a'-11+radix) Int32 = Int32*radix+*str-'a'+10;
+		else if(*str>='A' && *str<='A'-11+radix) Int32 = Int32*radix+*str-'A'+10;
+		else break;
+		if(Int32 >= max) {
+			type=tDouble, Double=double(Int32);
+			for(str++ ; *str; str++) {
+				if(*str >= '0' && *str <= '0'-1+radix) Double = Double *radix+*str-'0';
+				else if(*str>='a' && *str<='a'-11+radix) Double = Double *radix+*str-'a'+10;
+				else if(*str>='A' && *str<='A'-11+radix) Double = Double *radix+*str-'A'+10;
+				else break;
+			}
+			break;
+		}
+	}
+	if(str == start) {
+		type= tNaN;
+		return 0;
+	}
+	if(sign<0 && ((type==tInt32 && Int32==0) || (type==tDouble && Double==0.0))) { type=tnNULL,Int32=0; return radix; }
+	if(type==tInt32) operator=(sign<0 ? -Int32 : Int32);
+	else operator=(sign<0 ? -Double : Double);
+	if(endptr) *endptr = (char*)str;
+	return radix;
+}
+
+void CNumber::parseFloat(const char * str, const char **endptr/*=0*/) {
+	type=tInt32, Int32=0;
+	if(endptr) *endptr = str;
+	while(isWhitespace(*str)) str++;
+	int sign=1;
+	if(*str=='-') sign=-1,str++;
+	else if(*str=='+') str++;
+	if(strncmp(str, "Infinity", 8) == 0) { type=tInfinity, Int32=sign; return; }
+	double d = strtod(str, (char**)endptr);
+	operator=(sign>0 ? d : -d);
+	return;
+}
+
+CNumber CNumber::add(const CNumber &Value) const {
+	if(type==tNaN || Value.type==tNaN) 
+		return CNumber(tNaN);
+	else if(type==tInfinity || Value.type==tInfinity) {
+		if(type!=tInfinity)
+			return Value;
+		else if(Value.type!=tInfinity || sign()==Value.sign())
+			return *this;
+		else
+			return CNumber(tNaN);
+	} else if(type==tnNULL)
+		return Value;
+	else if(Value.type==tnNULL)
+		return *this;
+	else if(type==tDouble || Value.type==tDouble)
+		return CNumber(toDouble()+Value.toDouble());
+	else {
+		int32_t range_max = numeric_limits<int32_t>::max();
+		int32_t range_min = numeric_limits<int32_t>::min();
+		if(Int32>0) range_max-=Int32;
+		else if(Int32<0) range_min-=Int32;
+		if(range_min<=Value.Int32 && Value.Int32<=range_max)
+			return CNumber(Int32+Value.Int32);
+		else
+			return CNumber(double(Int32)+double(Value.Int32));
+	}
+}
+
+CNumber CNumber::operator-() const {
+	switch(type) {
+	case tInt32:
+		if(Int32==0)
+			return CNumber(NegativeZero);
+	case tnNULL:
+		return CNumber(-Int32);
+	case tDouble:
+		return CNumber(-Double);
+	case tInfinity:
+		return CNumber(tInfinity, -Int32);
+	default:
+		return CNumber(tNaN);
+	}
+}
+
+static inline int bits(uint32_t Value) {
+	uint32_t b=0, mask=0xFFFF0000UL;
+	for(int shift=16; shift>0 && Value!=0; shift>>=1, mask>>=shift) {
+		if(Value & mask) {
+			b += shift;
+			Value>>=shift;
+		}
+	}
+	return b;
+}
+static inline int bits(int32_t Value) {
+	return bits(uint32_t(Value<0?-Value:Value));
+}
+
+CNumber CNumber::multi(const CNumber &Value) const {
+	if(type==tNaN || Value.type==tNaN)
+		return CNumber(tNaN);
+	else if(type==tInfinity || Value.type==tInfinity) {
+		if(isZero() || Value.isZero())
+			return CNumber(tNaN);
+		else 
+			return CNumber(tInfinity, sign()==Value.sign()?1:-1);
+	} else if(isZero() || Value.isZero()) {
+		if(sign()==Value.sign())
+			return CNumber(0);
+		else
+			return CNumber(NegativeZero);
+	} else if(type==tDouble || Value.type==tDouble)
+		return CNumber(toDouble()*Value.toDouble());
+	else {
+		// Int32*Int32
+		if(bits(Int32)+bits(Value.Int32) <= 29)
+			return CNumber(Int32*Value.Int32);
+		else
+			return CNumber(double(Int32)*double(Value.Int32));
+	}
+}
+
+
+CNumber CNumber::div( const CNumber &Value ) const {
+	if(type==tNaN || Value.type==tNaN) return CNumber(tNaN);
+	int Sign = sign()*Value.sign();
+	if(type==tInfinity) {
+		if(Value.type==tInfinity) return CNumber(tNaN);
+		else return CNumber(tInfinity, Sign);
+	}
+	if(Value.type==tInfinity) {
+		if(Sign<0) return CNumber(NegativeZero);
+		else return CNumber(0);
+	} else if(Value.isZero()) {
+		if(isZero()) return CNumber(tNaN);
+		else return CNumber(tInfinity, Sign);
+	} else
+		return CNumber(toDouble() / Value.toDouble());
+}
+
+CNumber CNumber::modulo( const CNumber &Value ) const {
+	if(type==tNaN || type==tInfinity || Value.type==tNaN || Value.isZero()) return CNumber(tNaN);
+	if(Value.type==tInfinity) return CNumber(*this);
+	if(isZero()) return CNumber(0);
+	if(type==tDouble || Value.type==tDouble) {
+		double n = toDouble(), d = Value.toDouble(), q;
+		modf(n/d, &q);
+		return CNumber(n - (d * q));
+	} else
+		return CNumber(Int32 % Value.Int32);
+}
+
+CNumber CNumber::round() const {
+	if(type != tDouble) return CNumber(*this);
+	if(Double < 0.0 && Double >= -0.5)
+		return CNumber(NegativeZero);
+	return CNumber(::floor(Double+0.5));
+}
+
+CNumber CNumber::floor() const {
+	if(type != tDouble) return CNumber(*this);
+	return CNumber(::floor(Double));
+}
+
+CNumber CNumber::ceil() const {
+	if(type != tDouble) return CNumber(*this);
+	return CNumber(::ceil(Double));
+}
+
+CNumber CNumber::abs() const {
+	if(sign()<0) return -CNumber(*this);
+	else return CNumber(*this);
+}
+
+CNumber CNumber::shift(const CNumber &Value, bool Right) const {
+	int32_t lhs = toInt32();
+	uint32_t rhs = Value.toUInt32() & 0x1F;
+	return CNumber(Right ? lhs>>rhs : lhs<<rhs);
+}
+
+CNumber CNumber::ushift(const CNumber &Value, bool Right) const {
+	uint32_t lhs = toUInt32();
+	uint32_t rhs = Value.toUInt32() & 0x1F;
+	return CNumber(Right ? lhs>>rhs : lhs<<rhs);
+}
+
+CNumber CNumber::binary(const CNumber &Value, char Mode) const {
+	int32_t lhs = toInt32();
+	int32_t rhs = Value.toInt32();
+
+	switch(Mode) {
+	case '&':	lhs&=rhs; break;
+	case '|':	lhs|=rhs; break;
+	case '^':	lhs^=rhs; break;
+	}
+	return CNumber(lhs);
+}
+
+
+int CNumber::less( const CNumber &Value ) const {
+	if(type==tNaN || Value.type==tNaN) return 0;
+	else if(type==tInfinity) {
+		if(Value.type==tInfinity) return Int32<Value.Int32 ? 1 : -1;
+		return -Int32;
+	} else if(Value.type==tInfinity) 
+		return Value.Int32;
+	else if(isZero() && Value.isZero()) return -1;
+	else if(type==tDouble || Value.type==tDouble) return toDouble() < Value.toDouble() ? 1 : -1;
+	return toInt32() < Value.toInt32() ? 1 : -1;
+}
+
+bool CNumber::equal( const CNumber &Value ) const {
+	if(type==tNaN || Value.type==tNaN) return false;
+	else if(type==tInfinity) {
+		if(Value.type==tInfinity) return Int32==Value.Int32;
+		return false;
+	} else if(Value.type==tInfinity) 
+		return false;
+	else if(isZero() && Value.isZero()) return true;
+	else if(type==tDouble || Value.type==tDouble) return toDouble() == Value.toDouble();
+	return toInt32() == Value.toInt32();
+}
+
+bool CNumber::isZero() const
+{
+	switch(type) {
+	case tInt32:
+		return Int32==0;
+	case tnNULL:
+		return true;
+	case tDouble:
+		return Double==0.0;
+	default:
+		return false;
+	}
+}
+
+bool CNumber::isInteger() const
+{
+	double integral;
+	switch(type) {
+	case tInt32:
+	case tnNULL:
+		return true;
+	case tDouble:
+		return modf(Double, &integral)==0.0;
+	default:
+		return false;
+	}
+}
+
+int CNumber::sign() const {
+	switch(type) {
+	case tInt32:
+	case tInfinity:
+		return Int32<0?-1:1;
+	case tnNULL:
+		return -1;
+	case tDouble:
+		return Double<0.0?-1:1;
+	default:
+		return 1;
+	}
+}
+char *tiny_ltoa(int32_t val, unsigned radix) {
+	char *buf, *buf_end, *p, *firstdig, temp;
+	unsigned digval;
+
+	buf = (char*)malloc(64);
+	if(!buf) return 0;
+	buf_end = buf+64-1; // -1 for '\0'
+
+	p = buf;
+	if (val < 0) {
+		*p++ = '-';
+		val = -val;
+	}
+
+	do {
+		digval = (unsigned) (val % radix);
+		val /= radix;
+		*p++ = (char) (digval + (digval > 9 ? ('a'-10) : '0'));
+		if(p==buf_end) {
+			char *new_buf = (char *)realloc(buf, buf_end-buf+16+1); // for '\0'
+			if(!new_buf) { free(buf); return 0; }
+			p = new_buf + (buf_end - buf);
+			buf_end = p + 16;
+			buf = new_buf;
+		}
+	} while (val > 0);
+
+	// We now have the digit of the number in the buffer, but in reverse
+	// order.  Thus we reverse them now.
+	*p-- = '\0';
+	firstdig = buf;
+	if(*firstdig=='-') firstdig++;
+	do	{
+		temp = *p;
+		*p = *firstdig;
+		*firstdig = temp;
+		p--;
+		firstdig++;
+	} while (firstdig < p);
+	return buf;
+}
+
+static char *tiny_dtoa(double val, unsigned radix) {
+	char *buf, *buf_end, *p, temp;
+	unsigned digval;
+
+	buf = (char*)malloc(64);
+	if(!buf) return 0;
+	buf_end = buf+64-2; // -1 for '.' , -1 for '\0'
+
+	p = buf;
+	if (val < 0.0) {
+		*p++ = '-';
+		val = -val;
+	}
+
+	double val_1 = floor(val);
+	double val_2 = val - val_1;
+
+
+	do {
+		double tmp = val_1 / radix;
+		val_1 = floor(tmp);
+		digval = (unsigned)((tmp - val_1) * radix);
+
+		*p++ = (char) (digval + (digval > 9 ? ('a'-10) : '0'));
+		if(p==buf_end) {
+			char *new_buf = (char *)realloc(buf, buf_end-buf+16+2); // +2 for '.' + '\0'
+			if(!new_buf) { free(buf); return 0; }
+			p = new_buf + (buf_end - buf);
+			buf_end = p + 16;
+			buf = new_buf;
+		}
+	} while (val_1 > 0.0);
+
+	// We now have the digit of the number in the buffer, but in reverse
+	// order.  Thus we reverse them now.
+	char *p1 = buf;
+	char *p2 = p-1;
+	do	{
+		temp = *p2;
+		*p2-- = *p1;
+		*p1++ = temp;
+	} while (p1 < p2);
+
+	if(val_2) {
+		*p++ = '.';
+		do {
+			val_2 *= radix;
+			digval = (unsigned)(val_2);
+			val_2 -= digval;
+
+			*p++ = (char) (digval + (digval > 9 ? ('a'-10) : '0'));
+			if(p==buf_end) {
+				char *new_buf = (char *)realloc(buf, buf_end-buf+16);
+				if(!new_buf) { free(buf); return 0; }
+				p = new_buf + (buf_end - buf);
+				buf_end = p + 16;
+				buf = new_buf;
+			}
+		} while (val_2 > 0.0);
+
+	}
+	*p = '\0';
+	return buf;
+}
+std::string CNumber::toString( uint32_t Radix/*=10*/ ) const {
+	char *str;
+	if(2 > Radix || Radix > 36)
+		Radix = 10; // todo error;
+	switch(type) {
+	case tInt32:
+		if( (str = tiny_ltoa(Int32, Radix)) ) {
+			string ret(str); free(str);
+			return ret;
+		}
+		break;
+	case tnNULL:
+		return "0";
+	case tDouble:
+		if(Radix==10) {
+			ostringstream str;
+			str.unsetf(ios::floatfield);
+#if (defined(_MSC_VER) && _MSC_VER >= 1600) || __cplusplus >= 201103L
+			str.precision(numeric_limits<double>::max_digits10);
+#else
+			str.precision(numeric_limits<double>::digits10+2);
+#endif
+			str << Double;
+			return str.str();
+		} else if( (str = tiny_dtoa(Double, Radix)) ) {
+			string ret(str); free(str);
+			return ret;
+		}
+		break;
+	case tInfinity:
+		return Int32<0?"-Infinity":"Infinity";
+	case tNaN:
+		return "NaN";
+	}
+	return "";
+}
+
+double CNumber::toDouble() const
+{
+	switch(type) {
+	case tnNULL:
+		return -0.0;
+	case tInt32:
+		return double(Int32);
+	case tDouble:
+		return Double;
+	case tNaN:
+		return std::numeric_limits<double>::quiet_NaN();
+	case tInfinity:
+		return Int32<0 ? -std::numeric_limits<double>::infinity():std::numeric_limits<double>::infinity();
+	}
+	return 0.0;
+}
+
+#endif
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarNumber
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarNumber::CScriptVarNumber(CTinyJS *Context, const CNumber &Data) : CScriptVarPrimitive(Context, Context->numberPrototype), data(Data) {}
+CScriptVarNumber::~CScriptVarNumber() {}
+CScriptVarPtr CScriptVarNumber::clone() { return new CScriptVarNumber(*this); }
+bool CScriptVarNumber::isNumber() { return true; }
+bool CScriptVarNumber::isInt() { return data.isInt32(); }
+bool CScriptVarNumber::isDouble() { return data.isDouble(); }
+bool CScriptVarNumber::isRealNumber() { return isInt() || isDouble(); }
+bool CScriptVarNumber::isNaN() { return data.isNaN(); }
+int CScriptVarNumber::isInfinity() { return data.isInfinity(); }
+
+bool CScriptVarNumber::toBoolean() { return data.toBoolean(); }
+CNumber CScriptVarNumber::toNumber_Callback() { return data; }
+string CScriptVarNumber::toCString(int radix/*=0*/) { return data.toString(radix); }
+
+string CScriptVarNumber::getVarType() { return "number"; }
+
+CScriptVarPtr CScriptVarNumber::toObject() { return newScriptVar(CScriptVarPrimitivePtr(this), context->numberPrototype); }
+inline define_newScriptVar_Fnc(Number, CTinyJS *Context, const CNumber &Obj) { 
+	if(!Obj.isInt32() && !Obj.isDouble()) {
+		if(Obj.isNaN()) return Context->constScriptVar(NaN);
+		if(Obj.isInfinity()) return Context->constScriptVar(Infinity(Obj.sign()));
+		if(Obj.isNegativeZero()) return Context->constScriptVar(NegativeZero);
+	}
+	return new CScriptVarNumber(Context, Obj); 
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+// CScriptVarBool
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarBool::CScriptVarBool(CTinyJS *Context, bool Data) : CScriptVarPrimitive(Context, Context->booleanPrototype), data(Data) {}
+CScriptVarBool::~CScriptVarBool() {}
+CScriptVarPtr CScriptVarBool::clone() { return new CScriptVarBool(*this); }
+bool CScriptVarBool::isBool() { return true; }
+
+bool CScriptVarBool::toBoolean() { return data; }
+CNumber CScriptVarBool::toNumber_Callback() { return data?1:0; }
+string CScriptVarBool::toCString(int radix/*=0*/) { return data ? "true" : "false"; }
+
+string CScriptVarBool::getVarType() { return "boolean"; }
+
+CScriptVarPtr CScriptVarBool::toObject() { return newScriptVar(CScriptVarPrimitivePtr(this), context->booleanPrototype); }
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarObject
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(Object);
+declare_dummy_t(StopIteration);
+CScriptVarObject::CScriptVarObject(CTinyJS *Context) : CScriptVar(Context, Context->objectPrototype) { }
+CScriptVarObject::~CScriptVarObject() {}
+CScriptVarPtr CScriptVarObject::clone() { return new CScriptVarObject(*this); }
+CScriptVarPrimitivePtr CScriptVarObject::getRawPrimitive() { return value; }
+bool CScriptVarObject::isObject() { return true; }
+
+string CScriptVarObject::getParsableString(const string &indentString, const string &indent, uint32_t uniqueID, bool &hasRecursion) {
+	getParsableStringRecursionsCheck();
+	string destination;
+	const char *nl = indent.size() ? "\n" : " ";
+	const char *comma = "";
+	destination.append("{");
+	if(Childs.size()) {
+		string new_indentString = indentString + indent;
+		for(SCRIPTVAR_CHILDS_it it = Childs.begin(); it != Childs.end(); ++it) {
+			if((*it)->isEnumerable()) {
+				destination.append(comma); comma=",";
+				destination.append(nl).append(new_indentString).append(getIDString((*it)->getName()));
+				destination.append(" : ");
+				destination.append((*it)->getVarPtr()->getParsableString(new_indentString, indent, uniqueID, hasRecursion));
+			}
+		}
+		destination.append(nl).append(indentString);
+	}
+	destination.append("}");
+	return destination;
+}
+string CScriptVarObject::getVarType() { return "object"; }
+
+CScriptVarPtr CScriptVarObject::toObject() { return this; }
+
+CScriptVarPtr CScriptVarObject::valueOf_CallBack() {
+	if(value)
+		return value->valueOf_CallBack();
+	return CScriptVar::valueOf_CallBack();
+}
+CScriptVarPtr CScriptVarObject::toString_CallBack(CScriptResult &execute, int radix) { 
+	if(value)
+		return value->toString_CallBack(execute, radix);
+	return newScriptVar("[object Object]"); 
+};
+
+void CScriptVarObject::setTemporaryID_recursive( uint32_t ID ) {
+	CScriptVar::setTemporaryID_recursive(ID);
+	if(value) value->setTemporaryID_recursive(ID);
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarError
+//////////////////////////////////////////////////////////////////////////
+
+const char *ERROR_NAME[] = {"Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError"};
+
+CScriptVarError::CScriptVarError(CTinyJS *Context, ERROR_TYPES type, const char *message, const char *file, int line, int column) : CScriptVarObject(Context, Context->getErrorPrototype(type)) {
+	if(message && *message) addChild("message", newScriptVar(message));
+	if(file && *file) addChild("fileName", newScriptVar(file));
+	if(line>=0) addChild("lineNumber", newScriptVar(line+1));
+	if(column>=0) addChild("column", newScriptVar(column+1));
+}
+
+CScriptVarError::~CScriptVarError() {}
+CScriptVarPtr CScriptVarError::clone() { return new CScriptVarError(*this); }
+bool CScriptVarError::isError() { return true; }
+
+CScriptVarPtr CScriptVarError::toString_CallBack(CScriptResult &execute, int radix) {
+	CScriptVarLinkPtr link;
+	string name = ERROR_NAME[Error];
+	link = findChildWithPrototypeChain("name"); if(link) name = link->toString(execute);
+	string message; link = findChildWithPrototypeChain("message"); if(link) message = link->toString(execute);
+	string fileName; link = findChildWithPrototypeChain("fileName"); if(link) fileName = link->toString(execute);
+	int lineNumber=-1; link = findChildWithPrototypeChain("lineNumber"); if(link) lineNumber = link->toNumber().toInt32();
+	int column=-1; link = findChildWithPrototypeChain("column"); if(link) column = link->toNumber().toInt32();
+	ostringstream msg;
+	msg << name << ": " << message;
+	if(lineNumber >= 0) msg << " at Line:" << lineNumber+1;
+	if(column >=0) msg << " Column:" << column+1;
+	if(fileName.length()) msg << " in " << fileName;
+	return newScriptVar(msg.str());
+}
+
+CScriptException *CScriptVarError::toCScriptException()
+{
+	CScriptVarLinkPtr link;
+	string name = ERROR_NAME[Error];
+	link = findChildWithPrototypeChain("name"); if(link) name = link->toString();
+	int ErrorCode;
+	for(ErrorCode=(sizeof(ERROR_NAME)/sizeof(ERROR_NAME[0]))-1; ErrorCode>0; ErrorCode--) {
+		if(name == ERROR_NAME[ErrorCode]) break;
+	}
+	string message; link = findChildWithPrototypeChain("message"); if(link) message = link->toString();
+	string fileName; link = findChildWithPrototypeChain("fileName"); if(link) fileName = link->toString();
+	int lineNumber=-1; link = findChildWithPrototypeChain("lineNumber"); if(link) lineNumber = link->toNumber().toInt32();
+	int column=-1; link = findChildWithPrototypeChain("column"); if(link) column = link->toNumber().toInt32();
+	return new CScriptException((enum ERROR_TYPES)ErrorCode, message, fileName, lineNumber, column); 
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+// CScriptVarArray
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(Array);
+CScriptVarArray::CScriptVarArray(CTinyJS *Context) : CScriptVarObject(Context, Context->arrayPrototype) {
+	CScriptVarLinkPtr acc = addChild("length", newScriptVar(Accessor), 0);
+	CScriptVarFunctionPtr getter(::newScriptVar(Context, this, &CScriptVarArray::native_Length, 0));
+	getter->setFunctionData(new CScriptTokenDataFnc);
+	acc->getVarPtr()->addChild(TINYJS_ACCESSOR_GET_VAR, getter, 0);
+}
+
+CScriptVarArray::~CScriptVarArray() {}
+CScriptVarPtr CScriptVarArray::clone() { return new CScriptVarArray(*this); }
+bool CScriptVarArray::isArray() { return true; }
+string CScriptVarArray::getParsableString(const string &indentString, const string &indent, uint32_t uniqueID, bool &hasRecursion) {
+	getParsableStringRecursionsCheck();
+	string destination;
+	const char *nl = indent.size() ? "\n" : " ";
+	const char *comma = "";
+	destination.append("[");
+	int len = getArrayLength();
+	if(len) {
+		string new_indentString = indentString + indent;
+		for (int i=0;i<len;i++) {
+			destination.append(comma); comma = ",";
+			destination.append(nl).append(new_indentString).append(getArrayIndex(i)->getParsableString(new_indentString, indent, uniqueID, hasRecursion));
+		}
+		destination.append(nl).append(indentString);
+	}
+	destination.append("]");
+	return destination;
+}
+CScriptVarPtr CScriptVarArray::toString_CallBack( CScriptResult &execute, int radix/*=0*/ ) {
+	ostringstream destination;
+	int len = getArrayLength();
+	for (int i=0;i<len;i++) {
+		destination << getArrayIndex(i)->toString(execute);
+		if (i<len-1) destination  << ", ";
+	}
+	return newScriptVar(destination.str());
+
+}
+
+void CScriptVarArray::native_Length(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(newScriptVar(c->getArgument("this")->getArrayLength()));
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarRegExp
+//////////////////////////////////////////////////////////////////////////
+
+#ifndef NO_REGEXP
+
+CScriptVarRegExp::CScriptVarRegExp(CTinyJS *Context, const string &Regexp, const string &Flags) : CScriptVarObject(Context, Context->regexpPrototype), regexp(Regexp), flags(Flags) {
+	addChild("global", ::newScriptVarAccessor<CScriptVarRegExp>(Context, this, &CScriptVarRegExp::native_Global, 0, 0, 0), 0);
+	addChild("ignoreCase", ::newScriptVarAccessor<CScriptVarRegExp>(Context, this, &CScriptVarRegExp::native_IgnoreCase, 0, 0, 0), 0);
+	addChild("multiline", ::newScriptVarAccessor<CScriptVarRegExp>(Context, this, &CScriptVarRegExp::native_Multiline, 0, 0, 0), 0);
+	addChild("sticky", ::newScriptVarAccessor<CScriptVarRegExp>(Context, this, &CScriptVarRegExp::native_Sticky, 0, 0, 0), 0);
+	addChild("regexp", ::newScriptVarAccessor<CScriptVarRegExp>(Context, this, &CScriptVarRegExp::native_Source, 0, 0, 0), 0);
+	addChild("lastIndex", newScriptVar(0));
+}
+CScriptVarRegExp::~CScriptVarRegExp() {}
+CScriptVarPtr CScriptVarRegExp::clone() { return new CScriptVarRegExp(*this); }
+bool CScriptVarRegExp::isRegExp() { return true; }
+//int CScriptVarRegExp::getInt() {return strtol(regexp.c_str(),0,0); }
+//bool CScriptVarRegExp::getBool() {return regexp.length()!=0;}
+//double CScriptVarRegExp::getDouble() {return strtod(regexp.c_str(),0);}
+//string CScriptVarRegExp::getString() { return "/"+regexp+"/"+flags; }
+//string CScriptVarRegExp::getParsableString(const string &indentString, const string &indent, uint32_t uniqueID, bool &hasRecursion) { return getString(); }
+CScriptVarPtr CScriptVarRegExp::toString_CallBack(CScriptResult &execute, int radix) {
+	return newScriptVar("/"+regexp+"/"+flags);
+}
+void CScriptVarRegExp::native_Global(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(constScriptVar(Global()));
+}
+void CScriptVarRegExp::native_IgnoreCase(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(constScriptVar(IgnoreCase()));
+}
+void CScriptVarRegExp::native_Multiline(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(constScriptVar(Multiline()));
+}
+void CScriptVarRegExp::native_Sticky(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(constScriptVar(Sticky()));
+}
+void CScriptVarRegExp::native_Source(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(newScriptVar(regexp));
+}
+unsigned int CScriptVarRegExp::LastIndex() {
+	CScriptVarPtr lastIndex = findChild("lastIndex");
+	if(lastIndex) return lastIndex->toNumber().toInt32();
+	return 0;
+}
+void CScriptVarRegExp::LastIndex(unsigned int Idx) {
+	addChildOrReplace("lastIndex", newScriptVar((int)Idx));
+}
+
+CScriptVarPtr CScriptVarRegExp::exec( const string &Input, bool Test /*= false*/ )
+{
+	regex::flag_type flags = regex_constants::ECMAScript;
+	if(IgnoreCase()) flags |= regex_constants::icase;
+	bool global = Global(), sticky = Sticky();
+	unsigned int lastIndex = LastIndex();
+	int offset = 0;
+	if(global || sticky) {
+		if(lastIndex > Input.length()) goto failed; 
+		offset=lastIndex;
+	}
+	{
+		regex_constants::match_flag_type mflag = sticky?regex_constants::match_continuous:regex_constants::match_default;
+		if(offset) mflag |= regex_constants::match_prev_avail;
+		smatch match;
+		if(regex_search(Input.begin()+offset, Input.end(), match, regex(regexp, flags), mflag) ) {
+			LastIndex(offset+match.position()+match.str().length());
+			if(Test) return constScriptVar(true);
+
+			CScriptVarArrayPtr retVar = newScriptVar(Array);
+			retVar->addChild("input", newScriptVar(Input));
+			retVar->addChild("index", newScriptVar(match.position()));
+			for(smatch::size_type idx=0; idx<match.size(); idx++)
+				retVar->addChild(int2string(idx), newScriptVar(match[idx].str()));
+			return retVar;
+		}
+	}
+failed:
+	if(global || sticky) 
+		LastIndex(0); 
+	if(Test) return constScriptVar(false);
+	return constScriptVar(Null);
+}
+
+const char * CScriptVarRegExp::ErrorStr( int Error )
+{
+	switch(Error) {
+	case regex_constants::error_badbrace: return "the expression contained an invalid count in a { } expression";
+	case regex_constants::error_badrepeat: return "a repeat expression (one of '*', '?', '+', '{' in most contexts) was not preceded by an expression";
+	case regex_constants::error_brace: return "the expression contained an unmatched '{' or '}'";
+	case regex_constants::error_brack: return "the expression contained an unmatched '[' or ']'";
+	case regex_constants::error_collate: return "the expression contained an invalid collating element name";
+	case regex_constants::error_complexity: return "an attempted match failed because it was too complex";
+	case regex_constants::error_ctype: return "the expression contained an invalid character class name";
+	case regex_constants::error_escape: return "the expression contained an invalid escape sequence";
+	case regex_constants::error_paren: return "the expression contained an unmatched '(' or ')'";
+	case regex_constants::error_range: return "the expression contained an invalid character range specifier";
+	case regex_constants::error_space: return "parsing a regular expression failed because there were not enough resources available";
+	case regex_constants::error_stack: return "an attempted match failed because there was not enough memory available";
+	case regex_constants::error_backref: return "the expression contained an invalid back reference";
+	default: return "";
+	}
+}
+
+#endif /* NO_REGEXP */
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarDefaultIterator
+//////////////////////////////////////////////////////////////////////////
+
+//declare_dummy_t(DefaultIterator);
+CScriptVarDefaultIterator::CScriptVarDefaultIterator(CTinyJS *Context, const CScriptVarPtr &Object, int Mode) 
+	: CScriptVarObject(Context, Context->iteratorPrototype), mode(Mode), object(Object) {
+	object->keys(keys, true);
+	pos = keys.begin();
+	addChild("next", ::newScriptVar(context, this, &CScriptVarDefaultIterator::native_next, 0));
+}
+CScriptVarDefaultIterator::~CScriptVarDefaultIterator() {}
+CScriptVarPtr CScriptVarDefaultIterator::clone() { return new CScriptVarDefaultIterator(*this); }
+bool CScriptVarDefaultIterator::isIterator()		{return true;}
+void CScriptVarDefaultIterator::native_next(const CFunctionsScopePtr &c, void *data) {
+	if(pos==keys.end()) throw constScriptVar(StopIteration);
+	CScriptVarPtr ret, ret0, ret1;
+	if(mode&1) ret0 = newScriptVar(*pos);
+	if(mode&2) ret1 = object->findChildWithStringChars(*pos);
+	pos++;
+	if(mode==3) {
+		ret = newScriptVar(Array);
+		ret->setArrayIndex(0, ret0);
+		ret->setArrayIndex(1, ret1);
+	} else if(mode==1) 
+		ret = ret0;
+	else
+		ret = ret1;
+	c->setReturnVar(ret);
+}
+
+////////////////////////////////////////////////////////////////////////// 
+// CScriptVarFunction
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarFunction::CScriptVarFunction(CTinyJS *Context, CScriptTokenDataFnc *Data) : CScriptVarObject(Context, Context->functionPrototype), data(0) { 
+	setFunctionData(Data); 
+}
+CScriptVarFunction::~CScriptVarFunction() { setFunctionData(0); }
+CScriptVarPtr CScriptVarFunction::clone() { return new CScriptVarFunction(*this); }
+bool CScriptVarFunction::isObject() { return true; }
+bool CScriptVarFunction::isFunction() { return true; }
+bool CScriptVarFunction::isPrimitive()	{ return false; } 
+
+//string CScriptVarFunction::getString() {return "[ Function ]";}
+string CScriptVarFunction::getVarType() { return "function"; }
+string CScriptVarFunction::getParsableString(const string &indentString, const string &indent, uint32_t uniqueID, bool &hasRecursion) {
+	getParsableStringRecursionsCheck();
+	string destination;
+	destination.append("function ").append(data->name);
+	// get list of arguments
+	destination.append(data->getArgumentsString()); 
+
+	if(isNative() || isBounded())
+		destination.append("{ [native code] }");
+	else {
+		destination.append(CScriptToken::getParsableString(data->body, indentString, indent));
+		if(!data->body.size() || data->body.front().token != '{')
+			destination.append(";");
+	}
+	return destination;
+}
+
+CScriptVarPtr CScriptVarFunction::toString_CallBack(CScriptResult &execute, int radix){
+	bool hasRecursion;
+	return newScriptVar(getParsableString("", "  ", 0, hasRecursion));
+}
+
+CScriptTokenDataFnc *CScriptVarFunction::getFunctionData() { return data; }
+
+void CScriptVarFunction::setFunctionData(CScriptTokenDataFnc *Data) {
+	if(data) { data->unref(); data = 0; }
+	if(Data) { 
+		data = Data; data->ref(); 
+		addChildOrReplace("length", newScriptVar((int)data->arguments.size()), 0);
+		// can not add "name" here because name is a StingVar with length as getter
+		// length-getter is a function with a function name -> endless recursion
+		//addChildNoDup("name", newScriptVar(data->name), 0);
+	}
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarFunctionBounded
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarFunctionBounded::CScriptVarFunctionBounded(CScriptVarFunctionPtr BoundedFunction, CScriptVarPtr BoundedThis, const std::vector<CScriptVarPtr> &BoundedArguments) 
+	: CScriptVarFunction(BoundedFunction->getContext(), new CScriptTokenDataFnc) ,
+	boundedFunction(BoundedFunction),
+	boundedThis(BoundedThis),
+	boundedArguments(BoundedArguments) {
+		getFunctionData()->name = BoundedFunction->getFunctionData()->name;
+}
+CScriptVarFunctionBounded::~CScriptVarFunctionBounded(){}
+CScriptVarPtr CScriptVarFunctionBounded::clone() { return new CScriptVarFunctionBounded(*this); }
+bool CScriptVarFunctionBounded::isBounded() { return true; }
+void CScriptVarFunctionBounded::setTemporaryID_recursive( uint32_t ID ) {
+	CScriptVarFunction::setTemporaryID_recursive(ID);
+	boundedThis->setTemporaryID_recursive(ID);
+	for(vector<CScriptVarPtr>::iterator it=boundedArguments.begin(); it!=boundedArguments.end(); ++it)
+		(*it)->setTemporaryID_recursive(ID);
+}
+
+CScriptVarPtr CScriptVarFunctionBounded::callFunction( CScriptResult &execute, vector<CScriptVarPtr> &Arguments, const CScriptVarPtr &This, CScriptVarPtr *newThis/*=0*/ )
+{
+	vector<CScriptVarPtr> newArgs=boundedArguments;
+	newArgs.insert(newArgs.end(), Arguments.begin(), Arguments.end());
+	return context->callFunction(execute, boundedFunction, newArgs, newThis ? This : boundedThis, newThis);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarFunctionNative
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarFunctionNative::~CScriptVarFunctionNative() {}
+bool CScriptVarFunctionNative::isNative() { return true; }
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarFunctionNativeCallback
+//////////////////////////////////////////////////////////////////////////
+
+CScriptVarFunctionNativeCallback::~CScriptVarFunctionNativeCallback() {}
+CScriptVarPtr CScriptVarFunctionNativeCallback::clone() { return new CScriptVarFunctionNativeCallback(*this); }
+void CScriptVarFunctionNativeCallback::callFunction(const CFunctionsScopePtr &c) { jsCallback(c, jsUserData); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarAccessor
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(Accessor);
+CScriptVarAccessor::CScriptVarAccessor(CTinyJS *Context) : CScriptVarObject(Context, Context->objectPrototype) { }
+CScriptVarAccessor::CScriptVarAccessor(CTinyJS *Context, JSCallback getterFnc, void *getterData, JSCallback setterFnc, void *setterData) 
+	: CScriptVarObject(Context) 
+{
+	if(getterFnc)
+		addChild(TINYJS_ACCESSOR_GET_VAR, ::newScriptVar(Context, getterFnc, getterData), 0);
+	if(setterFnc)
+		addChild(TINYJS_ACCESSOR_SET_VAR, ::newScriptVar(Context, setterFnc, setterData), 0);
+}
+
+CScriptVarAccessor::CScriptVarAccessor( CTinyJS *Context, const CScriptVarFunctionPtr &getter, const CScriptVarFunctionPtr &setter) : CScriptVarObject(Context, Context->objectPrototype) {
+	if(getter)
+		addChild(TINYJS_ACCESSOR_GET_VAR, getter, 0);
+	if(setter)
+		addChild(TINYJS_ACCESSOR_SET_VAR, setter, 0);
+}
+
+CScriptVarAccessor::~CScriptVarAccessor() {}
+CScriptVarPtr CScriptVarAccessor::clone() { return new CScriptVarAccessor(*this); }
+bool CScriptVarAccessor::isAccessor() { return true; }
+bool CScriptVarAccessor::isPrimitive()	{ return false; } 
+string CScriptVarAccessor::getParsableString(const string &indentString, const string &indent, uint32_t uniqueID, bool &hasRecursion) {
+	return "";
+}
+string CScriptVarAccessor::getVarType() { return "accessor"; }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarScope
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(Scope);
+CScriptVarScope::~CScriptVarScope() {}
+CScriptVarPtr CScriptVarScope::clone() { return CScriptVarPtr(); }
+bool CScriptVarScope::isObject() { return false; }
+CScriptVarPtr CScriptVarScope::scopeVar() { return this; }	///< to create var like: var a = ...
+CScriptVarPtr CScriptVarScope::scopeLet() { return this; }	///< to create var like: let a = ...
+CScriptVarLinkWorkPtr CScriptVarScope::findInScopes(const string &childName) { 
+	return  CScriptVar::findChild(childName); 
+}
+CScriptVarScopePtr CScriptVarScope::getParent() { return CScriptVarScopePtr(); } ///< no Parent
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarScopeFnc
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(ScopeFnc);
+CScriptVarScopeFnc::~CScriptVarScopeFnc() {}
+CScriptVarLinkWorkPtr CScriptVarScopeFnc::findInScopes(const string &childName) { 
+	CScriptVarLinkWorkPtr ret = findChild(childName); 
+	if( !ret ) {
+		if(closure) ret = CScriptVarScopePtr(closure)->findInScopes(childName);
+		else ret = context->getRoot()->findChild(childName);
+	}
+	return ret;
+}
+
+void CScriptVarScopeFnc::setReturnVar(const CScriptVarPtr &var) {
+	addChildOrReplace(TINYJS_RETURN_VAR, var);
+}
+
+CScriptVarPtr CScriptVarScopeFnc::getParameter(const string &name) {
+	return getArgument(name);
+}
+
+CScriptVarPtr CScriptVarScopeFnc::getParameter(int Idx) {
+	return getArgument(Idx);
+}
+CScriptVarPtr CScriptVarScopeFnc::getArgument(const string &name) {
+	return findChildOrCreate(name);
+}
+CScriptVarPtr CScriptVarScopeFnc::getArgument(int Idx) {
+	CScriptVarLinkPtr arguments = findChildOrCreate(TINYJS_ARGUMENTS_VAR);
+	if(arguments) arguments = arguments->getVarPtr()->findChild(int2string(Idx));
+	return arguments ? arguments->getVarPtr() : constScriptVar(Undefined);
+}
+int CScriptVarScopeFnc::getParameterLength() {
+	return getArgumentsLength();
+}
+int CScriptVarScopeFnc::getArgumentsLength() {
+	CScriptVarLinkPtr arguments = findChild(TINYJS_ARGUMENTS_VAR);
+	if(arguments) arguments = arguments->getVarPtr()->findChild("length");
+	return arguments ? arguments.getter()->toNumber().toInt32() : 0;
+}
+
+void CScriptVarScopeFnc::throwError( ERROR_TYPES ErrorType, const string &message ) {
+	throw newScriptVarError(context, ErrorType, message.c_str());
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarScopeLet
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(ScopeLet);
+CScriptVarScopeLet::CScriptVarScopeLet(const CScriptVarScopePtr &Parent) // constructor for LetScope
+	: CScriptVarScope(Parent->getContext()), parent(addChild(TINYJS_SCOPE_PARENT_VAR, Parent, 0))
+	, letExpressionInitMode(false) {}
+
+CScriptVarScopeLet::~CScriptVarScopeLet() {}
+CScriptVarPtr CScriptVarScopeLet::scopeVar() {						// to create var like: var a = ...
+	return getParent()->scopeVar(); 
+}
+CScriptVarScopePtr CScriptVarScopeLet::getParent() { return (CScriptVarPtr)parent; }
+CScriptVarLinkWorkPtr CScriptVarScopeLet::findInScopes(const string &childName) { 
+	CScriptVarLinkWorkPtr ret;
+	if(letExpressionInitMode) {
+		return getParent()->findInScopes(childName);
+	} else {
+		ret = findChild(childName); 
+		if( !ret ) ret = getParent()->findInScopes(childName);
+	}
+	return ret;
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarScopeWith
+//////////////////////////////////////////////////////////////////////////
+
+declare_dummy_t(ScopeWith);
+CScriptVarScopeWith::~CScriptVarScopeWith() {}
+CScriptVarPtr CScriptVarScopeWith::scopeLet() { 							// to create var like: let a = ...
+	return getParent()->scopeLet();
+}
+CScriptVarLinkWorkPtr CScriptVarScopeWith::findInScopes(const string &childName) { 
+	if(childName == "this") return with;
+	CScriptVarLinkWorkPtr ret = with->getVarPtr()->findChild(childName); 
+	if( !ret ) {
+		ret = with->getVarPtr()->findChildInPrototypeChain(childName);
+		if(ret) {
+			ret(ret->getVarPtr(), ret->getName()); // recreate ret
+			ret.setReferencedOwner(with->getVarPtr()); // fake referenced Owner
+		}
+	}
+	if( !ret ) ret = getParent()->findInScopes(childName);
+	return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CTinyJS
+//////////////////////////////////////////////////////////////////////////
+
+extern "C" void _registerFunctions(CTinyJS *tinyJS);
+extern "C" void _registerStringFunctions(CTinyJS *tinyJS);
+extern "C" void _registerMathFunctions(CTinyJS *tinyJS);
+
+CTinyJS::CTinyJS() {
+	CScriptVarPtr var;
+	t = 0;
+	haveTry = false;
+	first = 0;
+	uniqueID = 0;
+
+	
+	//////////////////////////////////////////////////////////////////////////
+	// Object-Prototype
+	// must be created as first object because this prototype is the base of all objects
+	objectPrototype = newScriptVar(Object); 
+	
+	// all objects have a prototype. Also the prototype of prototypes
+	objectPrototype->addChild(TINYJS___PROTO___VAR, objectPrototype, 0);
+
+	//////////////////////////////////////////////////////////////////////////
+	// Function-Prototype
+	// must be created as second object because this is the base of all functions (also constructors)
+	functionPrototype = newScriptVar(Object);
+
+
+	//////////////////////////////////////////////////////////////////////////
+	// Scopes
+	root = ::newScriptVar(this, Scope);
+	scopes.push_back(root);
+
+	//////////////////////////////////////////////////////////////////////////
+	// Add built-in classes
+	//////////////////////////////////////////////////////////////////////////
+	// Object
+	var = addNative("function Object()", this, &CTinyJS::native_Object, 0, SCRIPTVARLINK_CONSTANT);
+	objectPrototype = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	addNative("function Object.getPrototypeOf(obj)", this, &CTinyJS::native_Object_getPrototypeOf); 
+	addNative("function Object.preventExtensions(obj)", this, &CTinyJS::native_Object_setObjectSecure); 
+	addNative("function Object.isExtensible(obj)", this, &CTinyJS::native_Object_isSecureObject); 
+	addNative("function Object.seel(obj)", this, &CTinyJS::native_Object_setObjectSecure, (void*)1); 
+	addNative("function Object.isSealed(obj)", this, &CTinyJS::native_Object_isSecureObject, (void*)1); 
+	addNative("function Object.freeze(obj)", this, &CTinyJS::native_Object_setObjectSecure, (void*)2); 
+	addNative("function Object.isFrozen(obj)", this, &CTinyJS::native_Object_isSecureObject, (void*)2); 
+	addNative("function Object.keys(obj)", this, &CTinyJS::native_Object_keys); 
+	addNative("function Object.getOwnPropertyNames(obj)", this, &CTinyJS::native_Object_keys, (void*)1); 
+	addNative("function Object.getOwnPropertyDescriptor(obj,name)", this, &CTinyJS::native_Object_getOwnPropertyDescriptor); 
+	addNative("function Object.defineProperty(obj,name,attributes)", this, &CTinyJS::native_Object_defineProperty); 
+	addNative("function Object.defineProperties(obj,properties)", this, &CTinyJS::native_Object_defineProperties); 
+	addNative("function Object.create(obj,properties)", this, &CTinyJS::native_Object_defineProperties, (void*)1); 
+
+	addNative("function Object.prototype.hasOwnProperty(prop)", this, &CTinyJS::native_Object_prototype_hasOwnProperty); 
+	objectPrototype_valueOf = addNative("function Object.prototype.valueOf()", this, &CTinyJS::native_Object_prototype_valueOf); 
+	objectPrototype_toString = addNative("function Object.prototype.toString(radix)", this, &CTinyJS::native_Object_prototype_toString); 
+	pseudo_refered.push_back(&objectPrototype);
+	pseudo_refered.push_back(&objectPrototype_valueOf);
+	pseudo_refered.push_back(&objectPrototype_toString);
+
+	//////////////////////////////////////////////////////////////////////////
+	// Array
+	var = addNative("function Array()", this, &CTinyJS::native_Array, 0, SCRIPTVARLINK_CONSTANT);
+	arrayPrototype = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	arrayPrototype->addChild("valueOf", objectPrototype_valueOf);
+	arrayPrototype->addChild("toString", objectPrototype_toString);
+	pseudo_refered.push_back(&arrayPrototype);
+	var = addNative("function Array.__constructor__()", this, &CTinyJS::native_Array, (void*)1, SCRIPTVARLINK_CONSTANT);
+	var->getFunctionData()->name = "Array";
+	//////////////////////////////////////////////////////////////////////////
+	// String
+	var = addNative("function String()", this, &CTinyJS::native_String, 0, SCRIPTVARLINK_CONSTANT);
+	stringPrototype  = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	stringPrototype->addChild("valueOf", objectPrototype_valueOf);
+	stringPrototype->addChild("toString", objectPrototype_toString);
+	pseudo_refered.push_back(&stringPrototype);
+	var = addNative("function String.__constructor__()", this, &CTinyJS::native_String, (void*)1, SCRIPTVARLINK_CONSTANT);
+	var->getFunctionData()->name = "String";
+
+	//////////////////////////////////////////////////////////////////////////
+	// RegExp
+#ifndef NO_REGEXP
+	var = addNative("function RegExp()", this, &CTinyJS::native_RegExp, 0, SCRIPTVARLINK_CONSTANT);
+	regexpPrototype  = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	regexpPrototype->addChild("valueOf", objectPrototype_valueOf);
+	regexpPrototype->addChild("toString", objectPrototype_toString);
+	pseudo_refered.push_back(&regexpPrototype);
+#endif /* NO_REGEXP */
+
+	//////////////////////////////////////////////////////////////////////////
+	// Number
+	var = addNative("function Number()", this, &CTinyJS::native_Number, 0, SCRIPTVARLINK_CONSTANT);
+	var->addChild("NaN", constNaN = newScriptVarNumber(this, NaN), SCRIPTVARLINK_CONSTANT);
+	var->addChild("MAX_VALUE", constInfinityPositive = newScriptVarNumber(this, numeric_limits<double>::max()), SCRIPTVARLINK_CONSTANT);
+	var->addChild("MIN_VALUE", constInfinityPositive = newScriptVarNumber(this, numeric_limits<double>::min()), SCRIPTVARLINK_CONSTANT);
+	var->addChild("POSITIVE_INFINITY", constInfinityPositive = newScriptVarNumber(this, InfinityPositive), SCRIPTVARLINK_CONSTANT);
+	var->addChild("NEGATIVE_INFINITY", constInfinityNegative = newScriptVarNumber(this, InfinityNegative), SCRIPTVARLINK_CONSTANT);
+	numberPrototype = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	numberPrototype->addChild("valueOf", objectPrototype_valueOf);
+	numberPrototype->addChild("toString", objectPrototype_toString);
+	pseudo_refered.push_back(&numberPrototype);
+	pseudo_refered.push_back(&constNaN);
+	pseudo_refered.push_back(&constInfinityPositive);
+	pseudo_refered.push_back(&constInfinityNegative);
+	var = addNative("function Number.__constructor__()", this, &CTinyJS::native_Number, (void*)1, SCRIPTVARLINK_CONSTANT);
+	var->getFunctionData()->name = "Number";
+
+	//////////////////////////////////////////////////////////////////////////
+	// Boolean
+	var = addNative("function Boolean()", this, &CTinyJS::native_Boolean, 0, SCRIPTVARLINK_CONSTANT);
+	booleanPrototype = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	booleanPrototype->addChild("valueOf", objectPrototype_valueOf);
+	booleanPrototype->addChild("toString", objectPrototype_toString);
+	pseudo_refered.push_back(&booleanPrototype);
+	var = addNative("function Boolean.__constructor__()", this, &CTinyJS::native_Boolean, (void*)1, SCRIPTVARLINK_CONSTANT);
+	var->getFunctionData()->name = "Boolean";
+
+	//////////////////////////////////////////////////////////////////////////
+	// Iterator
+	var = addNative("function Iterator(obj,mode)", this, &CTinyJS::native_Iterator, 0, SCRIPTVARLINK_CONSTANT); 
+	iteratorPrototype = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	pseudo_refered.push_back(&iteratorPrototype);
+
+	//////////////////////////////////////////////////////////////////////////
+	// Function
+	var = addNative("function Function(params, body)", this, &CTinyJS::native_Function, 0, SCRIPTVARLINK_CONSTANT); 
+	var->addChildOrReplace(TINYJS_PROTOTYPE_CLASS, functionPrototype);
+	addNative("function Function.prototype.call(objc)", this, &CTinyJS::native_Function_prototype_call); 
+	addNative("function Function.prototype.apply(objc, args)", this, &CTinyJS::native_Function_prototype_apply); 
+	addNative("function Function.prototype.bind(objc, args)", this, &CTinyJS::native_Function_prototype_bind); 
+	functionPrototype->addChild("valueOf", objectPrototype_valueOf);
+	functionPrototype->addChild("toString", objectPrototype_toString);
+	pseudo_refered.push_back(&functionPrototype);
+
+	//////////////////////////////////////////////////////////////////////////
+	// Error
+	var = addNative("function Error(message, fileName, lineNumber, column)", this, &CTinyJS::native_Error, 0, SCRIPTVARLINK_CONSTANT); 
+	errorPrototypes[Error] = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	errorPrototypes[Error]->addChild("message", newScriptVar(""));
+	errorPrototypes[Error]->addChild("name", newScriptVar("Error"));
+	errorPrototypes[Error]->addChild("fileName", newScriptVar(""));
+	errorPrototypes[Error]->addChild("lineNumber", newScriptVar(-1));	// -1 means not viable
+	errorPrototypes[Error]->addChild("column", newScriptVar(-1));			// -1 means not viable
+
+	var = addNative("function EvalError(message, fileName, lineNumber, column)", this, &CTinyJS::native_EvalError, 0, SCRIPTVARLINK_CONSTANT); 
+	errorPrototypes[EvalError] = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	errorPrototypes[EvalError]->addChildOrReplace(TINYJS___PROTO___VAR, errorPrototypes[Error], SCRIPTVARLINK_WRITABLE);
+	errorPrototypes[EvalError]->addChild("name", newScriptVar("EvalError"));
+
+	var = addNative("function RangeError(message, fileName, lineNumber, column)", this, &CTinyJS::native_RangeError, 0, SCRIPTVARLINK_CONSTANT); 
+	errorPrototypes[RangeError] = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	errorPrototypes[RangeError]->addChildOrReplace(TINYJS___PROTO___VAR, errorPrototypes[Error], SCRIPTVARLINK_WRITABLE);
+	errorPrototypes[RangeError]->addChild("name", newScriptVar("RangeError"));
+
+	var = addNative("function ReferenceError(message, fileName, lineNumber, column)", this, &CTinyJS::native_ReferenceError, 0, SCRIPTVARLINK_CONSTANT); 
+	errorPrototypes[ReferenceError] = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	errorPrototypes[ReferenceError]->addChildOrReplace(TINYJS___PROTO___VAR, errorPrototypes[Error], SCRIPTVARLINK_WRITABLE);
+	errorPrototypes[ReferenceError]->addChild("name", newScriptVar("ReferenceError"));
+
+	var = addNative("function SyntaxError(message, fileName, lineNumber, column)", this, &CTinyJS::native_SyntaxError, 0, SCRIPTVARLINK_CONSTANT); 
+	errorPrototypes[SyntaxError] = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	errorPrototypes[SyntaxError]->addChildOrReplace(TINYJS___PROTO___VAR, errorPrototypes[Error], SCRIPTVARLINK_WRITABLE);
+	errorPrototypes[SyntaxError]->addChild("name", newScriptVar("SyntaxError"));
+
+	var = addNative("function TypeError(message, fileName, lineNumber, column)", this, &CTinyJS::native_TypeError, 0, SCRIPTVARLINK_CONSTANT); 
+	errorPrototypes[TypeError] = var->findChild(TINYJS_PROTOTYPE_CLASS);
+	errorPrototypes[TypeError]->addChildOrReplace(TINYJS___PROTO___VAR, errorPrototypes[Error], SCRIPTVARLINK_WRITABLE);
+	errorPrototypes[TypeError]->addChild("name", newScriptVar("TypeError"));
+
+	//////////////////////////////////////////////////////////////////////////
+	// add global built-in vars & constants
+	root->addChild("undefined", constUndefined = newScriptVarUndefined(this), SCRIPTVARLINK_CONSTANT);
+	pseudo_refered.push_back(&constUndefined);
+	constNull	= newScriptVarNull(this);	pseudo_refered.push_back(&constNull);
+	root->addChild("NaN", constNaN, SCRIPTVARLINK_CONSTANT);
+	root->addChild("Infinity", constInfinityPositive, SCRIPTVARLINK_CONSTANT);
+	root->addChild("StopIteration", constStopIteration=newScriptVar(Object, var=newScriptVar(Object)), SCRIPTVARLINK_CONSTANT);
+	constStopIteration->addChild(TINYJS_PROTOTYPE_CLASS, var, SCRIPTVARLINK_CONSTANT);	pseudo_refered.push_back(&constStopIteration);
+	constNegativZero	= newScriptVarNumber(this, NegativeZero);	pseudo_refered.push_back(&constNegativZero);
+	constFalse	= newScriptVarBool(this, false);	pseudo_refered.push_back(&constFalse);
+	constTrue	= newScriptVarBool(this, true);	pseudo_refered.push_back(&constTrue);
+	
+	//////////////////////////////////////////////////////////////////////////
+	// add global functions
+	addNative("function eval(jsCode)", this, &CTinyJS::native_eval);
+	addNative("function isNaN(objc)", this, &CTinyJS::native_isNAN);
+	addNative("function isFinite(objc)", this, &CTinyJS::native_isFinite);
+	addNative("function parseInt(string, radix)", this, &CTinyJS::native_parseInt);
+	addNative("function parseFloat(string)", this, &CTinyJS::native_parseFloat);
+	
+	
+	addNative("function JSON.parse(text, reviver)", this, &CTinyJS::native_JSON_parse);
+	
+	_registerFunctions(this);
+	_registerStringFunctions(this);
+	_registerMathFunctions(this);
+}
+
+CTinyJS::~CTinyJS() {
+	ASSERT(!t);
+	for(vector<CScriptVarPtr*>::iterator it = pseudo_refered.begin(); it!=pseudo_refered.end(); ++it)
+		**it = CScriptVarPtr();
+	for(int i=Error; i<ERROR_COUNT; i++)
+		errorPrototypes[i] = CScriptVarPtr();
+	root->removeAllChildren();
+	scopes.clear();
+	ClearUnreferedVars();
+	root = CScriptVarPtr();
+#ifdef _DEBUG
+	for(CScriptVar *p = first; p; p=p->next)
+		printf("%p\n", p);
+#endif
+#if DEBUG_MEMORY
+	show_allocated();
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// throws an Error & Exception
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::throwError(CScriptResult &execute, ERROR_TYPES ErrorType, const string &message ) {
+	if(execute && haveTry) {
+		execute.set(CScriptResult::Throw, newScriptVarError(this, ErrorType, message.c_str(), t->currentFile.c_str(), t->currentLine(), t->currentColumn()));
+		return;
+	}
+	throw new CScriptException(ErrorType, message, t->currentFile, t->currentLine(), t->currentColumn());
+}
+void CTinyJS::throwException(ERROR_TYPES ErrorType, const string &message ) {
+	throw new CScriptException(ErrorType, message, t->currentFile, t->currentLine(), t->currentColumn());
+}
+
+void CTinyJS::throwError(CScriptResult &execute, ERROR_TYPES ErrorType, const string &message, CScriptTokenizer::ScriptTokenPosition &Pos ){
+	if(execute && haveTry) {
+		execute.set(CScriptResult::Throw, newScriptVarError(this, ErrorType, message.c_str(), t->currentFile.c_str(), Pos.currentLine(), Pos.currentColumn()));
+		return;
+	}
+	throw new CScriptException(ErrorType, message, t->currentFile, Pos.currentLine(), Pos.currentColumn());
+}
+void CTinyJS::throwException(ERROR_TYPES ErrorType, const string &message, CScriptTokenizer::ScriptTokenPosition &Pos ){
+	throw new CScriptException(ErrorType, message, t->currentFile, Pos.currentLine(), Pos.currentColumn());
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::trace() {
+	root->trace();
+}
+
+void CTinyJS::execute(CScriptTokenizer &Tokenizer) {
+	evaluateComplex(Tokenizer);
+}
+
+void CTinyJS::execute(const char *Code, const string &File, int Line, int Column) {
+	evaluateComplex(Code, File, Line, Column);
+}
+
+void CTinyJS::execute(const string &Code, const string &File, int Line, int Column) {
+	evaluateComplex(Code, File, Line, Column);
+}
+
+CScriptVarLinkPtr CTinyJS::evaluateComplex(CScriptTokenizer &Tokenizer) {
+	t = &Tokenizer;
+	CScriptResult execute;
+	try {
+		do {
+			execute_statement(execute);
+			while (t->tk==';') t->match(';'); // skip empty statements
+		} while (t->tk!=LEX_EOF);
+	} catch (...) {
+		haveTry = false;
+		t=0; // clean up Tokenizer
+		throw; // 
+	}
+	t=0;
+	ClearUnreferedVars(execute.value);
+
+	uint32_t UniqueID = getUniqueID(); 
+	setTemporaryID_recursive(UniqueID);
+	if(execute.value) execute.value->setTemporaryID_recursive(UniqueID);
+	for(CScriptVar *p = first; p; p=p->next)
+	{
+		if(p->temporaryID != UniqueID)
+			printf("%p\n", p);
+	}
+
+	if (execute.value)
+		return CScriptVarLinkPtr(execute.value);
+	// return undefined...
+	return CScriptVarLinkPtr(constScriptVar(Undefined));
+}
+CScriptVarLinkPtr CTinyJS::evaluateComplex(const char *Code, const string &File, int Line, int Column) {
+	CScriptTokenizer Tokenizer(Code, File, Line, Column);
+	return evaluateComplex(Tokenizer);
+}
+CScriptVarLinkPtr CTinyJS::evaluateComplex(const string &Code, const string &File, int Line, int Column) {
+	CScriptTokenizer Tokenizer(Code.c_str(), File, Line, Column);
+	return evaluateComplex(Tokenizer);
+}
+
+string CTinyJS::evaluate(CScriptTokenizer &Tokenizer) {
+	return evaluateComplex(Tokenizer)->toString();
+}
+string CTinyJS::evaluate(const char *Code, const string &File, int Line, int Column) {
+	return evaluateComplex(Code, File, Line, Column)->toString();
+}
+string CTinyJS::evaluate(const string &Code, const string &File, int Line, int Column) {
+	return evaluate(Code.c_str(), File, Line, Column);
+}
+
+CScriptVarFunctionNativePtr CTinyJS::addNative(const string &funcDesc, JSCallback ptr, void *userdata, int LinkFlags) {
+	return addNative(funcDesc, ::newScriptVar(this, ptr, userdata), LinkFlags);
+}
+
+CScriptVarFunctionNativePtr CTinyJS::addNative(const string &funcDesc, CScriptVarFunctionNativePtr Var, int LinkFlags) {
+	CScriptLex lex(funcDesc.c_str());
+	CScriptVarPtr base = root;
+
+	lex.match(LEX_R_FUNCTION);
+	string funcName = lex.tkStr;
+	lex.match(LEX_ID);
+	/* Check for dots, we might want to do something like function String.substring ... */
+	while (lex.tk == '.') {
+		lex.match('.');
+		CScriptVarLinkPtr link = base->findChild(funcName);
+		// if it doesn't exist, make an object class
+		if (!link) link = base->addChild(funcName, newScriptVar(Object));
+		base = link->getVarPtr();
+		funcName = lex.tkStr;
+		lex.match(LEX_ID);
+	}
+
+	auto_ptr<CScriptTokenDataFnc> pFunctionData(new CScriptTokenDataFnc);
+	pFunctionData->name = funcName;
+	lex.match('(');
+	while (lex.tk!=')') {
+		pFunctionData->arguments.push_back(CScriptToken(LEX_ID, lex.tkStr));
+		lex.match(LEX_ID);
+		if (lex.tk!=')') lex.match(',',')');
+	}
+	lex.match(')');
+	Var->setFunctionData(pFunctionData.release());
+	Var->addChild(TINYJS_PROTOTYPE_CLASS, newScriptVar(Object), SCRIPTVARLINK_WRITABLE);
+
+	base->addChild(funcName,  Var, LinkFlags);
+	return Var;
+
+}
+
+CScriptVarLinkWorkPtr CTinyJS::parseFunctionDefinition(const CScriptToken &FncToken) {
+	const CScriptTokenDataFnc &Fnc = FncToken.Fnc();
+//	string fncName = (FncToken.token == LEX_T_FUNCTION_OPERATOR) ? TINYJS_TEMP_NAME : Fnc.name;
+	CScriptVarLinkWorkPtr funcVar(newScriptVar((CScriptTokenDataFnc*)&Fnc), Fnc.name);
+	if(scope() != root)
+		funcVar->getVarPtr()->addChild(TINYJS_FUNCTION_CLOSURE_VAR, scope(), 0);
+	funcVar->getVarPtr()->addChild(TINYJS_PROTOTYPE_CLASS, newScriptVar(Object), SCRIPTVARLINK_WRITABLE);
+	return funcVar;
+}
+
+CScriptVarLinkWorkPtr CTinyJS::parseFunctionsBodyFromString(const string &ArgumentList, const string &FncBody) {
+	string Fnc = "function ("+ArgumentList+"){"+FncBody+"}";
+	CScriptTokenizer tokenizer(Fnc.c_str());
+	return parseFunctionDefinition(tokenizer.getToken());
+}
+CScriptVarPtr CTinyJS::callFunction(const CScriptVarFunctionPtr &Function, vector<CScriptVarPtr> &Arguments, const CScriptVarPtr &This, CScriptVarPtr *newThis) {
+	CScriptResult execute;
+	CScriptVarPtr retVar = callFunction(execute, Function, Arguments, This, newThis);
+	execute.cThrow();
+	return retVar;
+}
+
+CScriptVarPtr CTinyJS::callFunction(CScriptResult &execute, const CScriptVarFunctionPtr &Function, vector<CScriptVarPtr> &Arguments, const CScriptVarPtr &This, CScriptVarPtr *newThis) {
+	ASSERT(Function && Function->isFunction());
+
+	if(Function->isBounded()) return CScriptVarFunctionBoundedPtr(Function)->callFunction(execute, Arguments, This, newThis);
+
+	CScriptTokenDataFnc *Fnc = Function->getFunctionData();
+	CScriptVarScopeFncPtr functionRoot(::newScriptVar(this, ScopeFnc, CScriptVarPtr(Function->findChild(TINYJS_FUNCTION_CLOSURE_VAR))));
+	if(Fnc->name.size()) functionRoot->addChild(Fnc->name, Function);
+	functionRoot->addChild("this", This);
+	CScriptVarPtr arguments = functionRoot->addChild(TINYJS_ARGUMENTS_VAR, newScriptVar(Object));
+
+	CScriptResult function_execute;
+	int length_proto = Fnc->arguments.size();
+	int length_arguments = Arguments.size();
+	int length = max(length_proto, length_arguments);
+	for(int arguments_idx = 0; arguments_idx<length; ++arguments_idx) {
+		string arguments_idx_str = int2string(arguments_idx);
+		CScriptVarLinkWorkPtr value;
+		if(arguments_idx < length_arguments) {
+			value = arguments->addChild(arguments_idx_str, Arguments[arguments_idx]);
+		} else {
+			value = constScriptVar(Undefined);
+		}
+		if(arguments_idx < length_proto) {
+			CScriptToken &FncArguments = Fnc->arguments[arguments_idx];
+			if(FncArguments.token == LEX_ID)
+				functionRoot->addChildOrReplace(FncArguments.String(), value);
+			else
+				assign_destructuring_var(functionRoot, FncArguments.DestructuringVar(), value, function_execute);
+		}
+	}
+	arguments->addChild("length", newScriptVar(length_arguments));
+
+	// execute function!
+	// add the function's execute space to the symbol table so we can recurse
+	CScopeControl ScopeControl(this);
+	ScopeControl.addFncScope(functionRoot);
+	if (Function->isNative()) {
+		try {
+			CScriptVarFunctionNativePtr(Function)->callFunction(functionRoot);
+			CScriptVarLinkPtr ret = functionRoot->findChild(TINYJS_RETURN_VAR);
+			function_execute.set(CScriptResult::Return, ret ? CScriptVarPtr(ret) : constUndefined);
+		} catch (CScriptVarPtr v) {
+			if(haveTry) {
+				function_execute.set(CScriptResult::Throw, v);
+			} else if(v->isError()) {
+				CScriptException *err = CScriptVarErrorPtr(v)->toCScriptException();
+				if(err->fileName.empty()) err->fileName = "native function '"+Function->getFunctionData()->name+"'";
+				throw err;
+			}
+			else
+				throw new CScriptException(Error, v->toString(function_execute)+"' in: native function '"+Function->getFunctionData()->name+"'");
+		}
+	} else {
+		/* we just want to execute the block, but something could
+			* have messed up and left us with the wrong ScriptLex, so
+			* we want to be careful here... */
+		string oldFile = t->currentFile;
+		t->currentFile = Fnc->file;
+		t->pushTokenScope(Fnc->body);
+		if(Fnc->body.front().token == '{')
+			execute_block(function_execute);
+		else {
+			CScriptVarPtr ret = execute_base(function_execute);
+			if(function_execute) function_execute.set(CScriptResult::Return, ret);
+		}
+		t->currentFile = oldFile;
+
+		// because return will probably have called this, and set execute to false
+	}
+	if(function_execute.isReturnNormal()) {
+		if(newThis) *newThis = functionRoot->findChild("this");
+		if(function_execute.isReturn()) {
+			CScriptVarPtr ret = function_execute.value;
+			return ret;
+		}
+	} else
+		execute = function_execute;
+	return constScriptVar(Undefined);
+}
+
+CScriptVarPtr CTinyJS::mathsOp(CScriptResult &execute, const CScriptVarPtr &A, const CScriptVarPtr &B, int op) {
+	if(!execute) return constUndefined;
+	if (op == LEX_TYPEEQUAL || op == LEX_NTYPEEQUAL) {
+		// check type first
+		if( (A->getVarType() == B->getVarType()) ^ (op == LEX_TYPEEQUAL)) return constFalse;
+		// check value second
+		return mathsOp(execute, A, B, op == LEX_TYPEEQUAL ? LEX_EQUAL : LEX_NEQUAL);
+	}
+	if (!A->isPrimitive() && !B->isPrimitive()) { // Objects both
+		// check pointers
+		switch (op) {
+		case LEX_EQUAL:	return constScriptVar(A==B);
+		case LEX_NEQUAL:	return constScriptVar(A!=B);
+		}
+	}
+
+	CScriptVarPtr a = A->toPrimitive_hintNumber(execute);
+	CScriptVarPtr b = B->toPrimitive_hintNumber(execute);
+	if(!execute) return constUndefined;
+	// do maths...
+	bool a_isString = a->isString();
+	bool b_isString = b->isString();
+	// both a String or one a String and op='+'
+	if( (a_isString && b_isString) || ((a_isString || b_isString) && op == '+')) {
+		string da = a->isNull() ? "" : a->toString(execute);
+		string db = b->isNull() ? "" : b->toString(execute);
+		switch (op) {
+		case '+':			return newScriptVar(da+db);
+		case LEX_EQUAL:	return constScriptVar(da==db);
+		case LEX_NEQUAL:	return constScriptVar(da!=db);
+		case '<':			return constScriptVar(da<db);
+		case LEX_LEQUAL:	return constScriptVar(da<=db);
+		case '>':			return constScriptVar(da>db);
+		case LEX_GEQUAL:	return constScriptVar(da>=db);
+		}
+	}
+	// special for undefined and null --> every true: undefined==undefined, undefined==null, null==undefined and null=null
+	else if( (a->isUndefined() || a->isNull()) && (b->isUndefined() || b->isNull()) ) {
+		switch (op) {
+		case LEX_EQUAL:	return constScriptVar(true);
+		case LEX_NEQUAL:
+		case LEX_GEQUAL:	
+		case LEX_LEQUAL:
+		case '<':
+		case '>':			return constScriptVar(false);
+		}
+	} 
+	CNumber da = a->toNumber();
+	CNumber db = b->toNumber();
+	switch (op) {
+	case '+':			return a->newScriptVar(da+db);
+	case '-':			return a->newScriptVar(da-db);
+	case '*':			return a->newScriptVar(da*db);
+	case '/':			return a->newScriptVar(da/db);
+	case '%':			return a->newScriptVar(da%db);
+	case '&':			return a->newScriptVar(da.toInt32()&db.toInt32());
+	case '|':			return a->newScriptVar(da.toInt32()|db.toInt32());
+	case '^':			return a->newScriptVar(da.toInt32()^db.toInt32());
+	case '~':			return a->newScriptVar(~da);
+	case LEX_LSHIFT:	return a->newScriptVar(da<<db);
+	case LEX_RSHIFT:	return a->newScriptVar(da>>db);
+	case LEX_RSHIFTU:	return a->newScriptVar(da.ushift(db));
+	case LEX_EQUAL:	return a->constScriptVar(da==db);
+	case LEX_NEQUAL:	return a->constScriptVar(da!=db);
+	case '<':			return a->constScriptVar(da<db);
+	case LEX_LEQUAL:	return a->constScriptVar(da<=db);
+	case '>':			return a->constScriptVar(da>db);
+	case LEX_GEQUAL:	return a->constScriptVar(da>=db);
+	default: throw new CScriptException("This operation not supported on the int datatype");
+	}	
+}
+
+void CTinyJS::assign_destructuring_var(const CScriptVarPtr &Scope, const CScriptTokenDataDestructuringVar &Objc, const CScriptVarPtr &Val, CScriptResult &execute) {
+	if(!execute) return;
+	if(Objc.vars.size() == 1) {
+		if(Scope)
+			Scope->addChildOrReplace(Objc.vars.front().second, Val);
+		else {
+			CScriptVarLinkWorkPtr v(findInScopes(Objc.vars.front().second));
+			ASSERT(v==true);
+			if(v) v->setVarPtr(Val);
+		}
+	} else {
+		vector<CScriptVarPtr> Path(1, Val);
+		for(DESTRUCTURING_VARS_cit it=Objc.vars.begin()+1; it!=Objc.vars.end(); ++it) {
+			if(it->second == "}" || it->second == "]")
+				Path.pop_back();
+			else {
+				if(it->second.empty()) continue; // skip empty entries
+				CScriptVarLinkWorkPtr var = Path.back()->findChildWithStringChars(it->first);
+				if(var) var = var.getter(execute); else var = constUndefined;
+				if(!execute) return;
+				if(it->second == "{" || it->second == "[") {
+					Path.push_back(var);
+				} else if(Scope)
+					Scope->addChildOrReplace(it->second, var);
+				else {
+					CScriptVarLinkWorkPtr v(findInScopes(it->second));
+					ASSERT(v==true);
+					if(v) v->setVarPtr(var);
+				}
+			}
+		}
+	}
+}
+
+void CTinyJS::execute_var_init( bool hideLetScope, CScriptResult &execute )
+{
+	for(;;) {
+		t->check(LEX_T_DESTRUCTURING_VAR);
+		CScriptTokenDataDestructuringVar &Objc = t->getToken().DestructuringVar();
+		t->match(LEX_T_DESTRUCTURING_VAR);
+		if(t->tk == '=') {
+			t->match('=');
+			if(hideLetScope) CScriptVarScopeLetPtr(scope())->setletExpressionInitMode(true);
+			CScriptVarPtr Val = execute_assignment(execute);
+			if(hideLetScope) CScriptVarScopeLetPtr(scope())->setletExpressionInitMode(false);
+			assign_destructuring_var(0, Objc, Val, execute);
+		}
+		if (t->tk == ',') 
+			t->match(',');
+		else
+			break;
+	}
+}
+void CTinyJS::execute_destructuring(CScriptTokenDataObjectLiteral &Objc, const CScriptVarPtr &Val, CScriptResult &execute) {
+	for(vector<CScriptTokenDataObjectLiteral::ELEMENT>::iterator it=Objc.elements.begin(); execute && it!=Objc.elements.end(); ++it) {
+		if(it->value.empty()) continue;
+		CScriptVarPtr rhs = Val->findChildWithStringChars(it->id).getter(execute);
+		if(!rhs) rhs=constUndefined;
+		if(it->value.front().token == LEX_T_OBJECT_LITERAL && it->value.front().Object().destructuring) {
+			execute_destructuring(it->value.front().Object(), rhs, execute);
+		} else {
+			t->pushTokenScope(it->value);
+			CScriptVarLinkWorkPtr lhs = execute_condition(execute);
+			if(lhs->isWritable()) {
+				if (!lhs->isOwned()) {
+					CScriptVarPtr fakedOwner = lhs.getReferencedOwner();
+					if(fakedOwner) {
+						if(!fakedOwner->isExtensible())
+							continue;
+						lhs = fakedOwner->addChildOrReplace(lhs->getName(), lhs);
+					} else
+						lhs = root->addChildOrReplace(lhs->getName(), lhs);
+				}
+				lhs.setter(execute, rhs);
+			}
+		}
+	}
+}
+
+CScriptVarLinkWorkPtr CTinyJS::execute_literals(CScriptResult &execute) {
+	switch(t->tk) {
+	case LEX_ID: 
+		if(execute) {
+			CScriptVarLinkWorkPtr a(findInScopes(t->tkStr()));
+			if (!a) {
+				/* Variable doesn't exist! JavaScript says we should create it
+				 * (we won't add it here. This is done in the assignment operator)*/
+				if(t->tkStr() == "this") 
+					a = root; // fake this
+				else
+					a = CScriptVarLinkPtr(constScriptVar(Undefined), t->tkStr());
+			} 
+/*
+			prvention for assignment to this is now done by the tokenizer
+			else if(t->tkStr() == "this")
+				a(a->getVarPtr()); // prevent assign to this
+*/
+			t->match(LEX_ID);
+			return a;
+		}
+		t->match(LEX_ID);
+		break;
+	case LEX_INT:
+		{
+			CScriptVarPtr a = newScriptVar(t->getToken().Int());
+			a->setExtensible(false);
+			t->match(LEX_INT);
+			return a;
+		}
+		break;
+	case LEX_FLOAT:
+		{
+			CScriptVarPtr a = newScriptVar(t->getToken().Float());
+			t->match(LEX_FLOAT);
+			return a;
+		}
+		break;
+	case LEX_STR:
+		{
+			CScriptVarPtr a = newScriptVar(t->getToken().String());
+			t->match(LEX_STR);
+			return a;
+		}
+		break;
+#ifndef NO_REGEXP
+	case LEX_REGEXP:
+		{
+			string::size_type pos = t->getToken().String().find_last_of('/');
+			string source = t->getToken().String().substr(1, pos-1);
+			string flags = t->getToken().String().substr(pos+1);
+			CScriptVarPtr a = newScriptVar(source, flags);
+			t->match(LEX_REGEXP);
+			return a;
+		}
+		break;
+#endif /* NO_REGEXP */
+	case LEX_T_OBJECT_LITERAL:
+		if(execute) {
+			CScriptTokenDataObjectLiteral &Objc = t->getToken().Object();
+			t->match(LEX_T_OBJECT_LITERAL);
+			if(Objc.destructuring) {
+				t->match('=');
+				CScriptVarPtr a = execute_assignment(execute);
+				if(execute) execute_destructuring(Objc, a, execute);
+				return a;
+			} else {
+				CScriptVarPtr a = Objc.type==CScriptTokenDataObjectLiteral::OBJECT ? newScriptVar(Object) : newScriptVar(Array);
+				for(vector<CScriptTokenDataObjectLiteral::ELEMENT>::iterator it=Objc.elements.begin(); execute && it!=Objc.elements.end(); ++it) {
+					if(it->value.empty()) continue;
+					CScriptToken &tk = it->value.front();
+					if(tk.token==LEX_T_GET || tk.token==LEX_T_SET) {
+						CScriptTokenDataFnc &Fnc = tk.Fnc();
+						if((tk.token == LEX_T_GET && Fnc.arguments.size()==0) || (tk.token == LEX_T_SET && Fnc.arguments.size()==1)) {
+							CScriptVarLinkWorkPtr funcVar = parseFunctionDefinition(tk);
+							CScriptVarLinkWorkPtr child = a->findChild(Fnc.name);
+							if(child && !child->getVarPtr()->isAccessor()) child.clear();
+							if(!child) child = a->addChildOrReplace(Fnc.name, newScriptVar(Accessor));
+							child->getVarPtr()->addChildOrReplace((tk.token==LEX_T_GET?TINYJS_ACCESSOR_GET_VAR:TINYJS_ACCESSOR_SET_VAR), funcVar->getVarPtr());
+						}
+					} else {
+						t->pushTokenScope(it->value);
+						a->addChildOrReplace(it->id, execute_assignment(execute));
+						while(0);
+					}
+				}
+				return a;
+			}
+		} else
+			t->match(LEX_T_OBJECT_LITERAL);
+		break;
+	case LEX_R_LET: // let as expression
+		if(execute) {
+			CScopeControl ScopeControl(this);
+			t->match(LEX_R_LET);
+			t->match('(');
+			t->check(LEX_T_FORWARD);
+			ScopeControl.addLetScope();
+			execute_statement(execute); // execute forwarder
+			execute_var_init(true, execute);
+			t->match(')');
+			return execute_assignment(execute);
+		} else {
+			t->skip(t->getToken().Int());
+		}
+		break;
+	case LEX_T_FUNCTION_OPERATOR:
+		if(execute) {
+			CScriptVarLinkWorkPtr a = parseFunctionDefinition(t->getToken());
+			t->match(LEX_T_FUNCTION_OPERATOR);
+			return a;
+		}
+		t->match(LEX_T_FUNCTION_OPERATOR);
+		break;
+	case LEX_R_NEW: // new -> create a new object
+		if (execute) {
+			t->match(LEX_R_NEW);
+			CScriptVarLinkWorkPtr parent = execute_literals(execute);
+			CScriptVarLinkWorkPtr objClass = execute_member(parent, execute).getter(execute);
+			if (execute) {
+				if(objClass->getVarPtr()->isFunction()) {
+					CScriptVarPtr obj(newScriptVar(Object));
+					CScriptVarLinkPtr prototype = objClass->getVarPtr()->findChild(TINYJS_PROTOTYPE_CLASS);
+					if(!prototype || prototype->getVarPtr()->isUndefined() || prototype->getVarPtr()->isNull()) {
+						prototype = objClass->getVarPtr()->addChild(TINYJS_PROTOTYPE_CLASS, newScriptVar(Object), SCRIPTVARLINK_WRITABLE);
+						obj->addChildOrReplace(TINYJS___PROTO___VAR, prototype, SCRIPTVARLINK_WRITABLE);
+					}
+					CScriptVarLinkPtr constructor = objClass->getVarPtr()->findChild("__constructor__");
+					if(constructor && constructor->getVarPtr()->isFunction())
+						objClass = constructor;
+					vector<CScriptVarPtr> arguments;
+					if (t->tk == '(') {
+						t->match('(');
+						while(t->tk!=')') {
+							CScriptVarPtr value = execute_assignment(execute).getter(execute);
+							if (execute)
+								arguments.push_back(value);
+							if (t->tk!=')') t->match(',', ')');
+						}
+						t->match(')');
+					}
+					if(execute) {
+						CScriptVarPtr returnVar = callFunction(execute, objClass->getVarPtr(), arguments, obj, &obj);
+						if(returnVar->isObject())
+							return CScriptVarLinkWorkPtr(returnVar);
+						return CScriptVarLinkWorkPtr(obj);
+					}
+				} else
+					throwError(execute, TypeError, objClass->getName() + " is not a constructor");
+			} else
+				if (t->tk == '(') t->skip(t->getToken().Int());
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_R_TRUE:
+		t->match(LEX_R_TRUE);
+		return constScriptVar(true);
+	case LEX_R_FALSE:
+		t->match(LEX_R_FALSE);
+		return constScriptVar(false);
+	case LEX_R_NULL:
+		t->match(LEX_R_NULL);
+		return constScriptVar(Null);
+	case '(':
+		if(execute) {
+			t->match('(');
+			CScriptVarLinkWorkPtr a = execute_base(execute).getter(execute);
+			t->match(')');
+			return a;
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_T_EXCEPTION_VAR:
+		t->match(LEX_T_EXCEPTION_VAR);
+		if(execute.value) return execute.value;
+		break;
+	default:
+		t->match(LEX_EOF);
+		break;
+	}
+	return constScriptVar(Undefined);
+
+}
+CScriptVarLinkWorkPtr CTinyJS::execute_member(CScriptVarLinkWorkPtr &parent, CScriptResult &execute) {
+	CScriptVarLinkWorkPtr a;
+	parent.swap(a);
+	if(t->tk == '.' || t->tk == '[') {
+		while(t->tk == '.' || t->tk == '[') {
+			parent.swap(a);
+			a = parent.getter(execute); // a is now the "getted" var
+			if(execute && (a->getVarPtr()->isUndefined() || a->getVarPtr()->isNull())) {
+				throwError(execute, ReferenceError, a->getName() + " is " + a->toString(execute));
+			}
+			string name;
+			if(t->tk == '.') {
+				t->match('.');
+				name = t->tkStr();
+				t->match(LEX_ID);
+			} else {
+				if(execute) {
+					t->match('[');
+					name = execute_expression(execute)->toString(execute);
+					t->match(']');
+				} else
+					t->skip(t->getToken().Int());
+			}
+			if (execute) {
+				CScriptVarPtr aVar = a;
+				a = aVar->findChildWithPrototypeChain(name);
+				if(!a) {
+					a(constScriptVar(Undefined), name);
+					a.setReferencedOwner(aVar);
+				}
+			}
+		}
+	}
+	return a;
+}
+
+CScriptVarLinkWorkPtr CTinyJS::execute_function_call(CScriptResult &execute) {
+	CScriptVarLinkWorkPtr parent = execute_literals(execute);
+	CScriptVarLinkWorkPtr a = execute_member(parent, execute);
+	while (t->tk == '(') {
+		if (execute) {
+			if(a->getVarPtr()->isUndefined() || a->getVarPtr()->isNull())
+				throwError(execute, ReferenceError, a->getName() + " is " + a->toString(execute));
+			CScriptVarLinkWorkPtr fnc = a.getter(execute);
+			if (!fnc->getVarPtr()->isFunction())
+				throwError(execute, TypeError, a->getName() + " is not a function");
+			t->match('('); // path += '(';
+
+			// grab in all parameters
+			vector<CScriptVarPtr> arguments;
+			while(t->tk!=')') {
+				CScriptVarLinkWorkPtr value = execute_assignment(execute).getter(execute);
+//				path += (*value)->getString();
+				if (execute) {
+					arguments.push_back(value);
+				}
+				if (t->tk!=')') { t->match(','); /*path+=',';*/ }
+			}
+			t->match(')'); //path+=')';
+			// setup a return variable
+			CScriptVarLinkWorkPtr returnVar;
+			if(execute) {
+				if (!parent)
+					parent = findInScopes("this");
+				// if no parent use the root-scope
+				CScriptVarPtr This(parent ? parent->getVarPtr() : (CScriptVarPtr )root);
+				a = callFunction(execute, a->getVarPtr(), arguments, This);
+			}
+		} else {
+			// function, but not executing - just parse args and be done
+			t->match('(');
+			while (t->tk != ')') {
+				CScriptVarLinkWorkPtr value = execute_base(execute);
+				//	if (t->tk!=')') t->match(',');
+			}
+			t->match(')');
+		}
+		a = execute_member(parent = a, execute);
+	}
+	return a;
+}
+// R->L: Precedence 3 (in-/decrement) ++ --
+// R<-L: Precedence 4 (unary) ! ~ + - typeof void delete 
+bool CTinyJS::execute_unary_rhs(CScriptResult &execute, CScriptVarLinkWorkPtr& a) {
+	t->match(t->tk);
+	a = execute_unary(execute).getter(execute);
+	if(execute) CheckRightHandVar(execute, a);
+	return execute;
+};
+CScriptVarLinkWorkPtr CTinyJS::execute_unary(CScriptResult &execute) {
+	CScriptVarLinkWorkPtr a;
+	switch(t->tk) {
+	case '-':
+		if(execute_unary_rhs(execute, a)) 
+			a(newScriptVar(-a->getVarPtr()->toNumber(execute)));
+		break;
+	case '+':
+		if(execute_unary_rhs(execute, a)) 
+			a = newScriptVar(a->getVarPtr()->toNumber(execute));
+		break;
+	case '!':
+		if(execute_unary_rhs(execute, a)) 
+			a = constScriptVar(!a->getVarPtr()->toBoolean());
+		break;
+	case '~':
+		if(execute_unary_rhs(execute, a)) 
+			a = newScriptVar(~a->getVarPtr()->toNumber(execute));
+		break;
+	case LEX_R_TYPEOF:
+		if(execute_unary_rhs(execute, a)) 
+			a = newScriptVar(a->getVarPtr()->getVarType());
+		break;
+	case LEX_R_VOID:
+		if(execute_unary_rhs(execute, a)) 
+			a = constScriptVar(Undefined);
+		break;
+	case LEX_R_DELETE:
+		t->match(LEX_R_DELETE); // delete
+		a = execute_unary(execute); // no getter - delete can remove the accessor
+		if (execute) {
+			// !!! no right-hand-check by delete
+			if(a->isOwned() && a->isConfigurable()) {
+				a->getOwner()->removeLink(a);	// removes the link from owner
+				a = constScriptVar(true);
+			}
+			else
+				a = constScriptVar(false);
+		}
+		break;
+	case LEX_PLUSPLUS:
+	case LEX_MINUSMINUS:
+		{
+			int op = t->tk;
+			t->match(op); // pre increment/decrement
+			CScriptTokenizer::ScriptTokenPosition ErrorPos = t->getPos();
+			a = execute_function_call(execute);
+			if (execute) {
+				if(a->getName().empty())
+					throwError(execute, SyntaxError, string("invalid ")+(op==LEX_PLUSPLUS ? "increment" : "decrement")+" operand", ErrorPos);
+				else if(!a->isOwned() && !a.hasReferencedOwner() && !a->getName().empty())
+					throwError(execute, ReferenceError, a->getName() + " is not defined", ErrorPos);
+				CScriptVarPtr res = newScriptVar(a.getter(execute)->getVarPtr()->toNumber(execute).add(op==LEX_PLUSPLUS ? 1 : -1));
+				if(a->isWritable()) {
+					if(!a->isOwned() && a.hasReferencedOwner() && a.getReferencedOwner()->isExtensible())
+						a.getReferencedOwner()->addChildOrReplace(a->getName(), res);
+					else
+						a.setter(execute, res);
+				}
+				a = res;
+			}
+		}
+		break;
+	default:
+		a = execute_function_call(execute);
+		break;
+	}
+	// post increment/decrement
+	if (t->tk==LEX_PLUSPLUS || t->tk==LEX_MINUSMINUS) {
+		int op = t->tk;
+		t->match(op);
+		if (execute) {
+			if(a->getName().empty())
+				throwError(execute, SyntaxError, string("invalid ")+(op==LEX_PLUSPLUS ? "increment" : "decrement")+" operand", t->getPrevPos());
+			else if(!a->isOwned() && !a.hasReferencedOwner() && !a->getName().empty())
+				throwError(execute, ReferenceError, a->getName() + " is not defined", t->getPrevPos());
+			CNumber num = a.getter(execute)->getVarPtr()->toNumber(execute);
+			CScriptVarPtr res = newScriptVar(num.add(op==LEX_PLUSPLUS ? 1 : -1));
+			if(a->isWritable()) {
+				if(!a->isOwned() && a.hasReferencedOwner() && a.getReferencedOwner()->isExtensible())
+					a.getReferencedOwner()->addChildOrReplace(a->getName(), res);
+				else
+					a.setter(execute, res);
+			}
+			a = newScriptVar(num);
+		}
+	}
+	return a;
+}
+
+// L->R: Precedence 5 (term) * / %
+CScriptVarLinkWorkPtr CTinyJS::execute_term(CScriptResult &execute) {
+	CScriptVarLinkWorkPtr a = execute_unary(execute);
+	if (t->tk=='*' || t->tk=='/' || t->tk=='%') {
+		CheckRightHandVar(execute, a);
+		while (t->tk=='*' || t->tk=='/' || t->tk=='%') {
+			int op = t->tk;
+			t->match(t->tk);
+			CScriptVarLinkWorkPtr b = execute_unary(execute); // L->R
+			if (execute) {
+				CheckRightHandVar(execute, b);
+				a = mathsOp(execute, a.getter(execute), b.getter(execute), op);
+			}
+		}
+	}
+	return a;
+}
+
+// L->R: Precedence 6 (addition/subtraction) + -
+CScriptVarLinkWorkPtr CTinyJS::execute_expression(CScriptResult &execute) {
+	CScriptVarLinkWorkPtr a = execute_term(execute);
+	if (t->tk=='+' || t->tk=='-') {
+		CheckRightHandVar(execute, a);
+		while (t->tk=='+' || t->tk=='-') {
+			int op = t->tk;
+			t->match(t->tk);
+			CScriptVarLinkWorkPtr b = execute_term(execute); // L->R
+			if (execute) {
+				CheckRightHandVar(execute, b);
+				a = mathsOp(execute, a.getter(execute), b.getter(execute), op);
+			}
+		}
+	}
+	return a;
+}
+
+// L->R: Precedence 7 (bitwise shift) << >> >>>
+CScriptVarLinkWorkPtr CTinyJS::execute_binary_shift(CScriptResult &execute) {
+	CScriptVarLinkWorkPtr a = execute_expression(execute);
+	if (t->tk==LEX_LSHIFT || t->tk==LEX_RSHIFT || t->tk==LEX_RSHIFTU) {
+		CheckRightHandVar(execute, a);
+		while (t->tk>=LEX_SHIFTS_BEGIN && t->tk<=LEX_SHIFTS_END) {
+			int op = t->tk;
+			t->match(t->tk);
+
+			CScriptVarLinkWorkPtr b = execute_expression(execute); // L->R
+			if (execute) {
+				CheckRightHandVar(execute, a);
+				 // not in-place, so just replace
+				 a = mathsOp(execute, a.getter(execute), b.getter(execute), op);
+			}
+		}
+	}
+	return a;
+}
+// L->R: Precedence 8 (relational) < <= > <= in instanceof
+// L->R: Precedence 9 (equality) == != === !===
+CScriptVarLinkWorkPtr CTinyJS::execute_relation(CScriptResult &execute, int set, int set_n) {
+	CScriptVarLinkWorkPtr a = set_n ? execute_relation(execute, set_n, 0) : execute_binary_shift(execute);
+	if ((set==LEX_EQUAL && t->tk>=LEX_RELATIONS_1_BEGIN && t->tk<=LEX_RELATIONS_1_END)
+				||	(set=='<' && (t->tk==LEX_LEQUAL || t->tk==LEX_GEQUAL || t->tk=='<' || t->tk=='>' || t->tk == LEX_R_IN || t->tk == LEX_R_INSTANCEOF))) {
+		CheckRightHandVar(execute, a);
+		a = a.getter(execute);
+		while ((set==LEX_EQUAL && t->tk>=LEX_RELATIONS_1_BEGIN && t->tk<=LEX_RELATIONS_1_END)
+					||	(set=='<' && (t->tk==LEX_LEQUAL || t->tk==LEX_GEQUAL || t->tk=='<' || t->tk=='>' || t->tk == LEX_R_IN || t->tk == LEX_R_INSTANCEOF))) {
+			int op = t->tk;
+			t->match(t->tk);
+			CScriptVarLinkWorkPtr b = set_n ? execute_relation(execute, set_n, 0) : execute_binary_shift(execute); // L->R
+			if (execute) {
+				CheckRightHandVar(execute, b);
+				string nameOf_b = b->getName();
+				b = b.getter(execute);
+				if(op == LEX_R_IN) {
+					if(!b->getVarPtr()->isObject())
+						throwError(execute, TypeError, "invalid 'in' operand "+nameOf_b);
+					a(constScriptVar( (bool)b->getVarPtr()->findChildWithPrototypeChain(a->toString(execute))));
+				} else if(op == LEX_R_INSTANCEOF) {
+					CScriptVarLinkPtr prototype = b->getVarPtr()->findChild(TINYJS_PROTOTYPE_CLASS);
+					if(!prototype)
+						throwError(execute, TypeError, "invalid 'instanceof' operand "+nameOf_b);
+					else {
+						unsigned int uniqueID = getUniqueID();
+						CScriptVarPtr object = a->getVarPtr()->findChild(TINYJS___PROTO___VAR);
+						while( object && object!=prototype->getVarPtr() && object->getTempraryID() != uniqueID) {
+							object->setTemporaryID(uniqueID); // prevents recursions
+							object = object->findChild(TINYJS___PROTO___VAR);
+						}
+						a(constScriptVar(object && object==prototype->getVarPtr()));
+					}
+				} else
+					a = mathsOp(execute, a, b, op);
+			}
+		}
+	}
+	return a;
+}
+
+// L->R: Precedence 10 (bitwise-and) &
+// L->R: Precedence 11 (bitwise-xor) ^
+// L->R: Precedence 12 (bitwise-or) |
+CScriptVarLinkWorkPtr CTinyJS::execute_binary_logic(CScriptResult &execute, int op, int op_n1, int op_n2) {
+	CScriptVarLinkWorkPtr a = op_n1 ? execute_binary_logic(execute, op_n1, op_n2, 0) : execute_relation(execute);
+	if (t->tk==op) {
+		CheckRightHandVar(execute, a);
+		a = a.getter(execute);
+		while (t->tk==op) {
+			t->match(t->tk);
+			CScriptVarLinkWorkPtr b = op_n1 ? execute_binary_logic(execute, op_n1, op_n2, 0) : execute_relation(execute); // L->R
+			if (execute) {
+				CheckRightHandVar(execute, b);
+				a = mathsOp(execute, a, b.getter(execute), op);
+			}
+		}
+	}
+	return a;
+}
+// L->R: Precedence 13 ==> (logical-and) &&
+// L->R: Precedence 14 ==> (logical-or) ||
+CScriptVarLinkWorkPtr CTinyJS::execute_logic(CScriptResult &execute, int op /*= LEX_OROR*/, int op_n /*= LEX_ANDAND*/) {
+	CScriptVarLinkWorkPtr a = op_n ? execute_logic(execute, op_n, 0) : execute_binary_logic(execute);
+	if (t->tk==op) {
+		if(execute) {
+			CScriptVarLinkWorkPtr b;
+			CheckRightHandVar(execute, a);
+			a(a.getter(execute)); // rebuild a
+			do {
+				if(execute && (op==LEX_ANDAND ? a->toBoolean() : !a->toBoolean())) {
+					t->match(t->tk);
+					b = op_n ? execute_logic(execute, op_n, 0) : execute_binary_logic(execute);
+					CheckRightHandVar(execute, b); a(b.getter(execute)); // rebuild a
+				} else
+					t->skip(t->getToken().Int());
+			} while(t->tk==op);
+		} else
+			t->skip(t->getToken().Int());
+	} 
+	return a; 
+} 
+
+// L<-R: Precedence 15 (condition) ?: 
+CScriptVarLinkWorkPtr CTinyJS::execute_condition(CScriptResult &execute) {
+	CScriptVarLinkWorkPtr a = execute_logic(execute);
+	if (t->tk=='?') {
+		CheckRightHandVar(execute, a);
+		bool cond = execute && a.getter(execute)->toBoolean();
+		if(execute) {
+			if(cond) {
+				t->match('?');
+				a = execute_condition(execute);
+				t->check(':');
+				t->skip(t->getToken().Int());
+			} else { 
+				CScriptVarLinkWorkPtr b;
+				t->skip(t->getToken().Int());
+				t->match(':');
+				return execute_condition(execute);
+			}
+		} else {
+			t->skip(t->getToken().Int());
+			t->skip(t->getToken().Int());
+		}
+	}
+	return a;
+}
+	
+// L<-R: Precedence 16 (assignment) = += -= *= /= %= <<= >>= >>>= &= |= ^=
+// now we can return CScriptVarLinkPtr execute_assignment returns always no setters/getters
+// force life of the Owner is no more needed
+CScriptVarLinkPtr CTinyJS::execute_assignment(CScriptResult &execute) {
+	return execute_assignment(execute_condition(execute), execute);
+}
+CScriptVarLinkPtr CTinyJS::execute_assignment(CScriptVarLinkWorkPtr lhs, CScriptResult &execute) {
+	if (t->tk=='=' || (t->tk>=LEX_ASSIGNMENTS_BEGIN && t->tk<=LEX_ASSIGNMENTS_END) ) {
+		int op = t->tk;
+		CScriptTokenizer::ScriptTokenPosition leftHandPos = t->getPos();
+		t->match(t->tk);
+		CScriptVarLinkWorkPtr rhs = execute_assignment(execute).getter(execute); // L<-R
+		if (execute) {
+			if (!lhs->isOwned() && !lhs.hasReferencedOwner() && lhs->getName().empty()) {
+				throw new CScriptException(ReferenceError, "invalid assignment left-hand side (at runtime)", t->currentFile, leftHandPos.currentLine(), leftHandPos.currentColumn());
+			} else if (op != '=' && !lhs->isOwned()) {
+				throwError(execute, ReferenceError, lhs->getName() + " is not defined");
+			}
+			else if(lhs->isWritable()) {
+				if (op=='=') {
+					if (!lhs->isOwned()) {
+						CScriptVarPtr fakedOwner = lhs.getReferencedOwner();
+						if(fakedOwner) {
+							if(!fakedOwner->isExtensible())
+								return rhs->getVarPtr();
+							lhs = fakedOwner->addChildOrReplace(lhs->getName(), lhs);
+						} else
+							lhs = root->addChildOrReplace(lhs->getName(), lhs);
+					}
+					lhs.setter(execute, rhs);
+					return rhs->getVarPtr();
+				} else {
+					CScriptVarPtr result;
+					static int assignments[] = {'+', '-', '*', '/', '%', LEX_LSHIFT, LEX_RSHIFT, LEX_RSHIFTU, '&', '|', '^'};
+					result = mathsOp(execute, lhs, rhs, assignments[op-LEX_PLUSEQUAL]);
+					lhs.setter(execute, result);
+					return result;
+				}
+			} else {
+				// lhs is not writable we ignore lhs & use rhs
+				return rhs->getVarPtr();
+			}
+		}
+	}
+	else 
+		CheckRightHandVar(execute, lhs);
+	return lhs.getter(execute);
+}
+// L->R: Precedence 17 (comma) ,
+CScriptVarLinkPtr CTinyJS::execute_base(CScriptResult &execute) {
+	CScriptVarLinkPtr a;
+	for(;;)
+	{
+		a = execute_assignment(execute); // L->R
+		if (t->tk == ',') {
+			t->match(',');
+		} else
+			break;
+	}
+	return a;
+}
+void CTinyJS::execute_block(CScriptResult &execute) {
+	if(execute) {
+		t->match('{');
+		CScopeControl ScopeControl(this);
+		if(t->tk==LEX_T_FORWARD) // add a LetScope only if needed
+			ScopeControl.addLetScope();
+		while (t->tk && t->tk!='}')
+			execute_statement(execute);
+		t->match('}');
+		// scopes.pop_back();
+	}
+	else 
+		t->skip(t->getToken().Int());
+}
+void CTinyJS::execute_statement(CScriptResult &execute) {
+	switch(t->tk) {
+	case '{':		/* A block of code */
+		execute_block(execute);
+		break;
+	case ';':		/* Empty statement - to allow things like ;;; */
+		t->match(';');
+		break;
+	case LEX_T_FORWARD:
+		{
+			CScriptVarPtr in_scope = scope()->scopeLet();
+			STRING_SET_t *varNames = t->getToken().Forwarder().varNames;
+			for(int i=0; i<CScriptTokenDataForwards::END; ++i) {
+				for(STRING_SET_it it=varNames[i].begin(); it!=varNames[i].end(); ++it) {
+					CScriptVarLinkPtr a = in_scope->findChild(*it);
+					if(!a) in_scope->addChild(*it, constScriptVar(Undefined), i==CScriptTokenDataForwards::CONSTS ? SCRIPTVARLINK_CONSTDEFAULT : SCRIPTVARLINK_VARDEFAULT);
+				}
+					in_scope = scope()->scopeVar();
+			}
+			CScriptTokenDataForwards::FNC_SET_t &functions = t->getToken().Forwarder().functions;
+			for(CScriptTokenDataForwards::FNC_SET_it it=functions.begin(); it!=functions.end(); ++it) {
+				CScriptVarLinkWorkPtr funcVar = parseFunctionDefinition(*it);
+				in_scope->addChildOrReplace(funcVar->getName(), funcVar, SCRIPTVARLINK_VARDEFAULT);
+			}
+			t->match(LEX_T_FORWARD);
+		}
+		break;
+	case LEX_R_VAR:
+	case LEX_R_LET:
+	case LEX_R_CONST:
+		if(execute)
+		{
+			CScopeControl ScopeControl(this);
+			bool isLet = t->tk==LEX_R_LET, let_ext=false;
+			t->match(t->tk);
+			if(isLet && t->tk=='(') {
+				let_ext = true;
+				t->match('(');
+				t->check(LEX_T_FORWARD);
+				ScopeControl.addLetScope();
+				execute_statement(execute); // forwarder
+			}
+			execute_var_init(let_ext, execute);
+			if(let_ext) {
+				t->match(')');
+				execute_statement(execute);
+			} else
+				t->match(';');
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_R_WITH:
+		if(execute) {
+			t->match(LEX_R_WITH);
+			t->match('(');
+			CScriptVarLinkPtr var = execute_base(execute);
+			t->match(')');
+			CScopeControl ScopeControl(this);
+			ScopeControl.addWithScope(var);
+			execute_statement(execute);
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_R_IF:
+		if(execute) {
+			t->match(LEX_R_IF);
+			t->match('(');
+			bool cond = execute_base(execute)->toBoolean();
+			t->match(')');
+			if(cond && execute) {
+				t->match(LEX_T_SKIP);
+				execute_statement(execute);
+			} else {
+				t->check(LEX_T_SKIP);
+				t->skip(t->getToken().Int());
+			}
+			if (t->tk==LEX_R_ELSE) {
+				if(!cond && execute) {
+					t->match(LEX_R_ELSE);
+					execute_statement(execute);
+				}
+				else
+					t->skip(t->getToken().Int());
+			}
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_T_FOR_IN:
+		{
+			CScriptTokenDataLoop &LoopData = t->getToken().Loop();
+			t->match(LEX_T_FOR_IN);
+			if(!execute) break;
+
+			CScopeControl ScopeControl(this);
+			if(LoopData.init.size()) {
+				t->pushTokenScope(LoopData.init);
+				ScopeControl.addLetScope();
+				execute_statement(execute); // forwarder
+			}
+			if(!execute) break;
+	
+			t->pushTokenScope(LoopData.iter);
+			CScriptVarPtr for_in_var = execute_base(execute);
+
+			if(!execute) break;
+
+			CScriptVarPtr Iterator(for_in_var->toIterator(execute, LoopData.type!=CScriptTokenDataLoop::FOR_IN ? 2:1));
+			CScriptVarFunctionPtr Iterator_next(Iterator->findChildWithPrototypeChain("next").getter(execute));
+			if(execute && !Iterator_next) throwError(execute, TypeError, "'" + for_in_var->toString(execute) + "' is not iterable", t->getPrevPos());
+			if(!execute) break;
+			CScriptResult tmp_execute;
+			for(;;) {
+				bool old_haveTry = haveTry;
+				haveTry = true;
+				tmp_execute.set(CScriptResult::Normal, Iterator);
+				t->pushTokenScope(LoopData.condition);
+				execute_statement(tmp_execute);
+				haveTry = old_haveTry;
+				if(tmp_execute.isThrow()){
+					if(tmp_execute.value != constStopIteration) {
+						if(!haveTry)
+							throw new CScriptException("uncaught exception: ", t->currentFile, t->currentLine(), t->currentColumn());
+						else
+							execute = tmp_execute;
+					}
+					break;
+				}
+				t->pushTokenScope(LoopData.body);
+				execute_statement(execute);
+				if(!execute) {
+					bool Continue = false;
+					if(execute.isBreakContinue() 
+						&& 
+						(execute.target.empty() || find(LoopData.labels.begin(), LoopData.labels.end(), execute.target) != LoopData.labels.end())) {
+							Continue = execute.isContinue();
+							execute.set(CScriptResult::Normal, false);
+					}
+					if(!Continue) break;
+				}
+			}
+		}
+		break;
+	case LEX_T_LOOP:
+		{
+			CScriptTokenDataLoop &LoopData = t->getToken().Loop();
+			t->match(LEX_T_LOOP);
+			if(!execute) break;
+
+			CScopeControl ScopeControl(this);
+			if(LoopData.type == CScriptTokenDataLoop::FOR) {
+				CScriptResult tmp_execute;
+				t->pushTokenScope(LoopData.init);
+				if(t->tk == LEX_T_FORWARD) {
+					ScopeControl.addLetScope();
+					execute_statement(tmp_execute); // forwarder
+				}
+				if(t->tk==LEX_R_VAR || t->tk==LEX_R_LET)
+					execute_statement(tmp_execute); // initialisation
+				else
+					execute_base(tmp_execute); // initialisation
+				if(!execute(tmp_execute)) break;
+			}
+
+			bool loopCond = true;	// Empty Condition -->always true
+			if(LoopData.type != CScriptTokenDataLoop::DO && LoopData.condition.size()) {
+				t->pushTokenScope(LoopData.condition);
+				loopCond = execute_base(execute)->toBoolean();
+				if(!execute) break;
+			}
+			while (loopCond && execute) {
+				t->pushTokenScope(LoopData.body);
+				execute_statement(execute);
+				if(!execute) {
+					bool Continue = false;
+					if(execute.isBreakContinue() 
+						&& 
+						(execute.target.empty() || find(LoopData.labels.begin(), LoopData.labels.end(), execute.target) != LoopData.labels.end())) {
+							Continue = execute.isContinue();
+							execute.set(CScriptResult::Normal, false);
+					}
+					if(!Continue) break;
+				}
+				if(LoopData.type == CScriptTokenDataLoop::FOR && execute && LoopData.iter.size()) {
+					t->pushTokenScope(LoopData.iter);
+					execute_base(execute);
+				}
+				if(execute && LoopData.condition.size()) {
+					t->pushTokenScope(LoopData.condition);
+					loopCond = execute_base(execute)->toBoolean();
+				}
+			}
+		}
+		break;
+	case LEX_R_BREAK:
+	case LEX_R_CONTINUE:
+		if (execute)
+		{
+			CScriptResult::TYPE type = t->tk==LEX_R_BREAK ? CScriptResult::Break : CScriptResult::Continue;
+			string label;
+			t->match(t->tk);
+			if(t->tk == LEX_ID) {
+				label = t->tkStr();
+				t->match(LEX_ID);
+			}
+			t->match(';');
+			execute.set(type, label);
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_R_RETURN:
+		if (execute) {
+			t->match(LEX_R_RETURN);
+			CScriptVarPtr result;
+			if (t->tk != ';')
+				result = execute_base(execute);
+			t->match(';');
+			execute.set(CScriptResult::Return, result);
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_R_FUNCTION:
+		if(execute) {
+			CScriptVarLinkWorkPtr funcVar = parseFunctionDefinition(t->getToken());
+			scope()->scopeVar()->addChildOrReplace(funcVar->getName(), funcVar, SCRIPTVARLINK_VARDEFAULT);
+		}
+	case LEX_T_FUNCTION_PLACEHOLDER:
+		t->match(t->tk);
+		break;
+	case LEX_T_TRY:
+		if(execute) {
+			CScriptTokenDataTry &TryData = t->getToken().Try();
+
+			bool old_haveTry = haveTry;
+			haveTry = true;
+
+			// execute try-block
+			t->pushTokenScope(TryData.tryBlock);
+			execute_block(execute);
+
+			bool isThrow = execute.isThrow();
+
+			if(isThrow) {
+				// execute catch-blocks
+				for(CScriptTokenDataTry::CatchBlock_it catchBlock = TryData.catchBlocks.begin(); catchBlock!=TryData.catchBlocks.end(); catchBlock++) {
+					CScriptResult catch_execute;
+					CScopeControl ScopeControl(this);
+					ScopeControl.addLetScope();
+					t->pushTokenScope(catchBlock->condition); // condition;
+					execute_statement(catch_execute); // forwarder
+					assign_destructuring_var(0, *catchBlock->indentifiers, execute.value, catch_execute);
+					bool condition = true;
+					if(catchBlock->condition.size()>1)
+						condition = execute_base(catch_execute)->toBoolean();
+					if(!catch_execute) {
+						execute = catch_execute;
+						break;
+					} else if(condition) {
+						t->pushTokenScope(catchBlock->block); // condition;
+						execute_block(catch_execute);
+						execute = catch_execute;
+						break;
+					}
+				}
+			}
+			if(TryData.finallyBlock.size()) {
+				CScriptResult finally_execute; // alway execute finally-block
+				t->pushTokenScope(TryData.finallyBlock); // finally;
+				execute_block(finally_execute);
+				execute(finally_execute);
+			}
+			// restore haveTry
+			haveTry = old_haveTry;
+			if(execute.isThrow() && !haveTry) { // (exception in catch or finally or no catch-clause found) and no parent try-block 
+				if(execute.value->isError())
+					throw CScriptVarErrorPtr(execute.value)->toCScriptException();
+				throw new CScriptException("uncaught exception: '"+execute.value->toString()+"'", t->currentFile, t->currentLine(), t->currentColumn());
+			}
+
+		}
+		t->match(LEX_T_TRY);
+		break;
+	case LEX_R_THROW:
+		if(execute) {
+			CScriptTokenizer::ScriptTokenPosition tokenPos = t->getPos();
+			//		int tokenStart = t->getToken().pos;
+			t->match(LEX_R_THROW);
+			CScriptVarPtr a = execute_base(execute);
+			if(execute) {
+				if(haveTry)
+					execute.set(CScriptResult::Throw, a);
+				else
+					throw new CScriptException("uncaught exception: '"+a->toString(execute)+"'", t->currentFile, tokenPos.currentLine(), tokenPos.currentColumn());
+			}
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_R_SWITCH:
+		if(execute) {
+			t->match(LEX_R_SWITCH);
+			t->match('(');
+			CScriptVarPtr SwitchValue = execute_base(execute);
+			t->match(')');
+			if(execute) {
+				t->match('{');
+				CScopeControl ScopeControl(this);
+				if(t->tk == LEX_T_FORWARD) {
+					ScopeControl.addLetScope(); // add let-scope only if needed
+					execute_statement(execute); // execute forwarder
+				}
+				CScriptTokenizer::ScriptTokenPosition defaultStart = t->getPos();
+				bool hasDefault = false, found = false;
+				while (t->tk) {
+					switch(t->tk) {
+					case LEX_R_CASE:
+						if(!execute)
+							t->skip(t->getToken().Int());				// skip up to'}'
+						else if(found) {	// execute && found
+							t->match(LEX_R_CASE);
+							t->skip(t->getToken().Int());				// skip up to ':'
+							t->match(':');									// skip ':' and execute all after ':'
+						} else {	// execute && !found
+							t->match(LEX_R_CASE);
+							t->match(LEX_T_SKIP);						// skip 'L_T_SKIP'
+							CScriptVarLinkPtr CaseValue = execute_base(execute);
+							CaseValue = mathsOp(execute, CaseValue, SwitchValue, LEX_TYPEEQUAL);
+							if(execute) {
+								found = CaseValue->toBoolean();
+								if(found) t->match(':'); 				// skip ':' and execute all after ':'
+								else t->skip(t->getToken().Int());	// skip up to next 'case'/'default' or '}'
+							} else
+								t->skip(t->getToken().Int());			// skip up to next 'case'/'default' or '}'
+						}
+						break;
+					case LEX_R_DEFAULT:
+						if(!execute)
+							t->skip(t->getToken().Int());				// skip up to'}' NOTE: no extra 'L_T_SKIP' for skipping tp ':'
+						else {
+							t->match(LEX_R_DEFAULT);
+							if(found)
+								t->match(':'); 							// skip ':' and execute all after ':'
+							else {
+								hasDefault = true;						// in fist pass: skip default-area
+								defaultStart = t->getPos(); 			// remember pos of default
+								t->skip(t->getToken().Int());			// skip up to next 'case' or '}'
+							}
+						}
+						break;
+					case '}':
+						if(execute && !found && hasDefault) {		// if not found & have default -> execute default
+							found = true;
+							t->setPos(defaultStart);
+							t->match(':');
+						} else
+							goto end_while; // goto isn't fine but C supports no "break lable;"
+						break;
+					default:
+						ASSERT(found);
+						execute_statement(execute);
+						break;
+					}
+				}
+end_while:
+				t->match('}');
+				if(execute.isBreak() && execute.target.empty()) {
+					execute.set(CScriptResult::Normal);
+				}
+			} else
+				t->skip(t->getToken().Int());
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	case LEX_T_DUMMY_LABEL:
+		t->match(LEX_T_DUMMY_LABEL);
+		t->match(':');
+		break;
+	case LEX_T_LABEL:
+		{
+			STRING_VECTOR_t Labels;
+			while(t->tk == LEX_T_LABEL) {
+				Labels.push_back(t->tkStr());
+				t->match(LEX_T_LABEL);
+				t->match(':');
+			}
+			if(execute) {
+				execute_statement(execute);
+				if(execute.isBreak() && find(Labels.begin(), Labels.end(), execute.target) != Labels.end()) { // break this label
+					execute.set(CScriptResult::Normal, false);
+				}
+			}
+			else
+				execute_statement(execute);
+		}
+		break;
+	case LEX_EOF:
+		t->match(LEX_EOF);
+		break;
+	default:
+		if(execute) {
+			t->match(LEX_T_SKIP);
+			/* Execute a simple statement that only contains basic arithmetic... */
+			CScriptVarPtr ret = execute_base(execute);
+			if(execute) execute.set(CScriptResult::Normal, CScriptVarPtr(ret));
+			t->match(';');
+		} else
+			t->skip(t->getToken().Int());
+		break;
+	}
+}
+
+
+/// Finds a child, looking recursively up the scopes
+CScriptVarLinkPtr CTinyJS::findInScopes(const string &childName) {
+	return scope()->findInScopes(childName);
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// Object
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_Object(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(c->getArgument(0)->toObject());
+}
+void CTinyJS::native_Object_getPrototypeOf(const CFunctionsScopePtr &c, void *data) {
+	if(c->getArgumentsLength()>=1) {
+		CScriptVarPtr obj = c->getArgument(0);
+		if(obj->isObject()) {
+			c->setReturnVar(obj->findChild(TINYJS___PROTO___VAR));
+			return;
+		}
+	}
+	c->throwError(TypeError, "argument is not an object");
+}
+
+void CTinyJS::native_Object_setObjectSecure(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr obj = c->getArgument(0);
+	if(!obj->isObject()) c->throwError(TypeError, "argument is not an object");
+	if(data==(void*)2)
+		obj->freeze();
+	else if(data==(void*)1)
+		obj->seal();
+	else
+		obj->preventExtensions();
+	c->setReturnVar(obj);
+}
+
+void CTinyJS::native_Object_isSecureObject(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr obj = c->getArgument(0);
+	if(!obj->isObject()) c->throwError(TypeError, "argument is not an object");
+	bool ret;
+	if(data==(void*)2)
+		ret = obj->isFrozen();
+	else if(data==(void*)1)
+		ret = obj->isSealed();
+	else
+		ret = obj->isExtensible();
+	c->setReturnVar(constScriptVar(ret));
+}
+
+void CTinyJS::native_Object_keys(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr obj = c->getArgument(0);
+	if(!obj->isObject()) c->throwError(TypeError, "argument is not an object");
+	CScriptVarPtr returnVar = c->newScriptVar(Array);
+	c->setReturnVar(returnVar);
+
+	STRING_SET_t keys;
+	obj->keys(keys, data==0);
+
+	uint32_t idx=0;
+	for(STRING_SET_it it=keys.begin(); it!=keys.end(); ++it)
+		returnVar->setArrayIndex(idx++, newScriptVar(*it));
+}
+
+void CTinyJS::native_Object_getOwnPropertyDescriptor(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr obj = c->getArgument(0);
+	if(!obj->isObject()) c->throwError(TypeError, "argument is not an object");
+	c->setReturnVar(obj->getOwnPropertyDescriptor(c->getArgument(1)->toString()));
+}
+
+void CTinyJS::native_Object_defineProperty(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr obj = c->getArgument(0);
+	if(!obj->isObject()) c->throwError(TypeError, "argument is not an object");
+	string name = c->getArgument(1)->toString();
+	CScriptVarPtr attributes = c->getArgument(2);
+	if(!attributes->isObject()) c->throwError(TypeError, "attributes is not an object");
+	const char *err = obj->defineProperty(name, attributes);
+	if(err) c->throwError(TypeError, err);
+	c->setReturnVar(obj);
+}
+
+void CTinyJS::native_Object_defineProperties(const CFunctionsScopePtr &c, void *data) {
+	bool ObjectCreate = data!=0;
+	CScriptVarPtr obj = c->getArgument(0);
+	if(ObjectCreate) {
+		if(!obj->isObject() && !obj->isNull()) c->throwError(TypeError, "argument is not an object or null");
+		obj = newScriptVar(Object, obj);
+	} else
+		if(!obj->isObject()) c->throwError(TypeError, "argument is not an object");
+	c->setReturnVar(obj);
+	if(c->getArrayLength()<2) {
+		if(ObjectCreate) return;
+		c->throwError(TypeError, "Object.defineProperties requires 2 arguments");
+	}
+
+	CScriptVarPtr properties = c->getArgument(1);
+
+	STRING_SET_t names;
+	properties->keys(names, true);
+
+	for(STRING_SET_it it=names.begin(); it!=names.end(); ++it) {
+		CScriptVarPtr attributes = properties->findChildWithStringChars(*it).getter();
+		if(!attributes->isObject()) c->throwError(TypeError, "descriptor for "+*it+" is not an object");
+		const char *err = obj->defineProperty(*it, attributes);
+		if(err) c->throwError(TypeError, err);
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// Object.prototype
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_Object_prototype_hasOwnProperty(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr This = c->getArgument("this");
+	string PropStr = c->getArgument("prop")->toString();
+	CScriptVarLinkPtr Prop = This->findChild(PropStr);
+	bool res = Prop && !Prop->getVarPtr()->isUndefined();
+	if(!res) {
+		CScriptVarStringPtr This_asString = This->getRawPrimitive();
+		if(This_asString) {
+			uint32_t Idx = isArrayIndex(PropStr);
+			res = Idx!=uint32_t(-1) && Idx<This_asString->stringLength();
+		}
+	}
+	c->setReturnVar(c->constScriptVar(res));
+}
+void CTinyJS::native_Object_prototype_valueOf(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(c->getArgument("this")->valueOf_CallBack());
+}
+void CTinyJS::native_Object_prototype_toString(const CFunctionsScopePtr &c, void *data) {
+	CScriptResult execute;
+	int radix = 10;
+	if(c->getArgumentsLength()>=1) radix = c->getArgument("radix")->toNumber().toInt32();
+	c->setReturnVar(c->getArgument("this")->toString_CallBack(execute, radix));
+	if(!execute) {
+		// TODO
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// Array
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_Array(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr returnVar = c->newScriptVar(Array);
+	c->setReturnVar(returnVar);
+	int length = c->getArgumentsLength();
+	CScriptVarPtr Argument_0_Var = c->getArgument(0);
+	if(data!=0 && length == 1 && Argument_0_Var->isNumber()) {
+		CNumber Argument_0 = Argument_0_Var->toNumber();
+		uint32_t new_size = Argument_0.toUInt32();
+		if(Argument_0.isFinite() && Argument_0 == new_size)
+			returnVar->setArrayIndex(new_size-1, constScriptVar(Undefined));
+		else
+			c->throwError(RangeError, "invalid array length");
+	} else for(int i=0; i<length; i++)
+		returnVar->setArrayIndex(i, c->getArgument(i));
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// String
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_String(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr arg;
+	if(c->getArgumentsLength()==0)
+		arg = newScriptVar("");
+	else
+		arg = newScriptVar(c->getArgument(0)->toString());
+	if(data)
+		c->setReturnVar(arg->toObject());
+	else
+		c->setReturnVar(arg);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// RegExp
+//////////////////////////////////////////////////////////////////////////
+#ifndef NO_REGEXP
+
+void CTinyJS::native_RegExp(const CFunctionsScopePtr &c, void *data) {
+	int arglen = c->getArgumentsLength();
+	string RegExp, Flags;
+	if(arglen>=1) {
+		RegExp = c->getArgument(0)->toString();
+		try { regex(RegExp, regex_constants::ECMAScript); } catch(regex_error e) {
+			c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
+		}
+		if(arglen>=2) {
+			Flags = c->getArgument(1)->toString();
+			string::size_type pos = Flags.find_first_not_of("gimy");
+			if(pos != string::npos) {
+				c->throwError(SyntaxError, string("invalid regular expression flag ")+Flags[pos]);
+			}
+		} 
+	}
+	c->setReturnVar(newScriptVar(RegExp, Flags));
+}
+#endif /* NO_REGEXP */
+
+//////////////////////////////////////////////////////////////////////////
+/// Number
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_Number(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr arg;
+	if(c->getArgumentsLength()==0)
+		arg = newScriptVar(0);
+	else
+		arg = newScriptVar(c->getArgument(0)->toNumber());
+	if(data)
+		c->setReturnVar(arg->toObject());
+	else
+		c->setReturnVar(arg);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/// Boolean
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_Boolean(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr arg;
+	if(c->getArgumentsLength()==0)
+		arg = constScriptVar(false);
+	else
+		arg = constScriptVar(c->getArgument(0)->toBoolean());
+	if(data)
+		c->setReturnVar(arg->toObject());
+	else
+		c->setReturnVar(arg);
+}
+
+////////////////////////////////////////////////////////////////////////// 
+/// Iterator
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_Iterator(const CFunctionsScopePtr &c, void *data) {
+	if(c->getArgumentsLength()<1) c->throwError(TypeError, "missing argument 0 when calling function Iterator");
+	c->setReturnVar(c->getArgument(0)->toIterator(c->getArgument(1)->toBoolean()?1:3));
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// Function
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_Function(const CFunctionsScopePtr &c, void *data) {
+	int length = c->getArgumentsLength();
+	string params, body;
+	if(length>=1) 
+		body = c->getArgument(length-1)->toString();
+	if(length>=2) {
+		params = c->getArgument(0)->toString();
+		for(int i=1; i<length-1; i++)
+		{
+			params.append(",");
+			params.append(c->getArgument(i)->toString());
+		}
+	}
+	c->setReturnVar(parseFunctionsBodyFromString(params,body));
+}
+
+void CTinyJS::native_Function_prototype_call(const CFunctionsScopePtr &c, void *data) {
+	int length = c->getArgumentsLength();
+	CScriptVarPtr Fnc = c->getArgument("this");
+	if(!Fnc->isFunction()) c->throwError(TypeError, "Function.prototype.call called on incompatible Object");
+	CScriptVarPtr This = c->getArgument(0);
+	vector<CScriptVarPtr> Args;
+	for(int i=1; i<length; i++)
+		Args.push_back(c->getArgument(i));
+	c->setReturnVar(callFunction(Fnc, Args, This));
+}
+void CTinyJS::native_Function_prototype_apply(const CFunctionsScopePtr &c, void *data) {
+	int length=0;
+	CScriptVarPtr Fnc = c->getArgument("this");
+	if(!Fnc->isFunction()) c->throwError(TypeError, "Function.prototype.apply called on incompatible Object");
+	// Argument_0
+	CScriptVarPtr This = c->getArgument(0)->toObject();
+	if(This->isNull() || This->isUndefined()) This=root;
+	// Argument_1
+	CScriptVarPtr Array = c->getArgument(1);
+	if(!Array->isNull() && !Array->isUndefined()) { 
+		CScriptVarLinkWorkPtr Length = Array->findChild("length");
+		if(!Length) c->throwError(TypeError, "second argument to Function.prototype.apply must be an array or an array like object");
+		length = Length.getter()->toNumber().toInt32();
+	}
+	vector<CScriptVarPtr> Args;
+	for(int i=0; i<length; i++) {
+		CScriptVarLinkPtr value = Array->findChild(int2string(i));
+		if(value) Args.push_back(value);
+		else Args.push_back(constScriptVar(Undefined));
+	}
+	c->setReturnVar(callFunction(Fnc, Args, This));
+}
+void CTinyJS::native_Function_prototype_bind(const CFunctionsScopePtr &c, void *data) {
+	int length = c->getArgumentsLength();
+	CScriptVarPtr Fnc = c->getArgument("this");
+	if(!Fnc->isFunction()) c->throwError(TypeError, "Function.prototype.bind called on incompatible Object");
+	CScriptVarPtr This = c->getArgument(0);
+	if(This->isUndefined() || This->isNull()) This = root;
+	vector<CScriptVarPtr> Args;
+	for(int i=1; i<length; i++) Args.push_back(c->getArgument(i));
+	c->setReturnVar(newScriptVarFunctionBounded(Fnc, This, Args));
+}
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// Error
+//////////////////////////////////////////////////////////////////////////
+
+static CScriptVarPtr _newError(CTinyJS *context, ERROR_TYPES type, const CFunctionsScopePtr &c) {
+	int i = c->getArgumentsLength();
+	string message, fileName;
+	int line=-1, column=-1; 
+	if(i>0) message	= c->getArgument(0)->toString();
+	if(i>1) fileName	= c->getArgument(1)->toString();
+	if(i>2) line		= c->getArgument(2)->toNumber().toInt32();
+	if(i>3) column		= c->getArgument(3)->toNumber().toInt32();
+	return ::newScriptVarError(context, type, message.c_str(), fileName.c_str(), line, column);
+}
+void CTinyJS::native_Error(const CFunctionsScopePtr &c, void *data) { c->setReturnVar(_newError(this, Error,c)); }
+void CTinyJS::native_EvalError(const CFunctionsScopePtr &c, void *data) { c->setReturnVar(_newError(this, EvalError,c)); }
+void CTinyJS::native_RangeError(const CFunctionsScopePtr &c, void *data) { c->setReturnVar(_newError(this, RangeError,c)); }
+void CTinyJS::native_ReferenceError(const CFunctionsScopePtr &c, void *data){ c->setReturnVar(_newError(this, ReferenceError,c)); }
+void CTinyJS::native_SyntaxError(const CFunctionsScopePtr &c, void *data){ c->setReturnVar(_newError(this, SyntaxError,c)); }
+void CTinyJS::native_TypeError(const CFunctionsScopePtr &c, void *data){ c->setReturnVar(_newError(this, TypeError,c)); }
+
+////////////////////////////////////////////////////////////////////////// 
+/// global functions
+//////////////////////////////////////////////////////////////////////////
+
+void CTinyJS::native_eval(const CFunctionsScopePtr &c, void *data) {
+	string Code = c->getArgument("jsCode")->toString();
+	CScriptVarScopePtr scEvalScope = scopes.back(); // save scope
+	scopes.pop_back(); // go back to the callers scope
+	CScriptResult execute;
+	CScriptTokenizer *oldTokenizer = t; t=0;
+	try {
+		CScriptTokenizer Tokenizer(Code.c_str(), "eval");
+		t = &Tokenizer;
+		do {
+			execute_statement(execute);
+			while (t->tk==';') t->match(';'); // skip empty statements
+		} while (t->tk!=LEX_EOF);
+	} catch (CScriptException *e) { // script exceptions
+		t = oldTokenizer; // restore tokenizer
+		scopes.push_back(scEvalScope); // restore Scopes;
+		if(haveTry) { // an Error in eval is always catchable
+			CScriptVarPtr E = newScriptVarError(this, e->errorType, e->message.c_str(), e->fileName.c_str(), e->lineNumber, e->column);
+			delete e;
+			throw E;
+		} else
+			throw e;
+	} catch (...) { // all other exceptions
+		t = oldTokenizer; // restore tokenizer
+		scopes.push_back(scEvalScope); // restore Scopes;
+		throw; // re-throw
+	}
+	t = oldTokenizer; // restore tokenizer
+	scopes.push_back(scEvalScope); // restore Scopes;
+	if(execute.value)
+		c->setReturnVar(execute.value);
+}
+
+void CTinyJS::native_isNAN(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(constScriptVar(c->getArgument("objc")->toNumber().isNaN()));
+}
+
+void CTinyJS::native_isFinite(const CFunctionsScopePtr &c, void *data) {
+	c->setReturnVar(constScriptVar(c->getArgument("objc")->toNumber().isFinite()));
+}
+
+void CTinyJS::native_parseInt(const CFunctionsScopePtr &c, void *) {
+	CNumber result;
+	result.parseInt(c->getArgument("string")->toString(), c->getArgument("radix")->toNumber().toInt32());
+	c->setReturnVar(c->newScriptVar(result));
+}
+
+void CTinyJS::native_parseFloat(const CFunctionsScopePtr &c, void *) {
+	CNumber result;
+	result.parseFloat(c->getArgument("string")->toString());
+	c->setReturnVar(c->newScriptVar(result));
+}
+
+
+
+void CTinyJS::native_JSON_parse(const CFunctionsScopePtr &c, void *data) {
+	string Code = "§" + c->getArgument("text")->toString();
+	// "§" is a spezal-token - it's for the tokenizer and means the code begins not in Statement-level
+	CScriptVarLinkWorkPtr returnVar;
+	CScriptTokenizer *oldTokenizer = t; t=0;
+	try {
+		CScriptTokenizer Tokenizer(Code.c_str(), "JSON.parse", 0, -1);
+		t = &Tokenizer;
+		CScriptResult execute;
+		returnVar = execute_literals(execute);
+		t->match(LEX_EOF);
+	} catch (CScriptException *e) {
+		t = oldTokenizer;
+		throw e;
+	}
+	t = oldTokenizer;
+
+	if(returnVar)
+		c->setReturnVar(returnVar);
+}
+
+void CTinyJS::setTemporaryID_recursive(uint32_t ID) {
+	for(vector<CScriptVarPtr*>::iterator it = pseudo_refered.begin(); it!=pseudo_refered.end(); ++it)
+		if(**it) (**it)->setTemporaryID_recursive(ID);
+	for(int i=Error; i<ERROR_COUNT; i++)
+		if(errorPrototypes[i]) errorPrototypes[i]->setTemporaryID_recursive(ID);
+	root->setTemporaryID_recursive(ID);
+}
+
+void CTinyJS::ClearUnreferedVars(const CScriptVarPtr &extra/*=CScriptVarPtr()*/) {
+	uint32_t UniqueID = getUniqueID(); 
+	setTemporaryID_recursive(UniqueID);
+	if(extra) extra->setTemporaryID_recursive(UniqueID);
+	CScriptVar *p = first;
+	while(p)
+	{
+		if(p->temporaryID != UniqueID)
+		{
+			CScriptVarPtr var = p;
+			var->removeAllChildren();
+			p = var->next;
+		}
+		else
+			p = p->next;
+	}
+}
+
Index: XmlTools2/trunk/XmlTools/libs/TinyJS.h
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS.h	(revision 905)
@@ -0,0 +1,2145 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored / Changed By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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 TINYJS_H
+#define TINYJS_H
+
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <stdint.h>
+#include <cassert>
+#include <limits>
+
+#include "config.h"
+
+#if __cplusplus >= 201103L
+#	define MEMBER_DELETE =delete
+#else
+#	define MEMBER_DELETE
+#endif
+
+#ifdef NO_POOL_ALLOCATOR
+	template<typename T, int num_objects=64>
+	class fixed_size_object {};
+#else
+#	include "pool_allocator.h"
+#endif
+
+#ifdef _MSC_VER
+#	if defined(_DEBUG) && defined(_DEBUG_NEW)
+#		define _AFXDLL
+#		include <afx.h>         // MFC-Kern- und -Standardkomponenten
+#		define new DEBUG_NEW
+#	endif
+#	define DEPRECATED(_Text) __declspec(deprecated(_Text))
+#elif defined(__GNUC__)
+#	define DEPRECATED(_Text) __attribute__ ((deprecated))
+#else
+#	define DEPRECATED(_Text)
+#endif
+
+#ifndef ASSERT
+#	define ASSERT(X) assert(X)
+#endif
+
+#undef TRACE
+#ifndef TRACE
+#define TRACE printf
+#endif // TRACE
+
+enum LEX_TYPES {
+	LEX_EOF = 0,
+#define LEX_RELATIONS_1_BEGIN LEX_EQUAL
+	LEX_EQUAL = 256,
+	LEX_TYPEEQUAL,
+	LEX_NEQUAL,
+	LEX_NTYPEEQUAL,
+#define LEX_RELATIONS_1_END LEX_NTYPEEQUAL
+	LEX_LEQUAL,
+	LEX_GEQUAL,
+#define LEX_SHIFTS_BEGIN LEX_LSHIFT
+	LEX_LSHIFT,
+	LEX_RSHIFT,
+	LEX_RSHIFTU, // unsigned
+#define LEX_SHIFTS_END LEX_RSHIFTU
+	LEX_PLUSPLUS,
+	LEX_MINUSMINUS,
+	LEX_ANDAND,
+	LEX_OROR,
+	LEX_INT,
+
+#define LEX_ASSIGNMENTS_BEGIN LEX_PLUSEQUAL
+	LEX_PLUSEQUAL,
+	LEX_MINUSEQUAL,
+	LEX_ASTERISKEQUAL,
+	LEX_SLASHEQUAL,
+	LEX_PERCENTEQUAL,
+	LEX_LSHIFTEQUAL,
+	LEX_RSHIFTEQUAL,
+	LEX_RSHIFTUEQUAL, // unsigned
+	LEX_ANDEQUAL,
+	LEX_OREQUAL,
+	LEX_XOREQUAL,
+#define LEX_ASSIGNMENTS_END LEX_XOREQUAL
+
+#define LEX_TOKEN_NONSIMPLE_1_BEGIN LEX_TOKEN_STRING_BEGIN
+#define LEX_TOKEN_STRING_BEGIN LEX_ID
+	LEX_ID,
+	LEX_STR,
+	LEX_REGEXP,
+	LEX_T_LABEL,
+	LEX_T_DUMMY_LABEL,
+#define LEX_TOKEN_STRING_END LEX_T_DUMMY_LABEL
+
+	LEX_FLOAT,
+#define LEX_TOKEN_NONSIMPLE_1_END LEX_FLOAT
+
+	// reserved words
+	LEX_R_IF,
+	LEX_R_ELSE,
+	LEX_R_DO,
+	LEX_R_WHILE,
+	LEX_R_FOR,
+	LEX_R_IN,
+	LEX_T_OF,
+	LEX_R_BREAK,
+	LEX_R_CONTINUE,
+	LEX_R_RETURN,
+	LEX_R_VAR,
+	LEX_R_LET,
+	LEX_R_CONST,
+	LEX_R_WITH,
+	LEX_R_TRUE,
+	LEX_R_FALSE,
+	LEX_R_NULL,
+	LEX_R_NEW,
+	LEX_R_TRY,
+	LEX_R_CATCH,
+	LEX_R_FINALLY,
+	LEX_R_THROW,
+	LEX_R_TYPEOF,
+	LEX_R_VOID,
+	LEX_R_DELETE,
+	LEX_R_INSTANCEOF,
+	LEX_R_SWITCH,
+	LEX_R_CASE,
+	LEX_R_DEFAULT,
+
+	// special token
+//	LEX_T_FILE,
+#define LEX_TOKEN_NONSIMPLE_2_BEGIN LEX_TOKEN_FOR_BEGIN
+#define LEX_TOKEN_FOR_BEGIN LEX_T_LOOP
+	LEX_T_LOOP,
+	LEX_T_FOR_IN,
+#define LEX_TOKEN_FOR_END LEX_T_FOR_IN
+#define LEX_TOKEN_FUNCTION_BEGIN LEX_R_FUNCTION
+	LEX_R_FUNCTION,
+	LEX_T_FUNCTION_PLACEHOLDER,
+	LEX_T_FUNCTION_OPERATOR,
+	LEX_T_GET,
+	LEX_T_SET,
+#define LEX_TOKEN_FUNCTION_END LEX_T_SET
+	LEX_T_TRY,
+	LEX_T_OBJECT_LITERAL,
+	LEX_T_DESTRUCTURING_VAR,
+	LEX_T_FORWARD,
+#define LEX_TOKEN_NONSIMPLE_2_END LEX_T_FORWARD
+
+	LEX_T_EXCEPTION_VAR,
+	LEX_T_SKIP,
+};
+#define LEX_TOKEN_DATA_STRING(tk) ((LEX_TOKEN_STRING_BEGIN<= tk && tk <= LEX_TOKEN_STRING_END))
+#define LEX_TOKEN_DATA_FLOAT(tk) (tk==LEX_FLOAT)
+#define LEX_TOKEN_DATA_LOOP(tk) (LEX_TOKEN_FOR_BEGIN <= tk && tk <= LEX_TOKEN_FOR_END)
+#define LEX_TOKEN_DATA_FUNCTION(tk) (LEX_TOKEN_FUNCTION_BEGIN <= tk && tk <= LEX_TOKEN_FUNCTION_END)
+#define LEX_TOKEN_DATA_TRY(tk) (tk == LEX_T_TRY)
+#define LEX_TOKEN_DATA_OBJECT_LITERAL(tk) (tk==LEX_T_OBJECT_LITERAL)
+#define LEX_TOKEN_DATA_DESTRUCTURING_VAR(tk) (tk==LEX_T_DESTRUCTURING_VAR)
+#define LEX_TOKEN_DATA_FORWARDER(tk) (tk==LEX_T_FORWARD)
+
+#define LEX_TOKEN_DATA_SIMPLE(tk) (!((LEX_TOKEN_NONSIMPLE_1_BEGIN <= tk && tk <= LEX_TOKEN_NONSIMPLE_1_END) || (LEX_TOKEN_NONSIMPLE_2_BEGIN <= tk && tk <= LEX_TOKEN_NONSIMPLE_2_END)))
+
+enum SCRIPTVARLINK_FLAGS {
+	SCRIPTVARLINK_WRITABLE			= 1<<0,
+	SCRIPTVARLINK_CONFIGURABLE		= 1<<1,
+	SCRIPTVARLINK_ENUMERABLE		= 1<<2,
+	SCRIPTVARLINK_DEFAULT			= SCRIPTVARLINK_WRITABLE | SCRIPTVARLINK_CONFIGURABLE | SCRIPTVARLINK_ENUMERABLE,
+	SCRIPTVARLINK_VARDEFAULT		= SCRIPTVARLINK_WRITABLE | SCRIPTVARLINK_ENUMERABLE,
+	SCRIPTVARLINK_CONSTDEFAULT		= SCRIPTVARLINK_ENUMERABLE,
+	SCRIPTVARLINK_BUILDINDEFAULT	= SCRIPTVARLINK_WRITABLE | SCRIPTVARLINK_CONFIGURABLE,
+	SCRIPTVARLINK_READONLY			= SCRIPTVARLINK_CONFIGURABLE,
+	SCRIPTVARLINK_READONLY_ENUM	= SCRIPTVARLINK_CONFIGURABLE | SCRIPTVARLINK_ENUMERABLE,
+	SCRIPTVARLINK_CONSTANT			= 0,
+};
+
+enum ERROR_TYPES {
+	Error = 0,
+	EvalError,
+	RangeError,
+	ReferenceError,
+	SyntaxError,
+	TypeError
+};
+#define ERROR_MAX TypeError
+#define ERROR_COUNT (ERROR_MAX+1)
+extern const char *ERROR_NAME[];
+
+
+#define TINYJS_RETURN_VAR					"return"
+#define TINYJS_LOKALE_VAR					"__locale__"
+#define TINYJS_ANONYMOUS_VAR				"__anonymous__"
+#define TINYJS_ARGUMENTS_VAR				"arguments"
+#define TINYJS___PROTO___VAR				"__proto__"
+#define TINYJS_PROTOTYPE_CLASS			"prototype"
+#define TINYJS_FUNCTION_CLOSURE_VAR		"__function_closure__"
+#define TINYJS_SCOPE_PARENT_VAR			"__scope_parent__"
+#define TINYJS_SCOPE_WITH_VAR				"__scope_with__"
+#define TINYJS_ACCESSOR_GET_VAR			"__accessor_get__"
+#define TINYJS_ACCESSOR_SET_VAR			"__accessor_set__"
+#define TINYJS_TEMP_NAME			""
+#define TINYJS_BLANK_DATA			""
+
+typedef std::vector<std::string> STRING_VECTOR_t;
+typedef STRING_VECTOR_t::iterator STRING_VECTOR_it;
+
+typedef std::set<std::string> STRING_SET_t;
+typedef STRING_SET_t::iterator STRING_SET_it;
+
+/// convert the given string into a quoted string suitable for javascript
+std::string getJSString(const std::string &str);
+/// convert the given int into a string
+std::string int2string(int32_t intData);
+std::string int2string(uint32_t intData);
+/// convert the given double into a string
+std::string float2string(const double &floatData);
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptException
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptException {
+public:
+	ERROR_TYPES errorType;
+	std::string message;
+	std::string fileName;
+	int lineNumber;
+	int column;
+	CScriptException(const std::string &Message, const std::string &File, int Line=-1, int Column=-1) :
+						errorType(Error), message(Message), fileName(File), lineNumber(Line), column(Column){}
+	CScriptException(ERROR_TYPES ErrorType, const std::string &Message, const std::string &File, int Line=-1, int Column=-1) :
+						errorType(ErrorType), message(Message), fileName(File), lineNumber(Line), column(Column){}
+	CScriptException(const std::string &Message, const char *File="", int Line=-1, int Column=-1) :
+						errorType(Error), message(Message), fileName(File), lineNumber(Line), column(Column){}
+	CScriptException(ERROR_TYPES ErrorType, const std::string &Message, const char *File="", int Line=-1, int Column=-1) :
+						errorType(ErrorType), message(Message), fileName(File), lineNumber(Line), column(Column){}
+	std::string toString();
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptLex
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptLex
+{
+public:
+	CScriptLex(const char *Code, const std::string &File="", int Line=0, int Column=0);
+	struct POS;
+	int tk; ///< The type of the token that we have
+	int last_tk; ///< The type of the last token that we have
+	std::string tkStr; ///< Data contained in the token we have here
+
+	void check(int expected_tk, int alternate_tk=-1); ///< Lexical check wotsit
+	void match(int expected_tk, int alternate_tk=-1); ///< Lexical match wotsit
+	void reset(const POS &toPos); ///< Reset this lex so we can start again
+
+	std::string currentFile;
+	struct POS {
+		const char *tokenStart;
+		int currentLine;
+		const char *currentLineStart;
+	} pos;
+	int currentLine() { return pos.currentLine; }
+	int currentColumn() { return pos.tokenStart-pos.currentLineStart; }
+	bool lineBreakBeforeToken;
+private:
+	const char *data;
+	const char *dataPos;
+	char currCh, nextCh;
+
+	void getNextCh();
+	void getNextToken(); ///< Get the text token from our text string
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptTokenData
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptToken;
+typedef  std::vector<CScriptToken> TOKEN_VECT;
+typedef  std::vector<CScriptToken>::iterator TOKEN_VECT_it;
+typedef  std::vector<CScriptToken>::const_iterator TOKEN_VECT_cit;
+class CScriptTokenData
+{
+protected:
+	CScriptTokenData() : refs(0){}
+	virtual ~CScriptTokenData() {}
+private:
+//	CScriptTokenData(const CScriptTokenData &noCopy);
+//	CScriptTokenData &operator=(const CScriptTokenData &noCopy);
+public:
+	void ref() { refs++; }
+	void unref() { if(--refs == 0) delete this; }
+private:
+	int refs;
+};
+template<typename C>
+class CScriptTokenDataPtr {
+public:
+	CScriptTokenDataPtr() : ptr(0) {}
+	CScriptTokenDataPtr(const CScriptTokenDataPtr &Copy) : ptr(0) { *this=Copy; }
+	CScriptTokenDataPtr &operator=(const CScriptTokenDataPtr &Copy) { 
+		if(ptr != Copy.ptr) {
+			if(ptr) ptr->unref();
+			if((ptr = Copy.ptr)) ptr->ref();
+		}
+		return *this; 
+	}
+	CScriptTokenDataPtr(C &Init) { (ptr=&Init)->ref(); }
+	~CScriptTokenDataPtr() { if(ptr) ptr->unref(); }
+	C *operator->() { return ptr; }
+	C &operator*() { return *ptr; }
+	operator bool() { return ptr!=0; }
+	bool operator==(const CScriptTokenDataPtr& rhs) { return ptr==rhs.ptr; }
+private:
+	C *ptr;
+};
+
+class CScriptTokenDataString : public fixed_size_object<CScriptTokenDataString>, public CScriptTokenData {
+public:
+	CScriptTokenDataString(const std::string &String) : tokenStr(String) {}
+	std::string tokenStr;
+private:
+};
+
+class CScriptTokenDataFnc : public fixed_size_object<CScriptTokenDataFnc>, public CScriptTokenData {
+public:
+	std::string file;
+	int line;
+	std::string name;
+	TOKEN_VECT arguments;
+	TOKEN_VECT body;
+	std::string getArgumentsString();
+};
+
+class CScriptTokenDataForwards : public fixed_size_object<CScriptTokenDataForwards>, public CScriptTokenData {
+public:
+	CScriptTokenDataForwards() {}
+	enum { 
+		LETS = 0,
+		VARS,
+		CONSTS,
+		END
+	};
+	STRING_SET_t varNames[END];
+	STRING_SET_t vars_in_letscope;
+	class compare_fnc_token_by_name {
+	public:
+		bool operator()(const CScriptToken& lhs, const CScriptToken& rhs) const;
+	};
+	typedef std::set<CScriptToken, compare_fnc_token_by_name> FNC_SET_t;
+	typedef FNC_SET_t::iterator FNC_SET_it;
+	FNC_SET_t functions;
+	bool checkRedefinition(const std::string &Str, bool checkVars);
+	void addVars( STRING_VECTOR_t &Vars );
+	void addConsts( STRING_VECTOR_t &Vars );
+	std::string addVarsInLetscope(STRING_VECTOR_t &Vars);
+	std::string addLets(STRING_VECTOR_t &Lets);
+	bool empty() { return varNames[LETS].empty() && varNames[VARS].empty() && varNames[CONSTS].empty() && functions.empty(); }
+private:
+};
+class CScriptTokenDataForwardsPtr {
+public:
+	CScriptTokenDataForwardsPtr() : ptr(0) {}
+	CScriptTokenDataForwardsPtr(const CScriptTokenDataForwardsPtr &Copy) : ptr(0) { *this=Copy; }
+	CScriptTokenDataForwardsPtr &operator=(const CScriptTokenDataForwardsPtr &Copy) { 
+		if(ptr != Copy.ptr) {
+			if(ptr) ptr->unref();
+			if((ptr = Copy.ptr)) ptr->ref();
+		}
+		return *this; 
+	}
+	CScriptTokenDataForwardsPtr(CScriptTokenDataForwards &Init) { (ptr=&Init)->ref(); }
+	~CScriptTokenDataForwardsPtr() { if(ptr) ptr->unref(); }
+	CScriptTokenDataForwards *operator->() { return ptr; }
+	operator bool() { return ptr!=0; }
+	bool operator==(const CScriptTokenDataForwardsPtr& rhs) { return ptr==rhs.ptr; }
+private:
+	CScriptTokenDataForwards *ptr;
+};
+typedef std::vector<CScriptTokenDataForwardsPtr> FORWARDER_VECTOR_t;
+
+class CScriptTokenDataLoop : public fixed_size_object<CScriptTokenDataLoop>, public CScriptTokenData {
+public:
+	CScriptTokenDataLoop() { type=FOR; }
+	enum {FOR_EACH=0, FOR_IN, FOR_OF, FOR, WHILE, DO} type; // do not change the order
+	STRING_VECTOR_t labels;
+	TOKEN_VECT init;
+	TOKEN_VECT condition;
+	TOKEN_VECT iter;
+	TOKEN_VECT body;
+	std::string getParsableString(const std::string &IndentString="", const std::string &Indent="");
+};
+
+typedef std::pair<std::string, std::string> DESTRUCTURING_VAR_t;
+typedef std::vector<DESTRUCTURING_VAR_t> DESTRUCTURING_VARS_t;
+typedef DESTRUCTURING_VARS_t::iterator DESTRUCTURING_VARS_it;
+typedef DESTRUCTURING_VARS_t::const_iterator DESTRUCTURING_VARS_cit;
+class CScriptTokenDataDestructuringVar : public fixed_size_object<CScriptTokenDataDestructuringVar>, public CScriptTokenData {
+public:
+	DESTRUCTURING_VARS_t vars;
+	void getVarNames(STRING_VECTOR_t Name);
+	std::string getParsableString();
+private:
+};
+
+class CScriptTokenDataObjectLiteral : public fixed_size_object<CScriptTokenDataObjectLiteral>, public CScriptTokenData {
+public:
+	enum {ARRAY, OBJECT} type;
+	int flags;
+	struct ELEMENT {
+		std::string id;
+		TOKEN_VECT value;
+	};
+	bool destructuring;
+	bool structuring;
+	std::vector<ELEMENT> elements;
+	void setMode(bool Destructuring);
+	std::string getParsableString();
+private:
+};
+
+class CScriptTokenDataTry : public fixed_size_object<CScriptTokenDataTry>, public CScriptTokenData {
+public:
+	TOKEN_VECT tryBlock;
+	struct CatchBlock {
+		CScriptTokenDataPtr<CScriptTokenDataDestructuringVar> indentifiers;
+		TOKEN_VECT condition;
+		TOKEN_VECT block;
+	};
+	std::vector<CatchBlock> catchBlocks;
+	typedef std::vector<CatchBlock>::iterator CatchBlock_it;
+	TOKEN_VECT finallyBlock;
+	std::string getParsableString(const std::string &IndentString="", const std::string &Indent="");
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptToken
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptTokenizer;
+/*
+	a Token needs 8 Byte
+	2 Bytes for the Row-Position of the Token
+	2 Bytes for the Token self
+	and
+	4 Bytes for special Datas in an union
+			e.g. an int for interger-literals 
+			or pointer for double-literals,
+			for string-literals or for functions
+*/
+class CScriptToken : public fixed_size_object<CScriptToken>
+{
+public:
+	CScriptToken() : line(0), column(0), token(0), intData(0) {}
+	CScriptToken(CScriptLex *l, int Match=-1, int Alternate=-1);
+	CScriptToken(uint16_t Tk, int IntData=0);
+	CScriptToken(uint16_t Tk, const std::string &TkStr);
+	CScriptToken(const  CScriptToken &Copy) : token(0) { *this = Copy; }
+	CScriptToken &operator =(const CScriptToken &Copy);
+	~CScriptToken() { clear(); }
+
+	int &Int() { ASSERT(LEX_TOKEN_DATA_SIMPLE(token)); return intData; }
+	std::string &String() { ASSERT(LEX_TOKEN_DATA_STRING(token)); return dynamic_cast<CScriptTokenDataString*>(tokenData)->tokenStr; }
+	double &Float() { ASSERT(LEX_TOKEN_DATA_FLOAT(token)); return *floatData; }
+	CScriptTokenDataFnc &Fnc() { ASSERT(LEX_TOKEN_DATA_FUNCTION(token)); return *dynamic_cast<CScriptTokenDataFnc*>(tokenData); }
+	const CScriptTokenDataFnc &Fnc() const { ASSERT(LEX_TOKEN_DATA_FUNCTION(token)); return *dynamic_cast<CScriptTokenDataFnc*>(tokenData); }
+	CScriptTokenDataObjectLiteral &Object() { ASSERT(LEX_TOKEN_DATA_OBJECT_LITERAL(token)); return *dynamic_cast<CScriptTokenDataObjectLiteral*>(tokenData); }
+	CScriptTokenDataDestructuringVar &DestructuringVar() { ASSERT(LEX_TOKEN_DATA_DESTRUCTURING_VAR(token)); return *dynamic_cast<CScriptTokenDataDestructuringVar*>(tokenData); }
+	CScriptTokenDataLoop &Loop() { ASSERT(LEX_TOKEN_DATA_LOOP(token)); return *dynamic_cast<CScriptTokenDataLoop*>(tokenData); }
+	CScriptTokenDataTry &Try() { ASSERT(LEX_TOKEN_DATA_TRY(token)); return *dynamic_cast<CScriptTokenDataTry*>(tokenData); }
+	CScriptTokenDataForwards &Forwarder() { ASSERT(LEX_TOKEN_DATA_FORWARDER(token)); return *dynamic_cast<CScriptTokenDataForwards*>(tokenData); }
+#ifdef _DEBUG
+	std::string token_str;
+#endif
+	uint16_t			line;
+	uint16_t			column;
+	uint16_t			token;
+
+	static std::string getParsableString(TOKEN_VECT &Tokens, const std::string &IndentString="", const std::string &Indent="");
+	static std::string getParsableString(TOKEN_VECT_it Begin, TOKEN_VECT_it End, const std::string &IndentString="", const std::string &Indent="");
+	static std::string getTokenStr( int token, bool *need_space=0 );
+	static const char *isReservedWord(int Token);
+	static int isReservedWord(const std::string &Str);
+private:
+
+	void clear();
+	union {
+		int										intData;
+		double									*floatData;
+		CScriptTokenData						*tokenData;
+	};
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptTokenizer - converts the code in a vector with tokens
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptTokenizer
+{
+public:
+	struct ScriptTokenPosition {
+		ScriptTokenPosition(TOKEN_VECT *Tokens) : tokens(Tokens), pos(tokens->begin())/*, currentLine(0)*//*, currentColumn(0)*/ {}
+		bool operator ==(const ScriptTokenPosition &eq) { return pos == eq.pos; }
+		ScriptTokenPosition &operator =(const ScriptTokenPosition &copy) { 
+			tokens=copy.tokens; pos=copy.pos; 
+//			currentLine=copy.currentLine; 
+			return *this;
+		}
+		TOKEN_VECT *tokens;
+		TOKEN_VECT_it pos;
+		int currentLine()		{ return pos->line; }
+		int currentColumn()	{ return pos->column; }
+	};
+	struct ScriptTokenState {
+		TOKEN_VECT Tokens;
+		FORWARDER_VECTOR_t Forwarders;
+		std::vector<int> Marks;
+		STRING_VECTOR_t Labels;
+		STRING_VECTOR_t LoopLabels;
+		bool LeftHand;
+		void pushLeftHandState() { States.push_back(LeftHand); }
+		void popLeftHandeState() { LeftHand = States.back(); States.pop_back(); }
+		std::vector<bool> States;
+	};
+	CScriptTokenizer();
+	CScriptTokenizer(CScriptLex &Lexer);
+	CScriptTokenizer(const char *Code, const std::string &File="", int Line=0, int Column=0);
+	void tokenizeCode(CScriptLex &Lexer);
+
+	CScriptToken &getToken() { return *(tokenScopeStack.back().pos); }
+	void getNextToken();
+	bool check(int ExpectedToken, int AlternateToken=-1);
+	void match(int ExpectedToken, int AlternateToken=-1);
+	void pushTokenScope(TOKEN_VECT &Tokens);
+	ScriptTokenPosition &getPos() { return tokenScopeStack.back(); }
+	void setPos(ScriptTokenPosition &TokenPos);
+	ScriptTokenPosition &getPrevPos() { return prevPos; }
+	void skip(int Tokens);
+	int tk; // current Token
+	std::string currentFile;
+	int currentLine() { return getPos().currentLine();}
+	int currentColumn() { return getPos().currentColumn();}
+	const std::string &tkStr() { static std::string empty; return LEX_TOKEN_DATA_STRING(getToken().token)?getToken().String():empty; }
+private:
+	void tokenizeTry(ScriptTokenState &State, int Flags);
+	void tokenizeSwitch(ScriptTokenState &State, int Flags);
+	void tokenizeWith(ScriptTokenState &State, int Flags);
+	void tokenizeWhileAndDo(ScriptTokenState &State, int Flags);
+	void tokenizeIf(ScriptTokenState &State, int Flags);
+	void tokenizeFor(ScriptTokenState &State, int Flags);
+	CScriptToken tokenizeVarIdentifier(STRING_VECTOR_t *VarNames=0, bool *NeedAssignment=0);
+	void tokenizeFunction(ScriptTokenState &State, int Flags, bool noLetDef=false);
+	void tokenizeLet(ScriptTokenState &State, int Flags, bool noLetDef=false);
+	void tokenizeVarNoConst(ScriptTokenState &State, int Flags);
+	void tokenizeVarAndConst(ScriptTokenState &State, int Flags);
+	void _tokenizeLiteralObject(ScriptTokenState &State, int Flags);
+	void _tokenizeLiteralArray(ScriptTokenState &State, int Flags);
+
+	void tokenizeLiteral(ScriptTokenState &State, int Flags);
+	void tokenizeMember(ScriptTokenState &State, int Flags);
+	void tokenizeFunctionCall(ScriptTokenState &State, int Flags);
+	void tokenizeSubExpression(ScriptTokenState &State, int Flags);
+	void tokenizeLogic(ScriptTokenState &State, int Flags, int op= LEX_OROR, int op_n=LEX_ANDAND); 
+	void tokenizeCondition(ScriptTokenState &State, int Flags);
+	void tokenizeAssignment(ScriptTokenState &State, int Flags);
+	void tokenizeExpression(ScriptTokenState &State, int Flags);
+	void tokenizeBlock(ScriptTokenState &State, int Flags);
+	void tokenizeStatementNoLet(ScriptTokenState &State, int Flags);
+	void tokenizeStatement(ScriptTokenState &State, int Flags);
+
+	int pushToken(TOKEN_VECT &Tokens, int Match=-1, int Alternate=-1);
+	int pushToken(TOKEN_VECT &Tokens, const CScriptToken &Token);
+	void pushForwarder(ScriptTokenState &State, bool noMarks=false);
+	void removeEmptyForwarder(ScriptTokenState &State);
+	void pushForwarder(TOKEN_VECT &Tokens, FORWARDER_VECTOR_t &Forwarders, std::vector<int> &Marks);
+	void removeEmptyForwarder(TOKEN_VECT &Tokens, FORWARDER_VECTOR_t &Forwarders, std::vector<int> &Marks);
+	void throwTokenNotExpected();
+	CScriptLex *l;
+	TOKEN_VECT tokens;
+	ScriptTokenPosition prevPos;
+	std::vector<ScriptTokenPosition> tokenScopeStack;
+};
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// forward-declaration
+//////////////////////////////////////////////////////////////////////////
+
+class CNumber;
+class CScriptVar;
+class CScriptVarPtr;
+template<typename C> class CScriptVarPointer;
+class CScriptVarLink;
+class CScriptVarLinkPtr;
+class CScriptVarLinkWorkPtr;
+
+class CScriptVarPrimitive;
+typedef CScriptVarPointer<CScriptVarPrimitive> CScriptVarPrimitivePtr;
+
+class CScriptVarScopeFnc;
+typedef CScriptVarPointer<CScriptVarScopeFnc> CFunctionsScopePtr;
+typedef void (*JSCallback)(const CFunctionsScopePtr &var, void *userdata);
+
+class CTinyJS;
+class CScriptResult;
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVar
+//////////////////////////////////////////////////////////////////////////
+
+typedef	std::vector<class CScriptVarLinkPtr> SCRIPTVAR_CHILDS_t;
+typedef	SCRIPTVAR_CHILDS_t::iterator SCRIPTVAR_CHILDS_it;
+typedef	SCRIPTVAR_CHILDS_t::const_iterator SCRIPTVAR_CHILDS_cit;
+
+class CScriptVar : public fixed_size_object<CScriptVar> {
+protected:
+	CScriptVar(CTinyJS *Context, const CScriptVarPtr &Prototype); ///< Create
+	CScriptVar(const CScriptVar &Copy); ///< Copy protected -> use clone for public
+private:
+	CScriptVar & operator=(const CScriptVar &Copy) MEMBER_DELETE; ///< private -> no assignment-Copy
+public:
+	virtual ~CScriptVar();
+	virtual CScriptVarPtr clone()=0;
+
+	/// Type
+	virtual bool isObject();	///< is an Object
+	virtual bool isArray();		///< is an Array
+	virtual bool isError();		///< is an ErrorObject
+	virtual bool isRegExp();	///< is a RegExpObject
+	virtual bool isAccessor();	///< is an Accessor
+	virtual bool isNull();		///< is Null
+	virtual bool isUndefined();///< is Undefined
+	virtual bool isNaN();		///< is NaN
+	virtual bool isString();	///< is String
+	virtual bool isInt();		///< is Integer
+	virtual bool isBool();		///< is Bool
+	virtual int isInfinity();	///< is Infinity ///< +1==POSITIVE_INFINITY, -1==NEGATIVE_INFINITY, 0==is not an InfinityVar
+	virtual bool isDouble();	///< is Double
+
+	virtual bool isRealNumber();	///< is isInt | isDouble
+	virtual bool isNumber();	///< is isNaN | isInt | isDouble | isInfinity
+	virtual bool isPrimitive();///< isNull | isUndefined | isNaN | isString | isInt | isDouble | isInfinity
+
+	virtual bool isFunction();	///< is CScriptVarFunction / CScriptVarFunctionNativeCallback / CScriptVarFunctionNativeClass
+	virtual bool isNative();	///< is CScriptVarFunctionNativeCallback / CScriptVarFunctionNativeClass
+	virtual bool isBounded();	///< is CScriptVarFunctionBounded
+
+	virtual bool isIterator();
+
+	bool isBasic() { return Childs.empty(); } ///< Is this *not* an array/object/etc
+
+
+	//////////////////////////////////////////////////////////////////////////
+	/// Value
+	//////////////////////////////////////////////////////////////////////////
+
+	virtual CScriptVarPrimitivePtr getRawPrimitive()=0; ///< is Var==Primitive -> return this isObject return Value
+	CScriptVarPrimitivePtr toPrimitive(); ///< by default call getDefaultValue_hintNumber by a Date-object calls getDefaultValue_hintString
+	virtual CScriptVarPrimitivePtr toPrimitive(CScriptResult &execute); ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+	CScriptVarPrimitivePtr toPrimitive_hintString(int32_t radix=0); ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+	CScriptVarPrimitivePtr toPrimitive_hintString(CScriptResult &execute, int32_t radix=0); ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+	CScriptVarPrimitivePtr toPrimitive_hintNumber(); ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+	CScriptVarPrimitivePtr toPrimitive_hintNumber(CScriptResult &execute); ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+
+	CScriptVarPtr callJS_toString(CScriptResult &execute, int radix=0);
+	virtual CScriptVarPtr toString_CallBack(CScriptResult &execute, int radix=0);
+	CScriptVarPtr callJS_valueOf(CScriptResult &execute);
+	virtual CScriptVarPtr valueOf_CallBack();
+
+	CNumber toNumber();
+	CNumber toNumber(CScriptResult &execute);
+	virtual bool toBoolean();
+	std::string toString(int32_t radix=0); ///< shortcut for this->toPrimitive_hintString()->toCString();
+	std::string toString(CScriptResult &execute, int32_t radix=0); ///< shortcut for this->toPrimitive_hintString(execute)->toCString();
+#define WARN_DEPRECATED
+#ifdef WARN_DEPRECATED
+	int DEPRECATED("getInt() is deprecated use toNumber().toInt32 instead") getInt();
+	bool DEPRECATED("getBool() is deprecated use toBoolean() instead") getBool(); 
+	double DEPRECATED("getDouble() is deprecated use toNumber().toDouble() instead") getDouble();
+	std::string DEPRECATED("getString() is deprecated use toString() instead") getString();
+#else
+	int getInt();
+	bool getBool(); 
+	double getDouble();
+	std::string getString();
+#endif
+	virtual CScriptTokenDataFnc *getFunctionData(); ///< { return 0; }
+	
+	virtual CScriptVarPtr toObject()=0;
+
+	CScriptVarPtr toIterator(int Mode=3);
+	CScriptVarPtr toIterator(CScriptResult &execute, int Mode=3);
+
+
+//	virtual std::string getParsableString(const std::string &indentString, const std::string &indent, bool &hasRecursion); ///< get Data as a parsable javascript string
+#define getParsableStringRecursionsCheck() do{		\
+		if(uniqueID && uniqueID==temporaryID) { hasRecursion=true; return "recursion"; } \
+		temporaryID = uniqueID; \
+	} while(0)
+	virtual std::string getParsableString(const std::string &indentString, const std::string &indent, uint32_t uniqueID, bool &hasRecursion); ///< get Data as a parsable javascript string
+	virtual std::string getVarType()=0;
+
+#ifdef WARN_DEPRECATED
+	CScriptVarPtr DEPRECATED("getNumericVar() is deprecated use toNumber() instead") getNumericVar(); ///< returns an Integer, a Double, an Infinity or a NaN
+#else
+	CScriptVarPtr getNumericVar(); ///< returns an Integer, a Double, an Infinity or a NaN
+#endif
+
+	//////////////////////////////////////////////////////////////////////////
+	/// Childs
+	//////////////////////////////////////////////////////////////////////////
+
+
+	CScriptVarPtr getOwnPropertyDescriptor(const std::string &Name);
+	const char *defineProperty(const std::string &Name, CScriptVarPtr Attributes);
+
+	/// flags
+	void setExtensible(bool On=true)	{ extensible=On; }
+	void preventExtensions()			{ extensible=false; }
+	bool isExtensible() const			{ return extensible; }
+	void seal();
+	bool isSealed() const;
+	void freeze();
+	bool isFrozen() const;
+
+	/// find 
+	CScriptVarLinkPtr findChild(const std::string &childName); ///< Tries to find a child with the given name, may return 0
+	CScriptVarLinkWorkPtr findChildWithStringChars(const std::string &childName);
+	CScriptVarLinkPtr findChildInPrototypeChain(const std::string &childName);
+	CScriptVarLinkWorkPtr findChildWithPrototypeChain(const std::string &childName);
+	CScriptVarLinkPtr findChildByPath(const std::string &path); ///< Tries to find a child with the given path (separated by dots)
+	CScriptVarLinkPtr findChildOrCreate(const std::string &childName/*, int varFlags=SCRIPTVAR_UNDEFINED*/); ///< Tries to find a child with the given name, or will create it with the given flags
+	CScriptVarLinkPtr findChildOrCreateByPath(const std::string &path); ///< Tries to find a child with the given path (separated by dots)
+	void keys(STRING_SET_t &Keys, bool OnlyEnumerable=true, uint32_t ID=0);
+	/// add & remove
+	CScriptVarLinkPtr addChild(const std::string &childName, const CScriptVarPtr &child, int linkFlags = SCRIPTVARLINK_DEFAULT);
+	CScriptVarLinkPtr DEPRECATED("addChildNoDup is deprecated use addChildOrReplace instead!") addChildNoDup(const std::string &childName, const CScriptVarPtr &child, int linkFlags = SCRIPTVARLINK_DEFAULT);
+	CScriptVarLinkPtr addChildOrReplace(const std::string &childName, const CScriptVarPtr &child, int linkFlags = SCRIPTVARLINK_DEFAULT); ///< add a child overwriting any with the same name
+	bool removeLink(CScriptVarLinkPtr &link); ///< Remove a specific link (this is faster than finding via a child)
+	void removeAllChildren();
+
+	/// ARRAY
+	CScriptVarPtr getArrayIndex(uint32_t idx); ///< The the value at an array index
+	void setArrayIndex(uint32_t idx, const CScriptVarPtr &value); ///< Set the value at an array index
+	uint32_t getArrayLength(); ///< If this is an array, return the number of items in it (else 0)
+	
+	//////////////////////////////////////////////////////////////////////////
+	int getChildren() { return Childs.size(); } ///< Get the number of children
+	CTinyJS *getContext() { return context; }
+	CScriptVarPtr mathsOp(const CScriptVarPtr &b, int op); ///< do a maths op with another script variable
+
+	void trace(const std::string &name = ""); ///< Dump out the contents of this using trace
+	void trace(std::string &indentStr, uint32_t uniqueID, const std::string &name = ""); ///< Dump out the contents of this using trace
+	std::string getFlagsAsString(); ///< For debugging - just dump a string version of the flags
+//	void getJSON(std::ostringstream &destination, const std::string linePrefix=""); ///< Write out all the JS code needed to recreate this script variable to the stream (as JSON)
+
+	SCRIPTVAR_CHILDS_t Childs;
+
+	/// For memory management/garbage collection
+private:
+	CScriptVar *ref(); ///< Add reference to this variable
+	void unref(); ///< Remove a reference, and delete this variable if required
+public:
+	int getRefs(); ///< Get the number of references to this script variable
+	template<class T>
+	operator T *(){ T *ret = dynamic_cast<T*>(this); ASSERT(ret!=0); return ret; }
+	template<class T>
+	T *get(){ T *ret = dynamic_cast<T*>(this); ASSERT(ret!=0); return ret; }
+
+	//CScriptVarPtr newScriptVar(const CNumber &t); // { return ::newScriptVar(context, t); }
+	template<typename T>	CScriptVarPtr newScriptVar(T t); // { return ::newScriptVar(context, t); }
+	template<typename T1, typename T2>	CScriptVarPtr newScriptVar(T1 t1, T2 t2); // { return ::newScriptVar(context, t); }
+	template<typename T>	const CScriptVarPtr &constScriptVar(T t); // { return ::newScriptVar(context, t); }
+	void setTemporaryID(uint32_t ID) { temporaryID = ID; }
+	virtual void setTemporaryID_recursive(uint32_t ID);
+	uint32_t getTempraryID() { return temporaryID; }
+protected:
+	bool extensible;
+	CTinyJS *context;
+	int refs; ///< The number of references held to this - used for garbage collection
+	CScriptVar *prev;
+public:
+	CScriptVar *next;
+	uint32_t temporaryID;
+
+	friend class CScriptVarPtr;
+};
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarPtr 
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptVarPtr { 
+public: 
+	// construct
+	CScriptVarPtr() : var(0) {} ///< 0-Pointer 
+	CScriptVarPtr(CScriptVar *Var) : var(Var) { if(var) var->ref(); } // creates a new CScriptVar (from new);
+
+	// copy
+	CScriptVarPtr(const CScriptVarPtr &Copy) : var(Copy.var) { if(var) var->ref(); } 
+	CScriptVarPtr& operator=(const CScriptVarPtr &Copy) { 
+		if(var != Copy.var) { 
+			if(var) var->unref(); 
+			var = Copy.var; if(var) var->ref(); 
+		} 
+		return *this; 
+	}
+	// deconstruct 
+	~CScriptVarPtr() { if(var) var->unref(); } 
+
+	// if
+	operator bool() const { return var!=0; } 
+
+	bool operator ==(const CScriptVarPtr &Other) const { return var == Other.var; } 
+	bool operator !=(const CScriptVarPtr &Other) const { return var != Other.var; } 
+
+	// access
+	CScriptVar * operator ->() const { return var; } 
+	CScriptVar *getVar() const { return var; } 
+
+	void clear() { if(var) var->unref(); var=0; }
+protected: 
+	CScriptVar *var; 
+}; 
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarPointer - template
+//////////////////////////////////////////////////////////////////////////
+
+template<typename C> 
+class CScriptVarPointer : public CScriptVarPtr { 
+public:
+	CScriptVarPointer() {}
+	CScriptVarPointer(CScriptVar *Var) : CScriptVarPtr(dynamic_cast<C*>(Var)) {}
+	CScriptVarPointer(const CScriptVarPtr &Copy) : CScriptVarPtr(dynamic_cast<C*>(Copy.getVar())) {}
+	CScriptVarPointer<C> &operator=(const CScriptVarPtr &Copy) { CScriptVarPtr::operator=(dynamic_cast<C*>(Copy.getVar())); return *this; }
+	C * operator ->() const { C *Var = dynamic_cast<C*>(var); ASSERT(var && Var); return Var; }
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarLink
+//////////////////////////////////////////////////////////////////////////
+class CScriptVarLink : public fixed_size_object<CScriptVarLink>
+{
+private: // prevent gloabal creating
+	CScriptVarLink(const CScriptVarPtr &var, const std::string &name = TINYJS_TEMP_NAME, int flags = SCRIPTVARLINK_DEFAULT);
+private: // prevent Copy
+	CScriptVarLink(const CScriptVarLink &link) MEMBER_DELETE; ///< Copy constructor
+public:
+	~CScriptVarLink();
+
+	const std::string &getName() const { return name; }
+
+	int getFlags() { return flags; }
+	const CScriptVarPtr &getVarPtr() const { return var; }
+	const CScriptVarPtr &setVarPtr(const CScriptVarPtr &Var) { return var = Var; } ///< simple Replace the Variable pointed to
+
+
+	bool isOwned() const { return owner!=0; }
+
+	bool isWritable() const { return (flags & SCRIPTVARLINK_WRITABLE) != 0; }
+	void setWritable(bool On) { On ? (flags |= SCRIPTVARLINK_WRITABLE) : (flags &= ~SCRIPTVARLINK_WRITABLE); }
+	bool isConfigurable() const { return (flags & SCRIPTVARLINK_CONFIGURABLE) != 0; }
+	void setConfigurable(bool On) { On ? (flags |= SCRIPTVARLINK_CONFIGURABLE) : (flags &= ~SCRIPTVARLINK_CONFIGURABLE); }
+	bool isEnumerable() const { return (flags & SCRIPTVARLINK_ENUMERABLE) != 0; }
+	void setEnumerable(bool On) { On ? (flags |= SCRIPTVARLINK_ENUMERABLE) : (flags &= ~SCRIPTVARLINK_ENUMERABLE); }
+
+	CScriptVar *getOwner() { return owner; };
+	void setOwner(CScriptVar *Owner) { owner = Owner; }
+
+	/// forward to ScriptVar
+
+	CScriptVarPrimitivePtr toPrimitive() { ///< by default call getDefaultValue_hintNumber by a Date-object calls getDefaultValue_hintString
+		return var->toPrimitive(); } 	
+	CScriptVarPrimitivePtr toPrimitive(CScriptResult &execute) { ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+		return var->toPrimitive(execute); } 
+	CScriptVarPrimitivePtr toPrimitive_hintString(int32_t radix=0) { ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+		return var->toPrimitive_hintString(radix); } 
+	CScriptVarPrimitivePtr toPrimitive_hintString(CScriptResult &execute, int32_t radix=0) { ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+		return var->toPrimitive_hintString(execute, radix); } 
+	CScriptVarPrimitivePtr toPrimitive_hintNumber() { ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+		return var->toPrimitive_hintNumber(); } 
+	CScriptVarPrimitivePtr toPrimitive_hintNumber(CScriptResult &execute) { ///< if the var an ObjectType gets the valueOf; if valueOf of an ObjectType gets toString / otherwise gets the Var itself 
+		return var->toPrimitive_hintNumber(execute); } 
+
+	CNumber toNumber(); // { return var->toNumber(); }
+	CNumber toNumber(CScriptResult &execute); // { return var->toNumber(execute); }
+	bool toBoolean() { return var->toBoolean(); }
+	std::string toString(int32_t radix=0) { ///< shortcut for this->toPrimitive_hintString()->toCString();
+		return var->toString(radix); }
+	std::string toString(CScriptResult &execute, int32_t radix=0) { ///< shortcut for this->toPrimitive_hintString(execute)->toCString();
+		return var->toString(execute, radix); }
+	CScriptVarPtr toObject() { return var->toObject(); };
+
+private:
+	std::string name;
+	CScriptVar *owner; // pointer to the owner CScriptVar
+	uint32_t flags;
+	CScriptVarPtr var;
+#ifdef _DEBUG
+	char dummy[24];
+#endif
+	CScriptVarLink *ref();
+	void unref();
+private:
+	int refs;
+	friend class CScriptVarLinkPtr;
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarLinkPtr
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptVarLinkPtr { 
+public: 
+	// construct
+	CScriptVarLinkPtr() : link(0) {} ///< 0-Pointer 
+	CScriptVarLinkPtr(const CScriptVarPtr &var, const std::string &name = TINYJS_TEMP_NAME, int flags = SCRIPTVARLINK_DEFAULT) { link=(new CScriptVarLink(var, name, flags))->ref(); }
+	CScriptVarLinkPtr(CScriptVarLink *Link) : link(Link) { if(link) link->ref(); } // creates a new CScriptVarLink (from new);
+
+	// reconstruct
+	CScriptVarLinkPtr &operator()(const CScriptVarPtr &var, const std::string &name = TINYJS_TEMP_NAME, int flags = SCRIPTVARLINK_DEFAULT);
+	CScriptVarLinkPtr &operator=(const CScriptVarPtr &var) { return operator()(var); } 
+	// deconstruct 
+	~CScriptVarLinkPtr() { if(link) link->unref(); } 
+
+	// copy
+	CScriptVarLinkPtr(const CScriptVarLinkPtr &Copy) : link(Copy.link) { if(link) link->ref(); } 
+	CScriptVarLinkPtr &operator=(const CScriptVarLinkPtr &Copy) { 
+		if(link != Copy.link) { 
+			if(link) link->unref(); 
+			link = Copy.link; if(link) link->ref(); 
+		} 
+		return *this; 
+	}
+
+	// getter & setter
+	CScriptVarLinkWorkPtr getter();
+	CScriptVarLinkWorkPtr getter(CScriptResult &execute);
+	CScriptVarLinkWorkPtr setter(const CScriptVarPtr &Var);
+	CScriptVarLinkWorkPtr setter(CScriptResult &execute, const CScriptVarPtr &Var);
+
+	// if
+	operator bool() const { return link!=0; } 
+
+	// for sorting in child-list
+	bool operator <(const std::string &rhs) const;
+	bool operator ==(const CScriptVarLinkPtr &rhs) const { return link==rhs.link; }
+	// access to CScriptVarLink
+	CScriptVarLink *operator ->() const { return link; } 
+
+	operator const CScriptVarPtr &() const { static CScriptVarPtr NullPtr; return link?link->getVarPtr():NullPtr; }
+
+	void clear() { if(link) link->unref(); link=0; }
+protected: 
+	CScriptVarLink *link; 
+}; 
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarLinkWorkPtr
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptVarLinkWorkPtr : public CScriptVarLinkPtr {
+public:
+	// construct
+	CScriptVarLinkWorkPtr() {}
+	CScriptVarLinkWorkPtr(const CScriptVarPtr &var, const std::string &name = TINYJS_TEMP_NAME, int flags = SCRIPTVARLINK_DEFAULT) : CScriptVarLinkPtr(var, name, flags) {}
+	CScriptVarLinkWorkPtr(CScriptVarLink *Link) : CScriptVarLinkPtr(Link) { if(link) referencedOwner = link->getOwner(); } // creates a new CScriptVarLink (from new);
+	CScriptVarLinkWorkPtr(const CScriptVarLinkPtr &Copy) : CScriptVarLinkPtr(Copy) { if(link) referencedOwner = link->getOwner(); } 
+
+	// reconstruct
+	CScriptVarLinkWorkPtr &operator()(const CScriptVarPtr &var, const std::string &name = TINYJS_TEMP_NAME, int flags = SCRIPTVARLINK_DEFAULT) {CScriptVarLinkPtr::operator()(var, name, flags); referencedOwner.clear(); return *this; }
+
+	// copy
+	CScriptVarLinkWorkPtr(const CScriptVarLinkWorkPtr &Copy) : CScriptVarLinkPtr(Copy), referencedOwner(Copy.referencedOwner) {} 
+	CScriptVarLinkWorkPtr &operator=(const CScriptVarLinkWorkPtr &Copy) { CScriptVarLinkPtr::operator=(Copy); referencedOwner = Copy.referencedOwner; return *this; } 
+
+	// getter & setter
+	CScriptVarLinkWorkPtr getter();
+	CScriptVarLinkWorkPtr getter(CScriptResult &execute);
+	CScriptVarLinkWorkPtr setter(const CScriptVarPtr &Var);
+	CScriptVarLinkWorkPtr setter(CScriptResult &execute, const CScriptVarPtr &Var);
+
+
+	void swap(CScriptVarLinkWorkPtr &Link) { 
+		CScriptVarPtr _referencedOwner = referencedOwner; referencedOwner = Link.referencedOwner; Link.referencedOwner = _referencedOwner;
+		CScriptVarLink *_link=link; link=Link.link; Link.link=_link; 
+	}
+
+	void clear() { CScriptVarLinkPtr::clear(); referencedOwner.clear(); }
+	void setReferencedOwner(const CScriptVarPtr &Owner) { referencedOwner = Owner; }
+	const CScriptVarPtr &getReferencedOwner() const { return referencedOwner; }
+	bool hasReferencedOwner() const { return referencedOwner; }
+private:
+	CScriptVarPtr referencedOwner;
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+#define define_dummy_t(t1) struct t1##_t{}; extern t1##_t t1
+#define declare_dummy_t(t1) t1##_t t1
+#define define_newScriptVar_Fnc(t1, ...) CScriptVarPtr newScriptVar(__VA_ARGS__)
+#define define_newScriptVar_NamedFnc(t1, ...) CScriptVarPtr newScriptVar##t1(__VA_ARGS__)
+#define define_ScriptVarPtr_Type(t1) class CScriptVar##t1; typedef CScriptVarPointer<CScriptVar##t1> CScriptVar##t1##Ptr
+
+#define define_DEPRECATED_newScriptVar_Fnc(t1, ...) CScriptVarPtr DEPRECATED("newScriptVar("#__VA_ARGS__") is deprecated use constScriptVar("#__VA_ARGS__") instead") newScriptVar(__VA_ARGS__)
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CScriptVarPrimitive
+//////////////////////////////////////////////////////////////////////////
+
+define_ScriptVarPtr_Type(Primitive);
+class CScriptVarPrimitive : public CScriptVar {
+protected:
+	CScriptVarPrimitive(CTinyJS *Context, const CScriptVarPtr &Prototype) : CScriptVar(Context, Prototype) { setExtensible(false); }
+	CScriptVarPrimitive(const CScriptVarPrimitive &Copy) : CScriptVar(Copy) { } ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarPrimitive();
+
+	virtual bool isPrimitive();	///< return true; 
+
+	virtual CScriptVarPrimitivePtr getRawPrimitive();
+	virtual bool toBoolean();							/// false by default
+	virtual CNumber toNumber_Callback()=0;
+	virtual std::string toCString(int radix=0)=0;
+
+	virtual CScriptVarPtr toObject();
+	virtual CScriptVarPtr toString_CallBack(CScriptResult &execute, int radix=0);
+protected:
+};
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarUndefined
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(Undefined);
+define_ScriptVarPtr_Type(Undefined);
+class CScriptVarUndefined : public CScriptVarPrimitive {
+protected:
+	CScriptVarUndefined(CTinyJS *Context);
+	CScriptVarUndefined(const CScriptVarUndefined &Copy) : CScriptVarPrimitive(Copy) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarUndefined();
+	virtual CScriptVarPtr clone();
+
+	virtual bool isUndefined(); // { return true; }
+	
+	virtual CNumber toNumber_Callback(); // { return NaN; }
+	virtual std::string toCString(int radix=0);// { return "undefined"; }
+
+	virtual std::string getVarType(); // { return "undefined"; }
+	friend define_DEPRECATED_newScriptVar_Fnc(Undefined, CTinyJS *, Undefined_t);
+	friend define_newScriptVar_NamedFnc(Undefined, CTinyJS *Context);
+};
+inline define_DEPRECATED_newScriptVar_Fnc(Undefined, CTinyJS *Context, Undefined_t) { return new CScriptVarUndefined(Context); }
+inline define_newScriptVar_NamedFnc(Undefined, CTinyJS *Context) { return new CScriptVarUndefined(Context); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarNull
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(Null);
+define_ScriptVarPtr_Type(Null);
+class CScriptVarNull : public CScriptVarPrimitive {
+protected:
+	CScriptVarNull(CTinyJS *Context);
+	CScriptVarNull(const CScriptVarNull &Copy) : CScriptVarPrimitive(Copy) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarNull();
+	virtual CScriptVarPtr clone();
+
+	virtual bool isNull(); // { return true; }
+
+	virtual CNumber toNumber_Callback(); // { return 0; }
+	virtual std::string toCString(int radix=0);// { return "null"; }
+
+	virtual std::string getVarType(); // { return "null"; }
+
+	friend define_DEPRECATED_newScriptVar_Fnc(Null, CTinyJS *Context, Null_t);
+	friend define_newScriptVar_NamedFnc(Null, CTinyJS *Context);
+};
+inline define_DEPRECATED_newScriptVar_Fnc(Null, CTinyJS *Context, Null_t) { return new CScriptVarNull(Context); }
+inline define_newScriptVar_NamedFnc(Null, CTinyJS *Context) { return new CScriptVarNull(Context); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarString
+//////////////////////////////////////////////////////////////////////////
+
+define_ScriptVarPtr_Type(String);
+class CScriptVarString : public CScriptVarPrimitive {
+protected:
+	CScriptVarString(CTinyJS *Context, const std::string &Data);
+	CScriptVarString(const CScriptVarString &Copy) : CScriptVarPrimitive(Copy), data(Copy.data) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarString();
+	virtual CScriptVarPtr clone();
+	virtual bool isString(); // { return true; }
+
+	virtual bool toBoolean();
+	virtual CNumber toNumber_Callback();
+	virtual std::string toCString(int radix=0);
+
+	virtual std::string getParsableString(const std::string &indentString, const std::string &indent, uint32_t uniqueID, bool &hasRecursion); // { return getJSString(data); }
+	virtual std::string getVarType(); // { return "string"; }
+
+	virtual CScriptVarPtr toObject();
+	virtual CScriptVarPtr toString_CallBack(CScriptResult &execute, int radix=0);
+
+	uint32_t stringLength() { return data.size(); }
+	int getChar(uint32_t Idx);
+protected:
+	std::string data;
+private:
+	friend define_newScriptVar_Fnc(String, CTinyJS *Context, const std::string &);
+	friend define_newScriptVar_Fnc(String, CTinyJS *Context, const char *);
+	friend define_newScriptVar_Fnc(String, CTinyJS *Context, char *);
+};
+inline define_newScriptVar_Fnc(String, CTinyJS *Context, const std::string &Obj) { return new CScriptVarString(Context, Obj); }
+inline define_newScriptVar_Fnc(String, CTinyJS *Context, const char *Obj) { return new CScriptVarString(Context, Obj); }
+inline define_newScriptVar_Fnc(String, CTinyJS *Context, char *Obj) { return new CScriptVarString(Context, Obj); }
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CNumber
+//////////////////////////////////////////////////////////////////////////
+define_dummy_t(NegativeZero);
+define_dummy_t(NaN);
+class Infinity{public:Infinity(int Sig=1):sig(Sig){} int Sig(){return sig;} private:int sig; } ;
+extern Infinity InfinityPositive;
+extern Infinity InfinityNegative;
+
+class CNumber {
+private:
+	enum NType {
+		tnNULL, tInt32, tDouble, tNaN, tInfinity
+	};
+	CNumber(NType Type, int32_t InfinitySign=0) : type(Type) { Int32 = InfinitySign; }
+public:
+
+	CNumber(const CNumber &Copy) { *this=Copy; }
+
+	CNumber(int32_t Value=0) : type(tInt32) { Int32=Value; }
+#if 1
+	template<typename T>CNumber(T Value) { *this = Value; }
+#else
+	CNumber(negativeZero_t Value) { *this = Value; }  
+	CNumber(NaN_t Value)  { *this = Value; }  
+	CNumber(Infinity Value) { *this = Value; }  
+	CNumber(uint32_t Value) { *this = Value; }
+	CNumber(double Value) { *this = Value; }
+	CNumber(unsigned char Value) { *this = Value; }
+	CNumber(const char *Value) { *this = Value; }
+	CNumber(const std::string &Value) { *this = Value; }
+#endif
+	CNumber &operator=(NegativeZero_t) { type=tnNULL; Int32=0; return *this; }
+	CNumber &operator=(NaN_t) { type=tNaN; Int32=0; return *this; }
+	CNumber &operator=(Infinity v) { type=tInfinity; Int32=v.Sig(); return *this; }
+	CNumber &operator=(int32_t Value) { type=tInt32; Int32=Value; return *this; }
+	CNumber &operator=(uint32_t Value) { 
+		if(Value<=(uint32_t)std::numeric_limits<int32_t>::max()) 
+			type=tInt32, Int32=int32_t(Value);
+		else
+			type=tDouble, Double=Value; 
+		return *this; 
+	}
+	CNumber &operator=(double Value);
+	CNumber &operator=(unsigned char Value) { type=tInt32; Int32=Value; return *this; }
+	CNumber &operator=(const char *Value);
+	CNumber &operator=(const std::string &Value) { return operator=(Value.c_str());}
+
+	int32_t parseInt(const char *str, int32_t radix=0, const char **endptr=0);
+	void parseInt(const std::string &str, int32_t radix=0) { parseInt(str.c_str(), radix); }
+	void parseFloat(const char *str, const char **endptr=0);
+	void parseFloat(const std::string &str) { parseFloat(str.c_str()); }
+
+	CNumber add(const CNumber &Value) const;
+	CNumber operator-() const;
+	CNumber operator~() const { if(type==tNaN) return *this; else return ~toInt32(); }
+	bool operator!() const { return isZero(); }
+	CNumber multi(const CNumber &Value) const;
+	CNumber div(const CNumber &Value) const;
+	CNumber modulo(const CNumber &Value) const;
+
+	CNumber round() const;
+	CNumber floor() const;
+	CNumber ceil() const;
+	CNumber abs() const;
+
+	CNumber shift(const CNumber &Value, bool right) const;
+	CNumber ushift(const CNumber &Value, bool right=true) const;
+
+	CNumber binary(const CNumber &Value, char Mode) const;
+
+
+	int less(const CNumber &Value) const;
+	bool equal(const CNumber &Value) const;
+
+
+	bool isInt32() const { return type == tInt32; }
+	bool isDouble() const { return type == tDouble; }
+
+	bool isNaN() const { return type == tNaN; }
+	int isInfinity() const { return type == tInfinity ? Int32 : 0; }
+	bool isFinite() const { return type == tInt32 || type == tDouble || type == tnNULL; }
+	bool isNegativeZero() const { return type==tnNULL; }
+	bool isZero() const; ///< is 0, -0
+	bool isInteger() const;
+	int sign() const;
+
+	int32_t		toInt32() const { return cast<int32_t>(); }
+	uint32_t		toUInt32() const { return cast<uint32_t>(); }
+	double		toDouble() const;
+	bool			toBoolean() const { return !isZero() && type!=tNaN; }
+	std::string	toString(uint32_t Radix=10) const;
+private:
+	template<typename T> T cast() const { 
+		switch(type) {
+		case tInt32:
+			return T(Int32);
+		case tDouble:
+			return T(Double);
+		default:
+			return T(0);
+		}
+	}
+	NType type;
+	union {
+		int32_t	Int32;
+		double	Double;
+	};
+};
+inline CNumber operator+(const CNumber &lhs, const CNumber &rhs) { return lhs.add(rhs); }
+inline CNumber &operator+=(CNumber &lhs, const CNumber &rhs) { return lhs=lhs.add(rhs); }
+inline CNumber operator-(const CNumber &lhs, const CNumber &rhs) { return lhs.add(-rhs); }
+inline CNumber &operator-=(CNumber &lhs, const CNumber &rhs) { return lhs=lhs.add(-rhs); }
+inline CNumber operator*(const CNumber &lhs, const CNumber &rhs) { return lhs.multi(rhs); }
+inline CNumber &operator*=(CNumber &lhs, const CNumber &rhs) { return lhs=lhs.multi(rhs); }
+inline CNumber operator/(const CNumber &lhs, const CNumber &rhs) { return lhs.div(rhs); }
+inline CNumber &operator/=(CNumber &lhs, const CNumber &rhs) { return lhs=lhs.div(rhs); }
+inline CNumber operator%(const CNumber &lhs, const CNumber &rhs) { return lhs.modulo(rhs); }
+inline CNumber &operator%=(CNumber &lhs, const CNumber &rhs) { return lhs=lhs.modulo(rhs); }
+inline CNumber operator>>(const CNumber &lhs, const CNumber &rhs) { return lhs.shift(rhs, true); }
+inline CNumber &operator>>=(CNumber &lhs, const CNumber &rhs) { return lhs=lhs.shift(rhs, true); }
+inline CNumber operator<<(const CNumber &lhs, const CNumber &rhs) { return lhs.shift(rhs, false); }
+inline CNumber &operator<<=(CNumber &lhs, const CNumber &rhs) { return lhs=lhs.shift(rhs, false); }
+
+inline bool operator==(const CNumber &lhs, const CNumber &rhs) { return lhs.equal(rhs); }
+inline bool operator!=(const CNumber &lhs, const CNumber &rhs) { return !lhs.equal(rhs); }
+inline bool operator<(const CNumber &lhs, const CNumber &rhs) { return lhs.less(rhs)>0; }
+inline bool operator<=(const CNumber &lhs, const CNumber &rhs) { return rhs.less(lhs)<0; }
+inline bool operator>(const CNumber &lhs, const CNumber &rhs) { return rhs.less(lhs)>0; }
+inline bool operator>=(const CNumber &lhs, const CNumber &rhs) { return lhs.less(rhs)<0; }
+
+inline CNumber round(const CNumber &lhs) { return lhs.round(); }
+inline CNumber floor(const CNumber &lhs) { return lhs.floor(); }
+inline CNumber ceil(const CNumber &lhs) { return lhs.ceil(); }
+inline CNumber abs(const CNumber &lhs) { return lhs.abs(); }
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarNumber
+//////////////////////////////////////////////////////////////////////////
+
+define_ScriptVarPtr_Type(Number);
+class CScriptVarNumber : public CScriptVarPrimitive {
+protected:
+	CScriptVarNumber(CTinyJS *Context, const CNumber &Data);
+	CScriptVarNumber(const CScriptVarNumber &Copy) : CScriptVarPrimitive(Copy), data(Copy.data) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarNumber();
+	virtual CScriptVarPtr clone();
+	virtual bool isNumber(); // { return true; }
+	virtual bool isInt(); // { return true; }
+	virtual bool isDouble(); // { return true; }
+	virtual bool isRealNumber(); // { return true; }
+	virtual int isInfinity(); // { return data; }
+	virtual bool isNaN();// { return true; }
+
+	virtual bool toBoolean();
+	virtual CNumber toNumber_Callback();
+	virtual std::string toCString(int radix=0);
+
+	virtual std::string getVarType(); // { return "number"; }
+
+	virtual CScriptVarPtr toObject();
+private:
+	CNumber data;
+	friend define_newScriptVar_Fnc(Number, CTinyJS *Context, const CNumber &);
+	friend define_newScriptVar_NamedFnc(Number, CTinyJS *Context, const CNumber &);
+};
+define_newScriptVar_Fnc(Number, CTinyJS *Context, const CNumber &Obj);
+inline define_newScriptVar_NamedFnc(Number, CTinyJS *Context, const CNumber &Obj) { return new CScriptVarNumber(Context, Obj); }
+inline define_newScriptVar_Fnc(Number, CTinyJS *Context, unsigned int Obj) { return newScriptVarNumber(Context, CNumber(Obj)); }
+inline define_newScriptVar_Fnc(Number, CTinyJS *Context, int Obj) { return newScriptVarNumber(Context, CNumber(Obj)); }
+inline define_newScriptVar_Fnc(Number, CTinyJS *Context, double Obj) { return newScriptVarNumber(Context, CNumber(Obj)); }
+inline define_DEPRECATED_newScriptVar_Fnc(NaN, CTinyJS *Context, NaN_t) { return newScriptVarNumber(Context, CNumber(NaN)); }
+inline define_DEPRECATED_newScriptVar_Fnc(Infinity, CTinyJS *Context, Infinity Obj) { return newScriptVarNumber(Context, CNumber(Obj)); } 
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarBool
+//////////////////////////////////////////////////////////////////////////
+
+define_ScriptVarPtr_Type(Bool);
+class CScriptVarBool : public CScriptVarPrimitive {
+protected:
+	CScriptVarBool(CTinyJS *Context, bool Data);
+	CScriptVarBool(const CScriptVarBool &Copy) : CScriptVarPrimitive(Copy), data(Copy.data) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarBool();
+	virtual CScriptVarPtr clone();
+	virtual bool isBool(); // { return true; }
+
+	virtual bool toBoolean();
+	virtual CNumber toNumber_Callback();
+	virtual std::string toCString(int radix=0);
+
+	virtual std::string getVarType(); // { return "boolean"; }
+
+	virtual CScriptVarPtr toObject();
+protected:
+	bool data;
+
+	friend define_DEPRECATED_newScriptVar_Fnc(Bool, CTinyJS *, bool);
+	friend define_newScriptVar_NamedFnc(Bool, CTinyJS *Context, bool);
+};
+inline define_DEPRECATED_newScriptVar_Fnc(Bool, CTinyJS *Context, bool Obj) { return new CScriptVarBool(Context, Obj); }
+inline define_newScriptVar_NamedFnc(Bool, CTinyJS *Context, bool Obj) { return new CScriptVarBool(Context, Obj); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarObject
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(StopIteration);
+define_dummy_t(Object);
+define_ScriptVarPtr_Type(Object);
+
+class CScriptVarObject : public CScriptVar {
+protected:
+	CScriptVarObject(CTinyJS *Context);
+	CScriptVarObject(CTinyJS *Context, const CScriptVarPtr &Prototype) : CScriptVar(Context, Prototype) {}
+	CScriptVarObject(CTinyJS *Context, const CScriptVarPrimitivePtr &Value, const CScriptVarPtr &Prototype) : CScriptVar(Context, Prototype), value(Value) {}
+	CScriptVarObject(const CScriptVarObject &Copy) : CScriptVar(Copy) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarObject();
+	virtual CScriptVarPtr clone();
+
+	virtual CScriptVarPrimitivePtr getRawPrimitive();
+	virtual bool isObject(); // { return true; }
+
+	virtual std::string getParsableString(const std::string &indentString, const std::string &indent, uint32_t uniqueID, bool &hasRecursion);
+	virtual std::string getVarType(); ///< always "object"
+	virtual CScriptVarPtr toObject();
+
+	virtual CScriptVarPtr valueOf_CallBack();
+	virtual CScriptVarPtr toString_CallBack(CScriptResult &execute, int radix=0);
+	virtual void setTemporaryID_recursive(uint32_t ID);
+protected:
+private:
+	CScriptVarPrimitivePtr value;
+	friend define_newScriptVar_Fnc(Object, CTinyJS *Context, Object_t);
+	friend define_newScriptVar_Fnc(Object, CTinyJS *Context, Object_t, const CScriptVarPtr &);
+	friend define_newScriptVar_Fnc(Object, CTinyJS *Context, const CScriptVarPtr &);
+	friend define_newScriptVar_Fnc(Object, CTinyJS *Context, const CScriptVarPrimitivePtr &, const CScriptVarPtr &);
+};
+inline define_newScriptVar_Fnc(Object, CTinyJS *Context, Object_t) { return new CScriptVarObject(Context); }
+inline define_newScriptVar_Fnc(Object, CTinyJS *Context, Object_t, const CScriptVarPtr &Prototype) { return new CScriptVarObject(Context, Prototype); }
+inline define_newScriptVar_Fnc(Object, CTinyJS *Context, const CScriptVarPtr &Prototype) { return new CScriptVarObject(Context, Prototype); }
+inline define_newScriptVar_Fnc(Object, CTinyJS *Context, const CScriptVarPrimitivePtr &Value, const CScriptVarPtr &Prototype) { return new CScriptVarObject(Context, Value, Prototype); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarError
+////////////////////////////////////////////////////////////////////////// 
+
+define_ScriptVarPtr_Type(Error);
+
+class CScriptVarError : public CScriptVarObject {
+protected:
+	CScriptVarError(CTinyJS *Context, ERROR_TYPES type, const char *message, const char *file, int line, int column);// : CScriptVarObject(Context), value(Value) {}
+	CScriptVarError(const CScriptVarError &Copy) : CScriptVarObject(Copy) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarError();
+	virtual CScriptVarPtr clone();
+	virtual bool isError(); // { return true; }
+
+//	virtual std::string getParsableString(const std::string &indentString, const std::string &indent); ///< get Data as a parsable javascript string
+
+	virtual CScriptVarPtr toString_CallBack(CScriptResult &execute, int radix=0);
+	CScriptException *toCScriptException();
+private:
+	friend define_newScriptVar_NamedFnc(Error, CTinyJS *Context, ERROR_TYPES type, const char *message, const char *file, int line, int column);
+	friend define_newScriptVar_NamedFnc(Error, CTinyJS *Context, const CScriptException &Exception);
+};
+inline define_newScriptVar_NamedFnc(Error, CTinyJS *Context, ERROR_TYPES type, const char *message=0, const char *file=0, int line=-1, int column=-1) { return new CScriptVarError(Context, type, message, file, line, column); }
+inline define_newScriptVar_NamedFnc(Error, CTinyJS *Context, const CScriptException &Exception) { return new CScriptVarError(Context, Exception.errorType, Exception.message.c_str(), Exception.fileName.c_str(), Exception.lineNumber, Exception.column); }
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarArray
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(Array);
+define_ScriptVarPtr_Type(Array);
+class CScriptVarArray : public CScriptVarObject {
+protected:
+	CScriptVarArray(CTinyJS *Context);
+	CScriptVarArray(const CScriptVarArray &Copy) : CScriptVarObject(Copy) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarArray();
+	virtual CScriptVarPtr clone();
+	virtual bool isArray(); // { return true; }
+
+	virtual std::string getParsableString(const std::string &indentString, const std::string &indent, uint32_t uniqueID, bool &hasRecursion);
+
+	virtual CScriptVarPtr toString_CallBack(CScriptResult &execute, int radix=0);
+
+	friend define_newScriptVar_Fnc(Array, CTinyJS *Context, Array_t);
+private:
+	void native_Length(const CFunctionsScopePtr &c, void *data);
+};
+inline define_newScriptVar_Fnc(Array, CTinyJS *Context, Array_t) { return new CScriptVarArray(Context); } 
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarRegExp
+//////////////////////////////////////////////////////////////////////////
+#ifndef NO_REGEXP
+
+define_ScriptVarPtr_Type(RegExp);
+class CScriptVarRegExp : public CScriptVarObject {
+protected:
+	CScriptVarRegExp(CTinyJS *Context, const std::string &Source, const std::string &Flags);
+	CScriptVarRegExp(const CScriptVarRegExp &Copy) : CScriptVarObject(Copy), regexp(Copy.regexp), flags(Copy.flags) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarRegExp();
+	virtual CScriptVarPtr clone();
+	virtual bool isRegExp(); // { return true; }
+	virtual CScriptVarPtr toString_CallBack(CScriptResult &execute, int radix=0);
+
+	CScriptVarPtr exec(const std::string &Input, bool Test=false);
+
+	bool Global() { return flags.find('g')!=std::string::npos; }
+	bool IgnoreCase() { return flags.find('i')!=std::string::npos; }
+	bool Multiline() { return true; /* currently always true -- flags.find('m')!=std::string::npos;*/ }
+	bool Sticky() { return flags.find('y')!=std::string::npos; }
+	const std::string &Regexp() { return regexp; }
+	unsigned int LastIndex();
+	void LastIndex(unsigned int Idx);
+
+	static const char *ErrorStr(int Error);
+protected:
+	std::string regexp;
+	std::string flags;
+private:
+	void native_Global(const CFunctionsScopePtr &c, void *data);
+	void native_IgnoreCase(const CFunctionsScopePtr &c, void *data);
+	void native_Multiline(const CFunctionsScopePtr &c, void *data);
+	void native_Sticky(const CFunctionsScopePtr &c, void *data);
+	void native_Source(const CFunctionsScopePtr &c, void *data);
+
+	friend define_newScriptVar_Fnc(RegExp, CTinyJS *Context, const std::string &, const std::string &);
+
+};
+inline define_newScriptVar_Fnc(RegExp, CTinyJS *Context, const std::string &Obj, const std::string &Flags) { return new CScriptVarRegExp(Context, Obj, Flags); }
+
+#endif /* NO_REGEXP */
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarDefaultIterator
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(DefaultIterator);
+define_ScriptVarPtr_Type(DefaultIterator);
+
+class CScriptVarDefaultIterator : public CScriptVarObject {
+protected:
+	CScriptVarDefaultIterator(CTinyJS *Context, const CScriptVarPtr &Object, int Mode);
+	CScriptVarDefaultIterator(const CScriptVarDefaultIterator &Copy) 
+	: 
+	CScriptVarObject(Copy), mode(Copy.mode), object(Copy.object),
+	keys(Copy.keys), pos(keys.begin()){} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarDefaultIterator();
+	virtual CScriptVarPtr clone();
+	virtual bool isIterator();
+
+	void native_next(const CFunctionsScopePtr &c, void *data);
+private:
+	int mode;
+	CScriptVarPtr object;
+	STRING_SET_t keys;
+	STRING_SET_it pos;
+	friend define_newScriptVar_NamedFnc(DefaultIterator, CTinyJS *, const CScriptVarPtr &, int);
+
+};
+inline define_newScriptVar_NamedFnc(DefaultIterator, CTinyJS *Context, const CScriptVarPtr &Object, int Mode) { return new CScriptVarDefaultIterator(Context, Object, Mode); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarFunction
+//////////////////////////////////////////////////////////////////////////
+
+define_ScriptVarPtr_Type(Function);
+class CScriptVarFunction : public CScriptVarObject {
+protected:
+	CScriptVarFunction(CTinyJS *Context, CScriptTokenDataFnc *Data);
+	CScriptVarFunction(const CScriptVarFunction &Copy) : CScriptVarObject(Copy), data(Copy.data) { data->ref(); } ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarFunction();
+	virtual CScriptVarPtr clone();
+	virtual bool isObject(); // { return true; }
+	virtual bool isFunction(); // { return true; }
+	virtual bool isPrimitive(); // { return false; } 
+
+	virtual std::string getVarType(); // { return "function"; }
+	virtual std::string getParsableString(const std::string &indentString, const std::string &indent, uint32_t uniqueID, bool &hasRecursion);
+	virtual CScriptVarPtr toString_CallBack(CScriptResult &execute, int radix=0);
+	virtual CScriptTokenDataFnc *getFunctionData();
+	void setFunctionData(CScriptTokenDataFnc *Data);
+private:
+	CScriptTokenDataFnc *data;
+
+	friend define_newScriptVar_Fnc(Function, CTinyJS *Context, CScriptTokenDataFnc *);
+};
+inline define_newScriptVar_Fnc(Function, CTinyJS *Context, CScriptTokenDataFnc *Obj) { return new CScriptVarFunction(Context, Obj); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarFunctionBounded
+//////////////////////////////////////////////////////////////////////////
+
+define_ScriptVarPtr_Type(FunctionBounded);
+class CScriptVarFunctionBounded : public CScriptVarFunction {
+protected:
+	CScriptVarFunctionBounded(CScriptVarFunctionPtr BoundedFunction, CScriptVarPtr BoundedThis, const std::vector<CScriptVarPtr> &BoundedArguments);
+	CScriptVarFunctionBounded(const CScriptVarFunctionBounded &Copy) : CScriptVarFunction(Copy), boundedThis(Copy.boundedThis), boundedArguments(Copy.boundedArguments)  { } ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarFunctionBounded();
+	virtual CScriptVarPtr clone();
+	virtual bool isBounded();	///< is CScriptVarFunctionBounded
+	virtual void setTemporaryID_recursive(uint32_t ID);
+	CScriptVarPtr callFunction(CScriptResult &execute, std::vector<CScriptVarPtr> &Arguments, const CScriptVarPtr &This, CScriptVarPtr *newThis=0);
+protected:
+private:
+	CScriptVarFunctionPtr boundedFunction;
+	CScriptVarPtr boundedThis;
+	std::vector<CScriptVarPtr> boundedArguments;
+
+	friend define_newScriptVar_NamedFnc(FunctionBounded, CScriptVarFunctionPtr BoundedFunction, CScriptVarPtr BoundedThis, const std::vector<CScriptVarPtr> &BoundedArguments);
+};
+inline define_newScriptVar_NamedFnc(FunctionBounded, CScriptVarFunctionPtr BoundedFunction, CScriptVarPtr BoundedThis, const std::vector<CScriptVarPtr> &BoundedArguments) { return new CScriptVarFunctionBounded(BoundedFunction, BoundedThis, BoundedArguments); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarFunctionNative
+//////////////////////////////////////////////////////////////////////////
+
+define_ScriptVarPtr_Type(FunctionNative);
+class CScriptVarFunctionNative : public CScriptVarFunction {
+protected:
+	CScriptVarFunctionNative(CTinyJS *Context, void *Userdata) : CScriptVarFunction(Context, new CScriptTokenDataFnc), jsUserData(Userdata) { }
+	CScriptVarFunctionNative(const CScriptVarFunctionNative &Copy) : CScriptVarFunction(Copy), jsUserData(Copy.jsUserData) { } ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarFunctionNative();
+	virtual CScriptVarPtr clone()=0;
+	virtual bool isNative(); // { return true; }
+
+	virtual void callFunction(const CFunctionsScopePtr &c)=0;// { jsCallback(c, jsCallbackUserData); }
+protected:
+	void *jsUserData; ///< user data passed as second argument to native functions
+};
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarFunctionNativeCallback
+//////////////////////////////////////////////////////////////////////////
+
+define_ScriptVarPtr_Type(FunctionNativeCallback);
+class CScriptVarFunctionNativeCallback : public CScriptVarFunctionNative {
+protected:
+	CScriptVarFunctionNativeCallback(CTinyJS *Context, JSCallback Callback, void *Userdata) : CScriptVarFunctionNative(Context, Userdata), jsCallback(Callback) { }
+	CScriptVarFunctionNativeCallback(const CScriptVarFunctionNativeCallback &Copy) : CScriptVarFunctionNative(Copy), jsCallback(Copy.jsCallback) { } ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarFunctionNativeCallback();
+	virtual CScriptVarPtr clone();
+	virtual void callFunction(const CFunctionsScopePtr &c);
+private:
+	JSCallback jsCallback; ///< Callback for native functions
+	friend define_newScriptVar_Fnc(FunctionNativeCallback, CTinyJS *Context, JSCallback Callback, void*);
+};
+inline define_newScriptVar_Fnc(FunctionNativeCallback, CTinyJS *Context, JSCallback Callback, void *Userdata) { return new CScriptVarFunctionNativeCallback(Context, Callback, Userdata); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarFunctionNativeClass
+//////////////////////////////////////////////////////////////////////////
+
+template<class native>
+class CScriptVarFunctionNativeClass : public CScriptVarFunctionNative {
+protected:
+	CScriptVarFunctionNativeClass(CTinyJS *Context, native *ClassPtr, void (native::*ClassFnc)(const CFunctionsScopePtr &, void *), void *Userdata) : CScriptVarFunctionNative(Context, Userdata), classPtr(ClassPtr), classFnc(ClassFnc) { }
+	CScriptVarFunctionNativeClass(const CScriptVarFunctionNativeClass &Copy) : CScriptVarFunctionNative(Copy), classPtr(Copy.classPtr), classFnc(Copy.classFnc) { } ///< Copy protected -> use clone for public
+public:
+	virtual CScriptVarPtr clone() { return new CScriptVarFunctionNativeClass(*this); }
+
+	virtual void callFunction(const CFunctionsScopePtr &c) { (classPtr->*classFnc)(c, jsUserData); }
+private:
+	native *classPtr;
+	void (native::*classFnc)(const CFunctionsScopePtr &c, void *userdata);
+	template<typename native2>
+	friend define_newScriptVar_Fnc(FunctionNativeCallback, CTinyJS*, native2 *, void (native2::*)(const CFunctionsScopePtr &, void *), void *);
+};
+template<typename native>
+define_newScriptVar_Fnc(FunctionNativeCallback, CTinyJS *Context, native *ClassPtr, void (native::*ClassFnc)(const CFunctionsScopePtr &, void *), void *Userdata) { return new CScriptVarFunctionNativeClass<native>(Context, ClassPtr, ClassFnc, Userdata); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarAccessor
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(Accessor);
+define_ScriptVarPtr_Type(Accessor);
+
+class CScriptVarAccessor : public CScriptVarObject {
+protected:
+	CScriptVarAccessor(CTinyJS *Context);
+	CScriptVarAccessor(CTinyJS *Context, JSCallback getter, void *getterdata, JSCallback setter, void *setterdata);
+	template<class C>	CScriptVarAccessor(CTinyJS *Context, C *class_ptr, void(C::*getterFnc)(const CFunctionsScopePtr &, void *), void *getterData, void(C::*setterFnc)(const CFunctionsScopePtr &, void *), void *setterData) : CScriptVarObject(Context) {
+		if(getterFnc)
+			addChild(TINYJS_ACCESSOR_GET_VAR, ::newScriptVar(Context, class_ptr, getterFnc, getterData), 0);
+		if(setterFnc)
+			addChild(TINYJS_ACCESSOR_SET_VAR, ::newScriptVar(Context, class_ptr, setterFnc, setterData), 0);
+	}
+	CScriptVarAccessor(CTinyJS *Context, const CScriptVarFunctionPtr &getter, const CScriptVarFunctionPtr &setter);
+
+	CScriptVarAccessor(const CScriptVarAccessor &Copy) : CScriptVarObject(Copy) {} ///< Copy protected -> use clone for public
+public:
+	virtual ~CScriptVarAccessor();
+	virtual CScriptVarPtr clone();
+	virtual bool isAccessor(); // { return true; }
+	virtual bool isPrimitive(); // { return false; } 
+
+	virtual std::string getParsableString(const std::string &indentString, const std::string &indent, uint32_t uniqueID, bool &hasRecursion);
+	virtual std::string getVarType(); // { return "object"; }
+
+	CScriptVarPtr getValue();
+
+	friend define_newScriptVar_Fnc(Accessor, CTinyJS *Context, Accessor_t);
+	friend define_newScriptVar_NamedFnc(Accessor, CTinyJS *Context, JSCallback getter, void *getterdata, JSCallback setter, void *setterdata);
+	template<class C> friend define_newScriptVar_NamedFnc(Accessor, CTinyJS *Context, C *class_ptr, void(C::*getterFnc)(const CFunctionsScopePtr &, void *), void *getterData, void(C::*setterFnc)(const CFunctionsScopePtr &, void *), void *setterData);
+	friend define_newScriptVar_NamedFnc(Accessor, CTinyJS *Context, const CScriptVarFunctionPtr &, const CScriptVarFunctionPtr &);
+};
+inline define_newScriptVar_Fnc(Accessor, CTinyJS *Context, Accessor_t) { return new CScriptVarAccessor(Context); }
+inline define_newScriptVar_NamedFnc(Accessor, CTinyJS *Context, JSCallback getter, void *getterdata, JSCallback setter, void *setterdata) { return new CScriptVarAccessor(Context, getter, getterdata, setter, setterdata); }
+template<class C> define_newScriptVar_NamedFnc(Accessor, CTinyJS *Context, C *class_ptr, void(C::*getterFnc)(const CFunctionsScopePtr &, void *), void *getterData, void(C::*setterFnc)(const CFunctionsScopePtr &, void *), void *setterData)  { return new CScriptVarAccessor(Context, class_ptr, getterFnc, getterData, setterFnc, setterData); }
+inline define_newScriptVar_NamedFnc(Accessor, CTinyJS *Context, const CScriptVarFunctionPtr &getter, const CScriptVarFunctionPtr &setter) { return new CScriptVarAccessor(Context, getter, setter); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarDestructuring
+//////////////////////////////////////////////////////////////////////////
+
+class CScriptVarDestructuring : public CScriptVarObject {
+protected: // only derived classes or friends can be created
+	CScriptVarDestructuring(CTinyJS *Context) // constructor for rootScope
+		: CScriptVarObject(Context) {}
+	virtual CScriptVarPtr clone();
+public:
+	virtual ~CScriptVarDestructuring();
+};
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarScope
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(Scope);
+define_ScriptVarPtr_Type(Scope);
+class CScriptVarScope : public CScriptVarObject {
+protected: // only derived classes or friends can be created
+	CScriptVarScope(CTinyJS *Context) // constructor for rootScope
+		: CScriptVarObject(Context) {}
+	virtual CScriptVarPtr clone();
+	virtual bool isObject(); // { return false; }
+public:
+	virtual ~CScriptVarScope();
+	virtual CScriptVarPtr scopeVar(); ///< to create var like: var a = ...
+	virtual CScriptVarPtr scopeLet(); ///< to create var like: let a = ...
+	virtual CScriptVarLinkWorkPtr findInScopes(const std::string &childName);
+	virtual CScriptVarScopePtr getParent();
+	friend define_newScriptVar_Fnc(Scope, CTinyJS *Context, Scope_t);
+};
+inline define_newScriptVar_Fnc(Scope, CTinyJS *Context, Scope_t) { return new CScriptVarScope(Context); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarScopeFnc
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(ScopeFnc);
+define_ScriptVarPtr_Type(ScopeFnc);
+class CScriptVarScopeFnc : public CScriptVarScope {
+protected: // only derived classes or friends can be created
+	CScriptVarScopeFnc(CTinyJS *Context, const CScriptVarScopePtr &Closure) // constructor for FncScope
+		: CScriptVarScope(Context), closure(Closure ? addChild(TINYJS_FUNCTION_CLOSURE_VAR, Closure, 0) : CScriptVarLinkPtr()) {}
+public:
+	virtual ~CScriptVarScopeFnc();
+	virtual CScriptVarLinkWorkPtr findInScopes(const std::string &childName);
+	
+	void setReturnVar(const CScriptVarPtr &var); ///< Set the result value. Use this when setting complex return data as it avoids a deepCopy()
+	
+	#define DEPRECATED_getParameter DEPRECATED("getParameter is deprecated use getArgument instead")
+	DEPRECATED_getParameter CScriptVarPtr getParameter(const std::string &name); 
+	DEPRECATED_getParameter CScriptVarPtr getParameter(int Idx); 
+	CScriptVarPtr getArgument(const std::string &name); ///< If this is a function, get the parameter with the given name (for use by native functions)
+	CScriptVarPtr getArgument(int Idx); ///< If this is a function, get the parameter with the given index (for use by native functions)
+	DEPRECATED("getParameterLength is deprecated use getArgumentsLength instead") int getParameterLength(); ///< If this is a function, get the count of parameters
+	int getArgumentsLength(); ///< If this is a function, get the count of parameters
+
+	void throwError(ERROR_TYPES ErrorType, const std::string &message);
+
+protected:
+	CScriptVarLinkPtr closure;
+	friend define_newScriptVar_Fnc(ScopeFnc, CTinyJS *Context, ScopeFnc_t, const CScriptVarScopePtr &Closure);
+};
+inline define_newScriptVar_Fnc(ScopeFnc, CTinyJS *Context, ScopeFnc_t, const CScriptVarScopePtr &Closure) { return new CScriptVarScopeFnc(Context, Closure); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarScopeLet
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(ScopeLet);
+define_ScriptVarPtr_Type(ScopeLet);
+class CScriptVarScopeLet : public CScriptVarScope {
+protected: // only derived classes or friends can be created
+	CScriptVarScopeLet(const CScriptVarScopePtr &Parent); // constructor for LetScope
+//		: CScriptVarScope(Parent->getContext()), parent( context->getRoot() != Parent ? addChild(TINYJS_SCOPE_PARENT_VAR, Parent, 0) : 0) {}
+public:
+	virtual ~CScriptVarScopeLet();
+	virtual CScriptVarLinkWorkPtr findInScopes(const std::string &childName);
+	virtual CScriptVarPtr scopeVar(); ///< to create var like: var a = ...
+	virtual CScriptVarScopePtr getParent();
+	void setletExpressionInitMode(bool Mode) { letExpressionInitMode = Mode; }
+protected:
+	CScriptVarLinkPtr parent;
+	bool letExpressionInitMode;
+	friend define_newScriptVar_Fnc(ScopeLet, CTinyJS *Context, ScopeLet_t, const CScriptVarScopePtr &Parent);
+};
+inline define_newScriptVar_Fnc(ScopeLet, CTinyJS *, ScopeLet_t, const CScriptVarScopePtr &Parent) { return new CScriptVarScopeLet(Parent); }
+
+
+////////////////////////////////////////////////////////////////////////// 
+/// CScriptVarScopeWith
+//////////////////////////////////////////////////////////////////////////
+
+define_dummy_t(ScopeWith);
+define_ScriptVarPtr_Type(ScopeWith);
+class CScriptVarScopeWith : public CScriptVarScopeLet {
+protected:
+	CScriptVarScopeWith(const CScriptVarScopePtr &Parent, const CScriptVarPtr &With) 
+		: CScriptVarScopeLet(Parent), with(addChild(TINYJS_SCOPE_WITH_VAR, With, 0)) {}
+
+public:
+	virtual ~CScriptVarScopeWith();
+	virtual CScriptVarPtr scopeLet(); ///< to create var like: let a = ...
+	virtual CScriptVarLinkWorkPtr findInScopes(const std::string &childName);
+private:
+	CScriptVarLinkPtr with;
+	friend define_newScriptVar_Fnc(ScopeWith, CTinyJS *Context, ScopeWith_t, const CScriptVarScopePtr &Parent, const CScriptVarPtr &With);
+};
+inline define_newScriptVar_Fnc(ScopeWith, CTinyJS *, ScopeWith_t, const CScriptVarScopePtr &Parent, const CScriptVarPtr &With) { return new CScriptVarScopeWith(Parent, With); }
+
+
+//////////////////////////////////////////////////////////////////////////
+template<typename T>
+inline CScriptVarPtr CScriptVar::newScriptVar(T t) { return ::newScriptVar(context, t); }
+template<typename T1, typename T2>
+inline CScriptVarPtr CScriptVar::newScriptVar(T1 t1, T2 t2) { return ::newScriptVar(context, t1, t2); }
+//inline CScriptVarPtr newScriptVar(const CNumber &t) { return ::newScriptVar(context, t); }
+//////////////////////////////////////////////////////////////////////////
+
+
+class CScriptResult {
+public:
+	enum TYPE {
+		Normal,
+		Break,
+		Continue,
+		Return,
+		Throw,
+		noExecute
+	};
+	CScriptResult() : type(Normal) {}
+	CScriptResult(TYPE Type) : type(Type) {}
+//		~RESULT() { if(type==Throw) throw value; }
+	bool isNormal() { return type==Normal; }
+	bool isBreak() { return type==Break; }
+	bool isContinue() { return type==Continue; }
+	bool isBreakContinue() { return type==Break || type==Continue; }
+	bool isReturn() { return type==Return; }
+	bool isReturnNormal() { return type==Return || type==Normal; }
+	bool isThrow() { return type==Throw; }
+
+	operator bool() const { return type==Normal; }
+	void set(TYPE Type, bool Clear=true) { type=Type; if(Clear) value.clear(), target.clear(); }
+	void set(TYPE Type, const CScriptVarPtr &Value) { type=Type; value=Value; }
+	void set(TYPE Type, const std::string &Target) { type=Type; target=Target; }
+
+	void cThrow() { if(type==Throw) throw value; }
+
+	CScriptResult &operator()(const CScriptResult &rhs) { if(type!=Normal) *this=rhs; return *this; }
+
+	enum TYPE type;
+	CScriptVarPtr value;
+	std::string target;
+};
+
+
+
+//////////////////////////////////////////////////////////////////////////
+/// CTinyJS
+//////////////////////////////////////////////////////////////////////////
+
+class CTinyJS {
+public:
+	CTinyJS();
+	~CTinyJS();
+
+	void execute(CScriptTokenizer &Tokenizer);
+	void execute(const char *Code, const std::string &File="", int Line=0, int Column=0);
+	void execute(const std::string &Code, const std::string &File="", int Line=0, int Column=0);
+	/** Evaluate the given code and return a link to a javascript object,
+	 * useful for (dangerous) JSON parsing. If nothing to return, will return
+	 * 'undefined' variable type. CScriptVarLink is returned as this will
+	 * automatically unref the result as it goes out of scope. If you want to
+	 * keep it, you must use ref() and unref() */
+	CScriptVarLinkPtr evaluateComplex(CScriptTokenizer &Tokenizer);
+	/** Evaluate the given code and return a link to a javascript object,
+	 * useful for (dangerous) JSON parsing. If nothing to return, will return
+	 * 'undefined' variable type. CScriptVarLink is returned as this will
+	 * automatically unref the result as it goes out of scope. If you want to
+	 * keep it, you must use ref() and unref() */
+	CScriptVarLinkPtr evaluateComplex(const char *code, const std::string &File="", int Line=0, int Column=0);
+	/** Evaluate the given code and return a link to a javascript object,
+	 * useful for (dangerous) JSON parsing. If nothing to return, will return
+	 * 'undefined' variable type. CScriptVarLink is returned as this will
+	 * automatically unref the result as it goes out of scope. If you want to
+	 * keep it, you must use ref() and unref() */
+	CScriptVarLinkPtr evaluateComplex(const std::string &code, const std::string &File="", int Line=0, int Column=0);
+	/** Evaluate the given code and return a string. If nothing to return, will return
+	 * 'undefined' */
+	std::string evaluate(CScriptTokenizer &Tokenizer);
+	/** Evaluate the given code and return a string. If nothing to return, will return
+	 * 'undefined' */
+	std::string evaluate(const char *code, const std::string &File="", int Line=0, int Column=0);
+	/** Evaluate the given code and return a string. If nothing to return, will return
+	 * 'undefined' */
+	std::string evaluate(const std::string &code, const std::string &File="", int Line=0, int Column=0);
+
+	/// add a native function to be called from TinyJS
+	/** example:
+		\code
+			void scRandInt(const CFunctionsScopePtr &c, void *userdata) { ... }
+			tinyJS->addNative("function randInt(min, max)", scRandInt, 0);
+		\endcode
+
+		or
+
+		\code
+			void scSubstring(const CFunctionsScopePtr &c, void *userdata) { ... }
+			tinyJS->addNative("function String.substring(lo, hi)", scSubstring, 0);
+		\endcode
+		or
+
+		\code
+			class Class
+			{
+			public:
+				void scSubstring(const CFunctionsScopePtr &c, void *userdata) { ... }
+			};
+			Class Instanz;
+			tinyJS->addNative("function String.substring(lo, hi)", &Instanz, &Class::*scSubstring, 0);
+		\endcode
+	*/
+
+	CScriptVarFunctionNativePtr addNative(const std::string &funcDesc, JSCallback ptr, void *userdata=0, int LinkFlags=SCRIPTVARLINK_BUILDINDEFAULT);
+	template<class C>
+	CScriptVarFunctionNativePtr addNative(const std::string &funcDesc, C *class_ptr, void(C::*class_fnc)(const CFunctionsScopePtr &, void *), void *userdata=0, int LinkFlags=SCRIPTVARLINK_BUILDINDEFAULT)
+	{
+		return addNative(funcDesc, ::newScriptVar<C>(this, class_ptr, class_fnc, userdata), LinkFlags);
+	}
+
+	/// Send all variables to stdout
+	void trace();
+
+	const CScriptVarScopePtr &getRoot() { return root; };   /// gets the root of symbol table
+	//	CScriptVar *root;   /// root of symbol table
+
+	/// newVars & constVars
+	//CScriptVarPtr newScriptVar(const CNumber &t) { return ::newScriptVar(this, t); }
+	template<typename T>	CScriptVarPtr newScriptVar(T t) { return ::newScriptVar(this, t); }
+	template<typename T1, typename T2>	CScriptVarPtr newScriptVar(T1 t1, T2 t2) { return ::newScriptVar(this, t1, t2); }
+	const CScriptVarPtr &constScriptVar(Undefined_t)		{ return constUndefined; }
+	const CScriptVarPtr &constScriptVar(Null_t)				{ return constNull; }
+	const CScriptVarPtr &constScriptVar(NaN_t)				{ return constNaN; }
+	const CScriptVarPtr &constScriptVar(Infinity t)			{ return t.Sig()<0 ? constInfinityNegative : constInfinityPositive; }
+	const CScriptVarPtr &constScriptVar(bool Val)			{ return Val?constTrue:constFalse; }
+	const CScriptVarPtr &constScriptVar(NegativeZero_t)	{ return constNegativZero; }
+	const CScriptVarPtr &constScriptVar(StopIteration_t)	{ return constStopIteration; }
+
+private:
+	CScriptTokenizer *t;       /// current tokenizer
+	bool haveTry;
+	std::vector<CScriptVarScopePtr>scopes;
+	CScriptVarScopePtr root;
+	const CScriptVarScopePtr &scope() { return scopes.back(); }
+
+	class CScopeControl { // helper-class to manage scopes
+	private:
+		CScopeControl(const CScopeControl& Copy) MEMBER_DELETE; // no copy
+		CScopeControl& operator =(const CScopeControl& Copy) MEMBER_DELETE;
+	public:
+		CScopeControl(CTinyJS *Context) : context(Context), count(0) {} 
+		~CScopeControl() { while(count--) {CScriptVarScopePtr parent = context->scopes.back()->getParent(); if(parent) context->scopes.back() = parent; else context->scopes.pop_back() ;} } 
+		void addFncScope(const CScriptVarScopePtr &Scope) { context->scopes.push_back(Scope); count++; }
+		CScriptVarScopeLetPtr addLetScope() {	count++; return context->scopes.back() = ::newScriptVar(context, ScopeLet, context->scopes.back()); }
+		void addWithScope(const CScriptVarPtr &With) { context->scopes.back() = ::newScriptVar(context, ScopeWith, context->scopes.back(), With); count++; }  
+	private:
+		CTinyJS *context;
+		int		count;
+	};
+	friend class CScopeControl;
+public:
+	CScriptVarPtr objectPrototype; /// Built in object class
+	CScriptVarPtr objectPrototype_valueOf; /// Built in object class
+	CScriptVarPtr objectPrototype_toString; /// Built in object class
+	CScriptVarPtr arrayPrototype; /// Built in array class
+	CScriptVarPtr stringPrototype; /// Built in string class
+	CScriptVarPtr regexpPrototype; /// Built in string class
+	CScriptVarPtr numberPrototype; /// Built in number class
+	CScriptVarPtr booleanPrototype; /// Built in boolean class
+	CScriptVarPtr iteratorPrototype; /// Built in boolean class
+	CScriptVarPtr functionPrototype; /// Built in function class
+	const CScriptVarPtr &getErrorPrototype(ERROR_TYPES Type) { return errorPrototypes[Type]; }
+private:
+	CScriptVarPtr errorPrototypes[ERROR_COUNT]; /// Built in error class
+	CScriptVarPtr constUndefined;
+	CScriptVarPtr constNull;
+	CScriptVarPtr constNaN;
+	CScriptVarPtr constInfinityPositive;
+	CScriptVarPtr constInfinityNegative;
+	CScriptVarPtr constNegativZero;
+	CScriptVarPtr constTrue;
+	CScriptVarPtr constFalse;
+	CScriptVarPtr constStopIteration;
+
+	std::vector<CScriptVarPtr *> pseudo_refered;
+
+	void CheckRightHandVar(CScriptResult &execute, CScriptVarLinkWorkPtr &link)
+	{
+		if(execute && link && !link->isOwned() && !link.hasReferencedOwner() && !link->getName().empty())
+			throwError(execute, ReferenceError, link->getName() + " is not defined", t->getPrevPos());
+	}
+
+	void CheckRightHandVar(CScriptResult &execute, CScriptVarLinkWorkPtr &link, CScriptTokenizer::ScriptTokenPosition &Pos)
+	{
+		if(execute && link && !link->isOwned() && !link.hasReferencedOwner() && !link->getName().empty())
+			throwError(execute, ReferenceError, link->getName() + " is not defined", Pos);
+	}
+
+public:
+	// function call
+	CScriptVarPtr callFunction(const CScriptVarFunctionPtr &Function, std::vector<CScriptVarPtr> &Arguments, const CScriptVarPtr &This, CScriptVarPtr *newThis=0);
+	CScriptVarPtr callFunction(CScriptResult &execute, const CScriptVarFunctionPtr &Function, std::vector<CScriptVarPtr> &Arguments, const CScriptVarPtr &This, CScriptVarPtr *newThis=0);
+
+	// parsing - in order of precedence
+	CScriptVarPtr mathsOp(CScriptResult &execute, const CScriptVarPtr &a, const CScriptVarPtr &b, int op);
+private:
+	void assign_destructuring_var(const CScriptVarPtr &Scope, const CScriptTokenDataDestructuringVar &Objc, const CScriptVarPtr &Val, CScriptResult &execute);
+	void execute_var_init(bool hideLetScope, CScriptResult &execute);
+	void execute_destructuring(CScriptTokenDataObjectLiteral &Objc, const CScriptVarPtr &Val, CScriptResult &execute);
+	CScriptVarLinkWorkPtr execute_literals(CScriptResult &execute);
+	CScriptVarLinkWorkPtr execute_member(CScriptVarLinkWorkPtr &parent, CScriptResult &execute);
+	CScriptVarLinkWorkPtr execute_function_call(CScriptResult &execute);
+	bool execute_unary_rhs(CScriptResult &execute, CScriptVarLinkWorkPtr& a);
+	CScriptVarLinkWorkPtr execute_unary(CScriptResult &execute);
+	CScriptVarLinkWorkPtr execute_term(CScriptResult &execute);
+	CScriptVarLinkWorkPtr execute_expression(CScriptResult &execute);
+	CScriptVarLinkWorkPtr execute_binary_shift(CScriptResult &execute);
+	CScriptVarLinkWorkPtr execute_relation(CScriptResult &execute, int set=LEX_EQUAL, int set_n='<');
+	CScriptVarLinkWorkPtr execute_binary_logic(CScriptResult &execute, int op='|', int op_n1='^', int op_n2='&');
+	CScriptVarLinkWorkPtr execute_logic(CScriptResult &execute, int op=LEX_OROR, int op_n=LEX_ANDAND);
+	CScriptVarLinkWorkPtr execute_condition(CScriptResult &execute);
+	CScriptVarLinkPtr execute_assignment(CScriptVarLinkWorkPtr Lhs, CScriptResult &execute);
+	CScriptVarLinkPtr execute_assignment(CScriptResult &execute);
+	CScriptVarLinkPtr execute_base(CScriptResult &execute);
+	void execute_block(CScriptResult &execute);
+	void execute_statement(CScriptResult &execute);
+	// parsing utility functions
+	CScriptVarLinkWorkPtr parseFunctionDefinition(const CScriptToken &FncToken);
+	CScriptVarLinkWorkPtr parseFunctionsBodyFromString(const std::string &ArgumentList, const std::string &FncBody);
+public:
+	CScriptVarLinkPtr findInScopes(const std::string &childName); ///< Finds a child, looking recursively up the scopes
+private:
+	//////////////////////////////////////////////////////////////////////////
+	/// addNative-helper
+	CScriptVarFunctionNativePtr addNative(const std::string &funcDesc, CScriptVarFunctionNativePtr Var, int LinkFlags);
+
+	//////////////////////////////////////////////////////////////////////////
+	/// throws an Error & Exception
+public:
+	void throwError(CScriptResult &execute, ERROR_TYPES ErrorType, const std::string &message);
+	void throwException(ERROR_TYPES ErrorType, const std::string &message);
+	void throwError(CScriptResult &execute, ERROR_TYPES ErrorType, const std::string &message, CScriptTokenizer::ScriptTokenPosition &Pos);
+	void throwException(ERROR_TYPES ErrorType, const std::string &message, CScriptTokenizer::ScriptTokenPosition &Pos);
+private:
+	//////////////////////////////////////////////////////////////////////////
+	/// native Object-Constructors & prototype-functions
+
+	void native_Object(const CFunctionsScopePtr &c, void *data);
+	void native_Object_getPrototypeOf(const CFunctionsScopePtr &c, void *data);
+	/* Userdate for set-/isObjectState
+	 * 0 - preventExtensions / isExtensible
+	 * 1 - seal / isSealed
+	 * 2 - freeze / isFrozen
+	 */
+	void native_Object_setObjectSecure(const CFunctionsScopePtr &c, void *data);
+	void native_Object_isSecureObject(const CFunctionsScopePtr &c, void *data);
+	void native_Object_keys(const CFunctionsScopePtr &c, void *data);
+	void native_Object_getOwnPropertyDescriptor(const CFunctionsScopePtr &c, void *data);
+	void native_Object_defineProperty(const CFunctionsScopePtr &c, void *data);
+	void native_Object_defineProperties(const CFunctionsScopePtr &c, void *data);
+
+	void native_Object_prototype_hasOwnProperty(const CFunctionsScopePtr &c, void *data);
+	void native_Object_prototype_valueOf(const CFunctionsScopePtr &c, void *data);
+	void native_Object_prototype_toString(const CFunctionsScopePtr &c, void *data);
+
+	void native_Array(const CFunctionsScopePtr &c, void *data);
+
+	void native_String(const CFunctionsScopePtr &c, void *data);
+
+	void native_RegExp(const CFunctionsScopePtr &c, void *data);
+
+	void native_Number(const CFunctionsScopePtr &c, void *data);
+
+	void native_Boolean(const CFunctionsScopePtr &c, void *data);
+
+	void native_Iterator(const CFunctionsScopePtr &c, void *data);
+
+	void native_Function(const CFunctionsScopePtr &c, void *data);
+	void native_Function_prototype_call(const CFunctionsScopePtr &c, void *data);
+	void native_Function_prototype_apply(const CFunctionsScopePtr &c, void *data);
+	void native_Function_prototype_bind(const CFunctionsScopePtr &c, void *data);
+
+	void native_Error(const CFunctionsScopePtr &c, void *data);
+	void native_EvalError(const CFunctionsScopePtr &c, void *data);
+	void native_RangeError(const CFunctionsScopePtr &c, void *data);
+	void native_ReferenceError(const CFunctionsScopePtr &c, void *data);
+	void native_SyntaxError(const CFunctionsScopePtr &c, void *data);
+	void native_TypeError(const CFunctionsScopePtr &c, void *data);
+
+
+	//////////////////////////////////////////////////////////////////////////
+	/// global function
+
+	void native_eval(const CFunctionsScopePtr &c, void *data);
+	void native_isNAN(const CFunctionsScopePtr &c, void *data);
+	void native_isFinite(const CFunctionsScopePtr &c, void *data);
+	void native_parseInt(const CFunctionsScopePtr &c, void *data);
+	void native_parseFloat(const CFunctionsScopePtr &c, void *data);
+
+
+
+	void native_JSON_parse(const CFunctionsScopePtr &c, void *data);
+
+
+	uint32_t uniqueID;
+public:
+	uint32_t getUniqueID() { return ++uniqueID; }
+	CScriptVar *first;
+	void setTemporaryID_recursive(uint32_t ID);
+	void ClearUnreferedVars(const CScriptVarPtr &extra=CScriptVarPtr());
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+template<typename T>
+inline const CScriptVarPtr &CScriptVar::constScriptVar(T t) { return context->constScriptVar(t); }
+//////////////////////////////////////////////////////////////////////////
+inline CNumber CScriptVarLink::toNumber() { return var->toNumber(); }
+inline CNumber CScriptVarLink::toNumber(CScriptResult &execute) { return var->toNumber(execute); }
+
+#endif
+
+
Index: XmlTools2/trunk/XmlTools/libs/TinyJS_Functions.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS_Functions.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS_Functions.cpp	(revision 905)
@@ -0,0 +1,161 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored / Changed By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+
+#include <math.h>
+#include <cstdlib>
+#include <sstream>
+#include <time.h>
+#include "TinyJS.h"
+
+using namespace std;
+// ----------------------------------------------- Actual Functions
+
+static void scTrace(const CFunctionsScopePtr &c, void * userdata) {
+	CTinyJS *js = (CTinyJS*)userdata;
+	if(c->getArgumentsLength())
+		c->getArgument(0)->trace();
+	else
+		js->getRoot()->trace("root");
+}
+
+static void scObjectDump(const CFunctionsScopePtr &c, void *) {
+	c->getArgument("this")->trace("> ");
+}
+
+static void scObjectClone(const CFunctionsScopePtr &c, void *) {
+	CScriptVarPtr obj = c->getArgument("this");
+	c->setReturnVar(obj->clone());
+}
+
+static void scIntegerValueOf(const CFunctionsScopePtr &c, void *) {
+	string str = c->getArgument("str")->toString();
+
+	int val = 0;
+	if (str.length()==1)
+		val = str.operator[](0);
+	c->setReturnVar(c->newScriptVar(val));
+}
+
+static void scJSONStringify(const CFunctionsScopePtr &c, void *) {
+	uint32_t UniqueID = c->getContext()->getUniqueID();
+	bool hasRecursion=false;
+	c->setReturnVar(c->newScriptVar(c->getArgument("obj")->getParsableString("", "   ", UniqueID, hasRecursion)));
+	if(hasRecursion) c->throwError(TypeError, "cyclic object value");
+}
+
+static void scArrayContains(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr obj = c->getArgument("obj");
+	CScriptVarPtr arr = c->getArgument("this");
+
+	int l = arr->getArrayLength();
+	CScriptVarPtr equal = c->constScriptVar(Undefined);
+	for (int i=0;i<l;i++) {
+		equal = obj->mathsOp(arr->getArrayIndex(i), LEX_EQUAL);
+		if(equal->toBoolean()) {
+			c->setReturnVar(c->constScriptVar(true));
+			return;
+		}
+	}
+	c->setReturnVar(c->constScriptVar(false));
+}
+
+static void scArrayRemove(const CFunctionsScopePtr &c, void *data) {
+	CScriptVarPtr obj = c->getArgument("obj");
+	CScriptVarPtr arr = c->getArgument("this");
+	int i;
+	vector<int> removedIndices;
+
+	int l = arr->getArrayLength();
+	CScriptVarPtr equal = c->constScriptVar(Undefined);
+	for (i=0;i<l;i++) {
+		equal = obj->mathsOp(arr->getArrayIndex(i), LEX_EQUAL);
+		if(equal->toBoolean()) {
+			removedIndices.push_back(i);
+		}
+	}
+	if(removedIndices.size()) {
+		vector<int>::iterator remove_it = removedIndices.begin();
+		int next_remove = *remove_it;
+		int next_insert = *remove_it++;
+		for (i=next_remove;i<l;i++) {
+
+			CScriptVarLinkPtr link = arr->findChild(int2string(i));
+			if(i == next_remove) {
+				if(link) arr->removeLink(link);
+				if(remove_it != removedIndices.end())
+					next_remove = *remove_it++;
+			} else {
+				if(link) {
+					arr->setArrayIndex(next_insert++, link);
+					arr->removeLink(link);
+				}	
+			}
+		}
+	}
+}
+
+static void scArrayJoin(const CFunctionsScopePtr &c, void *data) {
+	string sep = c->getArgument("separator")->toString();
+	CScriptVarPtr arr = c->getArgument("this");
+
+	ostringstream sstr;
+	int l = arr->getArrayLength();
+	for (int i=0;i<l;i++) {
+		if (i>0) sstr << sep;
+		sstr << arr->getArrayIndex(i)->toString();
+	}
+
+	c->setReturnVar(c->newScriptVar(sstr.str()));
+}
+
+// ----------------------------------------------- Register Functions
+void registerFunctions(CTinyJS *tinyJS) {
+}
+extern "C" void _registerFunctions(CTinyJS *tinyJS) {
+	tinyJS->addNative("function trace()", scTrace, tinyJS, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function Object.prototype.dump()", scObjectDump, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function Object.prototype.clone()", scObjectClone, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+
+	tinyJS->addNative("function Integer.valueOf(str)", scIntegerValueOf, 0, SCRIPTVARLINK_BUILDINDEFAULT); // value of a single character
+	tinyJS->addNative("function JSON.stringify(obj, replacer)", scJSONStringify, 0, SCRIPTVARLINK_BUILDINDEFAULT); // convert to JSON. replacer is ignored at the moment
+	tinyJS->addNative("function Array.prototype.contains(obj)", scArrayContains, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function Array.prototype.remove(obj)", scArrayRemove, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function Array.prototype.join(separator)", scArrayJoin, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+}
+
Index: XmlTools2/trunk/XmlTools/libs/TinyJS_Functions.h
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS_Functions.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS_Functions.h	(revision 905)
@@ -0,0 +1,49 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * Authored By Gordon Williams <gw@pur3.co.uk>
+ *
+ * Copyright (C) 2009 Pur3 Ltd
+ *
+
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored / Changed By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+#pragma message("The include "__FILE__" is deprecated - Functions now registered by default")
+
+#ifndef TINYJS_FUNCTIONS_H
+#define TINYJS_FUNCTIONS_H
+
+#include "TinyJS.h"
+
+/// Register useful functions with the TinyJS interpreter
+extern void DEPRECATED("is deprecated - Functions now registered by default") registerFunctions(CTinyJS *tinyJS);
+
+#endif
Index: XmlTools2/trunk/XmlTools/libs/TinyJS_MathFunctions.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS_MathFunctions.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS_MathFunctions.cpp	(revision 905)
@@ -0,0 +1,441 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * -  Math and Trigonometry functions
+ *
+ * Authored By O.Z.L.B. <ozlbinfo@gmail.com>
+ *
+ * Copyright (C) 2011 O.Z.L.B.
+ *
+
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored / Changed By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+#include <cmath>
+#include <cstdlib>
+#include <sstream>
+#include <ctime>
+#include "TinyJS.h"
+
+using namespace std;
+
+#define k_E                 exp(1.0)
+#define k_PI                3.1415926535897932384626433832795
+#define k_LN2               log((double)2)
+#define k_LN10              log((double)10)
+#define k_LOG2E             (log(k_E)/log((double)2))
+#define k_LOG10E            log10(k_E)
+#define k_SQRT1_2           sqrt((double)0.5)
+#define k_SQRT2             sqrt((double)2)
+
+#define F_ABS(a)            ((a)>=0 ? (a) : (-(a)))
+#define F_MIN(a,b)          ((a)>(b) ? (b) : (a))
+#define F_MAX(a,b)          ((a)>(b) ? (a) : (b))
+#define F_SGN(a)            ((a)>0 ? 1 : ((a)<0 ? -1 : 0 ))
+#define F_RNG(a,min,max)    ((a)<(min) ? min : ((a)>(max) ? max : a ))
+ 
+#ifdef _MSC_VER
+namespace
+{
+	double asinh( const double &value ) {
+		double returned;
+
+		if(value>0)
+			returned = log(value + sqrt(value * value + 1));
+		else
+			returned = -log(-value + sqrt(value * value + 1));
+
+		return(returned);
+	}
+
+	double acosh( const double &value ) {
+		double returned;
+
+		if(value>0)
+			returned = log(value + sqrt(value * value - 1));
+		 else
+			returned = -log(-value + sqrt(value * value - 1));
+
+		return(returned);
+	}
+
+	 double atanh( double value ) {
+		bool neg = value<0;
+		if(neg) value=-value;
+		double value_x2 = 2.0*value;
+		if(value>=0.5)
+			value = log(1.0+value_x2/(1.0-value))/2.0;
+		 else
+			value = log(1.0+value_x2+value_x2*value/(1.0-value))/2.0;
+		return(neg ? -value : value);
+	}
+}
+#endif
+
+#define PARAMETER_TO_NUMBER(v,n) CNumber v = c->getArgument(n)->toNumber()
+#define RETURN_NAN_IS_NAN(v) do{ if(v.isNaN()) { c->setReturnVar(c->newScriptVar(v)); return; } }while(0)
+#define RETURN_NAN_IS_NAN_OR_INFINITY(v) do{ if(v.isNaN() || v.isInfinity()) { c->setReturnVar(c->newScriptVar(v)); return; } }while(0)
+#define RETURN_INFINITY_IS_INFINITY(v) do{ if(v.isInfinity()) { c->setReturnVar(c->newScriptVar(v)); return; } }while(0)
+#define RETURN_ZERO_IS_ZERO(v) do{ if(v.isZero()) { c->setReturnVar(c->newScriptVar(v)); return; } }while(0)
+#define RETURN(a)	do{ c->setReturnVar(c->newScriptVar(a)); return; }while(0)
+#define RETURNconst(a)	c->setReturnVar(c->constScriptVar(a))
+
+//Math.abs(x) - returns absolute of given value
+static void scMathAbs(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); 
+	RETURN(a.sign()<0?-a:a);
+}
+
+//Math.round(a) - returns nearest round of given value
+static void scMathRound(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a");
+	RETURN(a.round());
+}
+
+//Math.ceil(a) - returns nearest round of given value
+static void scMathCeil(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); RETURN_INFINITY_IS_INFINITY(a);
+	RETURN(a.ceil());
+}
+
+//Math.floor(a) - returns nearest round of given value
+static void scMathFloor(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); 
+	RETURN(a.floor());
+}
+
+//Math.min(a,b) - returns minimum of two given values 
+static void scMathMin(const CFunctionsScopePtr &c, void *userdata) {
+	int length = c->getArgumentsLength();
+	CNumber ret(InfinityPositive);
+	for(int i=0; i<length; i++)
+	{
+		PARAMETER_TO_NUMBER(a,i); RETURN_NAN_IS_NAN(a);
+		if(ret>a) ret=a;
+	}
+	RETURN(ret);
+}
+
+//Math.max(a,b) - returns maximum of two given values  
+static void scMathMax(const CFunctionsScopePtr &c, void *userdata) {
+	int length = c->getArgumentsLength();
+	CNumber ret(InfinityNegative);
+	for(int i=0; i<length; i++)
+	{
+		PARAMETER_TO_NUMBER(a,i); RETURN_NAN_IS_NAN(a);
+		if(ret<a) ret=a;
+	}
+	RETURN(ret);
+}
+
+//Math.range(x,a,b) - returns value limited between two given values  
+static void scMathRange(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(x,"x"); RETURN_NAN_IS_NAN(x); 
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	PARAMETER_TO_NUMBER(b,"b"); RETURN_NAN_IS_NAN(b);
+
+	if(a>b) RETURNconst(NaN);
+	if(x<a) RETURN(a);
+	if(x>b) RETURN(b);
+	RETURN(x);	
+}
+
+//Math.sign(a) - returns sign of given value (-1==negative,0=zero,1=positive)
+static void scMathSign(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	RETURN(a.isZero() ? 0 : a.sign());
+}
+static void scMathRandom(const CFunctionsScopePtr &c, void *) {
+	static int inited=0;
+	if(!inited) {
+		inited = 1;
+		srand((unsigned int)time(NULL));
+	}
+	RETURN(double(rand())/RAND_MAX);
+}
+
+//Math.toDegrees(a) - returns degree value of a given angle in radians
+static void scMathToDegrees(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); RETURN_INFINITY_IS_INFINITY(a); 
+	RETURN( (180.0/k_PI)*a );
+}
+
+//Math.toRadians(a) - returns radians value of a given angle in degrees
+static void scMathToRadians(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); RETURN_INFINITY_IS_INFINITY(a); 
+	RETURN( (k_PI/180.0)*a );
+}
+
+//Math.sin(a) - returns trig. sine of given angle in radians
+static void scMathSin(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN_OR_INFINITY(a); RETURN_ZERO_IS_ZERO(a);
+	RETURN( sin(a.toDouble()) );
+}
+
+//Math.asin(a) - returns trig. arcsine of given angle in radians
+static void scMathASin(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); RETURN_ZERO_IS_ZERO(a);
+	if(abs(a)>1) RETURNconst(NaN);
+	RETURN( asin(a.toDouble()) );
+}
+
+//Math.cos(a) - returns trig. cosine of given angle in radians
+static void scMathCos(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN_OR_INFINITY(a); 
+	if(a.isZero()) RETURN(1);
+	RETURN( cos(a.toDouble()) );
+}
+
+//Math.acos(a) - returns trig. arccosine of given angle in radians
+static void scMathACos(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN_OR_INFINITY(a); 
+	if(abs(a)>1) RETURNconst(NaN);
+	else if(a==1) RETURN(0);
+	RETURN( acos(a.toDouble()) );
+}
+
+//Math.tan(a) - returns trig. tangent of given angle in radians
+static void scMathTan(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN_OR_INFINITY(a); RETURN_ZERO_IS_ZERO(a);
+	RETURN( tan(a.toDouble()) );
+}
+
+//Math.atan(a) - returns trig. arctangent of given angle in radians
+static void scMathATan(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); RETURN_ZERO_IS_ZERO(a);
+	int infinity=a.isInfinity();
+	if(infinity) RETURN(k_PI/(infinity*2));
+	RETURN( atan(a.toDouble()) );
+}
+
+//Math.atan2(a,b) - returns trig. arctangent of given angle in radians
+static void scMathATan2(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a);
+	PARAMETER_TO_NUMBER(b,"b"); RETURN_NAN_IS_NAN(b);
+	int sign_a = a.sign();
+	int sign_b = b.sign();
+	if(a.isZero())
+		RETURN(sign_a>0 ? (sign_b>0 ? 0.0 : k_PI) : (sign_b>0 ? -0.0 : -k_PI));
+	else if(b.isZero())
+		RETURN((sign_a>0 ? k_PI : -k_PI)/2.0);
+	int infinity_a=a.isInfinity();
+	int infinity_b=b.isInfinity();
+	if(infinity_a) {
+		if(infinity_b>0) RETURN(k_PI/(infinity_a*4)); 
+		else if(infinity_b<0) RETURN(3.0*k_PI/(infinity_a*4));
+		else RETURN(k_PI/(infinity_a*2));
+	} else if(infinity_b>0)
+		RETURN(sign_a>0 ? 0.0 : -0.0);
+	else if(infinity_b<0)
+		RETURN(sign_a>0 ? k_PI : -k_PI);
+	RETURN( atan2(a.toDouble(), b.toDouble()) );
+}
+
+
+//Math.sinh(a) - returns trig. hyperbolic sine of given angle in radians
+static void scMathSinh(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	RETURN_ZERO_IS_ZERO(a);
+	if(abs(a)>1) RETURNconst(NaN);
+	RETURN( sinh(a.toDouble()) );
+}
+
+//Math.asinh(a) - returns trig. hyperbolic arcsine of given angle in radians
+static void scMathASinh(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	RETURN_INFINITY_IS_INFINITY(a);
+	RETURN_ZERO_IS_ZERO(a);
+	RETURN( asinh(a.toDouble()) );
+}
+
+//Math.cosh(a) - returns trig. hyperbolic cosine of given angle in radians
+static void scMathCosh(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	if(a.isInfinity()) RETURNconst(InfinityPositive);
+	RETURN( cosh(a.toDouble()) );
+}
+
+//Math.acosh(a) - returns trig. hyperbolic arccosine of given angle in radians
+static void scMathACosh(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	RETURN_INFINITY_IS_INFINITY(a);
+	if(abs(a)<1) RETURNconst(NaN);
+	RETURN( acosh(a.toDouble()) );
+}
+
+//Math.tanh(a) - returns trig. hyperbolic tangent of given angle in radians
+static void scMathTanh(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	RETURN_ZERO_IS_ZERO(a);
+	if(a.isInfinity()) RETURN(a.sign());
+	RETURN( tanh(a.toDouble()) );
+}
+
+//Math.atanh(a) - returns trig. hyperbolic arctangent of given angle in radians
+static void scMathATanh(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	RETURN_ZERO_IS_ZERO(a);
+	CNumber abs_a = abs(a);
+	if(abs_a > 1) RETURNconst(NaN);
+	if(abs_a == 1) RETURNconst(Infinity(a.sign()));
+	RETURN( atanh(a.toDouble()) );
+}
+
+//Math.log(a) - returns natural logaritm (base E) of given value
+static void scMathLog(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	if(a.isZero()) RETURNconst(InfinityNegative);
+	if(a.sign()<0) RETURNconst(NaN);
+	if(a.isInfinity()) RETURNconst(InfinityPositive);
+	RETURN( log( a.toDouble()) );
+}
+
+//Math.log10(a) - returns logaritm(base 10) of given value
+static void scMathLog10(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	if(a.isZero()) RETURNconst(InfinityNegative);
+	if(a.sign()<0) RETURNconst(NaN);
+	if(a.isInfinity()) RETURNconst(InfinityPositive);
+	RETURN( log10( a.toDouble()) );
+}
+
+//Math.exp(a) - returns e raised to the power of a given number
+static void scMathExp(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a);
+	if(a.isZero()) RETURN(1);
+	int a_i = a.isInfinity();
+	if(a_i>0) RETURNconst(InfinityPositive);
+	else if(a_i<0) RETURN(0);
+	RETURN( exp(a.toDouble()) );
+}
+
+//Math.pow(a,b) - returns the result of a number raised to a power (a)^(b)
+static void scMathPow(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a");
+	PARAMETER_TO_NUMBER(b,"b"); RETURN_NAN_IS_NAN(b); 
+	if(b.isZero()) RETURN(1);
+	RETURN_NAN_IS_NAN(a);
+	if(b==1) RETURN(a);
+
+	int sign;
+	CNumber a_abs = abs(a);
+	if((sign = b.isInfinity())) {
+		if( a_abs==1 ) RETURNconst(NaN);
+		else if( (a_abs>1) ^ (sign<0) )	RETURN(b); else RETURN(0);
+	} else if((sign = a.isInfinity())) {
+		if(sign>0) {
+			if(b.sign()>0) RETURN(a); else RETURN(0);
+		} else {
+			bool b_is_odd_int = ((b+1)/2).isInteger();
+			if(b.sign()>0) RETURNconst(b_is_odd_int?InfinityNegative:InfinityPositive);
+			else RETURN(b_is_odd_int?CNumber(NegativeZero):CNumber(0));
+		}
+	} else if(a.isZero()) {
+		if(a.isNegativeZero()) {
+			bool b_is_odd_int = ((b+1)/2).isInteger();
+			if(b.sign()>0) RETURN(b_is_odd_int?CNumber(NegativeZero):CNumber(0));
+			else RETURNconst(b_is_odd_int?InfinityNegative:InfinityPositive);
+		} else 
+			if(b.sign()>0) RETURN(a); else RETURNconst(InfinityPositive);
+	}
+	if(a.sign()<0 && !b.isInteger()) RETURNconst(NaN);
+
+	RETURN( pow(a.toDouble(), b.toDouble()) );
+}
+
+//Math.sqr(a) - returns square of given value
+static void scMathSqr(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a");
+	RETURN( a*a );
+}
+
+//Math.sqrt(a) - returns square root of given value
+static void scMathSqrt(const CFunctionsScopePtr &c, void *userdata) {
+	PARAMETER_TO_NUMBER(a,"a"); RETURN_NAN_IS_NAN(a); 
+	RETURN_ZERO_IS_ZERO(a);
+	if(a.sign()<0) RETURNconst(NaN);
+	RETURN_INFINITY_IS_INFINITY(a); 
+	RETURN( sqrt(a.toDouble()) );
+}
+
+// ----------------------------------------------- Register Functions
+void registerMathFunctions(CTinyJS *tinyJS) {}
+extern "C" void _registerMathFunctions(CTinyJS *tinyJS) {
+
+	 CScriptVarPtr Math = tinyJS->getRoot()->addChild("Math", tinyJS->newScriptVar(Object), SCRIPTVARLINK_CONSTANT);
+
+	 // --- Math and Trigonometry functions ---
+	 tinyJS->addNative("function Math.abs(a)", scMathAbs, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.round(a)", scMathRound, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.ceil(a)", scMathCeil, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.floor(a)", scMathFloor, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.min()", scMathMin, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.max()", scMathMax, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.range(x,a,b)", scMathRange, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.sign(a)", scMathSign, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.random(a)", scMathRandom, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+
+
+// atan2, ceil, floor, random, round, 
+
+	 Math->addChild("LN2", tinyJS->newScriptVar(k_LN2), SCRIPTVARLINK_READONLY);
+	 Math->addChild("LN10", tinyJS->newScriptVar(k_LN10), SCRIPTVARLINK_READONLY);
+	 Math->addChild("LOG2E", tinyJS->newScriptVar(k_LOG2E), SCRIPTVARLINK_READONLY);
+	 Math->addChild("LOG10E", tinyJS->newScriptVar(k_LOG10E), SCRIPTVARLINK_READONLY);
+	 Math->addChild("SQRT1_2", tinyJS->newScriptVar(k_SQRT1_2), SCRIPTVARLINK_READONLY);
+	 Math->addChild("SQRT2", tinyJS->newScriptVar(k_SQRT2), SCRIPTVARLINK_READONLY);
+	 Math->addChild("PI", tinyJS->newScriptVar(k_PI), SCRIPTVARLINK_READONLY);
+//    tinyJS->addNative("function Math.PI()", scMathPI, 0);
+	 tinyJS->addNative("function Math.toDegrees(a)", scMathToDegrees, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.toRadians(a)", scMathToRadians, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.sin(a)", scMathSin, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.asin(a)", scMathASin, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.cos(a)", scMathCos, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.acos(a)", scMathACos, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.tan(a)", scMathTan, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.atan(a)", scMathATan, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.atan2(a,b)", scMathATan2, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.sinh(a)", scMathSinh, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.asinh(a)", scMathASinh, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.cosh(a)", scMathCosh, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.acosh(a)", scMathACosh, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.tanh(a)", scMathTanh, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.atanh(a)", scMathATanh, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+		 
+	 Math->addChild("E", tinyJS->newScriptVar(k_E), SCRIPTVARLINK_READONLY);
+	 tinyJS->addNative("function Math.log(a)", scMathLog, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.log10(a)", scMathLog10, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.exp(a)", scMathExp, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.pow(a,b)", scMathPow, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 
+	 tinyJS->addNative("function Math.sqr(a)", scMathSqr, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	 tinyJS->addNative("function Math.sqrt(a)", scMathSqrt, 0, SCRIPTVARLINK_BUILDINDEFAULT);    
+  
+}
Index: XmlTools2/trunk/XmlTools/libs/TinyJS_MathFunctions.h
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS_MathFunctions.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS_MathFunctions.h	(revision 905)
@@ -0,0 +1,51 @@
+/*
+ * TinyJS
+ *
+ * A single-file Javascript-alike engine
+ *
+ * -  Math and Trigonometry functions
+ *
+ * Authored By O.Z.L.B. <ozlbinfo@gmail.com>
+ *
+ * Copyright (C) 2011 O.Z.L.B.
+ *
+
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored / Changed By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+#pragma message("The include "__FILE__" is deprecated - MathFunctions now registered by default")
+
+#ifndef TINYJS_MATHFUNCTIONS_H
+#define TINYJS_MATHFUNCTIONS_H
+
+#include "TinyJS.h"
+
+/// Register useful math. functions with the TinyJS interpreter
+extern void DEPRECATED("is deprecated - MathFunctions now registered by default") registerMathFunctions(CTinyJS *tinyJS);
+
+#endif
Index: XmlTools2/trunk/XmlTools/libs/TinyJS_StringFunctions.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS_StringFunctions.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS_StringFunctions.cpp	(revision 905)
@@ -0,0 +1,535 @@
+/*
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+#include <algorithm>
+#include "TinyJS.h"
+
+#ifndef NO_REGEXP 
+#	if defined HAVE_TR1_REGEX
+#		include <tr1/regex>
+		using namespace std::tr1;
+#	elif defined HAVE_BOOST_REGEX
+#		include <boost/regex.hpp>
+		using namespace boost;
+#	else
+#		include <regex>
+#	endif
+#endif
+using namespace std;
+// ----------------------------------------------- Actual Functions
+
+#define CheckObjectCoercible(var) do { \
+		if(var->isUndefined() || var->isNull())\
+			c->throwError(TypeError, "can't convert undefined to object");\
+	}while(0) 
+
+static string this2string(const CFunctionsScopePtr &c) {
+	CScriptVarPtr This = c->getArgument("this");
+	CheckObjectCoercible(This);
+	return This->toString();
+}
+
+static void scStringCharAt(const CFunctionsScopePtr &c, void *) {
+	string str = this2string(c);
+	int p = c->getArgument("pos")->toNumber().toInt32();
+	if (p>=0 && p<(int)str.length())
+		c->setReturnVar(c->newScriptVar(str.substr(p, 1)));
+	else
+		c->setReturnVar(c->newScriptVar(""));
+}
+
+static void scStringCharCodeAt(const CFunctionsScopePtr &c, void *) {
+	string str = this2string(c);
+	int p = c->getArgument("pos")->toNumber().toInt32();
+	if (p>=0 && p<(int)str.length())
+		c->setReturnVar(c->newScriptVar((unsigned char)str.at(p)));
+	else
+		c->setReturnVar(c->constScriptVar(NaN));
+}
+
+static void scStringConcat(const CFunctionsScopePtr &c, void *userdata) {
+	int length = c->getArgumentsLength();
+	string str = this2string(c);
+	for(int i=(int)userdata; i<length; i++)
+		str.append(c->getArgument(i)->toString());
+	c->setReturnVar(c->newScriptVar(str));
+}
+
+static void scStringIndexOf(const CFunctionsScopePtr &c, void *userdata) {
+	string str = this2string(c);
+	string search = c->getArgument("search")->toString();
+	CNumber pos_n = c->getArgument("pos")->toNumber();
+	string::size_type pos;
+	pos = (userdata) ? string::npos : 0;
+	if(pos_n.sign()<0) pos = 0;
+	else if(pos_n.isInfinity()) pos = string::npos;
+	else if(pos_n.isFinite()) pos = pos_n.toInt32();
+	string::size_type p = (userdata==0) ? str.find(search) : str.rfind(search);
+	int val = (p==string::npos) ? -1 : p;
+	c->setReturnVar(c->newScriptVar(val));
+}
+
+static void scStringLocaleCompare(const CFunctionsScopePtr &c, void *userdata) {
+	string str = this2string(c);
+	string compareString = c->getArgument("compareString")->toString();
+	int val = 0;
+	if(str<compareString) val = -1;
+	else if(str>compareString) val = 1;
+	c->setReturnVar(c->newScriptVar(val));
+}
+
+static void scStringQuote(const CFunctionsScopePtr &c, void *userdata) {
+	string str = this2string(c);
+	c->setReturnVar(c->newScriptVar(getJSString(str)));
+}
+
+#ifndef NO_REGEXP
+// helper-function for replace search
+static bool regex_search(const string &str, const string::const_iterator &search_begin, const string &substr, bool ignoreCase, bool sticky, string::const_iterator &match_begin, string::const_iterator &match_end, smatch &match) {
+	regex::flag_type flags = regex_constants::ECMAScript;
+	if(ignoreCase) flags |= regex_constants::icase;
+	regex_constants::match_flag_type mflag = sticky?regex_constants::match_continuous:regex_constants::format_default;
+	if(str.begin() != search_begin) mflag |= regex_constants::match_prev_avail;
+	if(regex_search(search_begin, str.end(), match, regex(substr, flags), mflag)) {
+		match_begin = match[0].first;
+		match_end = match[0].second;
+		return true;
+	}
+	return false;
+}
+static bool regex_search(const string &str, const string::const_iterator &search_begin, const string &substr, bool ignoreCase, bool sticky, string::const_iterator &match_begin, string::const_iterator &match_end) {
+	smatch match;
+	return regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end, match);
+}
+#endif /* NO_REGEXP */
+
+static bool charcmp (char i, char j) { return (i==j); }
+static bool charicmp (char i, char j) { return (toupper(i)==toupper(j)); }
+// helper-function for replace search
+static bool string_search(const string &str, const string::const_iterator &search_begin, const string &substr, bool ignoreCase, bool sticky, string::const_iterator &match_begin, string::const_iterator &match_end) {
+	bool (*cmp)(char,char) = ignoreCase ? charicmp : charcmp;
+	if(sticky) {
+		match_begin = match_end = search_begin;
+		string::const_iterator s1e=str.end();
+		string::const_iterator s2=substr.begin(), s2e=substr.end();
+		while(match_end!=s1e && s2!=s2e && cmp(*match_end++, *s2++));
+		return s2==s2e;
+	} 
+	match_begin = search(search_begin, str.end(), substr.begin(), substr.end(), cmp);
+	if(match_begin==str.end()) return false;
+	match_end = match_begin + substr.length();
+	return true;
+}
+//************************************
+// Method:    getRegExpData
+// FullName:  getRegExpData
+// Access:    public static 
+// Returns:   bool true if regexp-param=RegExp-Object / other false
+// Qualifier:
+// Parameter: const CFunctionsScopePtr & c
+// Parameter: const string & regexp - parameter name of the regexp
+// Parameter: bool noUndefined - true an undefined regexp aims in "" else in "undefined"
+// Parameter: const string & flags - parameter name of the flags
+// Parameter: string & substr - rgexp.source
+// Parameter: bool & global
+// Parameter: bool & ignoreCase
+// Parameter: bool & sticky
+//************************************
+static CScriptVarPtr getRegExpData(const CFunctionsScopePtr &c, const string &regexp, bool noUndefined, const char *flags_argument, string &substr, bool &global, bool &ignoreCase, bool &sticky) {
+	CScriptVarPtr regexpVar = c->getArgument(regexp);
+	if(regexpVar->isRegExp()) {
+#ifndef NO_REGEXP
+		CScriptVarRegExpPtr RegExp(regexpVar);
+		substr = RegExp->Regexp();
+		ignoreCase = RegExp->IgnoreCase();
+		global = RegExp->Global();
+		sticky = RegExp->Sticky();
+		return RegExp;
+#endif /* NO_REGEXP */
+	} else {
+		substr.clear();
+		if(!noUndefined || !regexpVar->isUndefined()) substr = regexpVar->toString();
+		CScriptVarPtr flagVar;
+		if(flags_argument && (flagVar = c->getArgument(flags_argument)) && !flagVar->isUndefined()) {
+			string flags = flagVar->toString();
+			string::size_type pos = flags.find_first_not_of("gimy");
+			if(pos != string::npos) {
+				c->throwError(SyntaxError, string("invalid regular expression flag ")+flags[pos]);
+			}
+			global = flags.find_first_of('g')!=string::npos;
+			ignoreCase = flags.find_first_of('i')!=string::npos;
+			sticky = flags.find_first_of('y')!=string::npos;
+		} else
+			global = ignoreCase = sticky = false;
+	}
+	return CScriptVarPtr();
+}
+
+static void scStringReplace(const CFunctionsScopePtr &c, void *) {
+	const string str = this2string(c);
+	CScriptVarPtr newsubstrVar = c->getArgument("newsubstr");
+	string substr, ret_str;
+	bool global, ignoreCase, sticky;
+	bool isRegExp = getRegExpData(c, "substr", false, "flags", substr, global, ignoreCase, sticky);
+	if(isRegExp && !newsubstrVar->isFunction()) {
+#ifndef NO_REGEXP
+		regex::flag_type flags = regex_constants::ECMAScript;
+		if(ignoreCase) flags |= regex_constants::icase;
+		regex_constants::match_flag_type mflags = regex_constants::match_default;
+		if(!global) mflags |= regex_constants::format_first_only;
+		if(sticky) mflags |= regex_constants::match_continuous;
+		ret_str = regex_replace(str, regex(substr, flags), newsubstrVar->toString(), mflags);
+#endif /* NO_REGEXP */
+	} else {
+		bool (*search)(const string &, const string::const_iterator &, const string &, bool, bool, string::const_iterator &, string::const_iterator &);
+#ifndef NO_REGEXP
+		if(isRegExp) 
+			search = regex_search;
+		else
+#endif /* NO_REGEXP */
+			search = string_search;
+		string newsubstr;
+		vector<CScriptVarPtr> arguments;
+		if(!newsubstrVar->isFunction()) 
+			newsubstr = newsubstrVar->toString();
+		global = global && substr.length();
+		string::const_iterator search_begin=str.begin(), match_begin, match_end;
+		if(search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)) {
+			do {
+				ret_str.append(search_begin, match_begin);
+				if(newsubstrVar->isFunction()) {
+					arguments.push_back(c->newScriptVar(string(match_begin, match_end)));
+					newsubstr = c->getContext()->callFunction(newsubstrVar, arguments, c)->toString();
+					arguments.pop_back();
+				}
+				ret_str.append(newsubstr);
+				search_begin = match_end;
+			} while(global && search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end));
+		}
+		ret_str.append(search_begin, str.end());
+	}
+	c->setReturnVar(c->newScriptVar(ret_str));
+}
+#ifndef NO_REGEXP
+static void scStringMatch(const CFunctionsScopePtr &c, void *) {
+	string str = this2string(c);
+
+	string flags="flags", substr, newsubstr, match;
+	bool global, ignoreCase, sticky;
+	CScriptVarRegExpPtr RegExp = getRegExpData(c, "regexp", true, "flags", substr, global, ignoreCase, sticky);
+	if(!global) {
+		if(!RegExp)
+			RegExp = ::newScriptVar(c->getContext(), substr, flags);
+		if(RegExp) {
+			try {
+				c->setReturnVar(RegExp->exec(str));
+			} catch(regex_error e) {
+				c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
+			}
+		}
+	} else {
+		try { 
+			CScriptVarArrayPtr retVar = c->newScriptVar(Array);
+			int idx=0;
+			string::size_type offset=0;
+			global = global && substr.length();
+			string::const_iterator search_begin=str.begin(), match_begin, match_end;
+			if(regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)) {
+				do {
+					offset = match_begin-str.begin();
+					retVar->addChild(int2string(idx++), c->newScriptVar(string(match_begin, match_end)));
+					search_begin = match_end;
+				} while(global && regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end));
+			}
+			if(idx) {
+				retVar->addChild("input", c->newScriptVar(str));
+				retVar->addChild("index", c->newScriptVar((int)offset));
+				c->setReturnVar(retVar);
+			} else
+				c->setReturnVar(c->constScriptVar(Null));
+		} catch(regex_error e) {
+			c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
+		}
+	}
+}
+#endif /* NO_REGEXP */
+
+static void scStringSearch(const CFunctionsScopePtr &c, void *userdata) {
+	string str = this2string(c);
+
+	string substr;
+	bool global, ignoreCase, sticky;
+	getRegExpData(c, "regexp", true, "flags", substr, global, ignoreCase, sticky);
+	string::const_iterator search_begin=str.begin(), match_begin, match_end;
+#ifndef NO_REGEXP
+	try { 
+		c->setReturnVar(c->newScriptVar(regex_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)?match_begin-search_begin:-1));
+	} catch(regex_error e) {
+		c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
+	}
+#else /* NO_REGEXP */
+	c->setReturnVar(c->newScriptVar(string_search(str, search_begin, substr, ignoreCase, sticky, match_begin, match_end)?match_begin-search_begin:-1));
+#endif /* NO_REGEXP */ 
+}
+
+static void scStringSlice(const CFunctionsScopePtr &c, void *userdata) {
+	string str = this2string(c);
+	int length = c->getArgumentsLength()-((int)userdata & 1);
+	bool slice = ((int)userdata & 2) == 0;
+	int start = c->getArgument("start")->toNumber().toInt32();
+	int end = (int)str.size();
+	if(slice && start<0) start = str.size()+start;
+	if(length>1) {
+		end = c->getArgument("end")->toNumber().toInt32();
+		if(slice && end<0) end = str.size()+end;
+	}
+	if(!slice && end < start) { end^=start; start^=end; end^=start; }
+	if(start<0) start = 0;
+	if(start>=(int)str.size()) 
+		c->setReturnVar(c->newScriptVar(""));
+	else if(end <= start)
+		c->setReturnVar(c->newScriptVar(""));
+	else
+		c->setReturnVar(c->newScriptVar(str.substr(start, end-start)));
+}
+
+//static void scStringSplit(const CFunctionsScopePtr &c, void *) {
+//	const string str = this2string(c);
+
+//	string seperator;
+//	bool global, ignoreCase, sticky;
+//	CScriptVarRegExpPtr RegExp = getRegExpData(c, "separator", true, 0, seperator, global, ignoreCase, sticky);
+
+//	CScriptVarPtr sep_var = c->getArgument("separator");
+//	CScriptVarPtr limit_var = c->getArgument("limit");
+//	int limit = limit_var->isUndefined() ? 0x7fffffff : limit_var->toNumber().toInt32();
+
+//	CScriptVarPtr result(newScriptVar(c->getContext(), Array));
+//	c->setReturnVar(result);
+//	if(limit == 0 || !str.size())
+//		return;
+//	else if(sep_var->isUndefined()) {
+//		result->setArrayIndex(0, c->newScriptVar(str));
+//		return;
+//	}
+//	if(seperator.size() == 0) {
+//		for(int i=0; i<min((int)seperator.size(), limit); ++i)
+//			result->setArrayIndex(i, c->newScriptVar(str.substr(i,1)));
+//		return;
+//	}
+//	int length = 0;
+//	string::const_iterator search_begin=str.begin(), match_begin, match_end;
+//	smatch match;
+//	bool found=true;
+//	while(found) {
+//		if(RegExp) {
+//			try {
+//				found = regex_search(str, search_begin, seperator, ignoreCase, sticky, match_begin, match_end, match);
+//			} catch(regex_error e) {
+//				c->throwError(SyntaxError, string(e.what())+" - "+CScriptVarRegExp::ErrorStr(e.code()));
+//			}
+//		} else /* NO_REGEXP */
+//			found = string_search(str, search_begin, seperator, ignoreCase, sticky, match_begin, match_end);
+//		string f;
+//		if(found) {
+//			result->setArrayIndex(length++, c->newScriptVar(string(search_begin, match_begin)));
+//			if(length>=limit) break;
+//			for(uint32_t i=1; i<match.size(); i++) {
+//				if(match[i].matched)
+//					result->setArrayIndex(length++, c->newScriptVar(string(match[i].first, match[i].second)));
+//				else
+//					result->setArrayIndex(length++, c->constScriptVar(Undefined));
+//				if(length>=limit) break;
+//			}
+//			if(length>=limit) break;
+//			search_begin = match_end;
+//		} else {
+//			result->setArrayIndex(length++, c->newScriptVar(string(search_begin,str.end())));
+//			if(length>=limit) break;
+//		}
+//	}
+//}
+
+static void scStringSubstr(const CFunctionsScopePtr &c, void *userdata) {
+	string str = this2string(c);
+	int length = c->getArgumentsLength()-(int)userdata;
+	int start = c->getArgument("start")->toNumber().toInt32();
+	if(start<0 || start>=(int)str.size()) 
+		c->setReturnVar(c->newScriptVar(""));
+	else if(length>1) {
+		int length = c->getArgument("length")->toNumber().toInt32();
+		c->setReturnVar(c->newScriptVar(str.substr(start, length)));
+	} else
+		c->setReturnVar(c->newScriptVar(str.substr(start)));
+}
+
+static void scStringToLowerCase(const CFunctionsScopePtr &c, void *) {
+	string str = this2string(c);
+	transform(str.begin(), str.end(), str.begin(), ::tolower);
+	c->setReturnVar(c->newScriptVar(str));
+}
+
+static void scStringToUpperCase(const CFunctionsScopePtr &c, void *) {
+	string str = this2string(c);
+	transform(str.begin(), str.end(), str.begin(), ::toupper);
+	c->setReturnVar(c->newScriptVar(str));
+}
+
+static void scStringTrim(const CFunctionsScopePtr &c, void *userdata) {
+	string str = this2string(c);
+	string::size_type start = 0;
+	string::size_type end = string::npos;
+	if((((int)userdata) & 2) == 0) {
+		start = str.find_first_not_of(" \t\r\n");
+		if(start == string::npos) start = 0;
+	}
+	if((((int)userdata) & 1) == 0) {
+		end = str.find_last_not_of(" \t\r\n");
+		if(end != string::npos) end = 1+end-start;
+	}
+	c->setReturnVar(c->newScriptVar(str.substr(start, end)));
+}
+
+
+
+static void scCharToInt(const CFunctionsScopePtr &c, void *) {
+	string str = c->getArgument("ch")->toString();;
+	int val = 0;
+	if (str.length()>0)
+		val = (int)str.c_str()[0];
+	c->setReturnVar(c->newScriptVar(val));
+}
+
+
+static void scStringFromCharCode(const CFunctionsScopePtr &c, void *) {
+	char str[2];
+	str[0] = c->getArgument("char")->toNumber().toInt32();
+	str[1] = 0;
+	c->setReturnVar(c->newScriptVar(str));
+}
+
+//////////////////////////////////////////////////////////////////////////
+// RegExp-Stuff
+//////////////////////////////////////////////////////////////////////////
+
+#ifndef NO_REGEXP
+
+static void scRegExpTest(const CFunctionsScopePtr &c, void *) {
+	CScriptVarRegExpPtr This = c->getArgument("this");
+	if(This)
+		c->setReturnVar(This->exec(c->getArgument("str")->toString(), true));
+	else
+		c->throwError(TypeError, "Object is not a RegExp-Object in test(str)");
+}
+static void scRegExpExec(const CFunctionsScopePtr &c, void *) {
+	CScriptVarRegExpPtr This = c->getArgument("this");
+	if(This)
+		c->setReturnVar(This->exec(c->getArgument("str")->toString()));
+	else
+		c->throwError(TypeError, "Object is not a RegExp-Object in exec(str)");
+}
+#endif /* NO_REGEXP */
+
+// ----------------------------------------------- Register Functions
+void registerStringFunctions(CTinyJS *tinyJS) {}
+extern "C" void _registerStringFunctions(CTinyJS *tinyJS) {
+	CScriptVarPtr fnc;
+	// charAt
+	tinyJS->addNative("function String.prototype.charAt(pos)", scStringCharAt, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.charAt(this,pos)", scStringCharAt, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// charCodeAt
+	tinyJS->addNative("function String.prototype.charCodeAt(pos)", scStringCharCodeAt, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.charCodeAt(this,pos)", scStringCharCodeAt, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// concat
+	tinyJS->addNative("function String.prototype.concat()", scStringConcat, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.concat(this)", scStringConcat, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT);
+	// indexOf
+	tinyJS->addNative("function String.prototype.indexOf(search,pos)", scStringIndexOf, 0, SCRIPTVARLINK_BUILDINDEFAULT); // find the position of a string in a string, -1 if not
+	tinyJS->addNative("function String.indexOf(this,search,pos)", scStringIndexOf, 0, SCRIPTVARLINK_BUILDINDEFAULT); // find the position of a string in a string, -1 if not
+	// lastIndexOf
+	tinyJS->addNative("function String.prototype.lastIndexOf(search,pos)", scStringIndexOf, (void*)-1, SCRIPTVARLINK_BUILDINDEFAULT); // find the last position of a string in a string, -1 if not
+	tinyJS->addNative("function String.lastIndexOf(this,search,pos)", scStringIndexOf, (void*)-1, SCRIPTVARLINK_BUILDINDEFAULT); // find the last position of a string in a string, -1 if not
+	// localeCompare
+	tinyJS->addNative("function String.prototype.localeCompare(compareString)", scStringLocaleCompare, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.localeCompare(this,compareString)", scStringLocaleCompare, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// quote
+	tinyJS->addNative("function String.prototype.quote()", scStringQuote, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.quote(this)", scStringQuote, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+#ifndef NO_REGEXP
+	// match
+	tinyJS->addNative("function String.prototype.match(regexp, flags)", scStringMatch, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.match(this, regexp, flags)", scStringMatch, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+#endif /* !REGEXP */
+	// replace
+	tinyJS->addNative("function String.prototype.replace(substr, newsubstr, flags)", scStringReplace, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.replace(this, substr, newsubstr, flags)", scStringReplace, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// search
+	tinyJS->addNative("function String.prototype.search(regexp, flags)", scStringSearch, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.search(this, regexp, flags)", scStringSearch, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// slice
+	tinyJS->addNative("function String.prototype.slice(start,end)", scStringSlice, 0, SCRIPTVARLINK_BUILDINDEFAULT); // find the last position of a string in a string, -1 if not
+	tinyJS->addNative("function String.slice(this,start,end)", scStringSlice, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT); // find the last position of a string in a string, -1 if not
+	// split
+    //tinyJS->addNative("function String.prototype.split(separator,limit)", scStringSplit, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+    //tinyJS->addNative("function String.split(this,separator,limit)", scStringSplit, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// substr
+	tinyJS->addNative("function String.prototype.substr(start,length)", scStringSubstr, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.substr(this,start,length)", scStringSubstr, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT);
+	// substring
+	tinyJS->addNative("function String.prototype.substring(start,end)", scStringSlice, (void*)2, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.substring(this,start,end)", scStringSlice, (void*)3, SCRIPTVARLINK_BUILDINDEFAULT);
+	// toLowerCase toLocaleLowerCase currently the same function
+	tinyJS->addNative("function String.prototype.toLowerCase()", scStringToLowerCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.toLowerCase(this)", scStringToLowerCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.prototype.toLocaleLowerCase()", scStringToLowerCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.toLocaleLowerCase(this)", scStringToLowerCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// toUpperCase toLocaleUpperCase currently the same function
+	tinyJS->addNative("function String.prototype.toUpperCase()", scStringToUpperCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.toUpperCase(this)", scStringToUpperCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.prototype.toLocaleUpperCase()", scStringToUpperCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.toLocaleUpperCase(this)", scStringToUpperCase, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// trim
+	tinyJS->addNative("function String.prototype.trim()", scStringTrim, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.trim(this)", scStringTrim, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	// trimLeft
+	tinyJS->addNative("function String.prototype.trimLeft()", scStringTrim, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.trimLeft(this)", scStringTrim, (void*)1, SCRIPTVARLINK_BUILDINDEFAULT);
+	// trimRight
+	tinyJS->addNative("function String.prototype.trimRight()", scStringTrim, (void*)2, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function String.trimRight(this)", scStringTrim, (void*)2, SCRIPTVARLINK_BUILDINDEFAULT);
+
+	tinyJS->addNative("function charToInt(ch)", scCharToInt, 0, SCRIPTVARLINK_BUILDINDEFAULT); //  convert a character to an int - get its value
+	
+	tinyJS->addNative("function String.prototype.fromCharCode(char)", scStringFromCharCode, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+#ifndef NO_REGEXP
+	tinyJS->addNative("function RegExp.prototype.test(str)", scRegExpTest, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+	tinyJS->addNative("function RegExp.prototype.exec(str)", scRegExpExec, 0, SCRIPTVARLINK_BUILDINDEFAULT);
+#endif /* NO_REGEXP */
+}
+
Index: XmlTools2/trunk/XmlTools/libs/TinyJS_StringFunctions.h
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS_StringFunctions.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS_StringFunctions.h	(revision 905)
@@ -0,0 +1,40 @@
+/*
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+#pragma message("The include "__FILE__" is deprecated - StringFunctions now registered by default")
+
+#ifndef TINYJS_STRINGFUNCTIONS_H
+#define TINYJS_STRINGFUNCTIONS_H
+
+#include "TinyJS.h"
+
+/// Register useful functions with the TinyJS interpreter
+extern void DEPRECATED("is deprecated - StringFunctions now registered by default") registerStringFunctions(CTinyJS *tinyJS);
+
+#endif
Index: XmlTools2/trunk/XmlTools/libs/TinyJS_Threading.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS_Threading.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS_Threading.cpp	(revision 905)
@@ -0,0 +1,88 @@
+#include "TinyJS_Threading.h"
+
+#undef HAVE_THREADING
+#if !defined(NO_THREADING) && !defined(HAVE_CUSTOM_THREADING_IMPL)
+#	define HAVE_THREADING
+#	if defined(WIN32) && !defined(HAVE_PTHREAD)
+#		include <windows.h>
+#	else
+#		include <pthread.h>
+#	endif
+#endif
+
+#ifdef HAVE_THREADING 
+
+#ifndef HAVE_PTHREAD
+// simple pthreads 4 windows
+#	define pthread_t HANDLE
+#	define pthread_create(t, stack, fnc, a) *(t) = CreateThread(NULL, stack, (LPTHREAD_START_ROUTINE)fnc, a, 0, NULL)
+#	define pthread_join(t, v) WaitForSingleObject(t, INFINITE), GetExitCodeThread(t,(LPDWORD)v), CloseHandle(t)
+
+#	define pthread_mutex_t HANDLE
+#	define pthread_mutex_init(m, a)	*(m) = CreateMutex(NULL, false, NULL)
+#	define pthread_mutex_destroy(m)	CloseHandle(*(m));
+#	define pthread_mutex_lock(m)		WaitForSingleObject(*(m), INFINITE);
+#	define pthread_mutex_unlock(m)	ReleaseMutex(*(m));
+#endif
+
+class CScriptMutex_impl : public CScriptMutex::CScriptMutex_t {
+public:
+	CScriptMutex_impl() {
+		pthread_mutex_init(&mutex, NULL);
+	}
+	~CScriptMutex_impl() {
+		pthread_mutex_destroy(&mutex);
+	}
+	void lock() {
+		pthread_mutex_lock(&mutex);
+	}
+	void unlock() {
+		pthread_mutex_unlock(&mutex);
+	}
+	pthread_mutex_t mutex;
+};
+
+CScriptMutex::CScriptMutex() {
+	mutex = new CScriptMutex_impl;
+}
+
+CScriptMutex::~CScriptMutex() {
+	delete mutex;
+}
+
+class CScriptThread_impl : public CScriptThread::CScriptThread_t {
+public:
+	CScriptThread_impl(CScriptThread *_this) : activ(false), running(false), This(_this) {}
+	~CScriptThread_impl() {}
+	void Run() {
+		if(running) return;
+		activ = true;
+		pthread_create(&thread, NULL, (void*(*)(void*))ThreadFnc, this);
+		while(!running);
+	}
+	int Stop() {
+		if(!running) return -1;
+		void *retvar;
+		activ = false;
+		pthread_join(thread, &retvar);
+		running = false;
+		return (int)retvar;
+	}
+	bool isActiv() { return activ; }
+	static void *ThreadFnc(CScriptThread_impl *This) {
+		This->running = true;
+		return (void*) This->This->ThreadFnc();
+	}
+	bool activ;
+	bool running;
+	CScriptThread *This;
+	pthread_t thread;
+};
+
+CScriptThread::CScriptThread() {
+	thread = new CScriptThread_impl(this);
+}
+CScriptThread::~CScriptThread() {
+	delete thread;
+}
+#endif // HAVE_THREADING
Index: XmlTools2/trunk/XmlTools/libs/TinyJS_Threading.h
===================================================================
--- XmlTools2/trunk/XmlTools/libs/TinyJS_Threading.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/TinyJS_Threading.h	(revision 905)
@@ -0,0 +1,70 @@
+#ifndef TinyJS_Threading_h__
+#define TinyJS_Threading_h__
+#include "config.h"
+#ifndef NO_THREADING
+/*
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+class CScriptMutex {
+public:
+	CScriptMutex();
+	~CScriptMutex();
+	void lock() { mutex->lock(); }
+	void unlock() { mutex->unlock(); }
+	class CScriptMutex_t{
+	public:
+//		virtual ~CScriptMutex_t()=0;
+		virtual void lock()=0;
+		virtual void unlock()=0;
+	};
+private:
+	CScriptMutex_t *mutex;
+
+};
+
+class CScriptThread {
+public:
+	CScriptThread();
+	virtual ~CScriptThread();
+	void Run() { thread->Run(); }
+	int Stop() { return thread->Stop(); }
+	virtual int ThreadFnc()=0;
+	bool isActiv() { return thread->isActiv(); }
+	class CScriptThread_t{
+	public:
+		virtual void Run()=0;
+		virtual int Stop()=0;
+		virtual bool isActiv()=0;
+	};
+private:
+	CScriptThread_t *thread;
+};
+
+#endif // NO_THREADING
+#endif // TinyJS_Threading_h__
Index: XmlTools2/trunk/XmlTools/libs/config.h
===================================================================
--- XmlTools2/trunk/XmlTools/libs/config.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/config.h	(revision 905)
@@ -0,0 +1,129 @@
+#ifndef _42TinyJS_config_h__
+#define _42TinyJS_config_h__
+
+/*
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+//////////////////////////////////////////////////////////////////////////
+
+/* POOL-ALLOCATOR 
+ * ==============
+ * To speed-up new & delete 42TinyJS adds an object-pool
+ * The pool is activated by default.
+ * To deactivate this stuff define NO_POOL_ALLOCATOR 
+ */
+//#define NO_POOL_ALLOCATOR
+
+/*
+ * for debugging-stuff you can define DEBUG_POOL_ALLOCATOR
+ * if a memory-leak detected the allocator usage is printed to stderr
+ */
+//#define DEBUG_POOL_ALLOCATOR
+/*
+ * with define LOG_POOL_ALLOCATOR_MEMORY_USAGE
+ * the allocator usage is always printed to stderr
+ */
+//#define LOG_POOL_ALLOCATOR_MEMORY_USAGE
+
+// NOTE: _DEBUG or LOG_POOL_ALLOCATOR_MEMORY_USAGE implies DEBUG_POOL_ALLOCATOR
+
+//////////////////////////////////////////////////////////////////////////
+
+/* REGEXP-SUPPORT
+ * ==============
+ * The RegExp-support needs boost-regex or TR1-regex
+ * To deactivate this stuff define NO_REGEXP 
+ */
+//#define NO_REGEXP
+
+/* if NO_REGEXP not defined <regex> is included and std::regex is used
+ * you can define HAVE_BOOST_REGEX and <boost/regex.hpp> is included and boost::regex is used
+ */
+#define HAVE_BOOST_REGEX
+
+/* or you can define HAVE_TR1_REGEX and <tr1/regex> is included and std::tr1::regex is used
+ */
+//#define HAVE_TR1_REGEX
+
+
+//////////////////////////////////////////////////////////////////////////
+
+/* LET-STUFF
+ * =========
+ * Redeclaration of LET-vars is not allowed in block-scopes.
+ * But in the root- and functions-scopes it is currently allowed
+ * In future ECMAScript versions this will be also in root-and functions-scopes forbidden
+ * To enable the future behavior define PREVENT_REDECLARATION_IN_FUNCTION_SCOPES
+ */
+//#define PREVENT_REDECLARATION_IN_FUNCTION_SCOPES
+
+
+//////////////////////////////////////////////////////////////////////////
+
+/* MULTI-THREADING
+ * ===============
+ * 42TinyJS is basically thread-save.
+ * You can run different or the same JS-code simultaneously in different instances of class TinyJS. 
+ * The threading-stuff is currently only needed by the pool-allocator
+ * to deactivate threading define NO_THREADING
+ * NOTE: if NO_POOL_ALLOCATOR not defined you can not run JS-code simultaneously
+ *       NO_POOL_ALLOCATOR implies NO_THREADING
+ */
+
+//#define NO_THREADING
+
+/* on Windows the windows-threading-API is used by default.
+ * on non-Windows (WIN32 is not defined) it is tried to use the POSIX pthread-API
+ * to force the pthread-API define HAVE_PTHREAD (windows needs in this case 
+ *   a pthread-lib e.g http://http://sourceware.org/pthreads-win32/)
+ */
+//#define HAVE_PTHREAD
+
+/* you can implement your own custom thread-implementation.
+ * to prevent the using of the win- or pthread-API define HAVE_CUSTOM_THREADING_IMPL
+ */
+//#define HAVE_CUSTOM_THREADING_IMPL
+
+////////////////////////////////////////////////
+// DO NOT MAKE CHANGES OF THE FOLLOWING STUFF //
+////////////////////////////////////////////////
+
+#if defined(NO_POOL_ALLOCATOR) && !defined(NO_THREADING)
+#	define NO_THREADING
+#endif
+
+#if !defined(NO_POOL_ALLOCATOR) && defined(NO_THREADING)
+#pragma message("\n***********************************************************************\n\
+* You have defined NO_THREADING and not defined NO_POOL_ALLOCATOR\n\
+* NOTE: you can not run JS-code simultaneously in different threads\n\
+***********************************************************************\n")
+#endif
+
+
+#endif // _42TinyJS_config_h__
Index: XmlTools2/trunk/XmlTools/libs/jsxml.js
===================================================================
--- XmlTools2/trunk/XmlTools/libs/jsxml.js	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/jsxml.js	(revision 905)
@@ -0,0 +1,497 @@
+//////////////////////////////////////////////////////////
+////////// JSXML XML Tools                    ////////////
+////////// Ver 1.3 Aug 29 2009                ////////////
+////////// Copyright 2000-2009 Peter Tracey   ////////////
+////////// http://levelthreesoltions.com/jsxml/
+////
+////	Objects:
+////
+////	REXML
+////    Regular Expression-based XML parser
+////
+////	JSXMLIterator
+////    Iterates through the tree structure without recursion
+////
+////	JSXMLBuilder
+////    Loads xml into a linear structure and provides 
+////	interface for adding and removing elements 
+////	and setting attributes, generates XML
+////
+////	Utility functions:
+////
+////	ParseAttribute
+////    Takes string of attibutes and attribute name
+////    Returns attribute value
+////
+////	Array_Remove
+////    Removes element in array
+////
+////	Array_Add
+////    Adds element to array
+////
+////	RepeatChar
+////    Repeats string specified number of times
+////
+///////////////////////////////////////////////////////////////
+
+
+function REXML(XML) {
+	this.XML = XML;
+
+	this.rootElement = null;
+
+	this.parse = REXML_parse;
+	if (this.XML && this.XML !== "") this.parse();
+}
+
+	function REXML_parse() {
+		var reTag = new RegExp("<([^>/ ]*)([^>]*)>","g"); // matches that tag name $1 and attribute string $2
+		var reTagText = new RegExp("<([^>/ ]*)([^>]*)>([^<]*)","g"); // matches tag name $1, attribute string $2, and text $3
+		var strType = "";
+		var strTag = "";
+		var strText = "";
+		var strAttributes = "";
+		var strOpen = "";
+		var strClose = "";
+		var iElements = 0;
+		var xmleLastElement = null;
+		if (this.XML.length === 0) return;
+		var arrElementsUnparsed = this.XML.match(reTag);
+		var arrElementsUnparsedText = this.XML.match(reTagText);
+		var i=0;
+		if (arrElementsUnparsed[0].replace(reTag, "$1") == "?xml") i++;
+
+		for (; i<arrElementsUnparsed.length; i++) {
+			strTag = arrElementsUnparsed[i].replace(reTag,"$1");
+			strAttributes = arrElementsUnparsed[i].replace(reTag,"$2");
+			strText = arrElementsUnparsedText[i].replace(reTagText,"$3").replace(/[\r\n\t ]+/g, " "); // remove white space
+			strClose = "";
+			if (strTag.indexOf("![CDATA[") === 0) {
+				strOpen = "<![CDATA[";
+				strClose = "]]>";
+				strType = "cdata";
+			} else if (strTag.indexOf("!--") === 0) {
+				strOpen = "<!--";
+				strClose = "-->";
+				strType = "comment";
+			} else if (strTag.indexOf("?") === 0) {
+				strOpen = "<?";
+				strClose = "?>";
+				strType = "pi";
+			} else strType = "element";
+			if (strClose !== "") {
+				strText = "";
+				if (arrElementsUnparsedText[i].indexOf(strClose) > -1) strText = arrElementsUnparsedText[i];
+				else {
+					for (; i<arrElementsUnparsed.length && arrElementsUnparsedText[i].indexOf(strClose) == -1; i++) {
+						strText += arrElementsUnparsedText[i];
+					}
+					strText += arrElementsUnparsedText[i];
+				}
+				if (strText.substring(strOpen.length, strText.indexOf(strClose)) !== "")	{
+					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, "","",xmleLastElement,strText.substring(strOpen.length, strText.indexOf(strClose)));
+					if (strType == "cdata") xmleLastElement.text += strText.substring(strOpen.length, strText.indexOf(strClose));
+				}
+				if (strText.indexOf(strClose)+ strClose.length < strText.length) {
+					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText.substring(strText.indexOf(strClose)+ strClose.length, strText.length));
+					if (strType == "cdata") xmleLastElement.text += strText.substring(strText.indexOf(strClose)+ strClose.length, strText.length);
+				}
+				continue;
+			}
+			if (strText.replace(/ */, "") === "") strText = "";
+			if (arrElementsUnparsed[i].substring(1,2) != "/") {
+				if (iElements === 0) {
+					xmleLastElement = this.rootElement = new REXML_XMLElement(strType, strTag,strAttributes,null,strText);
+					iElements++;
+					if (strText !== "") xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
+				} else if (arrElementsUnparsed[i].substring(arrElementsUnparsed[i].length-2,arrElementsUnparsed[i].length-1) != "/") {
+					xmleLastElement = xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, strTag,strAttributes,xmleLastElement,"");
+					iElements++;
+					if (strText !== "") {
+						xmleLastElement.text += strText;
+						xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
+					}
+				} else {
+					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, strTag,strAttributes,xmleLastElement,strText);
+					if (strText !== "") xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
+				}
+			} else {
+				xmleLastElement = xmleLastElement.parentElement;
+				iElements--;
+				if (xmleLastElement && strText !== "") {
+					xmleLastElement.text += strText;
+					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
+				}
+			}
+		}
+	}
+
+	function REXML_XMLElement(strType, strName, strAttributes, xmlParent, strText) {
+		this.type = strType;
+		this.name = strName;
+		this.attributeString = strAttributes;
+		this.attributes = null;
+		this.childElements = [];
+		this.parentElement = xmlParent;
+		this.text = strText; // text of element
+
+		this.getText = REXML_XMLElement_getText; // text of element and child elements
+		this.childElement = REXML_XMLElement_childElement;
+		this.attribute = REXML_XMLElement_attribute;
+	}
+
+		function REXML_XMLElement_getText() {
+			if (this.type == "text" || this.type == "cdata") {
+				return this.text;
+			} else if (this.childElements.length) {
+				var L = "";
+				for (var i=0; i<this.childElements.length; i++) {
+					L += this.childElements[i].getText();
+				}
+				return L;
+			} else return "";
+		}
+		
+		function REXML_XMLElement_childElement(strElementName) {
+			for (var i=0; i<this.childElements.length; i++) if (this.childElements[i].name == strElementName) return this.childElements[i];
+			return null;
+		}
+
+		function REXML_XMLElement_attribute(strAttributeName) {
+			if (!this.attributes) {
+				var reAttributes = new RegExp(" ([^= ]*)=","g"); // matches attributes
+				if (this.attributeString.match(reAttributes) && this.attributeString.match(reAttributes).length) {
+					var arrAttributes = this.attributeString.match(reAttributes);
+					if (!arrAttributes.length) arrAttributes = null;
+					else for (var j=0; j<arrAttributes.length; j++) {
+						arrAttributes[j] = new Array(
+							(arrAttributes[j]+"").replace(/[= ]/g,""),
+							ParseAttribute(this.attributeString, (arrAttributes[j]+"").replace(/[= ]/g,""))
+										);
+					}
+					this.attributes = arrAttributes;
+				}
+			}
+			if (this.attributes) for (var i=0; i<this.attributes.length; i++) if (this.attributes[i][0] == strAttributeName) return this.attributes[i][1];
+			return "";
+		}
+
+
+function JSXMLBuilder() {
+	this.XML = "";
+	this.elements = [];
+	Array.prototype.remove = Array_Remove;
+	Array.prototype.add = Array_Add;
+
+	this.load = JSXMLBuilder_load;
+	this.element = JSXMLBuilder_element;
+	this.addElementAt = JSXMLBuilder_addElementAt;
+	this.insertElementAt = JSXMLBuilder_insertElementAt;
+	this.removeElement = JSXMLBuilder_removeElement;
+	this.generateXML = JSXMLBuilder_generateXML;
+	this.moveElement = JSXMLBuilder_moveElement;
+}
+
+	function JSXMLBuilder_load(strXML, xmleElem) {
+		this.XML = strXML;
+
+		if (!xmleElem) {
+			if (strXML.length) xmleElem = (new REXML(strXML)).rootElement;
+			else return false;
+		}
+
+		var xmlBuilder = new JSXMLIterator(xmleElem);
+
+		while (true) {
+			if (xmlBuilder.xmleElem.type == "element") {
+				if (xmlBuilder.xmleElem.attributes) {
+					this.addElementAt(xmlBuilder.xmleElem.name,xmlBuilder.xmleElem.attributes, xmlBuilder.xmleElem.text, this.elements.length, xmlBuilder.iElemLevel);
+				} else {	
+					this.addElementAt(xmlBuilder.xmleElem.name,xmlBuilder.xmleElem.attributeString, xmlBuilder.xmleElem.text, this.elements.length, xmlBuilder.iElemLevel);
+				}
+			}
+			if (!xmlBuilder.getNextNode(false)) break;
+		}
+		for (var i=0; i<this.elements.length; i++) this.elements[i].index = i;
+	}
+
+	function JSXMLBuilder_element(iIndex) {
+		return this.elements[iIndex];
+	}
+
+	function JSXMLBuilder_addElementAt(strElement,Attributes,strText,iElemIndex,iElemLevel) {
+		iElemIndex = parseInt(iElemIndex);
+		iElemLevel = parseInt(iElemLevel);
+		if (iElemIndex < 0 || typeof(iElemIndex) != "number" || isNaN(iElemIndex)) iElemIndex = (this.elements.length>0) ? this.elements.length-1 : 0;
+		if (iElemLevel < 0 || typeof(iElemLevel) != "number" || isNaN(iElemLevel)) iElemLevel = this.elements[iElemIndex-1].level;
+		if (!Attributes) Attributes = "";
+		var Elem = [];
+		var iAddIndex = iElemIndex;
+		if (iElemIndex > 0) {
+			for (var i=iElemIndex; i<this.elements.length; i++) if (this.elements[i].level > iElemLevel) iAddIndex++;
+			else if (this.elements[i].level <= this.elements[iElemIndex].level) break;
+			Elem = new JSXMLBuilder_XMLElement(strElement,Attributes,strText,iElemLevel+1,this);
+		} else {
+			Elem = new JSXMLBuilder_XMLElement(strElement,Attributes,strText,1,this);
+		}
+		this.elements = this.elements.add(iAddIndex,Elem);
+		for (var i=iAddIndex; i<this.elements.length; i++) this.elements[i].index = i;
+	}
+
+	function JSXMLBuilder_insertElementAt(strElement,Attributes,strText,iElemIndex,iElemLevel) {
+		iElemIndex = parseInt(iElemIndex);
+		iElemLevel = parseInt(iElemLevel);
+		if (iElemIndex < 0 || typeof(iElemIndex) != "number" || isNaN(iElemIndex)) iElemIndex = (this.elements.length>0) ? this.elements.length-1 : 0;
+		if (iElemLevel < 0 || typeof(iElemLevel) != "number" || isNaN(iElemLevel)) iElemLevel = this.elements[iElemIndex-1].level;
+		if (!Attributes) Attributes = "";
+		var Elem = null;
+		var iAddIndex = iElemIndex;
+		if (iElemIndex > 0 && iElemLevel > 0) {
+			Elem = new JSXMLBuilder_XMLElement(strElement,Attributes,strText,iElemLevel+1,this);
+		} else {
+			Elem = new JSXMLBuilder_XMLElement(strElement,Attributes,strText,1,this);
+		}
+		this.elements = this.elements.add(iAddIndex,Elem);
+		for (var i=iAddIndex; i<this.elements.length; i++) this.elements[i].index = i;
+	}
+
+
+	function JSXMLBuilder_removeElement(iElemIndex) {
+		iElemIndex = parseInt(iElemIndex);
+		for (var iAfterElem=iElemIndex+1; iAfterElem<this.elements.length; iAfterElem++) if (this.elements[iAfterElem].level < this.elements[iElemIndex].level+1) break;
+
+		this.elements = this.elements.slice(0,iElemIndex).concat(this.elements.slice(iAfterElem,this.elements.length));
+		for (var i=iElemIndex; i<this.elements.length; i++) this.elements[i].index = i;
+	}
+
+	function JSXMLBuilder_moveElement(iElem1Index,iElem2Index) {
+		var arrElem1Elements = new Array(this.elements[iElem1Index]);
+		var arrElem2Elements = new Array(this.elements[iElem2Index]);
+		for (var i=iElem1Index; i<this.elements.length; i++) if (this.elements[i].level > this.elements[iElem1Index].level) arrElem1Elements[arrElem1Elements.length] = this.elements[i]; else if (i>iElem1Index) break;
+		for (var i=iElem2Index; i<this.elements.length; i++) if (this.elements[i].level > this.elements[iElem2Index].level) arrElem2Elements[arrElem2Elements.length] = this.elements[i]; else if (i>iElem2Index) break;
+		var arrMovedElements = [];
+		if (iElem1Index < iElem2Index) {
+			for (i=0; i<iElem1Index; i++) arrMovedElements[arrMovedElements.length] = this.elements[i]; // start to the 1st element
+			for (i=iElem1Index+arrElem1Elements.length; i<iElem2Index+arrElem2Elements.length; i++) arrMovedElements[arrMovedElements.length] = this.elements[i]; // end of 1st element to end of 2nd element
+			for (i=0; i<arrElem1Elements.length; i++) arrMovedElements[arrMovedElements.length] = arrElem1Elements[i]; // 1st element and all child elements
+			for (i=iElem2Index+arrElem2Elements.length; i<this.elements.length; i++) arrMovedElements[arrMovedElements.length] = this.elements[i]; // end of 2nd element to end
+			this.elements = arrMovedElements;
+		} else {
+			for (i=0; i<iElem2Index; i++) arrMovedElements[arrMovedElements.length] = this.elements[i]; // start to the 2nd element
+			for (i=0; i<arrElem1Elements.length; i++) arrMovedElements[arrMovedElements.length] = arrElem1Elements[i]; // 1st element and all child elements
+			for (i=iElem2Index; i<iElem1Index; i++) arrMovedElements[arrMovedElements.length] = this.elements[i]; // 2nd element to 1st element
+			for (i=iElem1Index+arrElem1Elements.length; i<this.elements.length; i++) arrMovedElements[arrMovedElements.length] = this.elements[i]; // end of 1st element to end
+			this.elements = arrMovedElements;
+		}
+		for (var i=0; i<this.elements.length; i++) this.elements[i].index = i;
+	}
+
+
+	function JSXMLBuilder_generateXML(bXMLTag) {
+		var strXML = "";
+		var arrXML = [];
+		if (bXMLTag) strXML += '<?xml version="1.0"?>\n\n';
+		for (var i=0; i<this.elements.length; i++) {
+			strXML += RepeatChar("\t",this.elements[i].level-1);
+			strXML += "<" + this.element(i).name; // open tag
+			if (this.element(i).attributes) {
+				for (var j=0; j<this.element(i).attributes.length; j++) { // set attributes
+					if (this.element(i).attributes[j]) {
+						strXML += ' ' + this.element(i).attributes[j][0] + '="' + this.element(i).attributes[j][1] + '"';
+					}
+				}
+			} else strXML += this.element(i).attributeString.replace(/[\/>]$/gi, "");
+			if (((this.elements[i+1] && this.elements[i+1].level <= this.elements[i].level) || // next element is a lower or equal to
+				(!this.elements[i+1] && this.elements[i-1])) // no next element, previous element
+				&& this.element(i).text === "") {
+				strXML += "/";
+			}
+			strXML += ">";
+			if (this.element(i).text !== "") strXML += this.element(i).text;
+			else strXML += "\n";
+			if (((this.elements[i+1] && this.elements[i+1].level <= this.elements[i].level) || // next element is a lower or equal to
+				(!this.elements[i+1] && this.elements[i-1])) // no next element, previous element
+				&& this.element(i).text !== "") strXML += "</" + this.element(i).name + ">\n";
+			if (!this.elements[i+1]) {
+				var lastelem = i;
+				for (var j=i; j>-1; j--) {
+					if (this.elements[j].level >= this.elements[i].level) continue;
+					else {
+						if (this.elements[j].level < this.elements[lastelem].level) {
+							strXML += RepeatChar("\t",this.elements[j].level-1) + "</" + this.element(j).name + ">\n";
+							lastelem = j;
+						}
+					}
+				}
+			} else {
+				if (this.elements[i+1].level < this.elements[i].level) {
+					var lastelem = i;
+					for (var j=i; this.elements[j].level>=this.elements[i+1].level; j--) {
+						if (this.elements[i] && this.elements[j] && this.elements[j].level < this.elements[i].level && this.elements[j].level < this.elements[lastelem].level) {
+							strXML += RepeatChar("\t",this.elements[j].level-1) + "</" + this.element(j).name + ">\n";
+							lastelem = j;
+						}
+					}
+				}
+			}
+			if (strXML.length > 1000) {
+				arrXML[arrXML.length] = strXML;
+				strXML = "";
+			}
+		}
+		arrXML[arrXML.length] = strXML;
+		return arrXML.join("");
+	}
+
+	function JSXMLBuilder_XMLElement(strName,Attributes,strText,iLevel,xmlBuilder) {
+		this.type = "element";
+		this.name = strName;
+		this.attributes = (typeof(Attributes) != "string") ? Attributes : null;
+		this.attributeString = (typeof(Attributes) == "string") ? Attributes : "";
+		this.text = strText;
+		this.level = iLevel;
+		this.index = -1;
+		this.xmlBuilder = xmlBuilder;
+
+		this.parseAttributes = JSXMLBuilder_XMLElement_parseAttributes;
+		this.attribute = JSXMLBuilder_XMLElement_attribute;
+		this.setAttribute = JSXMLBuilder_XMLElement_setAttribute;
+		this.removeAttribute = JSXMLBuilder_XMLElement_removeAttribute;
+		this.parentElement = JSXMLBuilder_XMLElement_parentElement;
+		this.childElement = JSXMLBuilder_XMLElement_childElement;
+	}
+
+		function JSXMLBuilder_XMLElement_parseAttributes() {
+			if (!this.attributes) {
+				var reAttributes = new RegExp(" ([^= ]*)=","g"); // matches attributes
+				if (this.attributeString.match(reAttributes) && this.attributeString.match(reAttributes).length) {
+					var arrAttributes = this.attributeString.match(reAttributes);
+					if (!arrAttributes.length) arrAttributes = null;
+					else for (var j=0; j<arrAttributes.length; j++) {
+						arrAttributes[j] = new Array(
+							(arrAttributes[j]+"").replace(/[= ]/g,""),
+							ParseAttribute(this.attributeString, (arrAttributes[j]+"").replace(/[= ]/g,""))
+										);
+					}
+					this.attributes = arrAttributes;
+				}
+			}
+		}
+	
+		function JSXMLBuilder_XMLElement_attribute(AttributeName) {
+			if (!this.attributes) this.parseAttributes();
+			if (this.attributes) for (var i=0; i<this.attributes.length; i++) if (this.attributes[i][0] == AttributeName) return this.attributes[i][1];
+			return "";
+		}
+
+		function JSXMLBuilder_XMLElement_setAttribute(AttributeName,Value) {
+			if (!this.attributes) this.parseAttributes();
+			if (this.attributes) for (var i=0; i<this.attributes.length; i++) if (this.attributes[i][0] == AttributeName) {
+				this.attributes[i][1] = Value;
+				return;
+			}
+			this.attributes[this.attributes.length] = new Array(AttributeName,Value);
+		}
+
+		function JSXMLBuilder_XMLElement_removeAttribute(AttributeName,Value) {
+			if (!this.attributes) this.parseAttributes();
+			if (this.attributes) for (var i=0; i<this.attributes.length; i++) if (this.attributes[i][0] == AttributeName) {
+				this.attributes = this.attributes.remove(i);
+				return;
+			}
+		}
+
+		function JSXMLBuilder_XMLElement_parentElement() {
+			for (var i=this.index; this.xmlBuilder.element(i) && this.xmlBuilder.element(i).level != this.level-1; i--);
+			return this.xmlBuilder.element(i);
+		}
+
+		function JSXMLBuilder_XMLElement_childElement(Child) {
+			var iFind = -1;
+			for (var i=this.index+1; i<this.xmlBuilder.elements.length; i++) {
+				if (this.xmlBuilder.elements[i].level == this.level+1) {
+					iFind++;
+					if (iFind == Child || this.xmlBuilder.elements[i].name == Child) return this.xmlBuilder.elements[i];
+				} else if (this.xmlBuilder.elements[i].level <= this.level) break;
+			}
+			return null;
+		}
+
+
+function JSXMLIterator(xmleElem) {
+	this.xmleElem = xmleElem;
+	
+	this.iElemIndex = 0;
+	this.arrElemIndex = new Array(0);
+	this.iElemLevel = 0;
+	this.iElem = 0;
+	this.arrElemIndex[this.iElemLevel] = -1;
+
+	this.getNextNode = JSXMLIterator_getNextNode;
+}
+
+	function JSXMLIterator_getNextNode() {
+		if (!this.xmleElem || this.iElemLevel<0)	return false;
+		if (this.xmleElem.childElements.length) {  // move up
+			this.arrElemIndex[this.iElemLevel]++;
+			this.iElemIndex++;
+			this.iElemLevel++;
+			this.arrElemIndex[this.iElemLevel] = 0;
+			this.xmleElem = this.xmleElem.childElements[0];
+		} else { // move next
+			this.iElemIndex++;
+			this.arrElemIndex[this.iElemLevel]++;
+			if (this.xmleElem.parentElement && this.xmleElem.parentElement.childElements.length && this.arrElemIndex[this.iElemLevel] < this.xmleElem.parentElement.childElements.length) this.xmleElem = this.xmleElem.parentElement.childElements[this.arrElemIndex[this.iElemLevel]];
+			else {
+				if (this.iElemLevel>0) { // move down
+					for (; this.iElemLevel > 0; this.iElemLevel--) {
+						if (this.xmleElem.parentElement && this.xmleElem.parentElement.childElements[this.arrElemIndex[this.iElemLevel]]) {
+							this.xmleElem = this.xmleElem.parentElement.childElements[this.arrElemIndex[this.iElemLevel]];
+							this.iElemLevel++;
+							this.arrElemIndex = this.arrElemIndex.slice(0,this.iElemLevel+1);
+							break;
+						} else {
+							this.xmleElem = this.xmleElem.parentElement;
+						}
+					}
+					this.iElemLevel--;
+				} else {
+					return false;
+				}
+			}
+		}
+		return (typeof(this.xmleElem) == "object" && this.iElemLevel > -1);
+	}
+
+function ParseAttribute(str,Attribute) {
+	var str = str +  ">";
+	if (str.indexOf(Attribute + "='")>-1) var Attr = new RegExp(".*" + Attribute + "='([^']*)'.*>");
+	else if (str.indexOf(Attribute + '="')>-1) var Attr = new RegExp(".*" + Attribute + '="([^"]*)".*>');
+	return str.replace(Attr, "$1");
+}
+
+function Array_Remove(c) {
+	var tmparr = [];
+	for (var i=0; i<this.length; i++) if (i!=c) tmparr[tmparr.length] = this[i];
+	return tmparr;
+}
+
+function Array_Add(c, cont) {
+	if (c == this.length) {
+		this[this.length] = cont;
+		return this;
+	}
+	var tmparr = [];
+	for (var i=0; i<this.length; i++) {
+		if (i==c) tmparr[tmparr.length] = cont;
+		tmparr[tmparr.length] = this[i];
+	}
+	if (!tmparr[c]) tmparr[c] = cont;
+	return tmparr;
+}
+
+function RepeatChar(sChar,iNum) {
+	var L = "";
+	for (var i=0; i<iNum; i++) L += sChar;
+	return L;
+}
Index: XmlTools2/trunk/XmlTools/libs/pool_allocator.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/pool_allocator.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/pool_allocator.cpp	(revision 905)
@@ -0,0 +1,258 @@
+/*
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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.
+ */
+
+#include "pool_allocator.h"
+#include <vector>
+#include <algorithm>
+#include <stdio.h>
+
+struct block {
+	block* next;
+};
+struct block_head {
+	block_head* next;
+};
+
+static void set_next(void* p, void* next) {
+	static_cast<block*>(p)->next = static_cast<block*>(next);
+}
+
+static void* get_next(void* p) {
+	return static_cast<block*>(p)->next;
+}
+
+fixed_size_allocator::fixed_size_allocator( size_t numObjects, size_t objectSize, const char *for_class )
+{
+	num_objects = numObjects;
+	object_size = objectSize >= sizeof(block) ? objectSize : sizeof(block);
+
+	head_of_free_list = head = 0;
+
+#ifdef DEBUG_POOL_ALLOCATOR
+	if(for_class) name = for_class;
+	allocs=
+	frees=
+	max =
+	current=
+	blocks =
+#endif
+	refs = 0;
+}
+
+fixed_size_allocator::~fixed_size_allocator()
+{
+	while(head) {
+		char *p = (char*)head;
+		head = head->next;
+		delete [] p;
+	}
+#ifdef DEBUG_POOL_ALLOCATOR
+#	ifndef LOG_POOL_ALLOCATOR_MEMORY_USAGE
+	if(refs) {
+#	endif
+	fprintf(stderr, "allocator [%s](%d) destroyed\n", name.c_str(), object_size);
+	fprintf(stderr, "  allocs:%i, ", allocs);
+	fprintf(stderr, "frees:%i, ", frees);
+	fprintf(stderr, "max:%i, ", max);
+	fprintf(stderr, "blocks:%i\n", blocks);
+	if(refs) fprintf(stderr, "************ %i x not freed ************\n", refs);
+	fprintf(stderr, "\n");
+#	ifndef LOG_POOL_ALLOCATOR_MEMORY_USAGE
+	}
+#	endif
+#endif
+}
+
+void* fixed_size_allocator::_alloc( size_t ) {
+	refs++;
+#ifdef DEBUG_POOL_ALLOCATOR
+	allocs++;current++;
+	if(current>max)max=current;
+#endif
+	void* p = head_of_free_list;
+	if(p)  {
+		head_of_free_list = get_next(p);
+	} else {
+
+		char* new_block = new char[sizeof(block_head) + num_objects * object_size];
+		((block_head*)new_block)->next = head;
+		head = (block_head*)new_block;
+		new_block += sizeof(block_head);
+		for(std::size_t i = object_size; i < (num_objects - 1) * object_size; i += object_size) {
+			set_next(&new_block[i], &new_block[i + object_size]);
+		}
+		set_next(&new_block[(num_objects - 1) * object_size], 0);
+		p = new_block;
+		head_of_free_list = &new_block[object_size];
+
+#ifdef DEBUG_POOL_ALLOCATOR
+		blocks++;
+#endif
+	}
+	return p;
+}
+#include <assert.h>
+#ifndef ASSERT
+#	define ASSERT(X) assert(X)
+#endif
+
+bool fixed_size_allocator::_free( void* p, size_t ) {
+	if(p == 0) return refs==0;
+	refs--;
+#ifdef DEBUG_POOL_ALLOCATOR
+	ASSERT(refs>=0);
+	frees++;current--;
+#endif
+	block* dead_object = static_cast<block*>(p);
+
+	dead_object->next = static_cast<block*>(head_of_free_list);
+	head_of_free_list = dead_object;
+	return refs==0;
+}
+typedef std::vector<fixed_size_allocator*> allocator_pool_t;
+typedef allocator_pool_t::iterator allocator_pool_it;
+
+static bool compare_allocator_pool(fixed_size_allocator *allocator, size_t Size) {
+	return allocator->objectSize() < Size;
+}
+
+static class _allocator_pool
+{
+public:
+	_allocator_pool() : allocator_pool(0) {
+#ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
+	last_ok = last_access = 0;
+#endif
+	}
+	~_allocator_pool() {
+		if(allocator_pool && !allocator_pool->empty())
+			for(allocator_pool_it it = allocator_pool->begin(); it!=allocator_pool->end(); it++)
+				delete *it;
+		delete allocator_pool;
+#ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
+		if(last_access) fprintf(stderr, "last_ok:%i(%i)=%i%%\n", last_ok, last_access, (last_ok*100)/last_access);
+#endif
+	}
+	allocator_pool_it *findAllocator(size_t size, allocator_pool_it &it) {
+		if(!allocator_pool) return 0;
+		it = lower_bound(allocator_pool->begin(), allocator_pool->end(), size, compare_allocator_pool);
+		if(it != allocator_pool->end() && (*it)->objectSize() == size)
+			return &it;
+		return 0;
+	}
+	fixed_size_allocator *checkLastAllocator(size_t size) {
+#ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
+		last_access++;
+#endif
+		if(last_allocate_allocator && last_allocate_allocator->objectSize()==size) {
+#ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
+			last_ok++;
+#endif
+			return last_allocate_allocator;
+		}
+		else if(last_free_allocator && last_free_allocator->objectSize()==size) {
+#ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
+			last_ok++;
+#endif
+			return last_free_allocator;
+		} else
+			return 0;
+	}
+	void removeAllocator(allocator_pool_it it) {
+		if(last_allocate_allocator == *it) last_allocate_allocator = 0;
+		if(last_free_allocator == *it) last_free_allocator = 0;
+		delete *it; allocator_pool->erase(it);
+		if(allocator_pool->empty()) { 
+			delete allocator_pool; allocator_pool=0; 
+		}
+	}
+	allocator_pool_t *allocator_pool;
+	fixed_size_allocator *last_allocate_allocator;
+	fixed_size_allocator *last_free_allocator;
+#ifdef LOG_POOL_ALLOCATOR_MEMORY_USAGE
+	int last_ok;
+	int last_access;
+#endif
+}allocator_pool;
+
+//#define WITH_TIME_LOGGER
+#include "time_logger.h"
+
+TimeLoggerCreate(alloc, false);
+TimeLoggerCreate(free, false);
+#ifdef NO_THREADING
+#	define LOCK do{}while(0)
+#else
+CScriptMutex fixed_size_allocator::locker;
+class lock_help {
+public:
+	lock_help() { fixed_size_allocator::locker.lock(); }
+	~lock_help() { fixed_size_allocator::locker.unlock(); }
+};
+#define LOCK lock_help lock
+#endif
+void* fixed_size_allocator::alloc(size_t size, const char *for_class) {
+	TimeLoggerHelper(alloc);
+	LOCK;
+	if(!allocator_pool.allocator_pool) {
+		allocator_pool.allocator_pool = new allocator_pool_t();
+		allocator_pool.last_allocate_allocator = allocator_pool.last_free_allocator = 0;
+	}
+	fixed_size_allocator *last = allocator_pool.checkLastAllocator(size);
+	if(last) 
+		return last->_alloc(size);
+	else {
+		allocator_pool_it it; if(allocator_pool.findAllocator(size, it))
+			return (allocator_pool.last_allocate_allocator = *(it))->_alloc(size);
+		else {
+			return (allocator_pool.last_allocate_allocator = (*allocator_pool.allocator_pool->insert(it, new fixed_size_allocator(64, size, for_class))))->_alloc(size);
+		}
+	}
+}
+void fixed_size_allocator::free(void *p, size_t size) {
+	TimeLoggerHelper(free);
+	LOCK;
+	if(!allocator_pool.allocator_pool) {
+		ASSERT(0/* free called but not allocator defined*/);
+		return;
+	}
+	fixed_size_allocator *last = allocator_pool.checkLastAllocator(size);
+	if(last) { 
+		if( last->_free(p, size) ) {
+			allocator_pool_it it; if(allocator_pool.findAllocator(size, it))
+				allocator_pool.removeAllocator(it);
+		}
+	} else {
+		allocator_pool_it it; if(allocator_pool.findAllocator(size, it)) {
+			if( (allocator_pool.last_free_allocator = *it)->_free(p, size) )
+				allocator_pool.removeAllocator(it);
+		} else
+			ASSERT(0/* free called but not allocator defined*/);
+	}
+}
Index: XmlTools2/trunk/XmlTools/libs/pool_allocator.h
===================================================================
--- XmlTools2/trunk/XmlTools/libs/pool_allocator.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/pool_allocator.h	(revision 905)
@@ -0,0 +1,162 @@
+/*
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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 pool_allocator_h__
+#define pool_allocator_h__
+
+#include <typeinfo>
+#include <stdint.h>
+#include <string>
+#include "config.h"
+#include "TinyJS_Threading.h"
+
+/************************************************************************
+ * TinyJS must many many times allocates and frees objects
+ * To prevent memory fragmentation and speed ups allocates & frees, i have
+ * added to 42TinyJS a pool_allocator. This allocator allocates every 64 objects
+ * as a pool of objects. Is an object needed it can faster allocated from this pool as 
+ * from the heap.
+ ************************************************************************/ 
+
+#if !defined(DEBUG_POOL_ALLOCATOR) && (defined(_DEBUG) || defined(LOG_POOL_ALLOCATOR_MEMORY_USAGE))
+#	define DEBUG_POOL_ALLOCATOR
+#endif
+
+struct block_head;
+class fixed_size_allocator {
+public:
+	~fixed_size_allocator();
+	static void *alloc(size_t,const char* for_class=0);
+	static void free(void *, size_t);
+	size_t objectSize() { return object_size; }
+#ifndef NO_THREADING
+	static CScriptMutex locker;
+#endif
+private:
+	fixed_size_allocator(size_t num_objects, size_t object_size, const char* for_class); 
+	fixed_size_allocator(const fixed_size_allocator&);
+	fixed_size_allocator& operator=(const fixed_size_allocator&);
+	void *_alloc(size_t);
+	bool _free(void* p, size_t);
+	size_t num_objects;
+	size_t object_size;
+	void *head_of_free_list;
+	block_head *head;
+	int refs;
+#ifdef DEBUG_POOL_ALLOCATOR
+	// Debug
+	std::string name;
+	int allocs;
+	int frees;
+	int current;
+	int max;
+	int blocks;
+#endif
+};
+//**************************************************************************************
+template<typename T, int num_objects=64>
+class fixed_size_object {
+public:
+	static void* operator new(size_t size) {
+#ifdef DEBUG_POOL_ALLOCATOR
+		return fixed_size_allocator::alloc(size, typeid(T).name());
+#else
+		return fixed_size_allocator::alloc(size);
+#endif
+	}
+	static void* operator new(size_t size, void* p) {
+		return p;
+	}
+	static void operator delete(void* p, size_t size) {
+		fixed_size_allocator::free(p, size);
+	}
+private:
+};
+#if 0 // under construction
+template<typename T>
+class block_allocator_stl {
+public : 
+	//    typedefs
+
+	typedef T value_type;
+	typedef value_type* pointer;
+	typedef const value_type* const_pointer;
+	typedef value_type& reference;
+	typedef const value_type& const_reference;
+	typedef std::size_t size_type;
+	typedef std::ptrdiff_t difference_type;
+public : 
+	//    convert an allocator<T> to allocator<U>
+
+	template<typename U>
+	struct rebind {
+		typedef block_allocator_stl<U> other;
+	};
+
+	inline explicit block_allocator_stl() {}
+	inline ~block_allocator_stl() {}
+	inline block_allocator_stl(block_allocator_stl const&) {}
+	template<typename U>
+	inline block_allocator_stl(block_allocator_stl<U> const&) {}
+	inline block_allocator_stl<T> &operator=(block_allocator_stl<T> const&) {}
+	template<typename U>
+	inline block_allocator_stl<T> &operator=(block_allocator_stl<U> const&) {}
+
+	//    address
+
+	inline pointer address(reference r) { return &r; }
+	inline const_pointer address(const_reference r) { return &r; }
+
+	//    memory allocation
+	inline pointer allocate(size_type cnt, const void*) { 
+			return reinterpret_cast<pointer>(fixed_size_allocator::get(cnt * sizeof (T), true, typeid(T).name())->alloc(cnt * sizeof (T)));
+			//			return reinterpret_cast<pointer>(::operator new(cnt * sizeof (T))); 
+	}
+	inline void deallocate(pointer p, size_type cnt) { 
+		fixed_size_allocator::get(cnt * sizeof (T), false)->free(p, cnt * sizeof (T));
+		//		::operator delete(p); 
+	}
+
+	//    size
+
+	inline size_type max_size() const { 
+		return SIZE_MAX / sizeof(T);
+	}
+
+	inline void construct(pointer _Ptr, value_type& _Val) {
+		::new ((void*)_Ptr) value_type(_Val);
+	}
+	inline void destroy(pointer _Ptr) {
+		_Ptr->~value_type();
+	}
+};
+#endif
+
+#endif // pool_allocator_h__
Index: XmlTools2/trunk/XmlTools/libs/pugiconfig.hpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/pugiconfig.hpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/pugiconfig.hpp	(revision 905)
@@ -0,0 +1,69 @@
+/**
+ * pugixml parser - version 1.2
+ * --------------------------------------------------------
+ * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
+ * Report bugs and download new versions at http://pugixml.org/
+ *
+ * This library is distributed under the MIT License. See notice at the end
+ * of this file.
+ *
+ * This work is based on the pugxml parser, which is:
+ * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
+ */
+
+#ifndef HEADER_PUGICONFIG_HPP
+#define HEADER_PUGICONFIG_HPP
+
+// Uncomment this to enable wchar_t mode
+// #define PUGIXML_WCHAR_MODE
+
+// Uncomment this to disable XPath
+// #define PUGIXML_NO_XPATH
+
+// Uncomment this to disable STL
+// #define PUGIXML_NO_STL
+
+// Uncomment this to disable exceptions
+// #define PUGIXML_NO_EXCEPTIONS
+
+// Set this to control attributes for public classes/functions, i.e.:
+// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
+// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
+// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
+// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
+
+// Uncomment this to switch to header-only version
+// #define PUGIXML_HEADER_ONLY
+// #include "pugixml.cpp"
+
+// Tune these constants to adjust memory-related behavior
+// #define PUGIXML_MEMORY_PAGE_SIZE 32768
+// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
+// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
+
+#endif
+
+/**
+ * Copyright (c) 2006-2012 Arseny Kapoulkine
+ *
+ * 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.
+ */
Index: XmlTools2/trunk/XmlTools/libs/pugixml.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/pugixml.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/pugixml.cpp	(revision 905)
@@ -0,0 +1,10250 @@
+/**
+ * pugixml parser - version 1.2
+ * --------------------------------------------------------
+ * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
+ * Report bugs and download new versions at http://pugixml.org/
+ *
+ * This library is distributed under the MIT License. See notice at the end
+ * of this file.
+ *
+ * This work is based on the pugxml parser, which is:
+ * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
+ */
+
+#ifndef SOURCE_PUGIXML_CPP
+#define SOURCE_PUGIXML_CPP
+
+#include "pugixml.hpp"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <wchar.h>
+
+#ifndef PUGIXML_NO_XPATH
+#	include <math.h>
+#	include <float.h>
+#	ifdef PUGIXML_NO_EXCEPTIONS
+#		include <setjmp.h>
+#	endif
+#endif
+
+#ifndef PUGIXML_NO_STL
+#	include <istream>
+#	include <ostream>
+#	include <string>
+#endif
+
+// For placement new
+#include <new>
+
+#ifdef _MSC_VER
+#	pragma warning(push)
+#	pragma warning(disable: 4127) // conditional expression is constant
+#	pragma warning(disable: 4324) // structure was padded due to __declspec(align())
+#	pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
+#	pragma warning(disable: 4702) // unreachable code
+#	pragma warning(disable: 4996) // this function or variable may be unsafe
+#	pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
+#endif
+
+#ifdef __INTEL_COMPILER
+#	pragma warning(disable: 177) // function was declared but never referenced 
+#	pragma warning(disable: 279) // controlling expression is constant
+#	pragma warning(disable: 1478 1786) // function was declared "deprecated"
+#	pragma warning(disable: 1684) // conversion from pointer to same-sized integral type
+#endif
+
+#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
+#	pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away
+#endif
+
+#ifdef __BORLANDC__
+#	pragma option push
+#	pragma warn -8008 // condition is always false
+#	pragma warn -8066 // unreachable code
+#endif
+
+#ifdef __SNC__
+// Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug
+#	pragma diag_suppress=178 // function was declared but never referenced
+#	pragma diag_suppress=237 // controlling expression is constant
+#endif
+
+// Inlining controls
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+#	define PUGI__NO_INLINE __declspec(noinline)
+#elif defined(__GNUC__)
+#	define PUGI__NO_INLINE __attribute__((noinline))
+#else
+#	define PUGI__NO_INLINE 
+#endif
+
+// Simple static assertion
+#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
+
+// Digital Mars C++ bug workaround for passing char loaded from memory via stack
+#ifdef __DMC__
+#	define PUGI__DMC_VOLATILE volatile
+#else
+#	define PUGI__DMC_VOLATILE
+#endif
+
+// Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all)
+#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
+using std::memcpy;
+using std::memmove;
+#endif
+
+// In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features
+#if defined(_MSC_VER) && !defined(__S3E__)
+#	define PUGI__MSVC_CRT_VERSION _MSC_VER
+#endif
+
+#ifdef PUGIXML_HEADER_ONLY
+#	define PUGI__NS_BEGIN namespace pugi { namespace impl {
+#	define PUGI__NS_END } }
+#	define PUGI__FN inline
+#	define PUGI__FN_NO_INLINE inline
+#else
+#	if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
+#		define PUGI__NS_BEGIN namespace pugi { namespace impl {
+#		define PUGI__NS_END } }
+#	else
+#		define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace {
+#		define PUGI__NS_END } } }
+#	endif
+#	define PUGI__FN
+#	define PUGI__FN_NO_INLINE PUGI__NO_INLINE
+#endif
+
+// uintptr_t
+#if !defined(_MSC_VER) || _MSC_VER >= 1600
+#	include <stdint.h>
+#else
+#	ifndef _UINTPTR_T_DEFINED
+// No native uintptr_t in MSVC6 and in some WinCE versions
+typedef size_t uintptr_t;
+#define _UINTPTR_T_DEFINED
+#	endif
+PUGI__NS_BEGIN
+	typedef unsigned __int8 uint8_t;
+	typedef unsigned __int16 uint16_t;
+	typedef unsigned __int32 uint32_t;
+PUGI__NS_END
+#endif
+
+// Memory allocation
+PUGI__NS_BEGIN
+	PUGI__FN void* default_allocate(size_t size)
+	{
+		return malloc(size);
+	}
+
+	PUGI__FN void default_deallocate(void* ptr)
+	{
+		free(ptr);
+	}
+
+	template <typename T>
+	struct xml_memory_management_function_storage
+	{
+		static allocation_function allocate;
+		static deallocation_function deallocate;
+	};
+
+	template <typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate;
+	template <typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;
+
+	typedef xml_memory_management_function_storage<int> xml_memory;
+PUGI__NS_END
+
+// String utilities
+PUGI__NS_BEGIN
+	// Get string length
+	PUGI__FN size_t strlength(const char_t* s)
+	{
+		assert(s);
+
+	#ifdef PUGIXML_WCHAR_MODE
+		return wcslen(s);
+	#else
+		return strlen(s);
+	#endif
+	}
+
+	// Compare two strings
+	PUGI__FN bool strequal(const char_t* src, const char_t* dst)
+	{
+		assert(src && dst);
+
+	#ifdef PUGIXML_WCHAR_MODE
+		return wcscmp(src, dst) == 0;
+	#else
+		return strcmp(src, dst) == 0;
+	#endif
+	}
+
+	// Compare lhs with [rhs_begin, rhs_end)
+	PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
+	{
+		for (size_t i = 0; i < count; ++i)
+			if (lhs[i] != rhs[i])
+				return false;
+	
+		return lhs[count] == 0;
+	}
+	
+#ifdef PUGIXML_WCHAR_MODE
+	// Convert string to wide string, assuming all symbols are ASCII
+	PUGI__FN void widen_ascii(wchar_t* dest, const char* source)
+	{
+		for (const char* i = source; *i; ++i) *dest++ = *i;
+		*dest = 0;
+	}
+#endif
+PUGI__NS_END
+
+#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH)
+// auto_ptr-like buffer holder for exception recovery
+PUGI__NS_BEGIN
+	struct buffer_holder
+	{
+		void* data;
+		void (*deleter)(void*);
+
+		buffer_holder(void* data_, void (*deleter_)(void*)): data(data_), deleter(deleter_)
+		{
+		}
+
+		~buffer_holder()
+		{
+			if (data) deleter(data);
+		}
+
+		void* release()
+		{
+			void* result = data;
+			data = 0;
+			return result;
+		}
+	};
+PUGI__NS_END
+#endif
+
+PUGI__NS_BEGIN
+	static const size_t xml_memory_page_size =
+	#ifdef PUGIXML_MEMORY_PAGE_SIZE
+		PUGIXML_MEMORY_PAGE_SIZE
+	#else
+		32768
+	#endif
+		;
+
+	static const uintptr_t xml_memory_page_alignment = 32;
+	static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1);
+	static const uintptr_t xml_memory_page_name_allocated_mask = 16;
+	static const uintptr_t xml_memory_page_value_allocated_mask = 8;
+	static const uintptr_t xml_memory_page_type_mask = 7;
+
+	struct xml_allocator;
+
+	struct xml_memory_page
+	{
+		static xml_memory_page* construct(void* memory)
+		{
+			if (!memory) return 0; //$ redundant, left for performance
+
+			xml_memory_page* result = static_cast<xml_memory_page*>(memory);
+
+			result->allocator = 0;
+			result->memory = 0;
+			result->prev = 0;
+			result->next = 0;
+			result->busy_size = 0;
+			result->freed_size = 0;
+
+			return result;
+		}
+
+		xml_allocator* allocator;
+
+		void* memory;
+
+		xml_memory_page* prev;
+		xml_memory_page* next;
+
+		size_t busy_size;
+		size_t freed_size;
+
+		char data[1];
+	};
+
+	struct xml_memory_string_header
+	{
+		uint16_t page_offset; // offset from page->data
+		uint16_t full_size; // 0 if string occupies whole page
+	};
+
+	struct xml_allocator
+	{
+		xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
+		{
+		}
+
+		xml_memory_page* allocate_page(size_t data_size)
+		{
+			size_t size = offsetof(xml_memory_page, data) + data_size;
+
+			// allocate block with some alignment, leaving memory for worst-case padding
+			void* memory = xml_memory::allocate(size + xml_memory_page_alignment);
+			if (!memory) return 0;
+
+			// align upwards to page boundary
+			void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1));
+
+			// prepare page structure
+			xml_memory_page* page = xml_memory_page::construct(page_memory);
+
+			page->memory = memory;
+			page->allocator = _root->allocator;
+
+			return page;
+		}
+
+		static void deallocate_page(xml_memory_page* page)
+		{
+			xml_memory::deallocate(page->memory);
+		}
+
+		void* allocate_memory_oob(size_t size, xml_memory_page*& out_page);
+
+		void* allocate_memory(size_t size, xml_memory_page*& out_page)
+		{
+			if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page);
+
+			void* buf = _root->data + _busy_size;
+
+			_busy_size += size;
+
+			out_page = _root;
+
+			return buf;
+		}
+
+		void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
+		{
+			if (page == _root) page->busy_size = _busy_size;
+
+			assert(ptr >= page->data && ptr < page->data + page->busy_size);
+			(void)!ptr;
+
+			page->freed_size += size;
+			assert(page->freed_size <= page->busy_size);
+
+			if (page->freed_size == page->busy_size)
+			{
+				if (page->next == 0)
+				{
+					assert(_root == page);
+
+					// top page freed, just reset sizes
+					page->busy_size = page->freed_size = 0;
+					_busy_size = 0;
+				}
+				else
+				{
+					assert(_root != page);
+					assert(page->prev);
+
+					// remove from the list
+					page->prev->next = page->next;
+					page->next->prev = page->prev;
+
+					// deallocate
+					deallocate_page(page);
+				}
+			}
+		}
+
+		char_t* allocate_string(size_t length)
+		{
+			// allocate memory for string and header block
+			size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
+			
+			// round size up to pointer alignment boundary
+			size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1);
+
+			xml_memory_page* page;
+			xml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page));
+
+			if (!header) return 0;
+
+			// setup header
+			ptrdiff_t page_offset = reinterpret_cast<char*>(header) - page->data;
+
+			assert(page_offset >= 0 && page_offset < (1 << 16));
+			header->page_offset = static_cast<uint16_t>(page_offset);
+
+			// full_size == 0 for large strings that occupy the whole page
+			assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0));
+			header->full_size = static_cast<uint16_t>(full_size < (1 << 16) ? full_size : 0);
+
+			// round-trip through void* to avoid 'cast increases required alignment of target type' warning
+			// header is guaranteed a pointer-sized alignment, which should be enough for char_t
+			return static_cast<char_t*>(static_cast<void*>(header + 1));
+		}
+
+		void deallocate_string(char_t* string)
+		{
+			// this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
+			// we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string
+
+			// get header
+			xml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1;
+
+			// deallocate
+			size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset;
+			xml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset));
+
+			// if full_size == 0 then this string occupies the whole page
+			size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size;
+
+			deallocate_memory(header, full_size, page);
+		}
+
+		xml_memory_page* _root;
+		size_t _busy_size;
+	};
+
+	PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)
+	{
+		const size_t large_allocation_threshold = xml_memory_page_size / 4;
+
+		xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
+		out_page = page;
+
+		if (!page) return 0;
+
+		if (size <= large_allocation_threshold)
+		{
+			_root->busy_size = _busy_size;
+
+			// insert page at the end of linked list
+			page->prev = _root;
+			_root->next = page;
+			_root = page;
+
+			_busy_size = size;
+		}
+		else
+		{
+			// insert page before the end of linked list, so that it is deleted as soon as possible
+			// the last page is not deleted even if it's empty (see deallocate_memory)
+			assert(_root->prev);
+
+			page->prev = _root->prev;
+			page->next = _root;
+
+			_root->prev->next = page;
+			_root->prev = page;
+		}
+
+		// allocate inside page
+		page->busy_size = size;
+
+		return page->data;
+	}
+PUGI__NS_END
+
+namespace pugi
+{
+	/// A 'name=value' XML attribute structure.
+	struct xml_attribute_struct
+	{
+		/// Default ctor
+		xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0)
+		{
+		}
+
+		uintptr_t header;
+
+		char_t* name;	///< Pointer to attribute name.
+		char_t*	value;	///< Pointer to attribute value.
+
+		xml_attribute_struct* prev_attribute_c;	///< Previous attribute (cyclic list)
+		xml_attribute_struct* next_attribute;	///< Next attribute
+	};
+
+	/// An XML document tree node.
+	struct xml_node_struct
+	{
+		/// Default ctor
+		/// \param type - node type
+		xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast<uintptr_t>(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
+		{
+		}
+
+		uintptr_t header;
+
+		xml_node_struct*		parent;					///< Pointer to parent
+
+		char_t*					name;					///< Pointer to element name.
+		char_t*					value;					///< Pointer to any associated string data.
+
+		xml_node_struct*		first_child;			///< First child
+		
+		xml_node_struct*		prev_sibling_c;			///< Left brother (cyclic list)
+		xml_node_struct*		next_sibling;			///< Right brother
+		
+		xml_attribute_struct*	first_attribute;		///< First attribute
+	};
+}
+
+PUGI__NS_BEGIN
+	struct xml_document_struct: public xml_node_struct, public xml_allocator
+	{
+		xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0)
+		{
+		}
+
+		const char_t* buffer;
+	};
+
+	inline xml_allocator& get_allocator(const xml_node_struct* node)
+	{
+		assert(node);
+
+		return *reinterpret_cast<xml_memory_page*>(node->header & xml_memory_page_pointer_mask)->allocator;
+	}
+PUGI__NS_END
+
+// Low-level DOM operations
+PUGI__NS_BEGIN
+	inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
+	{
+		xml_memory_page* page;
+		void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page);
+
+		return new (memory) xml_attribute_struct(page);
+	}
+
+	inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type)
+	{
+		xml_memory_page* page;
+		void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page);
+
+		return new (memory) xml_node_struct(page, type);
+	}
+
+	inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
+	{
+		uintptr_t header = a->header;
+
+		if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name);
+		if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value);
+
+		alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
+	}
+
+	inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
+	{
+		uintptr_t header = n->header;
+
+		if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name);
+		if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value);
+
+		for (xml_attribute_struct* attr = n->first_attribute; attr; )
+		{
+			xml_attribute_struct* next = attr->next_attribute;
+
+			destroy_attribute(attr, alloc);
+
+			attr = next;
+		}
+
+		for (xml_node_struct* child = n->first_child; child; )
+		{
+			xml_node_struct* next = child->next_sibling;
+
+			destroy_node(child, alloc);
+
+			child = next;
+		}
+
+		alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
+	}
+
+	PUGI__FN_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
+	{
+		xml_node_struct* child = allocate_node(alloc, type);
+		if (!child) return 0;
+
+		child->parent = node;
+
+		xml_node_struct* first_child = node->first_child;
+			
+		if (first_child)
+		{
+			xml_node_struct* last_child = first_child->prev_sibling_c;
+
+			last_child->next_sibling = child;
+			child->prev_sibling_c = last_child;
+			first_child->prev_sibling_c = child;
+		}
+		else
+		{
+			node->first_child = child;
+			child->prev_sibling_c = child;
+		}
+			
+		return child;
+	}
+
+	PUGI__FN_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc)
+	{
+		xml_attribute_struct* a = allocate_attribute(alloc);
+		if (!a) return 0;
+
+		xml_attribute_struct* first_attribute = node->first_attribute;
+
+		if (first_attribute)
+		{
+			xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c;
+
+			last_attribute->next_attribute = a;
+			a->prev_attribute_c = last_attribute;
+			first_attribute->prev_attribute_c = a;
+		}
+		else
+		{
+			node->first_attribute = a;
+			a->prev_attribute_c = a;
+		}
+			
+		return a;
+	}
+PUGI__NS_END
+
+// Helper classes for code generation
+PUGI__NS_BEGIN
+	struct opt_false
+	{
+		enum { value = 0 };
+	};
+
+	struct opt_true
+	{
+		enum { value = 1 };
+	};
+PUGI__NS_END
+
+// Unicode utilities
+PUGI__NS_BEGIN
+	inline uint16_t endian_swap(uint16_t value)
+	{
+		return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
+	}
+
+	inline uint32_t endian_swap(uint32_t value)
+	{
+		return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
+	}
+
+	struct utf8_counter
+	{
+		typedef size_t value_type;
+
+		static value_type low(value_type result, uint32_t ch)
+		{
+			// U+0000..U+007F
+			if (ch < 0x80) return result + 1;
+			// U+0080..U+07FF
+			else if (ch < 0x800) return result + 2;
+			// U+0800..U+FFFF
+			else return result + 3;
+		}
+
+		static value_type high(value_type result, uint32_t)
+		{
+			// U+10000..U+10FFFF
+			return result + 4;
+		}
+	};
+
+	struct utf8_writer
+	{
+		typedef uint8_t* value_type;
+
+		static value_type low(value_type result, uint32_t ch)
+		{
+			// U+0000..U+007F
+			if (ch < 0x80)
+			{
+				*result = static_cast<uint8_t>(ch);
+				return result + 1;
+			}
+			// U+0080..U+07FF
+			else if (ch < 0x800)
+			{
+				result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));
+				result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
+				return result + 2;
+			}
+			// U+0800..U+FFFF
+			else
+			{
+				result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));
+				result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
+				result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
+				return result + 3;
+			}
+		}
+
+		static value_type high(value_type result, uint32_t ch)
+		{
+			// U+10000..U+10FFFF
+			result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));
+			result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));
+			result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
+			result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
+			return result + 4;
+		}
+
+		static value_type any(value_type result, uint32_t ch)
+		{
+			return (ch < 0x10000) ? low(result, ch) : high(result, ch);
+		}
+	};
+
+	struct utf16_counter
+	{
+		typedef size_t value_type;
+
+		static value_type low(value_type result, uint32_t)
+		{
+			return result + 1;
+		}
+
+		static value_type high(value_type result, uint32_t)
+		{
+			return result + 2;
+		}
+	};
+
+	struct utf16_writer
+	{
+		typedef uint16_t* value_type;
+
+		static value_type low(value_type result, uint32_t ch)
+		{
+			*result = static_cast<uint16_t>(ch);
+
+			return result + 1;
+		}
+
+		static value_type high(value_type result, uint32_t ch)
+		{
+			uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10;
+			uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff;
+
+			result[0] = static_cast<uint16_t>(0xD800 + msh);
+			result[1] = static_cast<uint16_t>(0xDC00 + lsh);
+
+			return result + 2;
+		}
+
+		static value_type any(value_type result, uint32_t ch)
+		{
+			return (ch < 0x10000) ? low(result, ch) : high(result, ch);
+		}
+	};
+
+	struct utf32_counter
+	{
+		typedef size_t value_type;
+
+		static value_type low(value_type result, uint32_t)
+		{
+			return result + 1;
+		}
+
+		static value_type high(value_type result, uint32_t)
+		{
+			return result + 1;
+		}
+	};
+
+	struct utf32_writer
+	{
+		typedef uint32_t* value_type;
+
+		static value_type low(value_type result, uint32_t ch)
+		{
+			*result = ch;
+
+			return result + 1;
+		}
+
+		static value_type high(value_type result, uint32_t ch)
+		{
+			*result = ch;
+
+			return result + 1;
+		}
+
+		static value_type any(value_type result, uint32_t ch)
+		{
+			*result = ch;
+
+			return result + 1;
+		}
+	};
+
+	struct latin1_writer
+	{
+		typedef uint8_t* value_type;
+
+		static value_type low(value_type result, uint32_t ch)
+		{
+			*result = static_cast<uint8_t>(ch > 255 ? '?' : ch);
+
+			return result + 1;
+		}
+
+		static value_type high(value_type result, uint32_t ch)
+		{
+			(void)ch;
+
+			*result = '?';
+
+			return result + 1;
+		}
+	};
+
+	template <size_t size> struct wchar_selector;
+
+	template <> struct wchar_selector<2>
+	{
+		typedef uint16_t type;
+		typedef utf16_counter counter;
+		typedef utf16_writer writer;
+	};
+
+	template <> struct wchar_selector<4>
+	{
+		typedef uint32_t type;
+		typedef utf32_counter counter;
+		typedef utf32_writer writer;
+	};
+
+	typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
+	typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
+
+	template <typename Traits, typename opt_swap = opt_false> struct utf_decoder
+	{
+		static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result)
+		{
+			const uint8_t utf8_byte_mask = 0x3f;
+
+			while (size)
+			{
+				uint8_t lead = *data;
+
+				// 0xxxxxxx -> U+0000..U+007F
+				if (lead < 0x80)
+				{
+					result = Traits::low(result, lead);
+					data += 1;
+					size -= 1;
+
+					// process aligned single-byte (ascii) blocks
+					if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
+					{
+						// round-trip through void* to silence 'cast increases required alignment of target type' warnings
+						while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)
+						{
+							result = Traits::low(result, data[0]);
+							result = Traits::low(result, data[1]);
+							result = Traits::low(result, data[2]);
+							result = Traits::low(result, data[3]);
+							data += 4;
+							size -= 4;
+						}
+					}
+				}
+				// 110xxxxx -> U+0080..U+07FF
+				else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
+				{
+					result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
+					data += 2;
+					size -= 2;
+				}
+				// 1110xxxx -> U+0800-U+FFFF
+				else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
+				{
+					result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
+					data += 3;
+					size -= 3;
+				}
+				// 11110xxx -> U+10000..U+10FFFF
+				else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
+				{
+					result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
+					data += 4;
+					size -= 4;
+				}
+				// 10xxxxxx or 11111xxx -> invalid
+				else
+				{
+					data += 1;
+					size -= 1;
+				}
+			}
+
+			return result;
+		}
+
+		static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result)
+		{
+			const uint16_t* end = data + size;
+
+			while (data < end)
+			{
+				uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
+
+				// U+0000..U+D7FF
+				if (lead < 0xD800)
+				{
+					result = Traits::low(result, lead);
+					data += 1;
+				}
+				// U+E000..U+FFFF
+				else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
+				{
+					result = Traits::low(result, lead);
+					data += 1;
+				}
+				// surrogate pair lead
+				else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && data + 1 < end)
+				{
+					uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
+
+					if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
+					{
+						result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
+						data += 2;
+					}
+					else
+					{
+						data += 1;
+					}
+				}
+				else
+				{
+					data += 1;
+				}
+			}
+
+			return result;
+		}
+
+		static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result)
+		{
+			const uint32_t* end = data + size;
+
+			while (data < end)
+			{
+				uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
+
+				// U+0000..U+FFFF
+				if (lead < 0x10000)
+				{
+					result = Traits::low(result, lead);
+					data += 1;
+				}
+				// U+10000..U+10FFFF
+				else
+				{
+					result = Traits::high(result, lead);
+					data += 1;
+				}
+			}
+
+			return result;
+		}
+
+		static inline typename Traits::value_type decode_latin1_block(const uint8_t* data, size_t size, typename Traits::value_type result)
+		{
+			for (size_t i = 0; i < size; ++i)
+			{
+				result = Traits::low(result, data[i]);
+			}
+
+			return result;
+		}
+
+		static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t* data, size_t size, typename Traits::value_type result)
+		{
+			return decode_utf16_block(data, size, result);
+		}
+
+		static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t* data, size_t size, typename Traits::value_type result)
+		{
+			return decode_utf32_block(data, size, result);
+		}
+
+		static inline typename Traits::value_type decode_wchar_block(const wchar_t* data, size_t size, typename Traits::value_type result)
+		{
+			return decode_wchar_block_impl(reinterpret_cast<const wchar_selector<sizeof(wchar_t)>::type*>(data), size, result);
+		}
+	};
+
+	template <typename T> PUGI__FN void convert_utf_endian_swap(T* result, const T* data, size_t length)
+	{
+		for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]);
+	}
+
+#ifdef PUGIXML_WCHAR_MODE
+	PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
+	{
+		for (size_t i = 0; i < length; ++i) result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
+	}
+#endif
+PUGI__NS_END
+
+PUGI__NS_BEGIN
+	enum chartype_t
+	{
+		ct_parse_pcdata = 1,	// \0, &, \r, <
+		ct_parse_attr = 2,		// \0, &, \r, ', "
+		ct_parse_attr_ws = 4,	// \0, &, \r, ', ", \n, tab
+		ct_space = 8,			// \r, \n, space, tab
+		ct_parse_cdata = 16,	// \0, ], >, \r
+		ct_parse_comment = 32,	// \0, -, >, \r
+		ct_symbol = 64,			// Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .
+		ct_start_symbol = 128	// Any symbol > 127, a-z, A-Z, _, :
+	};
+
+	static const unsigned char chartype_table[256] =
+	{
+		55,  0,   0,   0,   0,   0,   0,   0,      0,   12,  12,  0,   0,   63,  0,   0,   // 0-15
+		0,   0,   0,   0,   0,   0,   0,   0,      0,   0,   0,   0,   0,   0,   0,   0,   // 16-31
+		8,   0,   6,   0,   0,   0,   7,   6,      0,   0,   0,   0,   0,   96,  64,  0,   // 32-47
+		64,  64,  64,  64,  64,  64,  64,  64,     64,  64,  192, 0,   1,   0,   48,  0,   // 48-63
+		0,   192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 64-79
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 0,   0,   16,  0,   192, // 80-95
+		0,   192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 96-111
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 0, 0, 0, 0, 0,           // 112-127
+
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 128+
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192,
+		192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192
+	};
+
+	enum chartypex_t
+	{
+		ctx_special_pcdata = 1,   // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
+		ctx_special_attr = 2,     // Any symbol >= 0 and < 32 (except \t), &, <, >, "
+		ctx_start_symbol = 4,	  // Any symbol > 127, a-z, A-Z, _
+		ctx_digit = 8,			  // 0-9
+		ctx_symbol = 16			  // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
+	};
+	
+	static const unsigned char chartypex_table[256] =
+	{
+		3,  3,  3,  3,  3,  3,  3,  3,     3,  0,  2,  3,  3,  2,  3,  3,     // 0-15
+		3,  3,  3,  3,  3,  3,  3,  3,     3,  3,  3,  3,  3,  3,  3,  3,     // 16-31
+		0,  0,  2,  0,  0,  0,  3,  0,     0,  0,  0,  0,  0, 16, 16,  0,     // 32-47
+		24, 24, 24, 24, 24, 24, 24, 24,    24, 24, 0,  0,  3,  0,  3,  0,     // 48-63
+
+		0,  20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 64-79
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 0,  0,  0,  0,  20,    // 80-95
+		0,  20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 96-111
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 0,  0,  0,  0,  0,     // 112-127
+
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 128+
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,
+		20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20
+	};
+	
+#ifdef PUGIXML_WCHAR_MODE
+	#define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
+#else
+	#define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
+#endif
+
+	#define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
+	#define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
+
+	PUGI__FN bool is_little_endian()
+	{
+		unsigned int ui = 1;
+
+		return *reinterpret_cast<unsigned char*>(&ui) == 1;
+	}
+
+	PUGI__FN xml_encoding get_wchar_encoding()
+	{
+		PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
+
+		if (sizeof(wchar_t) == 2)
+			return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+		else 
+			return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+	}
+
+	PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
+	{
+		// look for BOM in first few bytes
+		if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be;
+		if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le;
+		if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be;
+		if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le;
+		if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8;
+
+		// look for <, <? or <?xm in various encodings
+		if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be;
+		if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le;
+		if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be;
+		if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le;
+		if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8;
+
+		// look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)
+		if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be;
+		if (d0 == 0x3c && d1 == 0) return encoding_utf16_le;
+
+		// no known BOM detected, assume utf8
+		return encoding_utf8;
+	}
+
+	PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
+	{
+		// replace wchar encoding with utf implementation
+		if (encoding == encoding_wchar) return get_wchar_encoding();
+
+		// replace utf16 encoding with utf16 with specific endianness
+		if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+		// replace utf32 encoding with utf32 with specific endianness
+		if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+		// only do autodetection if no explicit encoding is requested
+		if (encoding != encoding_auto) return encoding;
+
+		// skip encoding autodetection if input buffer is too small
+		if (size < 4) return encoding_utf8;
+
+		// try to guess encoding (based on XML specification, Appendix F.1)
+		const uint8_t* data = static_cast<const uint8_t*>(contents);
+
+		PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
+
+		return guess_buffer_encoding(d0, d1, d2, d3);
+	}
+
+	PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
+	{
+		if (is_mutable)
+		{
+			out_buffer = static_cast<char_t*>(const_cast<void*>(contents));
+		}
+		else
+		{
+			void* buffer = xml_memory::allocate(size > 0 ? size : 1);
+			if (!buffer) return false;
+
+			memcpy(buffer, contents, size);
+
+			out_buffer = static_cast<char_t*>(buffer);
+		}
+
+		out_length = size / sizeof(char_t);
+
+		return true;
+	}
+
+#ifdef PUGIXML_WCHAR_MODE
+	PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
+	{
+		return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
+			   (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
+	}
+
+	PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
+	{
+		const char_t* data = static_cast<const char_t*>(contents);
+	
+		if (is_mutable)
+		{
+			out_buffer = const_cast<char_t*>(data);
+		}
+		else
+		{
+			out_buffer = static_cast<char_t*>(xml_memory::allocate(size > 0 ? size : 1));
+			if (!out_buffer) return false;
+		}
+
+		out_length = size / sizeof(char_t);
+
+		convert_wchar_endian_swap(out_buffer, data, out_length);
+
+		return true;
+	}
+
+	PUGI__FN bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size)
+	{
+		const uint8_t* data = static_cast<const uint8_t*>(contents);
+
+		// first pass: get length in wchar_t units
+		out_length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
+
+		// allocate buffer of suitable length
+		out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+		if (!out_buffer) return false;
+
+		// second pass: convert utf8 input to wchar_t
+		wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
+		wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, out_begin);
+
+		assert(out_end == out_begin + out_length);
+		(void)!out_end;
+
+		return true;
+	}
+
+	template <typename opt_swap> PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
+	{
+		const uint16_t* data = static_cast<const uint16_t*>(contents);
+		size_t length = size / sizeof(uint16_t);
+
+		// first pass: get length in wchar_t units
+		out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf16_block(data, length, 0);
+
+		// allocate buffer of suitable length
+		out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+		if (!out_buffer) return false;
+
+		// second pass: convert utf16 input to wchar_t
+		wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
+		wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, length, out_begin);
+
+		assert(out_end == out_begin + out_length);
+		(void)!out_end;
+
+		return true;
+	}
+
+	template <typename opt_swap> PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
+	{
+		const uint32_t* data = static_cast<const uint32_t*>(contents);
+		size_t length = size / sizeof(uint32_t);
+
+		// first pass: get length in wchar_t units
+		out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf32_block(data, length, 0);
+
+		// allocate buffer of suitable length
+		out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+		if (!out_buffer) return false;
+
+		// second pass: convert utf32 input to wchar_t
+		wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
+		wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, length, out_begin);
+
+		assert(out_end == out_begin + out_length);
+		(void)!out_end;
+
+		return true;
+	}
+
+	PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size)
+	{
+		const uint8_t* data = static_cast<const uint8_t*>(contents);
+
+		// get length in wchar_t units
+		out_length = size;
+
+		// allocate buffer of suitable length
+		out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+		if (!out_buffer) return false;
+
+		// convert latin1 input to wchar_t
+		wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
+		wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_latin1_block(data, size, out_begin);
+
+		assert(out_end == out_begin + out_length);
+		(void)!out_end;
+
+		return true;
+	}
+
+	PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
+	{
+		// get native encoding
+		xml_encoding wchar_encoding = get_wchar_encoding();
+
+		// fast path: no conversion required
+		if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
+
+		// only endian-swapping is required
+		if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
+
+		// source encoding is utf8
+		if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size);
+
+		// source encoding is utf16
+		if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
+		{
+			xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+			return (native_encoding == encoding) ?
+				convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
+				convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
+		}
+
+		// source encoding is utf32
+		if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
+		{
+			xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+			return (native_encoding == encoding) ?
+				convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
+				convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
+		}
+
+		// source encoding is latin1
+		if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size);
+
+		assert(!"Invalid encoding");
+		return false;
+	}
+#else
+	template <typename opt_swap> PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
+	{
+		const uint16_t* data = static_cast<const uint16_t*>(contents);
+		size_t length = size / sizeof(uint16_t);
+
+		// first pass: get length in utf8 units
+		out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, length, 0);
+
+		// allocate buffer of suitable length
+		out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+		if (!out_buffer) return false;
+
+		// second pass: convert utf16 input to utf8
+		uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer);
+		uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, length, out_begin);
+
+		assert(out_end == out_begin + out_length);
+		(void)!out_end;
+
+		return true;
+	}
+
+	template <typename opt_swap> PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
+	{
+		const uint32_t* data = static_cast<const uint32_t*>(contents);
+		size_t length = size / sizeof(uint32_t);
+
+		// first pass: get length in utf8 units
+		out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, length, 0);
+
+		// allocate buffer of suitable length
+		out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+		if (!out_buffer) return false;
+
+		// second pass: convert utf32 input to utf8
+		uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer);
+		uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, length, out_begin);
+
+		assert(out_end == out_begin + out_length);
+		(void)!out_end;
+
+		return true;
+	}
+
+	PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
+	{
+		for (size_t i = 0; i < size; ++i)
+			if (data[i] > 127)
+				return i;
+
+		return size;
+	}
+
+	PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
+	{
+		const uint8_t* data = static_cast<const uint8_t*>(contents);
+
+		// get size of prefix that does not need utf8 conversion
+		size_t prefix_length = get_latin1_7bit_prefix_length(data, size);
+		assert(prefix_length <= size);
+
+		const uint8_t* postfix = data + prefix_length;
+		size_t postfix_length = size - prefix_length;
+
+		// if no conversion is needed, just return the original buffer
+		if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
+
+		// first pass: get length in utf8 units
+		out_length = prefix_length + utf_decoder<utf8_counter>::decode_latin1_block(postfix, postfix_length, 0);
+
+		// allocate buffer of suitable length
+		out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
+		if (!out_buffer) return false;
+
+		// second pass: convert latin1 input to utf8
+		memcpy(out_buffer, data, prefix_length);
+
+		uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer);
+		uint8_t* out_end = utf_decoder<utf8_writer>::decode_latin1_block(postfix, postfix_length, out_begin + prefix_length);
+
+		assert(out_end == out_begin + out_length);
+		(void)!out_end;
+
+		return true;
+	}
+
+	PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
+	{
+		// fast path: no conversion required
+		if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
+
+		// source encoding is utf16
+		if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
+		{
+			xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+			return (native_encoding == encoding) ?
+				convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
+				convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
+		}
+
+		// source encoding is utf32
+		if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
+		{
+			xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+			return (native_encoding == encoding) ?
+				convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
+				convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
+		}
+
+		// source encoding is latin1
+		if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
+
+		assert(!"Invalid encoding");
+		return false;
+	}
+#endif
+
+	PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length)
+	{
+		// get length in utf8 characters
+		return utf_decoder<utf8_counter>::decode_wchar_block(str, length, 0);
+	}
+
+	PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
+	{
+		// convert to utf8
+		uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
+		uint8_t* end = utf_decoder<utf8_writer>::decode_wchar_block(str, length, begin);
+	
+		assert(begin + size == end);
+		(void)!end;
+
+		// zero-terminate
+		buffer[size] = 0;
+	}
+	
+#ifndef PUGIXML_NO_STL
+	PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length)
+	{
+		// first pass: get length in utf8 characters
+		size_t size = as_utf8_begin(str, length);
+
+		// allocate resulting string
+		std::string result;
+		result.resize(size);
+
+		// second pass: convert to utf8
+		if (size > 0) as_utf8_end(&result[0], size, str, length);
+
+		return result;
+	}
+
+	PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)
+	{
+		const uint8_t* data = reinterpret_cast<const uint8_t*>(str);
+
+		// first pass: get length in wchar_t units
+		size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
+
+		// allocate resulting string
+		std::basic_string<wchar_t> result;
+		result.resize(length);
+
+		// second pass: convert to wchar_t
+		if (length > 0)
+		{
+			wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
+			wchar_writer::value_type end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, begin);
+
+			assert(begin + length == end);
+			(void)!end;
+		}
+
+		return result;
+	}
+#endif
+
+	inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target)
+	{
+		assert(target);
+		size_t target_length = strlength(target);
+
+		// always reuse document buffer memory if possible
+		if (!allocated) return target_length >= length;
+
+		// reuse heap memory if waste is not too great
+		const size_t reuse_threshold = 32;
+
+		return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
+	}
+
+	PUGI__FN bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source)
+	{
+		size_t source_length = strlength(source);
+
+		if (source_length == 0)
+		{
+			// empty string and null pointer are equivalent, so just deallocate old memory
+			xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
+
+			if (header & header_mask) alloc->deallocate_string(dest);
+			
+			// mark the string as not allocated
+			dest = 0;
+			header &= ~header_mask;
+
+			return true;
+		}
+		else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest))
+		{
+			// we can reuse old buffer, so just copy the new data (including zero terminator)
+			memcpy(dest, source, (source_length + 1) * sizeof(char_t));
+			
+			return true;
+		}
+		else
+		{
+			xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
+
+			// allocate new buffer
+			char_t* buf = alloc->allocate_string(source_length + 1);
+			if (!buf) return false;
+
+			// copy the string (including zero terminator)
+			memcpy(buf, source, (source_length + 1) * sizeof(char_t));
+
+			// deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
+			if (header & header_mask) alloc->deallocate_string(dest);
+			
+			// the string is now allocated, so set the flag
+			dest = buf;
+			header |= header_mask;
+
+			return true;
+		}
+	}
+
+	struct gap
+	{
+		char_t* end;
+		size_t size;
+			
+		gap(): end(0), size(0)
+		{
+		}
+			
+		// Push new gap, move s count bytes further (skipping the gap).
+		// Collapse previous gap.
+		void push(char_t*& s, size_t count)
+		{
+			if (end) // there was a gap already; collapse it
+			{
+				// Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
+				assert(s >= end);
+				memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
+			}
+				
+			s += count; // end of current gap
+				
+			// "merge" two gaps
+			end = s;
+			size += count;
+		}
+			
+		// Collapse all gaps, return past-the-end pointer
+		char_t* flush(char_t* s)
+		{
+			if (end)
+			{
+				// Move [old_gap_end, current_pos) to [old_gap_start, ...)
+				assert(s >= end);
+				memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
+
+				return s - size;
+			}
+			else return s;
+		}
+	};
+	
+	PUGI__FN char_t* strconv_escape(char_t* s, gap& g)
+	{
+		char_t* stre = s + 1;
+
+		switch (*stre)
+		{
+			case '#':	// &#...
+			{
+				unsigned int ucsc = 0;
+
+				if (stre[1] == 'x') // &#x... (hex code)
+				{
+					stre += 2;
+
+					char_t ch = *stre;
+
+					if (ch == ';') return stre;
+
+					for (;;)
+					{
+						if (static_cast<unsigned int>(ch - '0') <= 9)
+							ucsc = 16 * ucsc + (ch - '0');
+						else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)
+							ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);
+						else if (ch == ';')
+							break;
+						else // cancel
+							return stre;
+
+						ch = *++stre;
+					}
+					
+					++stre;
+				}
+				else	// &#... (dec code)
+				{
+					char_t ch = *++stre;
+
+					if (ch == ';') return stre;
+
+					for (;;)
+					{
+						if (static_cast<unsigned int>(ch - '0') <= 9)
+							ucsc = 10 * ucsc + (ch - '0');
+						else if (ch == ';')
+							break;
+						else // cancel
+							return stre;
+
+						ch = *++stre;
+					}
+					
+					++stre;
+				}
+
+			#ifdef PUGIXML_WCHAR_MODE
+				s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
+			#else
+				s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));
+			#endif
+					
+				g.push(s, stre - s);
+				return stre;
+			}
+
+			case 'a':	// &a
+			{
+				++stre;
+
+				if (*stre == 'm') // &am
+				{
+					if (*++stre == 'p' && *++stre == ';') // &amp;
+					{
+						*s++ = '&';
+						++stre;
+							
+						g.push(s, stre - s);
+						return stre;
+					}
+				}
+				else if (*stre == 'p') // &ap
+				{
+					if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // &apos;
+					{
+						*s++ = '\'';
+						++stre;
+
+						g.push(s, stre - s);
+						return stre;
+					}
+				}
+				break;
+			}
+
+			case 'g': // &g
+			{
+				if (*++stre == 't' && *++stre == ';') // &gt;
+				{
+					*s++ = '>';
+					++stre;
+					
+					g.push(s, stre - s);
+					return stre;
+				}
+				break;
+			}
+
+			case 'l': // &l
+			{
+				if (*++stre == 't' && *++stre == ';') // &lt;
+				{
+					*s++ = '<';
+					++stre;
+						
+					g.push(s, stre - s);
+					return stre;
+				}
+				break;
+			}
+
+			case 'q': // &q
+			{
+				if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // &quot;
+				{
+					*s++ = '"';
+					++stre;
+					
+					g.push(s, stre - s);
+					return stre;
+				}
+				break;
+			}
+
+			default:
+				break;
+		}
+		
+		return stre;
+	}
+
+	// Utility macro for last character handling
+	#define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
+
+	PUGI__FN char_t* strconv_comment(char_t* s, char_t endch)
+	{
+		gap g;
+		
+		while (true)
+		{
+			while (!PUGI__IS_CHARTYPE(*s, ct_parse_comment)) ++s;
+		
+			if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
+			{
+				*s++ = '\n'; // replace first one with 0x0a
+				
+				if (*s == '\n') g.push(s, 1);
+			}
+			else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here
+			{
+				*g.flush(s) = 0;
+				
+				return s + (s[2] == '>' ? 3 : 2);
+			}
+			else if (*s == 0)
+			{
+				return 0;
+			}
+			else ++s;
+		}
+	}
+
+	PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch)
+	{
+		gap g;
+			
+		while (true)
+		{
+			while (!PUGI__IS_CHARTYPE(*s, ct_parse_cdata)) ++s;
+			
+			if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
+			{
+				*s++ = '\n'; // replace first one with 0x0a
+				
+				if (*s == '\n') g.push(s, 1);
+			}
+			else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here
+			{
+				*g.flush(s) = 0;
+				
+				return s + 1;
+			}
+			else if (*s == 0)
+			{
+				return 0;
+			}
+			else ++s;
+		}
+	}
+	
+	typedef char_t* (*strconv_pcdata_t)(char_t*);
+		
+	template <typename opt_eol, typename opt_escape> struct strconv_pcdata_impl
+	{
+		static char_t* parse(char_t* s)
+		{
+			gap g;
+			
+			while (true)
+			{
+				while (!PUGI__IS_CHARTYPE(*s, ct_parse_pcdata)) ++s;
+					
+				if (*s == '<') // PCDATA ends here
+				{
+					*g.flush(s) = 0;
+					
+					return s + 1;
+				}
+				else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
+				{
+					*s++ = '\n'; // replace first one with 0x0a
+					
+					if (*s == '\n') g.push(s, 1);
+				}
+				else if (opt_escape::value && *s == '&')
+				{
+					s = strconv_escape(s, g);
+				}
+				else if (*s == 0)
+				{
+					return s;
+				}
+				else ++s;
+			}
+		}
+	};
+	
+	PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
+	{
+		PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20);
+
+		switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes)
+		{
+		case 0: return strconv_pcdata_impl<opt_false, opt_false>::parse;
+		case 1: return strconv_pcdata_impl<opt_false, opt_true>::parse;
+		case 2: return strconv_pcdata_impl<opt_true, opt_false>::parse;
+		case 3: return strconv_pcdata_impl<opt_true, opt_true>::parse;
+		default: return 0; // should not get here
+		}
+	}
+
+	typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
+	
+	template <typename opt_escape> struct strconv_attribute_impl
+	{
+		static char_t* parse_wnorm(char_t* s, char_t end_quote)
+		{
+			gap g;
+
+			// trim leading whitespaces
+			if (PUGI__IS_CHARTYPE(*s, ct_space))
+			{
+				char_t* str = s;
+				
+				do ++str;
+				while (PUGI__IS_CHARTYPE(*str, ct_space));
+				
+				g.push(s, str - s);
+			}
+
+			while (true)
+			{
+				while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s;
+				
+				if (*s == end_quote)
+				{
+					char_t* str = g.flush(s);
+					
+					do *str-- = 0;
+					while (PUGI__IS_CHARTYPE(*str, ct_space));
+				
+					return s + 1;
+				}
+				else if (PUGI__IS_CHARTYPE(*s, ct_space))
+				{
+					*s++ = ' ';
+		
+					if (PUGI__IS_CHARTYPE(*s, ct_space))
+					{
+						char_t* str = s + 1;
+						while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
+						
+						g.push(s, str - s);
+					}
+				}
+				else if (opt_escape::value && *s == '&')
+				{
+					s = strconv_escape(s, g);
+				}
+				else if (!*s)
+				{
+					return 0;
+				}
+				else ++s;
+			}
+		}
+
+		static char_t* parse_wconv(char_t* s, char_t end_quote)
+		{
+			gap g;
+
+			while (true)
+			{
+				while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s;
+				
+				if (*s == end_quote)
+				{
+					*g.flush(s) = 0;
+				
+					return s + 1;
+				}
+				else if (PUGI__IS_CHARTYPE(*s, ct_space))
+				{
+					if (*s == '\r')
+					{
+						*s++ = ' ';
+				
+						if (*s == '\n') g.push(s, 1);
+					}
+					else *s++ = ' ';
+				}
+				else if (opt_escape::value && *s == '&')
+				{
+					s = strconv_escape(s, g);
+				}
+				else if (!*s)
+				{
+					return 0;
+				}
+				else ++s;
+			}
+		}
+
+		static char_t* parse_eol(char_t* s, char_t end_quote)
+		{
+			gap g;
+
+			while (true)
+			{
+				while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s;
+				
+				if (*s == end_quote)
+				{
+					*g.flush(s) = 0;
+				
+					return s + 1;
+				}
+				else if (*s == '\r')
+				{
+					*s++ = '\n';
+					
+					if (*s == '\n') g.push(s, 1);
+				}
+				else if (opt_escape::value && *s == '&')
+				{
+					s = strconv_escape(s, g);
+				}
+				else if (!*s)
+				{
+					return 0;
+				}
+				else ++s;
+			}
+		}
+
+		static char_t* parse_simple(char_t* s, char_t end_quote)
+		{
+			gap g;
+
+			while (true)
+			{
+				while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s;
+				
+				if (*s == end_quote)
+				{
+					*g.flush(s) = 0;
+				
+					return s + 1;
+				}
+				else if (opt_escape::value && *s == '&')
+				{
+					s = strconv_escape(s, g);
+				}
+				else if (!*s)
+				{
+					return 0;
+				}
+				else ++s;
+			}
+		}
+	};
+
+	PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
+	{
+		PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
+		
+		switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes)
+		{
+		case 0:  return strconv_attribute_impl<opt_false>::parse_simple;
+		case 1:  return strconv_attribute_impl<opt_true>::parse_simple;
+		case 2:  return strconv_attribute_impl<opt_false>::parse_eol;
+		case 3:  return strconv_attribute_impl<opt_true>::parse_eol;
+		case 4:  return strconv_attribute_impl<opt_false>::parse_wconv;
+		case 5:  return strconv_attribute_impl<opt_true>::parse_wconv;
+		case 6:  return strconv_attribute_impl<opt_false>::parse_wconv;
+		case 7:  return strconv_attribute_impl<opt_true>::parse_wconv;
+		case 8:  return strconv_attribute_impl<opt_false>::parse_wnorm;
+		case 9:  return strconv_attribute_impl<opt_true>::parse_wnorm;
+		case 10: return strconv_attribute_impl<opt_false>::parse_wnorm;
+		case 11: return strconv_attribute_impl<opt_true>::parse_wnorm;
+		case 12: return strconv_attribute_impl<opt_false>::parse_wnorm;
+		case 13: return strconv_attribute_impl<opt_true>::parse_wnorm;
+		case 14: return strconv_attribute_impl<opt_false>::parse_wnorm;
+		case 15: return strconv_attribute_impl<opt_true>::parse_wnorm;
+		default: return 0; // should not get here
+		}
+	}
+
+	inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
+	{
+		xml_parse_result result;
+		result.status = status;
+		result.offset = offset;
+
+		return result;
+	}
+
+	struct xml_parser
+	{
+		xml_allocator alloc;
+		char_t* error_offset;
+		xml_parse_status error_status;
+		
+		// Parser utilities.
+		#define PUGI__SKIPWS()			{ while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
+		#define PUGI__OPTSET(OPT)			( optmsk & (OPT) )
+		#define PUGI__PUSHNODE(TYPE)		{ cursor = append_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
+		#define PUGI__POPNODE()			{ cursor = cursor->parent; }
+		#define PUGI__SCANFOR(X)			{ while (*s != 0 && !(X)) ++s; }
+		#define PUGI__SCANWHILE(X)		{ while ((X)) ++s; }
+		#define PUGI__ENDSEG()			{ ch = *s; *s = 0; ++s; }
+		#define PUGI__THROW_ERROR(err, m)	return error_offset = m, error_status = err, static_cast<char_t*>(0)
+		#define PUGI__CHECK_ERROR(err, m)	{ if (*s == 0) PUGI__THROW_ERROR(err, m); }
+		
+		xml_parser(const xml_allocator& alloc_): alloc(alloc_), error_offset(0), error_status(status_ok)
+		{
+		}
+
+		// DOCTYPE consists of nested sections of the following possible types:
+		// <!-- ... -->, <? ... ?>, "...", '...'
+		// <![...]]>
+		// <!...>
+		// First group can not contain nested groups
+		// Second group can contain nested groups of the same type
+		// Third group can contain all other groups
+		char_t* parse_doctype_primitive(char_t* s)
+		{
+			if (*s == '"' || *s == '\'')
+			{
+				// quoted string
+				char_t ch = *s++;
+				PUGI__SCANFOR(*s == ch);
+				if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
+
+				s++;
+			}
+			else if (s[0] == '<' && s[1] == '?')
+			{
+				// <? ... ?>
+				s += 2;
+				PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
+				if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
+
+				s += 2;
+			}
+			else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')
+			{
+				s += 4;
+				PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
+				if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
+
+				s += 4;
+			}
+			else PUGI__THROW_ERROR(status_bad_doctype, s);
+
+			return s;
+		}
+
+		char_t* parse_doctype_ignore(char_t* s)
+		{
+			assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
+			s++;
+
+			while (*s)
+			{
+				if (s[0] == '<' && s[1] == '!' && s[2] == '[')
+				{
+					// nested ignore section
+					s = parse_doctype_ignore(s);
+					if (!s) return s;
+				}
+				else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
+				{
+					// ignore section end
+					s += 3;
+
+					return s;
+				}
+				else s++;
+			}
+
+			PUGI__THROW_ERROR(status_bad_doctype, s);
+		}
+
+		char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel)
+		{
+			assert(s[0] == '<' && s[1] == '!');
+			s++;
+
+			while (*s)
+			{
+				if (s[0] == '<' && s[1] == '!' && s[2] != '-')
+				{
+					if (s[2] == '[')
+					{
+						// ignore
+						s = parse_doctype_ignore(s);
+						if (!s) return s;
+					}
+					else
+					{
+						// some control group
+						s = parse_doctype_group(s, endch, false);
+						if (!s) return s;
+					}
+				}
+				else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
+				{
+					// unknown tag (forbidden), or some primitive group
+					s = parse_doctype_primitive(s);
+					if (!s) return s;
+				}
+				else if (*s == '>')
+				{
+					s++;
+
+					return s;
+				}
+				else s++;
+			}
+
+			if (!toplevel || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
+
+			return s;
+		}
+
+		char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch)
+		{
+			// parse node contents, starting with exclamation mark
+			++s;
+
+			if (*s == '-') // '<!-...'
+			{
+				++s;
+
+				if (*s == '-') // '<!--...'
+				{
+					++s;
+
+					if (PUGI__OPTSET(parse_comments))
+					{
+						PUGI__PUSHNODE(node_comment); // Append a new node on the tree.
+						cursor->value = s; // Save the offset.
+					}
+
+					if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments))
+					{
+						s = strconv_comment(s, endch);
+
+						if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
+					}
+					else
+					{
+						// Scan for terminating '-->'.
+						PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>'));
+						PUGI__CHECK_ERROR(status_bad_comment, s);
+
+						if (PUGI__OPTSET(parse_comments))
+							*s = 0; // Zero-terminate this segment at the first terminating '-'.
+
+						s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
+					}
+				}
+				else PUGI__THROW_ERROR(status_bad_comment, s);
+			}
+			else if (*s == '[')
+			{
+				// '<![CDATA[...'
+				if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')
+				{
+					++s;
+
+					if (PUGI__OPTSET(parse_cdata))
+					{
+						PUGI__PUSHNODE(node_cdata); // Append a new node on the tree.
+						cursor->value = s; // Save the offset.
+
+						if (PUGI__OPTSET(parse_eol))
+						{
+							s = strconv_cdata(s, endch);
+
+							if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
+						}
+						else
+						{
+							// Scan for terminating ']]>'.
+							PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
+							PUGI__CHECK_ERROR(status_bad_cdata, s);
+
+							*s++ = 0; // Zero-terminate this segment.
+						}
+					}
+					else // Flagged for discard, but we still have to scan for the terminator.
+					{
+						// Scan for terminating ']]>'.
+						PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
+						PUGI__CHECK_ERROR(status_bad_cdata, s);
+
+						++s;
+					}
+
+					s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
+				}
+				else PUGI__THROW_ERROR(status_bad_cdata, s);
+			}
+			else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E'))
+			{
+				s -= 2;
+
+				if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
+
+				char_t* mark = s + 9;
+
+				s = parse_doctype_group(s, endch, true);
+				if (!s) return s;
+
+				if (PUGI__OPTSET(parse_doctype))
+				{
+					while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
+
+					PUGI__PUSHNODE(node_doctype);
+
+					cursor->value = mark;
+
+					assert((s[0] == 0 && endch == '>') || s[-1] == '>');
+					s[*s == 0 ? 0 : -1] = 0;
+
+					PUGI__POPNODE();
+				}
+			}
+			else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s);
+			else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s);
+			else PUGI__THROW_ERROR(status_unrecognized_tag, s);
+
+			return s;
+		}
+
+		char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch)
+		{
+			// load into registers
+			xml_node_struct* cursor = ref_cursor;
+			char_t ch = 0;
+
+			// parse node contents, starting with question mark
+			++s;
+
+			// read PI target
+			char_t* target = s;
+
+			if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s);
+
+			PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
+			PUGI__CHECK_ERROR(status_bad_pi, s);
+
+			// determine node type; stricmp / strcasecmp is not portable
+			bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
+
+			if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
+			{
+				if (declaration)
+				{
+					// disallow non top-level declarations
+					if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
+
+					PUGI__PUSHNODE(node_declaration);
+				}
+				else
+				{
+					PUGI__PUSHNODE(node_pi);
+				}
+
+				cursor->name = target;
+
+				PUGI__ENDSEG();
+
+				// parse value/attributes
+				if (ch == '?')
+				{
+					// empty node
+					if (!ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s);
+					s += (*s == '>');
+
+					PUGI__POPNODE();
+				}
+				else if (PUGI__IS_CHARTYPE(ch, ct_space))
+				{
+					PUGI__SKIPWS();
+
+					// scan for tag end
+					char_t* value = s;
+
+					PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
+					PUGI__CHECK_ERROR(status_bad_pi, s);
+
+					if (declaration)
+					{
+						// replace ending ? with / so that 'element' terminates properly
+						*s = '/';
+
+						// we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES
+						s = value;
+					}
+					else
+					{
+						// store value and step over >
+						cursor->value = value;
+						PUGI__POPNODE();
+
+						PUGI__ENDSEG();
+
+						s += (*s == '>');
+					}
+				}
+				else PUGI__THROW_ERROR(status_bad_pi, s);
+			}
+			else
+			{
+				// scan for tag end
+				PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
+				PUGI__CHECK_ERROR(status_bad_pi, s);
+
+				s += (s[1] == '>' ? 2 : 1);
+			}
+
+			// store from registers
+			ref_cursor = cursor;
+
+			return s;
+		}
+
+		char_t* parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch)
+		{
+			strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
+			strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
+			
+			char_t ch = 0;
+			xml_node_struct* cursor = xmldoc;
+			char_t* mark = s;
+
+			while (*s != 0)
+			{
+				if (*s == '<')
+				{
+					++s;
+
+				LOC_TAG:
+					if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
+					{
+						PUGI__PUSHNODE(node_element); // Append a new node to the tree.
+
+						cursor->name = s;
+
+						PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
+						PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
+
+						if (ch == '>')
+						{
+							// end of tag
+						}
+						else if (PUGI__IS_CHARTYPE(ch, ct_space))
+						{
+						LOC_ATTRIBUTES:
+							while (true)
+							{
+								PUGI__SKIPWS(); // Eat any whitespace.
+						
+								if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
+								{
+									xml_attribute_struct* a = append_attribute_ll(cursor, alloc); // Make space for this attribute.
+									if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
+
+									a->name = s; // Save the offset.
+
+									PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
+									PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
+
+									PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
+									PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
+
+									if (PUGI__IS_CHARTYPE(ch, ct_space))
+									{
+										PUGI__SKIPWS(); // Eat any whitespace.
+										PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
+
+										ch = *s;
+										++s;
+									}
+									
+									if (ch == '=') // '<... #=...'
+									{
+										PUGI__SKIPWS(); // Eat any whitespace.
+
+										if (*s == '"' || *s == '\'') // '<... #="...'
+										{
+											ch = *s; // Save quote char to avoid breaking on "''" -or- '""'.
+											++s; // Step over the quote.
+											a->value = s; // Save the offset.
+
+											s = strconv_attribute(s, ch);
+										
+											if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
+
+											// After this line the loop continues from the start;
+											// Whitespaces, / and > are ok, symbols and EOF are wrong,
+											// everything else will be detected
+											if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s);
+										}
+										else PUGI__THROW_ERROR(status_bad_attribute, s);
+									}
+									else PUGI__THROW_ERROR(status_bad_attribute, s);
+								}
+								else if (*s == '/')
+								{
+									++s;
+									
+									if (*s == '>')
+									{
+										PUGI__POPNODE();
+										s++;
+										break;
+									}
+									else if (*s == 0 && endch == '>')
+									{
+										PUGI__POPNODE();
+										break;
+									}
+									else PUGI__THROW_ERROR(status_bad_start_element, s);
+								}
+								else if (*s == '>')
+								{
+									++s;
+
+									break;
+								}
+								else if (*s == 0 && endch == '>')
+								{
+									break;
+								}
+								else PUGI__THROW_ERROR(status_bad_start_element, s);
+							}
+
+							// !!!
+						}
+						else if (ch == '/') // '<#.../'
+						{
+							if (!ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s);
+
+							PUGI__POPNODE(); // Pop.
+
+							s += (*s == '>');
+						}
+						else if (ch == 0)
+						{
+							// we stepped over null terminator, backtrack & handle closing tag
+							--s;
+							
+							if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s);
+						}
+						else PUGI__THROW_ERROR(status_bad_start_element, s);
+					}
+					else if (*s == '/')
+					{
+						++s;
+
+						char_t* name = cursor->name;
+						if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s);
+						
+						while (PUGI__IS_CHARTYPE(*s, ct_symbol))
+						{
+							if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s);
+						}
+
+						if (*name)
+						{
+							if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
+							else PUGI__THROW_ERROR(status_end_element_mismatch, s);
+						}
+							
+						PUGI__POPNODE(); // Pop.
+
+						PUGI__SKIPWS();
+
+						if (*s == 0)
+						{
+							if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
+						}
+						else
+						{
+							if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
+							++s;
+						}
+					}
+					else if (*s == '?') // '<?...'
+					{
+						s = parse_question(s, cursor, optmsk, endch);
+						if (!s) return s;
+
+						assert(cursor);
+						if ((cursor->header & xml_memory_page_type_mask) + 1 == node_declaration) goto LOC_ATTRIBUTES;
+					}
+					else if (*s == '!') // '<!...'
+					{
+						s = parse_exclamation(s, cursor, optmsk, endch);
+						if (!s) return s;
+					}
+					else if (*s == 0 && endch == '?') PUGI__THROW_ERROR(status_bad_pi, s);
+					else PUGI__THROW_ERROR(status_unrecognized_tag, s);
+				}
+				else
+				{
+					mark = s; // Save this offset while searching for a terminator.
+
+					PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
+
+					if (*s == '<')
+					{
+						// We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one
+						assert(mark != s);
+
+						if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single))
+						{
+							continue;
+						}
+						else if (PUGI__OPTSET(parse_ws_pcdata_single))
+						{
+							if (s[1] != '/' || cursor->first_child) continue;
+						}
+					}
+
+					s = mark;
+							
+					if (cursor->parent)
+					{
+						PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree.
+						cursor->value = s; // Save the offset.
+
+						s = strconv_pcdata(s);
+								
+						PUGI__POPNODE(); // Pop since this is a standalone.
+						
+						if (!*s) break;
+					}
+					else
+					{
+						PUGI__SCANFOR(*s == '<'); // '...<'
+						if (!*s) break;
+						
+						++s;
+					}
+
+					// We're after '<'
+					goto LOC_TAG;
+				}
+			}
+
+			// check that last tag is closed
+			if (cursor != xmldoc) PUGI__THROW_ERROR(status_end_element_mismatch, s);
+
+			return s;
+		}
+
+		static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk)
+		{
+			xml_document_struct* xmldoc = static_cast<xml_document_struct*>(root);
+
+			// store buffer for offset_debug
+			xmldoc->buffer = buffer;
+
+			// early-out for empty documents
+			if (length == 0) return make_parse_result(status_ok);
+
+			// create parser on stack
+			xml_parser parser(*xmldoc);
+
+			// save last character and make buffer zero-terminated (speeds up parsing)
+			char_t endch = buffer[length - 1];
+			buffer[length - 1] = 0;
+			
+			// perform actual parsing
+			parser.parse(buffer, xmldoc, optmsk, endch);
+
+			xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
+			assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
+
+			// update allocator state
+			*static_cast<xml_allocator*>(xmldoc) = parser.alloc;
+
+			// since we removed last character, we have to handle the only possible false positive
+			if (result && endch == '<')
+			{
+				// there's no possible well-formed document with < at the end
+				return make_parse_result(status_unrecognized_tag, length);
+			}
+
+			return result;
+		}
+	};
+
+	// Output facilities
+	PUGI__FN xml_encoding get_write_native_encoding()
+	{
+	#ifdef PUGIXML_WCHAR_MODE
+		return get_wchar_encoding();
+	#else
+		return encoding_utf8;
+	#endif
+	}
+
+	PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
+	{
+		// replace wchar encoding with utf implementation
+		if (encoding == encoding_wchar) return get_wchar_encoding();
+
+		// replace utf16 encoding with utf16 with specific endianness
+		if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+		// replace utf32 encoding with utf32 with specific endianness
+		if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+		// only do autodetection if no explicit encoding is requested
+		if (encoding != encoding_auto) return encoding;
+
+		// assume utf8 encoding
+		return encoding_utf8;
+	}
+
+#ifdef PUGIXML_WCHAR_MODE
+	PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
+	{
+		assert(length > 0);
+
+		// discard last character if it's the lead of a surrogate pair 
+		return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
+	}
+
+	PUGI__FN size_t convert_buffer(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
+	{
+		// only endian-swapping is required
+		if (need_endian_swap_utf(encoding, get_wchar_encoding()))
+		{
+			convert_wchar_endian_swap(r_char, data, length);
+
+			return length * sizeof(char_t);
+		}
+	
+		// convert to utf8
+		if (encoding == encoding_utf8)
+		{
+			uint8_t* dest = r_u8;
+			uint8_t* end = utf_decoder<utf8_writer>::decode_wchar_block(data, length, dest);
+
+			return static_cast<size_t>(end - dest);
+		}
+
+		// convert to utf16
+		if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
+		{
+			uint16_t* dest = r_u16;
+
+			// convert to native utf16
+			uint16_t* end = utf_decoder<utf16_writer>::decode_wchar_block(data, length, dest);
+
+			// swap if necessary
+			xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+			if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
+
+			return static_cast<size_t>(end - dest) * sizeof(uint16_t);
+		}
+
+		// convert to utf32
+		if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
+		{
+			uint32_t* dest = r_u32;
+
+			// convert to native utf32
+			uint32_t* end = utf_decoder<utf32_writer>::decode_wchar_block(data, length, dest);
+
+			// swap if necessary
+			xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+			if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
+
+			return static_cast<size_t>(end - dest) * sizeof(uint32_t);
+		}
+
+		// convert to latin1
+		if (encoding == encoding_latin1)
+		{
+			uint8_t* dest = r_u8;
+			uint8_t* end = utf_decoder<latin1_writer>::decode_wchar_block(data, length, dest);
+
+			return static_cast<size_t>(end - dest);
+		}
+
+		assert(!"Invalid encoding");
+		return 0;
+	}
+#else
+	PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
+	{
+		assert(length > 4);
+
+		for (size_t i = 1; i <= 4; ++i)
+		{
+			uint8_t ch = static_cast<uint8_t>(data[length - i]);
+
+			// either a standalone character or a leading one
+			if ((ch & 0xc0) != 0x80) return length - i;
+		}
+
+		// there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk
+		return length;
+	}
+
+	PUGI__FN size_t convert_buffer(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
+	{
+		if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
+		{
+			uint16_t* dest = r_u16;
+
+			// convert to native utf16
+			uint16_t* end = utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
+
+			// swap if necessary
+			xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
+
+			if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
+
+			return static_cast<size_t>(end - dest) * sizeof(uint16_t);
+		}
+
+		if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
+		{
+			uint32_t* dest = r_u32;
+
+			// convert to native utf32
+			uint32_t* end = utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
+
+			// swap if necessary
+			xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
+
+			if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
+
+			return static_cast<size_t>(end - dest) * sizeof(uint32_t);
+		}
+
+		if (encoding == encoding_latin1)
+		{
+			uint8_t* dest = r_u8;
+			uint8_t* end = utf_decoder<latin1_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
+
+			return static_cast<size_t>(end - dest);
+		}
+
+		assert(!"Invalid encoding");
+		return 0;
+	}
+#endif
+
+	class xml_buffered_writer
+	{
+		xml_buffered_writer(const xml_buffered_writer&);
+		xml_buffered_writer& operator=(const xml_buffered_writer&);
+
+	public:
+		xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
+		{
+			PUGI__STATIC_ASSERT(bufcapacity >= 8);
+		}
+
+		~xml_buffered_writer()
+		{
+			flush();
+		}
+
+		void flush()
+		{
+			flush(buffer, bufsize);
+			bufsize = 0;
+		}
+
+		void flush(const char_t* data, size_t size)
+		{
+			if (size == 0) return;
+
+			// fast path, just write data
+			if (encoding == get_write_native_encoding())
+				writer.write(data, size * sizeof(char_t));
+			else
+			{
+				// convert chunk
+				size_t result = convert_buffer(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);
+				assert(result <= sizeof(scratch));
+
+				// write data
+				writer.write(scratch.data_u8, result);
+			}
+		}
+
+		void write(const char_t* data, size_t length)
+		{
+			if (bufsize + length > bufcapacity)
+			{
+				// flush the remaining buffer contents
+				flush();
+
+				// handle large chunks
+				if (length > bufcapacity)
+				{
+					if (encoding == get_write_native_encoding())
+					{
+						// fast path, can just write data chunk
+						writer.write(data, length * sizeof(char_t));
+						return;
+					}
+
+					// need to convert in suitable chunks
+					while (length > bufcapacity)
+					{
+						// get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer
+						// and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
+						size_t chunk_size = get_valid_length(data, bufcapacity);
+
+						// convert chunk and write
+						flush(data, chunk_size);
+
+						// iterate
+						data += chunk_size;
+						length -= chunk_size;
+					}
+
+					// small tail is copied below
+					bufsize = 0;
+				}
+			}
+
+			memcpy(buffer + bufsize, data, length * sizeof(char_t));
+			bufsize += length;
+		}
+
+		void write(const char_t* data)
+		{
+			write(data, strlength(data));
+		}
+
+		void write(char_t d0)
+		{
+			if (bufsize + 1 > bufcapacity) flush();
+
+			buffer[bufsize + 0] = d0;
+			bufsize += 1;
+		}
+
+		void write(char_t d0, char_t d1)
+		{
+			if (bufsize + 2 > bufcapacity) flush();
+
+			buffer[bufsize + 0] = d0;
+			buffer[bufsize + 1] = d1;
+			bufsize += 2;
+		}
+
+		void write(char_t d0, char_t d1, char_t d2)
+		{
+			if (bufsize + 3 > bufcapacity) flush();
+
+			buffer[bufsize + 0] = d0;
+			buffer[bufsize + 1] = d1;
+			buffer[bufsize + 2] = d2;
+			bufsize += 3;
+		}
+
+		void write(char_t d0, char_t d1, char_t d2, char_t d3)
+		{
+			if (bufsize + 4 > bufcapacity) flush();
+
+			buffer[bufsize + 0] = d0;
+			buffer[bufsize + 1] = d1;
+			buffer[bufsize + 2] = d2;
+			buffer[bufsize + 3] = d3;
+			bufsize += 4;
+		}
+
+		void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
+		{
+			if (bufsize + 5 > bufcapacity) flush();
+
+			buffer[bufsize + 0] = d0;
+			buffer[bufsize + 1] = d1;
+			buffer[bufsize + 2] = d2;
+			buffer[bufsize + 3] = d3;
+			buffer[bufsize + 4] = d4;
+			bufsize += 5;
+		}
+
+		void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
+		{
+			if (bufsize + 6 > bufcapacity) flush();
+
+			buffer[bufsize + 0] = d0;
+			buffer[bufsize + 1] = d1;
+			buffer[bufsize + 2] = d2;
+			buffer[bufsize + 3] = d3;
+			buffer[bufsize + 4] = d4;
+			buffer[bufsize + 5] = d5;
+			bufsize += 6;
+		}
+
+		// utf8 maximum expansion: x4 (-> utf32)
+		// utf16 maximum expansion: x2 (-> utf32)
+		// utf32 maximum expansion: x1
+		enum
+		{
+			bufcapacitybytes =
+			#ifdef PUGIXML_MEMORY_OUTPUT_STACK
+				PUGIXML_MEMORY_OUTPUT_STACK
+			#else
+				10240
+			#endif
+			,
+			bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4)
+		};
+
+		char_t buffer[bufcapacity];
+
+		union
+		{
+			uint8_t data_u8[4 * bufcapacity];
+			uint16_t data_u16[2 * bufcapacity];
+			uint32_t data_u32[bufcapacity];
+			char_t data_char[bufcapacity];
+		} scratch;
+
+		xml_writer& writer;
+		size_t bufsize;
+		xml_encoding encoding;
+	};
+
+	PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type)
+	{
+		while (*s)
+		{
+			const char_t* prev = s;
+			
+			// While *s is a usual symbol
+			while (!PUGI__IS_CHARTYPEX(*s, type)) ++s;
+		
+			writer.write(prev, static_cast<size_t>(s - prev));
+
+			switch (*s)
+			{
+				case 0: break;
+				case '&':
+					writer.write('&', 'a', 'm', 'p', ';');
+					++s;
+					break;
+				case '<':
+					writer.write('&', 'l', 't', ';');
+					++s;
+					break;
+				case '>':
+					writer.write('&', 'g', 't', ';');
+					++s;
+					break;
+				case '"':
+					writer.write('&', 'q', 'u', 'o', 't', ';');
+					++s;
+					break;
+				default: // s is not a usual symbol
+				{
+					unsigned int ch = static_cast<unsigned int>(*s++);
+					assert(ch < 32);
+
+					writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');
+				}
+			}
+		}
+	}
+
+	PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
+	{
+		if (flags & format_no_escapes)
+			writer.write(s);
+		else
+			text_output_escaped(writer, s, type);
+	}
+
+	PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s)
+	{
+		do
+		{
+			writer.write('<', '!', '[', 'C', 'D');
+			writer.write('A', 'T', 'A', '[');
+
+			const char_t* prev = s;
+
+			// look for ]]> sequence - we can't output it as is since it terminates CDATA
+			while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s;
+
+			// skip ]] if we stopped at ]]>, > will go to the next CDATA section
+			if (*s) s += 2;
+
+			writer.write(prev, static_cast<size_t>(s - prev));
+
+			writer.write(']', ']', '>');
+		}
+		while (*s);
+	}
+
+	PUGI__FN void node_output_attributes(xml_buffered_writer& writer, const xml_node& node, unsigned int flags)
+	{
+		const char_t* default_name = PUGIXML_TEXT(":anonymous");
+
+		for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute())
+		{
+			writer.write(' ');
+			writer.write(a.name()[0] ? a.name() : default_name);
+			writer.write('=', '"');
+
+			text_output(writer, a.value(), ctx_special_attr, flags);
+
+			writer.write('"');
+		}
+	}
+
+	PUGI__FN void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth)
+	{
+		const char_t* default_name = PUGIXML_TEXT(":anonymous");
+
+		if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
+			for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
+
+		switch (node.type())
+		{
+		case node_document:
+		{
+			for (xml_node n = node.first_child(); n; n = n.next_sibling())
+				node_output(writer, n, indent, flags, depth);
+			break;
+		}
+			
+		case node_element:
+		{
+			const char_t* name = node.name()[0] ? node.name() : default_name;
+
+			writer.write('<');
+			writer.write(name);
+
+			node_output_attributes(writer, node, flags);
+
+			if (flags & format_raw)
+			{
+				if (!node.first_child())
+					writer.write(' ', '/', '>');
+				else
+				{
+					writer.write('>');
+
+					for (xml_node n = node.first_child(); n; n = n.next_sibling())
+						node_output(writer, n, indent, flags, depth + 1);
+
+					writer.write('<', '/');
+					writer.write(name);
+					writer.write('>');
+				}
+			}
+			else if (!node.first_child())
+				writer.write(' ', '/', '>', '\n');
+			else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata))
+			{
+				writer.write('>');
+
+				if (node.first_child().type() == node_pcdata)
+					text_output(writer, node.first_child().value(), ctx_special_pcdata, flags);
+				else
+					text_output_cdata(writer, node.first_child().value());
+
+				writer.write('<', '/');
+				writer.write(name);
+				writer.write('>', '\n');
+			}
+			else
+			{
+				writer.write('>', '\n');
+				
+				for (xml_node n = node.first_child(); n; n = n.next_sibling())
+					node_output(writer, n, indent, flags, depth + 1);
+
+				if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
+					for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
+				
+				writer.write('<', '/');
+				writer.write(name);
+				writer.write('>', '\n');
+			}
+
+			break;
+		}
+		
+		case node_pcdata:
+			text_output(writer, node.value(), ctx_special_pcdata, flags);
+			if ((flags & format_raw) == 0) writer.write('\n');
+			break;
+
+		case node_cdata:
+			text_output_cdata(writer, node.value());
+			if ((flags & format_raw) == 0) writer.write('\n');
+			break;
+
+		case node_comment:
+			writer.write('<', '!', '-', '-');
+			writer.write(node.value());
+			writer.write('-', '-', '>');
+			if ((flags & format_raw) == 0) writer.write('\n');
+			break;
+
+		case node_pi:
+		case node_declaration:
+			writer.write('<', '?');
+			writer.write(node.name()[0] ? node.name() : default_name);
+
+			if (node.type() == node_declaration)
+			{
+				node_output_attributes(writer, node, flags);
+			}
+			else if (node.value()[0])
+			{
+				writer.write(' ');
+				writer.write(node.value());
+			}
+
+			writer.write('?', '>');
+			if ((flags & format_raw) == 0) writer.write('\n');
+			break;
+
+		case node_doctype:
+			writer.write('<', '!', 'D', 'O', 'C');
+			writer.write('T', 'Y', 'P', 'E');
+
+			if (node.value()[0])
+			{
+				writer.write(' ');
+				writer.write(node.value());
+			}
+
+			writer.write('>');
+			if ((flags & format_raw) == 0) writer.write('\n');
+			break;
+
+		default:
+			assert(!"Invalid node type");
+		}
+	}
+
+	inline bool has_declaration(const xml_node& node)
+	{
+		for (xml_node child = node.first_child(); child; child = child.next_sibling())
+		{
+			xml_node_type type = child.type();
+
+			if (type == node_declaration) return true;
+			if (type == node_element) return false;
+		}
+
+		return false;
+	}
+
+	inline bool allow_insert_child(xml_node_type parent, xml_node_type child)
+	{
+		if (parent != node_document && parent != node_element) return false;
+		if (child == node_document || child == node_null) return false;
+		if (parent != node_document && (child == node_declaration || child == node_doctype)) return false;
+
+		return true;
+	}
+
+	PUGI__FN void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip)
+	{
+		assert(dest.type() == source.type());
+
+		switch (source.type())
+		{
+		case node_element:
+		{
+			dest.set_name(source.name());
+
+			for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
+				dest.append_attribute(a.name()).set_value(a.value());
+
+			for (xml_node c = source.first_child(); c; c = c.next_sibling())
+			{
+				if (c == skip) continue;
+
+				xml_node cc = dest.append_child(c.type());
+				assert(cc);
+
+				recursive_copy_skip(cc, c, skip);
+			}
+
+			break;
+		}
+
+		case node_pcdata:
+		case node_cdata:
+		case node_comment:
+		case node_doctype:
+			dest.set_value(source.value());
+			break;
+
+		case node_pi:
+			dest.set_name(source.name());
+			dest.set_value(source.value());
+			break;
+
+		case node_declaration:
+		{
+			dest.set_name(source.name());
+
+			for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
+				dest.append_attribute(a.name()).set_value(a.value());
+
+			break;
+		}
+
+		default:
+			assert(!"Invalid node type");
+		}
+	}
+
+	inline bool is_text_node(xml_node_struct* node)
+	{
+		xml_node_type type = static_cast<xml_node_type>((node->header & impl::xml_memory_page_type_mask) + 1);
+
+		return type == node_pcdata || type == node_cdata;
+	}
+
+	// get value with conversion functions
+	PUGI__FN int get_value_int(const char_t* value, int def)
+	{
+		if (!value) return def;
+
+	#ifdef PUGIXML_WCHAR_MODE
+		return static_cast<int>(wcstol(value, 0, 10));
+	#else
+		return static_cast<int>(strtol(value, 0, 10));
+	#endif
+	}
+
+	PUGI__FN unsigned int get_value_uint(const char_t* value, unsigned int def)
+	{
+		if (!value) return def;
+
+	#ifdef PUGIXML_WCHAR_MODE
+		return static_cast<unsigned int>(wcstoul(value, 0, 10));
+	#else
+		return static_cast<unsigned int>(strtoul(value, 0, 10));
+	#endif
+	}
+
+	PUGI__FN double get_value_double(const char_t* value, double def)
+	{
+		if (!value) return def;
+
+	#ifdef PUGIXML_WCHAR_MODE
+		return wcstod(value, 0);
+	#else
+		return strtod(value, 0);
+	#endif
+	}
+
+	PUGI__FN float get_value_float(const char_t* value, float def)
+	{
+		if (!value) return def;
+
+	#ifdef PUGIXML_WCHAR_MODE
+		return static_cast<float>(wcstod(value, 0));
+	#else
+		return static_cast<float>(strtod(value, 0));
+	#endif
+	}
+
+	PUGI__FN bool get_value_bool(const char_t* value, bool def)
+	{
+		if (!value) return def;
+
+		// only look at first char
+		char_t first = *value;
+
+		// 1*, t* (true), T* (True), y* (yes), Y* (YES)
+		return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
+	}
+
+	// set value with conversion functions
+	PUGI__FN bool set_value_buffer(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char (&buf)[128])
+	{
+	#ifdef PUGIXML_WCHAR_MODE
+		char_t wbuf[128];
+		impl::widen_ascii(wbuf, buf);
+
+		return strcpy_insitu(dest, header, header_mask, wbuf);
+	#else
+		return strcpy_insitu(dest, header, header_mask, buf);
+	#endif
+	}
+
+	PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, int value)
+	{
+		char buf[128];
+		sprintf(buf, "%d", value);
+	
+		return set_value_buffer(dest, header, header_mask, buf);
+	}
+
+	PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned int value)
+	{
+		char buf[128];
+		sprintf(buf, "%u", value);
+
+		return set_value_buffer(dest, header, header_mask, buf);
+	}
+
+	PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, double value)
+	{
+		char buf[128];
+		sprintf(buf, "%g", value);
+
+		return set_value_buffer(dest, header, header_mask, buf);
+	}
+	
+	PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, bool value)
+	{
+		return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
+	}
+
+	// we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick
+	PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
+	{
+	#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
+		// there are 64-bit versions of fseek/ftell, let's use them
+		typedef __int64 length_type;
+
+		_fseeki64(file, 0, SEEK_END);
+		length_type length = _ftelli64(file);
+		_fseeki64(file, 0, SEEK_SET);
+	#elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__)
+		// there are 64-bit versions of fseek/ftell, let's use them
+		typedef off64_t length_type;
+
+		fseeko64(file, 0, SEEK_END);
+		length_type length = ftello64(file);
+		fseeko64(file, 0, SEEK_SET);
+	#else
+		// if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway.
+		typedef long length_type;
+
+		fseek(file, 0, SEEK_END);
+		length_type length = ftell(file);
+		fseek(file, 0, SEEK_SET);
+	#endif
+
+		// check for I/O errors
+		if (length < 0) return status_io_error;
+		
+		// check for overflow
+		size_t result = static_cast<size_t>(length);
+
+		if (static_cast<length_type>(result) != length) return status_out_of_memory;
+
+		// finalize
+		out_result = result;
+
+		return status_ok;
+	}
+
+	PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding)
+	{
+		if (!file) return make_parse_result(status_file_not_found);
+
+		// get file size (can result in I/O errors)
+		size_t size = 0;
+		xml_parse_status size_status = get_file_size(file, size);
+
+		if (size_status != status_ok)
+		{
+			fclose(file);
+			return make_parse_result(size_status);
+		}
+		
+		// allocate buffer for the whole file
+		char* contents = static_cast<char*>(xml_memory::allocate(size > 0 ? size : 1));
+
+		if (!contents)
+		{
+			fclose(file);
+			return make_parse_result(status_out_of_memory);
+		}
+
+		// read file in memory
+		size_t read_size = fread(contents, 1, size, file);
+		fclose(file);
+
+		if (read_size != size)
+		{
+			xml_memory::deallocate(contents);
+			return make_parse_result(status_io_error);
+		}
+		
+		return doc.load_buffer_inplace_own(contents, size, options, encoding);
+	}
+
+#ifndef PUGIXML_NO_STL
+	template <typename T> struct xml_stream_chunk
+	{
+		static xml_stream_chunk* create()
+		{
+			void* memory = xml_memory::allocate(sizeof(xml_stream_chunk));
+			
+			return new (memory) xml_stream_chunk();
+		}
+
+		static void destroy(void* ptr)
+		{
+			xml_stream_chunk* chunk = static_cast<xml_stream_chunk*>(ptr);
+
+			// free chunk chain
+			while (chunk)
+			{
+				xml_stream_chunk* next = chunk->next;
+				xml_memory::deallocate(chunk);
+				chunk = next;
+			}
+		}
+
+		xml_stream_chunk(): next(0), size(0)
+		{
+		}
+
+		xml_stream_chunk* next;
+		size_t size;
+
+		T data[xml_memory_page_size / sizeof(T)];
+	};
+
+	template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
+	{
+		buffer_holder chunks(0, xml_stream_chunk<T>::destroy);
+
+		// read file to a chunk list
+		size_t total = 0;
+		xml_stream_chunk<T>* last = 0;
+
+		while (!stream.eof())
+		{
+			// allocate new chunk
+			xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create();
+			if (!chunk) return status_out_of_memory;
+
+			// append chunk to list
+			if (last) last = last->next = chunk;
+			else chunks.data = last = chunk;
+
+			// read data to chunk
+			stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));
+			chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);
+
+			// read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors
+			if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
+
+			// guard against huge files (chunk size is small enough to make this overflow check work)
+			if (total + chunk->size < total) return status_out_of_memory;
+			total += chunk->size;
+		}
+
+		// copy chunk list to a contiguous buffer
+		char* buffer = static_cast<char*>(xml_memory::allocate(total));
+		if (!buffer) return status_out_of_memory;
+
+		char* write = buffer;
+
+		for (xml_stream_chunk<T>* chunk = static_cast<xml_stream_chunk<T>*>(chunks.data); chunk; chunk = chunk->next)
+		{
+			assert(write + chunk->size <= buffer + total);
+			memcpy(write, chunk->data, chunk->size);
+			write += chunk->size;
+		}
+
+		assert(write == buffer + total);
+
+		// return buffer
+		*out_buffer = buffer;
+		*out_size = total;
+
+		return status_ok;
+	}
+
+	template <typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
+	{
+		// get length of remaining data in stream
+		typename std::basic_istream<T>::pos_type pos = stream.tellg();
+		stream.seekg(0, std::ios::end);
+		std::streamoff length = stream.tellg() - pos;
+		stream.seekg(pos);
+
+		if (stream.fail() || pos < 0) return status_io_error;
+
+		// guard against huge files
+		size_t read_length = static_cast<size_t>(length);
+
+		if (static_cast<std::streamsize>(read_length) != length || length < 0) return status_out_of_memory;
+
+		// read stream data into memory (guard against stream exceptions with buffer holder)
+		buffer_holder buffer(xml_memory::allocate((read_length > 0 ? read_length : 1) * sizeof(T)), xml_memory::deallocate);
+		if (!buffer.data) return status_out_of_memory;
+
+		stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
+
+		// read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors
+		if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
+
+		// return buffer
+		size_t actual_length = static_cast<size_t>(stream.gcount());
+		assert(actual_length <= read_length);
+
+		*out_buffer = buffer.release();
+		*out_size = actual_length * sizeof(T);
+
+		return status_ok;
+	}
+
+	template <typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding)
+	{
+		void* buffer = 0;
+		size_t size = 0;
+
+		// load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)
+		xml_parse_status status = (stream.tellg() < 0) ? load_stream_data_noseek(stream, &buffer, &size) : load_stream_data_seek(stream, &buffer, &size);
+		if (status != status_ok) return make_parse_result(status);
+
+		return doc.load_buffer_inplace_own(buffer, size, options, encoding);
+	}
+#endif
+
+#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__))
+	PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
+	{
+		return _wfopen(path, mode);
+	}
+#else
+	PUGI__FN char* convert_path_heap(const wchar_t* str)
+	{
+		assert(str);
+
+		// first pass: get length in utf8 characters
+		size_t length = wcslen(str);
+		size_t size = as_utf8_begin(str, length);
+
+		// allocate resulting string
+		char* result = static_cast<char*>(xml_memory::allocate(size + 1));
+		if (!result) return 0;
+
+		// second pass: convert to utf8
+		as_utf8_end(result, size, str, length);
+
+		return result;
+	}
+
+	PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
+	{
+		// there is no standard function to open wide paths, so our best bet is to try utf8 path
+		char* path_utf8 = convert_path_heap(path);
+		if (!path_utf8) return 0;
+
+		// convert mode to ASCII (we mirror _wfopen interface)
+		char mode_ascii[4] = {0};
+		for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);
+
+		// try to open the utf8 path
+		FILE* result = fopen(path_utf8, mode_ascii);
+
+		// free dummy buffer
+		xml_memory::deallocate(path_utf8);
+
+		return result;
+	}
+#endif
+
+	PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)
+	{
+		if (!file) return false;
+
+		xml_writer_file writer(file);
+		doc.save(writer, indent, flags, encoding);
+
+		int result = ferror(file);
+
+		fclose(file);
+
+		return result == 0;
+	}
+PUGI__NS_END
+
+namespace pugi
+{
+	PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_)
+	{
+	}
+
+	PUGI__FN void xml_writer_file::write(const void* data, size_t size)
+	{
+		size_t result = fwrite(data, 1, size, static_cast<FILE*>(file));
+		(void)!result; // unfortunately we can't do proper error handling here
+	}
+
+#ifndef PUGIXML_NO_STL
+	PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
+	{
+	}
+
+	PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
+	{
+	}
+
+	PUGI__FN void xml_writer_stream::write(const void* data, size_t size)
+	{
+		if (narrow_stream)
+		{
+			assert(!wide_stream);
+			narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
+		}
+		else
+		{
+			assert(wide_stream);
+			assert(size % sizeof(wchar_t) == 0);
+
+			wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size / sizeof(wchar_t)));
+		}
+	}
+#endif
+
+	PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0)
+	{
+	}
+	
+	PUGI__FN xml_tree_walker::~xml_tree_walker()
+	{
+	}
+
+	PUGI__FN int xml_tree_walker::depth() const
+	{
+		return _depth;
+	}
+
+	PUGI__FN bool xml_tree_walker::begin(xml_node&)
+	{
+		return true;
+	}
+
+	PUGI__FN bool xml_tree_walker::end(xml_node&)
+	{
+		return true;
+	}
+
+	PUGI__FN xml_attribute::xml_attribute(): _attr(0)
+	{
+	}
+
+	PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
+	{
+	}
+
+	PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***)
+	{
+	}
+
+	PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
+	{
+		return _attr ? unspecified_bool_xml_attribute : 0;
+	}
+
+	PUGI__FN bool xml_attribute::operator!() const
+	{
+		return !_attr;
+	}
+
+	PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const
+	{
+		return (_attr == r._attr);
+	}
+	
+	PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const
+	{
+		return (_attr != r._attr);
+	}
+
+	PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const
+	{
+		return (_attr < r._attr);
+	}
+	
+	PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const
+	{
+		return (_attr > r._attr);
+	}
+	
+	PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const
+	{
+		return (_attr <= r._attr);
+	}
+	
+	PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const
+	{
+		return (_attr >= r._attr);
+	}
+
+	PUGI__FN xml_attribute xml_attribute::next_attribute() const
+	{
+		return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
+	}
+
+	PUGI__FN xml_attribute xml_attribute::previous_attribute() const
+	{
+		return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
+	}
+
+	PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const
+	{
+		return (_attr && _attr->value) ? _attr->value : def;
+	}
+
+	PUGI__FN int xml_attribute::as_int(int def) const
+	{
+		return impl::get_value_int(_attr ? _attr->value : 0, def);
+	}
+
+	PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
+	{
+		return impl::get_value_uint(_attr ? _attr->value : 0, def);
+	}
+
+	PUGI__FN double xml_attribute::as_double(double def) const
+	{
+		return impl::get_value_double(_attr ? _attr->value : 0, def);
+	}
+
+	PUGI__FN float xml_attribute::as_float(float def) const
+	{
+		return impl::get_value_float(_attr ? _attr->value : 0, def);
+	}
+
+	PUGI__FN bool xml_attribute::as_bool(bool def) const
+	{
+		return impl::get_value_bool(_attr ? _attr->value : 0, def);
+	}
+
+	PUGI__FN bool xml_attribute::empty() const
+	{
+		return !_attr;
+	}
+
+	PUGI__FN const char_t* xml_attribute::name() const
+	{
+		return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT("");
+	}
+
+	PUGI__FN const char_t* xml_attribute::value() const
+	{
+		return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");
+	}
+
+	PUGI__FN size_t xml_attribute::hash_value() const
+	{
+		return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
+	}
+
+	PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const
+	{
+		return _attr;
+	}
+
+	PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs)
+	{
+		set_value(rhs);
+		return *this;
+	}
+	
+	PUGI__FN xml_attribute& xml_attribute::operator=(int rhs)
+	{
+		set_value(rhs);
+		return *this;
+	}
+
+	PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs)
+	{
+		set_value(rhs);
+		return *this;
+	}
+
+	PUGI__FN xml_attribute& xml_attribute::operator=(double rhs)
+	{
+		set_value(rhs);
+		return *this;
+	}
+	
+	PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs)
+	{
+		set_value(rhs);
+		return *this;
+	}
+
+	PUGI__FN bool xml_attribute::set_name(const char_t* rhs)
+	{
+		if (!_attr) return false;
+		
+		return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs);
+	}
+		
+	PUGI__FN bool xml_attribute::set_value(const char_t* rhs)
+	{
+		if (!_attr) return false;
+
+		return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
+	}
+
+	PUGI__FN bool xml_attribute::set_value(int rhs)
+	{
+		if (!_attr) return false;
+
+		return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
+	}
+
+	PUGI__FN bool xml_attribute::set_value(unsigned int rhs)
+	{
+		if (!_attr) return false;
+
+		return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
+	}
+
+	PUGI__FN bool xml_attribute::set_value(double rhs)
+	{
+		if (!_attr) return false;
+
+		return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
+	}
+	
+	PUGI__FN bool xml_attribute::set_value(bool rhs)
+	{
+		if (!_attr) return false;
+
+		return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
+	}
+
+#ifdef __BORLANDC__
+	PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs)
+	{
+		return (bool)lhs && rhs;
+	}
+
+	PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs)
+	{
+		return (bool)lhs || rhs;
+	}
+#endif
+
+	PUGI__FN xml_node::xml_node(): _root(0)
+	{
+	}
+
+	PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p)
+	{
+	}
+	
+	PUGI__FN static void unspecified_bool_xml_node(xml_node***)
+	{
+	}
+
+	PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const
+	{
+		return _root ? unspecified_bool_xml_node : 0;
+	}
+
+	PUGI__FN bool xml_node::operator!() const
+	{
+		return !_root;
+	}
+
+	PUGI__FN xml_node::iterator xml_node::begin() const
+	{
+		return iterator(_root ? _root->first_child : 0, _root);
+	}
+
+	PUGI__FN xml_node::iterator xml_node::end() const
+	{
+		return iterator(0, _root);
+	}
+	
+	PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const
+	{
+		return attribute_iterator(_root ? _root->first_attribute : 0, _root);
+	}
+
+	PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const
+	{
+		return attribute_iterator(0, _root);
+	}
+	
+	PUGI__FN xml_object_range<xml_node_iterator> xml_node::children() const
+	{
+		return xml_object_range<xml_node_iterator>(begin(), end());
+	}
+
+	PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(const char_t* name_) const
+	{
+		return xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_), name_), xml_named_node_iterator());
+	}
+
+	PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes() const
+	{
+		return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());
+	}
+
+	PUGI__FN bool xml_node::operator==(const xml_node& r) const
+	{
+		return (_root == r._root);
+	}
+
+	PUGI__FN bool xml_node::operator!=(const xml_node& r) const
+	{
+		return (_root != r._root);
+	}
+
+	PUGI__FN bool xml_node::operator<(const xml_node& r) const
+	{
+		return (_root < r._root);
+	}
+	
+	PUGI__FN bool xml_node::operator>(const xml_node& r) const
+	{
+		return (_root > r._root);
+	}
+	
+	PUGI__FN bool xml_node::operator<=(const xml_node& r) const
+	{
+		return (_root <= r._root);
+	}
+	
+	PUGI__FN bool xml_node::operator>=(const xml_node& r) const
+	{
+		return (_root >= r._root);
+	}
+
+	PUGI__FN bool xml_node::empty() const
+	{
+		return !_root;
+	}
+	
+	PUGI__FN const char_t* xml_node::name() const
+	{
+		return (_root && _root->name) ? _root->name : PUGIXML_TEXT("");
+	}
+
+	PUGI__FN xml_node_type xml_node::type() const
+	{
+		return _root ? static_cast<xml_node_type>((_root->header & impl::xml_memory_page_type_mask) + 1) : node_null;
+	}
+	
+	PUGI__FN const char_t* xml_node::value() const
+	{
+		return (_root && _root->value) ? _root->value : PUGIXML_TEXT("");
+	}
+	
+	PUGI__FN xml_node xml_node::child(const char_t* name_) const
+	{
+		if (!_root) return xml_node();
+
+		for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
+			if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
+
+		return xml_node();
+	}
+
+	PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const
+	{
+		if (!_root) return xml_attribute();
+
+		for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
+			if (i->name && impl::strequal(name_, i->name))
+				return xml_attribute(i);
+		
+		return xml_attribute();
+	}
+	
+	PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const
+	{
+		if (!_root) return xml_node();
+		
+		for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
+			if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
+
+		return xml_node();
+	}
+
+	PUGI__FN xml_node xml_node::next_sibling() const
+	{
+		if (!_root) return xml_node();
+		
+		if (_root->next_sibling) return xml_node(_root->next_sibling);
+		else return xml_node();
+	}
+
+	PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const
+	{
+		if (!_root) return xml_node();
+		
+		for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
+			if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
+
+		return xml_node();
+	}
+
+	PUGI__FN xml_node xml_node::previous_sibling() const
+	{
+		if (!_root) return xml_node();
+		
+		if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c);
+		else return xml_node();
+	}
+
+	PUGI__FN xml_node xml_node::parent() const
+	{
+		return _root ? xml_node(_root->parent) : xml_node();
+	}
+
+	PUGI__FN xml_node xml_node::root() const
+	{
+		if (!_root) return xml_node();
+
+		impl::xml_memory_page* page = reinterpret_cast<impl::xml_memory_page*>(_root->header & impl::xml_memory_page_pointer_mask);
+
+		return xml_node(static_cast<impl::xml_document_struct*>(page->allocator));
+	}
+
+	PUGI__FN xml_text xml_node::text() const
+	{
+		return xml_text(_root);
+	}
+
+	PUGI__FN const char_t* xml_node::child_value() const
+	{
+		if (!_root) return PUGIXML_TEXT("");
+		
+		for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
+			if (i->value && impl::is_text_node(i))
+				return i->value;
+
+		return PUGIXML_TEXT("");
+	}
+
+	PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const
+	{
+		return child(name_).child_value();
+	}
+
+	PUGI__FN xml_attribute xml_node::first_attribute() const
+	{
+		return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
+	}
+
+	PUGI__FN xml_attribute xml_node::last_attribute() const
+	{
+		return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute();
+	}
+
+	PUGI__FN xml_node xml_node::first_child() const
+	{
+		return _root ? xml_node(_root->first_child) : xml_node();
+	}
+
+	PUGI__FN xml_node xml_node::last_child() const
+	{
+		return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
+	}
+
+	PUGI__FN bool xml_node::set_name(const char_t* rhs)
+	{
+		switch (type())
+		{
+		case node_pi:
+		case node_declaration:
+		case node_element:
+			return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs);
+
+		default:
+			return false;
+		}
+	}
+		
+	PUGI__FN bool xml_node::set_value(const char_t* rhs)
+	{
+		switch (type())
+		{
+		case node_pi:
+		case node_cdata:
+		case node_pcdata:
+		case node_comment:
+		case node_doctype:
+			return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs);
+
+		default:
+			return false;
+		}
+	}
+
+	PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_)
+	{
+		if (type() != node_element && type() != node_declaration) return xml_attribute();
+		
+		xml_attribute a(impl::append_attribute_ll(_root, impl::get_allocator(_root)));
+		a.set_name(name_);
+		
+		return a;
+	}
+
+	PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_)
+	{
+		if (type() != node_element && type() != node_declaration) return xml_attribute();
+		
+		xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
+		if (!a) return xml_attribute();
+
+		a.set_name(name_);
+		
+		xml_attribute_struct* head = _root->first_attribute;
+
+		if (head)
+		{
+			a._attr->prev_attribute_c = head->prev_attribute_c;
+			head->prev_attribute_c = a._attr;
+		}
+		else
+			a._attr->prev_attribute_c = a._attr;
+		
+		a._attr->next_attribute = head;
+		_root->first_attribute = a._attr;
+				
+		return a;
+	}
+
+	PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr)
+	{
+		if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute();
+		
+		// check that attribute belongs to *this
+		xml_attribute_struct* cur = attr._attr;
+
+		while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c;
+
+		if (cur != _root->first_attribute) return xml_attribute();
+
+		xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
+		if (!a) return xml_attribute();
+
+		a.set_name(name_);
+
+		if (attr._attr->prev_attribute_c->next_attribute)
+			attr._attr->prev_attribute_c->next_attribute = a._attr;
+		else
+			_root->first_attribute = a._attr;
+		
+		a._attr->prev_attribute_c = attr._attr->prev_attribute_c;
+		a._attr->next_attribute = attr._attr;
+		attr._attr->prev_attribute_c = a._attr;
+				
+		return a;
+	}
+
+	PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr)
+	{
+		if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute();
+		
+		// check that attribute belongs to *this
+		xml_attribute_struct* cur = attr._attr;
+
+		while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c;
+
+		if (cur != _root->first_attribute) return xml_attribute();
+
+		xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
+		if (!a) return xml_attribute();
+
+		a.set_name(name_);
+
+		if (attr._attr->next_attribute)
+			attr._attr->next_attribute->prev_attribute_c = a._attr;
+		else
+			_root->first_attribute->prev_attribute_c = a._attr;
+		
+		a._attr->next_attribute = attr._attr->next_attribute;
+		a._attr->prev_attribute_c = attr._attr;
+		attr._attr->next_attribute = a._attr;
+
+		return a;
+	}
+
+	PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto)
+	{
+		if (!proto) return xml_attribute();
+
+		xml_attribute result = append_attribute(proto.name());
+		result.set_value(proto.value());
+
+		return result;
+	}
+
+	PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto)
+	{
+		if (!proto) return xml_attribute();
+
+		xml_attribute result = prepend_attribute(proto.name());
+		result.set_value(proto.value());
+
+		return result;
+	}
+
+	PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr)
+	{
+		if (!proto) return xml_attribute();
+
+		xml_attribute result = insert_attribute_after(proto.name(), attr);
+		result.set_value(proto.value());
+
+		return result;
+	}
+
+	PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr)
+	{
+		if (!proto) return xml_attribute();
+
+		xml_attribute result = insert_attribute_before(proto.name(), attr);
+		result.set_value(proto.value());
+
+		return result;
+	}
+
+	PUGI__FN xml_node xml_node::append_child(xml_node_type type_)
+	{
+		if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
+		
+		xml_node n(impl::append_node(_root, impl::get_allocator(_root), type_));
+
+		if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
+
+		return n;
+	}
+
+	PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_)
+	{
+		if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
+		
+		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
+		if (!n) return xml_node();
+
+		n._root->parent = _root;
+
+		xml_node_struct* head = _root->first_child;
+
+		if (head)
+		{
+			n._root->prev_sibling_c = head->prev_sibling_c;
+			head->prev_sibling_c = n._root;
+		}
+		else
+			n._root->prev_sibling_c = n._root;
+		
+		n._root->next_sibling = head;
+		_root->first_child = n._root;
+				
+		if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
+
+		return n;
+	}
+
+	PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node)
+	{
+		if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
+		if (!node._root || node._root->parent != _root) return xml_node();
+	
+		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
+		if (!n) return xml_node();
+
+		n._root->parent = _root;
+		
+		if (node._root->prev_sibling_c->next_sibling)
+			node._root->prev_sibling_c->next_sibling = n._root;
+		else
+			_root->first_child = n._root;
+		
+		n._root->prev_sibling_c = node._root->prev_sibling_c;
+		n._root->next_sibling = node._root;
+		node._root->prev_sibling_c = n._root;
+
+		if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
+
+		return n;
+	}
+
+	PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node)
+	{
+		if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
+		if (!node._root || node._root->parent != _root) return xml_node();
+	
+		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
+		if (!n) return xml_node();
+
+		n._root->parent = _root;
+	
+		if (node._root->next_sibling)
+			node._root->next_sibling->prev_sibling_c = n._root;
+		else
+			_root->first_child->prev_sibling_c = n._root;
+		
+		n._root->next_sibling = node._root->next_sibling;
+		n._root->prev_sibling_c = node._root;
+		node._root->next_sibling = n._root;
+
+		if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
+
+		return n;
+	}
+
+	PUGI__FN xml_node xml_node::append_child(const char_t* name_)
+	{
+		xml_node result = append_child(node_element);
+
+		result.set_name(name_);
+
+		return result;
+	}
+
+	PUGI__FN xml_node xml_node::prepend_child(const char_t* name_)
+	{
+		xml_node result = prepend_child(node_element);
+
+		result.set_name(name_);
+
+		return result;
+	}
+
+	PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node)
+	{
+		xml_node result = insert_child_after(node_element, node);
+
+		result.set_name(name_);
+
+		return result;
+	}
+
+	PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node)
+	{
+		xml_node result = insert_child_before(node_element, node);
+
+		result.set_name(name_);
+
+		return result;
+	}
+
+	PUGI__FN xml_node xml_node::append_copy(const xml_node& proto)
+	{
+		xml_node result = append_child(proto.type());
+
+		if (result) impl::recursive_copy_skip(result, proto, result);
+
+		return result;
+	}
+
+	PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto)
+	{
+		xml_node result = prepend_child(proto.type());
+
+		if (result) impl::recursive_copy_skip(result, proto, result);
+
+		return result;
+	}
+
+	PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)
+	{
+		xml_node result = insert_child_after(proto.type(), node);
+
+		if (result) impl::recursive_copy_skip(result, proto, result);
+
+		return result;
+	}
+
+	PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)
+	{
+		xml_node result = insert_child_before(proto.type(), node);
+
+		if (result) impl::recursive_copy_skip(result, proto, result);
+
+		return result;
+	}
+
+	PUGI__FN bool xml_node::remove_attribute(const char_t* name_)
+	{
+		return remove_attribute(attribute(name_));
+	}
+
+	PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a)
+	{
+		if (!_root || !a._attr) return false;
+
+		// check that attribute belongs to *this
+		xml_attribute_struct* attr = a._attr;
+
+		while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c;
+
+		if (attr != _root->first_attribute) return false;
+
+		if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c;
+		else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c;
+		
+		if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute;
+		else _root->first_attribute = a._attr->next_attribute;
+
+		impl::destroy_attribute(a._attr, impl::get_allocator(_root));
+
+		return true;
+	}
+
+	PUGI__FN bool xml_node::remove_child(const char_t* name_)
+	{
+		return remove_child(child(name_));
+	}
+
+	PUGI__FN bool xml_node::remove_child(const xml_node& n)
+	{
+		if (!_root || !n._root || n._root->parent != _root) return false;
+
+		if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c;
+		else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c;
+		
+		if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling;
+		else _root->first_child = n._root->next_sibling;
+		
+		impl::destroy_node(n._root, impl::get_allocator(_root));
+
+		return true;
+	}
+
+	PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const
+	{
+		if (!_root) return xml_node();
+		
+		for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
+			if (i->name && impl::strequal(name_, i->name))
+			{
+				for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
+					if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value))
+						return xml_node(i);
+			}
+
+		return xml_node();
+	}
+
+	PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
+	{
+		if (!_root) return xml_node();
+		
+		for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
+			for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
+				if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value))
+					return xml_node(i);
+
+		return xml_node();
+	}
+
+#ifndef PUGIXML_NO_STL
+	PUGI__FN string_t xml_node::path(char_t delimiter) const
+	{
+		xml_node cursor = *this; // Make a copy.
+		
+		string_t result = cursor.name();
+
+		while (cursor.parent())
+		{
+			cursor = cursor.parent();
+			
+			string_t temp = cursor.name();
+			temp += delimiter;
+			temp += result;
+			result.swap(temp);
+		}
+
+		return result;
+	}
+#endif
+
+	PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const
+	{
+		xml_node found = *this; // Current search context.
+
+		if (!_root || !path_ || !path_[0]) return found;
+
+		if (path_[0] == delimiter)
+		{
+			// Absolute path; e.g. '/foo/bar'
+			found = found.root();
+			++path_;
+		}
+
+		const char_t* path_segment = path_;
+
+		while (*path_segment == delimiter) ++path_segment;
+
+		const char_t* path_segment_end = path_segment;
+
+		while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;
+
+		if (path_segment == path_segment_end) return found;
+
+		const char_t* next_segment = path_segment_end;
+
+		while (*next_segment == delimiter) ++next_segment;
+
+		if (*path_segment == '.' && path_segment + 1 == path_segment_end)
+			return found.first_element_by_path(next_segment, delimiter);
+		else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end)
+			return found.parent().first_element_by_path(next_segment, delimiter);
+		else
+		{
+			for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling)
+			{
+				if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
+				{
+					xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
+
+					if (subsearch) return subsearch;
+				}
+			}
+
+			return xml_node();
+		}
+	}
+
+	PUGI__FN bool xml_node::traverse(xml_tree_walker& walker)
+	{
+		walker._depth = -1;
+		
+		xml_node arg_begin = *this;
+		if (!walker.begin(arg_begin)) return false;
+
+		xml_node cur = first_child();
+				
+		if (cur)
+		{
+			++walker._depth;
+
+			do 
+			{
+				xml_node arg_for_each = cur;
+				if (!walker.for_each(arg_for_each))
+					return false;
+						
+				if (cur.first_child())
+				{
+					++walker._depth;
+					cur = cur.first_child();
+				}
+				else if (cur.next_sibling())
+					cur = cur.next_sibling();
+				else
+				{
+					// Borland C++ workaround
+					while (!cur.next_sibling() && cur != *this && !cur.parent().empty())
+					{
+						--walker._depth;
+						cur = cur.parent();
+					}
+						
+					if (cur != *this)
+						cur = cur.next_sibling();
+				}
+			}
+			while (cur && cur != *this);
+		}
+
+		assert(walker._depth == -1);
+
+		xml_node arg_end = *this;
+		return walker.end(arg_end);
+	}
+
+	PUGI__FN size_t xml_node::hash_value() const
+	{
+		return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
+	}
+
+	PUGI__FN xml_node_struct* xml_node::internal_object() const
+	{
+		return _root;
+	}
+
+	PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
+	{
+		if (!_root) return;
+
+		impl::xml_buffered_writer buffered_writer(writer, encoding);
+
+		impl::node_output(buffered_writer, *this, indent, flags, depth);
+	}
+
+#ifndef PUGIXML_NO_STL
+	PUGI__FN void xml_node::print(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
+	{
+		xml_writer_stream writer(stream);
+
+		print(writer, indent, flags, encoding, depth);
+	}
+
+	PUGI__FN void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const
+	{
+		xml_writer_stream writer(stream);
+
+		print(writer, indent, flags, encoding_wchar, depth);
+	}
+#endif
+
+	PUGI__FN ptrdiff_t xml_node::offset_debug() const
+	{
+		xml_node_struct* r = root()._root;
+
+		if (!r) return -1;
+
+		const char_t* buffer = static_cast<impl::xml_document_struct*>(r)->buffer;
+
+		if (!buffer) return -1;
+
+		switch (type())
+		{
+		case node_document:
+			return 0;
+
+		case node_element:
+		case node_declaration:
+		case node_pi:
+			return (_root->header & impl::xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer;
+
+		case node_pcdata:
+		case node_cdata:
+		case node_comment:
+		case node_doctype:
+			return (_root->header & impl::xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer;
+
+		default:
+			return -1;
+		}
+	}
+
+#ifdef __BORLANDC__
+	PUGI__FN bool operator&&(const xml_node& lhs, bool rhs)
+	{
+		return (bool)lhs && rhs;
+	}
+
+	PUGI__FN bool operator||(const xml_node& lhs, bool rhs)
+	{
+		return (bool)lhs || rhs;
+	}
+#endif
+
+	PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root)
+	{
+	}
+
+	PUGI__FN xml_node_struct* xml_text::_data() const
+	{
+		if (!_root || impl::is_text_node(_root)) return _root;
+
+		for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
+			if (impl::is_text_node(node))
+				return node;
+
+		return 0;
+	}
+
+	PUGI__FN xml_node_struct* xml_text::_data_new()
+	{
+		xml_node_struct* d = _data();
+		if (d) return d;
+
+		return xml_node(_root).append_child(node_pcdata).internal_object();
+	}
+
+	PUGI__FN xml_text::xml_text(): _root(0)
+	{
+	}
+
+	PUGI__FN static void unspecified_bool_xml_text(xml_text***)
+	{
+	}
+
+	PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const
+	{
+		return _data() ? unspecified_bool_xml_text : 0;
+	}
+
+	PUGI__FN bool xml_text::operator!() const
+	{
+		return !_data();
+	}
+
+	PUGI__FN bool xml_text::empty() const
+	{
+		return _data() == 0;
+	}
+
+	PUGI__FN const char_t* xml_text::get() const
+	{
+		xml_node_struct* d = _data();
+
+		return (d && d->value) ? d->value : PUGIXML_TEXT("");
+	}
+
+	PUGI__FN const char_t* xml_text::as_string(const char_t* def) const
+	{
+		xml_node_struct* d = _data();
+
+		return (d && d->value) ? d->value : def;
+	}
+
+	PUGI__FN int xml_text::as_int(int def) const
+	{
+		xml_node_struct* d = _data();
+
+		return impl::get_value_int(d ? d->value : 0, def);
+	}
+
+	PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
+	{
+		xml_node_struct* d = _data();
+
+		return impl::get_value_uint(d ? d->value : 0, def);
+	}
+
+	PUGI__FN double xml_text::as_double(double def) const
+	{
+		xml_node_struct* d = _data();
+
+		return impl::get_value_double(d ? d->value : 0, def);
+	}
+
+	PUGI__FN float xml_text::as_float(float def) const
+	{
+		xml_node_struct* d = _data();
+
+		return impl::get_value_float(d ? d->value : 0, def);
+	}
+
+	PUGI__FN bool xml_text::as_bool(bool def) const
+	{
+		xml_node_struct* d = _data();
+
+		return impl::get_value_bool(d ? d->value : 0, def);
+	}
+
+	PUGI__FN bool xml_text::set(const char_t* rhs)
+	{
+		xml_node_struct* dn = _data_new();
+
+		return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
+	}
+
+	PUGI__FN bool xml_text::set(int rhs)
+	{
+		xml_node_struct* dn = _data_new();
+
+		return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
+	}
+
+	PUGI__FN bool xml_text::set(unsigned int rhs)
+	{
+		xml_node_struct* dn = _data_new();
+
+		return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
+	}
+
+	PUGI__FN bool xml_text::set(double rhs)
+	{
+		xml_node_struct* dn = _data_new();
+
+		return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
+	}
+
+	PUGI__FN bool xml_text::set(bool rhs)
+	{
+		xml_node_struct* dn = _data_new();
+
+		return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
+	}
+
+	PUGI__FN xml_text& xml_text::operator=(const char_t* rhs)
+	{
+		set(rhs);
+		return *this;
+	}
+
+	PUGI__FN xml_text& xml_text::operator=(int rhs)
+	{
+		set(rhs);
+		return *this;
+	}
+
+	PUGI__FN xml_text& xml_text::operator=(unsigned int rhs)
+	{
+		set(rhs);
+		return *this;
+	}
+
+	PUGI__FN xml_text& xml_text::operator=(double rhs)
+	{
+		set(rhs);
+		return *this;
+	}
+
+	PUGI__FN xml_text& xml_text::operator=(bool rhs)
+	{
+		set(rhs);
+		return *this;
+	}
+
+	PUGI__FN xml_node xml_text::data() const
+	{
+		return xml_node(_data());
+	}
+
+#ifdef __BORLANDC__
+	PUGI__FN bool operator&&(const xml_text& lhs, bool rhs)
+	{
+		return (bool)lhs && rhs;
+	}
+
+	PUGI__FN bool operator||(const xml_text& lhs, bool rhs)
+	{
+		return (bool)lhs || rhs;
+	}
+#endif
+
+	PUGI__FN xml_node_iterator::xml_node_iterator()
+	{
+	}
+
+	PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
+	{
+	}
+
+	PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
+	{
+	}
+
+	PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const
+	{
+		return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
+	}
+	
+	PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const
+	{
+		return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
+	}
+
+	PUGI__FN xml_node& xml_node_iterator::operator*() const
+	{
+		assert(_wrap._root);
+		return _wrap;
+	}
+
+	PUGI__FN xml_node* xml_node_iterator::operator->() const
+	{
+		assert(_wrap._root);
+		return const_cast<xml_node*>(&_wrap); // BCC32 workaround
+	}
+
+	PUGI__FN const xml_node_iterator& xml_node_iterator::operator++()
+	{
+		assert(_wrap._root);
+		_wrap._root = _wrap._root->next_sibling;
+		return *this;
+	}
+
+	PUGI__FN xml_node_iterator xml_node_iterator::operator++(int)
+	{
+		xml_node_iterator temp = *this;
+		++*this;
+		return temp;
+	}
+
+	PUGI__FN const xml_node_iterator& xml_node_iterator::operator--()
+	{
+		_wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
+		return *this;
+	}
+
+	PUGI__FN xml_node_iterator xml_node_iterator::operator--(int)
+	{
+		xml_node_iterator temp = *this;
+		--*this;
+		return temp;
+	}
+
+	PUGI__FN xml_attribute_iterator::xml_attribute_iterator()
+	{
+	}
+
+	PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
+	{
+	}
+
+	PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
+	{
+	}
+
+	PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const
+	{
+		return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
+	}
+	
+	PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const
+	{
+		return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
+	}
+
+	PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const
+	{
+		assert(_wrap._attr);
+		return _wrap;
+	}
+
+	PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const
+	{
+		assert(_wrap._attr);
+		return const_cast<xml_attribute*>(&_wrap); // BCC32 workaround
+	}
+
+	PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++()
+	{
+		assert(_wrap._attr);
+		_wrap._attr = _wrap._attr->next_attribute;
+		return *this;
+	}
+
+	PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int)
+	{
+		xml_attribute_iterator temp = *this;
+		++*this;
+		return temp;
+	}
+
+	PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--()
+	{
+		_wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
+		return *this;
+	}
+
+	PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int)
+	{
+		xml_attribute_iterator temp = *this;
+		--*this;
+		return temp;
+	}
+
+	PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0)
+	{
+	}
+
+	PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _node(node), _name(name)
+	{
+	}
+
+	PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const
+	{
+		return _node == rhs._node;
+	}
+
+	PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const
+	{
+		return _node != rhs._node;
+	}
+
+	PUGI__FN xml_node& xml_named_node_iterator::operator*() const
+	{
+		assert(_node._root);
+		return _node;
+	}
+
+	PUGI__FN xml_node* xml_named_node_iterator::operator->() const
+	{
+		assert(_node._root);
+		return const_cast<xml_node*>(&_node); // BCC32 workaround
+	}
+
+	PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++()
+	{
+		assert(_node._root);
+		_node = _node.next_sibling(_name);
+		return *this;
+	}
+
+	PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int)
+	{
+		xml_named_node_iterator temp = *this;
+		++*this;
+		return temp;
+	}
+
+	PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
+	{
+	}
+
+	PUGI__FN xml_parse_result::operator bool() const
+	{
+		return status == status_ok;
+	}
+
+	PUGI__FN const char* xml_parse_result::description() const
+	{
+		switch (status)
+		{
+		case status_ok: return "No error";
+
+		case status_file_not_found: return "File was not found";
+		case status_io_error: return "Error reading from file/stream";
+		case status_out_of_memory: return "Could not allocate memory";
+		case status_internal_error: return "Internal error occurred";
+
+		case status_unrecognized_tag: return "Could not determine tag type";
+
+		case status_bad_pi: return "Error parsing document declaration/processing instruction";
+		case status_bad_comment: return "Error parsing comment";
+		case status_bad_cdata: return "Error parsing CDATA section";
+		case status_bad_doctype: return "Error parsing document type declaration";
+		case status_bad_pcdata: return "Error parsing PCDATA section";
+		case status_bad_start_element: return "Error parsing start element tag";
+		case status_bad_attribute: return "Error parsing element attribute";
+		case status_bad_end_element: return "Error parsing end element tag";
+		case status_end_element_mismatch: return "Start-end tags mismatch";
+
+		default: return "Unknown error";
+		}
+	}
+
+	PUGI__FN xml_document::xml_document(): _buffer(0)
+	{
+		create();
+	}
+
+	PUGI__FN xml_document::~xml_document()
+	{
+		destroy();
+	}
+
+	PUGI__FN void xml_document::reset()
+	{
+		destroy();
+		create();
+	}
+
+	PUGI__FN void xml_document::reset(const xml_document& proto)
+	{
+		reset();
+
+		for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
+			append_copy(cur);
+	}
+
+	PUGI__FN void xml_document::create()
+	{
+		// initialize sentinel page
+		PUGI__STATIC_ASSERT(offsetof(impl::xml_memory_page, data) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment <= sizeof(_memory));
+
+		// align upwards to page boundary
+		void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1));
+
+		// prepare page structure
+		impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory);
+
+		page->busy_size = impl::xml_memory_page_size;
+
+		// allocate new root
+		_root = new (page->data) impl::xml_document_struct(page);
+		_root->prev_sibling_c = _root;
+
+		// setup sentinel page
+		page->allocator = static_cast<impl::xml_document_struct*>(_root);
+	}
+
+	PUGI__FN void xml_document::destroy()
+	{
+		// destroy static storage
+		if (_buffer)
+		{
+			impl::xml_memory::deallocate(_buffer);
+			_buffer = 0;
+		}
+
+		// destroy dynamic storage, leave sentinel page (it's in static memory)
+		if (_root)
+		{
+			impl::xml_memory_page* root_page = reinterpret_cast<impl::xml_memory_page*>(_root->header & impl::xml_memory_page_pointer_mask);
+			assert(root_page && !root_page->prev && !root_page->memory);
+
+			// destroy all pages
+			for (impl::xml_memory_page* page = root_page->next; page; )
+			{
+				impl::xml_memory_page* next = page->next;
+
+				impl::xml_allocator::deallocate_page(page);
+
+				page = next;
+			}
+
+			// cleanup root page
+			root_page->allocator = 0;
+			root_page->next = 0;
+			root_page->busy_size = root_page->freed_size = 0;
+
+			_root = 0;
+		}
+	}
+
+#ifndef PUGIXML_NO_STL
+	PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
+	{
+		reset();
+
+		return impl::load_stream_impl(*this, stream, options, encoding);
+	}
+
+	PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
+	{
+		reset();
+
+		return impl::load_stream_impl(*this, stream, options, encoding_wchar);
+	}
+#endif
+
+	PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
+	{
+		// Force native encoding (skip autodetection)
+	#ifdef PUGIXML_WCHAR_MODE
+		xml_encoding encoding = encoding_wchar;
+	#else
+		xml_encoding encoding = encoding_utf8;
+	#endif
+
+		return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
+	}
+
+	PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
+	{
+		reset();
+
+		FILE* file = fopen(path_, "rb");
+
+		return impl::load_file_impl(*this, file, options, encoding);
+	}
+
+	PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)
+	{
+		reset();
+
+		FILE* file = impl::open_file_wide(path_, L"rb");
+
+		return impl::load_file_impl(*this, file, options, encoding);
+	}
+
+	PUGI__FN xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own)
+	{
+		reset();
+
+		// check input buffer
+		assert(contents || size == 0);
+
+		// get actual encoding
+		xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
+
+		// get private buffer
+		char_t* buffer = 0;
+		size_t length = 0;
+
+		if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
+		
+		// delete original buffer if we performed a conversion
+		if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
+
+		// parse
+		xml_parse_result res = impl::xml_parser::parse(buffer, length, _root, options);
+
+		// remember encoding
+		res.encoding = buffer_encoding;
+
+		// grab onto buffer if it's our buffer, user is responsible for deallocating contens himself
+		if (own || buffer != contents) _buffer = buffer;
+
+		return res;
+	}
+
+	PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
+	{
+		return load_buffer_impl(const_cast<void*>(contents), size, options, encoding, false, false);
+	}
+
+	PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
+	{
+		return load_buffer_impl(contents, size, options, encoding, true, false);
+	}
+		
+	PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
+	{
+		return load_buffer_impl(contents, size, options, encoding, true, true);
+	}
+
+	PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
+	{
+		impl::xml_buffered_writer buffered_writer(writer, encoding);
+
+		if ((flags & format_write_bom) && encoding != encoding_latin1)
+		{
+			// BOM always represents the codepoint U+FEFF, so just write it in native encoding
+		#ifdef PUGIXML_WCHAR_MODE
+			unsigned int bom = 0xfeff;
+			buffered_writer.write(static_cast<wchar_t>(bom));
+		#else
+			buffered_writer.write('\xef', '\xbb', '\xbf');
+		#endif
+		}
+
+		if (!(flags & format_no_declaration) && !impl::has_declaration(*this))
+		{
+			buffered_writer.write(PUGIXML_TEXT("<?xml version=\"1.0\""));
+			if (encoding == encoding_latin1) buffered_writer.write(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
+			buffered_writer.write('?', '>');
+			if (!(flags & format_raw)) buffered_writer.write('\n');
+		}
+
+		impl::node_output(buffered_writer, *this, indent, flags, 0);
+	}
+
+#ifndef PUGIXML_NO_STL
+	PUGI__FN void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const
+	{
+		xml_writer_stream writer(stream);
+
+		save(writer, indent, flags, encoding);
+	}
+
+	PUGI__FN void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const
+	{
+		xml_writer_stream writer(stream);
+
+		save(writer, indent, flags, encoding_wchar);
+	}
+#endif
+
+	PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
+	{
+		FILE* file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb");
+		return impl::save_file_impl(*this, file, indent, flags, encoding);
+	}
+
+	PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
+	{
+		FILE* file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb");
+		return impl::save_file_impl(*this, file, indent, flags, encoding);
+	}
+
+	PUGI__FN xml_node xml_document::document_element() const
+	{
+		for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
+			if ((i->header & impl::xml_memory_page_type_mask) + 1 == node_element)
+				return xml_node(i);
+
+		return xml_node();
+	}
+
+#ifndef PUGIXML_NO_STL
+	PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
+	{
+		assert(str);
+
+		return impl::as_utf8_impl(str, wcslen(str));
+	}
+
+	PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str)
+	{
+		return impl::as_utf8_impl(str.c_str(), str.size());
+	}
+	
+	PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str)
+	{
+		assert(str);
+
+		return impl::as_wide_impl(str, strlen(str));
+	}
+	
+	PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str)
+	{
+		return impl::as_wide_impl(str.c_str(), str.size());
+	}
+#endif
+
+	PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
+	{
+		impl::xml_memory::allocate = allocate;
+		impl::xml_memory::deallocate = deallocate;
+	}
+
+	PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
+	{
+		return impl::xml_memory::allocate;
+	}
+
+	PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
+	{
+		return impl::xml_memory::deallocate;
+	}
+}
+
+#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
+namespace std
+{
+	// Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
+	PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
+	{
+		return std::bidirectional_iterator_tag();
+	}
+
+	PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
+	{
+		return std::bidirectional_iterator_tag();
+	}
+
+	PUGI__FN std::forward_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)
+	{
+		return std::forward_iterator_tag();
+	}
+}
+#endif
+
+#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
+namespace std
+{
+	// Workarounds for (non-standard) iterator category detection
+	PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)
+	{
+		return std::bidirectional_iterator_tag();
+	}
+
+	PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)
+	{
+		return std::bidirectional_iterator_tag();
+	}
+
+	PUGI__FN std::forward_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)
+	{
+		return std::forward_iterator_tag();
+	}
+}
+#endif
+
+#ifndef PUGIXML_NO_XPATH
+
+// STL replacements
+PUGI__NS_BEGIN
+	struct equal_to
+	{
+		template <typename T> bool operator()(const T& lhs, const T& rhs) const
+		{
+			return lhs == rhs;
+		}
+	};
+
+	struct not_equal_to
+	{
+		template <typename T> bool operator()(const T& lhs, const T& rhs) const
+		{
+			return lhs != rhs;
+		}
+	};
+
+	struct less
+	{
+		template <typename T> bool operator()(const T& lhs, const T& rhs) const
+		{
+			return lhs < rhs;
+		}
+	};
+
+	struct less_equal
+	{
+		template <typename T> bool operator()(const T& lhs, const T& rhs) const
+		{
+			return lhs <= rhs;
+		}
+	};
+
+	template <typename T> void swap(T& lhs, T& rhs)
+	{
+		T temp = lhs;
+		lhs = rhs;
+		rhs = temp;
+	}
+
+	template <typename I, typename Pred> I min_element(I begin, I end, const Pred& pred)
+	{
+		I result = begin;
+
+		for (I it = begin + 1; it != end; ++it)
+			if (pred(*it, *result))
+				result = it;
+
+		return result;
+	}
+
+	template <typename I> void reverse(I begin, I end)
+	{
+		while (begin + 1 < end) swap(*begin++, *--end);
+	}
+
+	template <typename I> I unique(I begin, I end)
+	{
+		// fast skip head
+		while (begin + 1 < end && *begin != *(begin + 1)) begin++;
+
+		if (begin == end) return begin;
+
+		// last written element
+		I write = begin++; 
+
+		// merge unique elements
+		while (begin != end)
+		{
+			if (*begin != *write)
+				*++write = *begin++;
+			else
+				begin++;
+		}
+
+		// past-the-end (write points to live element)
+		return write + 1;
+	}
+
+	template <typename I> void copy_backwards(I begin, I end, I target)
+	{
+		while (begin != end) *--target = *--end;
+	}
+
+	template <typename I, typename Pred, typename T> void insertion_sort(I begin, I end, const Pred& pred, T*)
+	{
+		assert(begin != end);
+
+		for (I it = begin + 1; it != end; ++it)
+		{
+			T val = *it;
+
+			if (pred(val, *begin))
+			{
+				// move to front
+				copy_backwards(begin, it, it + 1);
+				*begin = val;
+			}
+			else
+			{
+				I hole = it;
+
+				// move hole backwards
+				while (pred(val, *(hole - 1)))
+				{
+					*hole = *(hole - 1);
+					hole--;
+				}
+
+				// fill hole with element
+				*hole = val;
+			}
+		}
+	}
+
+	// std variant for elements with ==
+	template <typename I, typename Pred> void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend)
+	{
+		I eqbeg = middle, eqend = middle + 1;
+
+		// expand equal range
+		while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg;
+		while (eqend != end && *eqend == *eqbeg) ++eqend;
+
+		// process outer elements
+		I ltend = eqbeg, gtbeg = eqend;
+
+		for (;;)
+		{
+			// find the element from the right side that belongs to the left one
+			for (; gtbeg != end; ++gtbeg)
+				if (!pred(*eqbeg, *gtbeg))
+				{
+					if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++);
+					else break;
+				}
+
+			// find the element from the left side that belongs to the right one
+			for (; ltend != begin; --ltend)
+				if (!pred(*(ltend - 1), *eqbeg))
+				{
+					if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg);
+					else break;
+				}
+
+			// scanned all elements
+			if (gtbeg == end && ltend == begin)
+			{
+				*out_eqbeg = eqbeg;
+				*out_eqend = eqend;
+				return;
+			}
+
+			// make room for elements by moving equal area
+			if (gtbeg == end)
+			{
+				if (--ltend != --eqbeg) swap(*ltend, *eqbeg);
+				swap(*eqbeg, *--eqend);
+			}
+			else if (ltend == begin)
+			{
+				if (eqend != gtbeg) swap(*eqbeg, *eqend);
+				++eqend;
+				swap(*gtbeg++, *eqbeg++);
+			}
+			else swap(*gtbeg++, *--ltend);
+		}
+	}
+
+	template <typename I, typename Pred> void median3(I first, I middle, I last, const Pred& pred)
+	{
+		if (pred(*middle, *first)) swap(*middle, *first);
+		if (pred(*last, *middle)) swap(*last, *middle);
+		if (pred(*middle, *first)) swap(*middle, *first);
+	}
+
+	template <typename I, typename Pred> void median(I first, I middle, I last, const Pred& pred)
+	{
+		if (last - first <= 40)
+		{
+			// median of three for small chunks
+			median3(first, middle, last, pred);
+		}
+		else
+		{
+			// median of nine
+			size_t step = (last - first + 1) / 8;
+
+			median3(first, first + step, first + 2 * step, pred);
+			median3(middle - step, middle, middle + step, pred);
+			median3(last - 2 * step, last - step, last, pred);
+			median3(first + step, middle, last - step, pred);
+		}
+	}
+
+	template <typename I, typename Pred> void sort(I begin, I end, const Pred& pred)
+	{
+		// sort large chunks
+		while (end - begin > 32)
+		{
+			// find median element
+			I middle = begin + (end - begin) / 2;
+			median(begin, middle, end - 1, pred);
+
+			// partition in three chunks (< = >)
+			I eqbeg, eqend;
+			partition(begin, middle, end, pred, &eqbeg, &eqend);
+
+			// loop on larger half
+			if (eqbeg - begin > end - eqend)
+			{
+				sort(eqend, end, pred);
+				end = eqbeg;
+			}
+			else
+			{
+				sort(begin, eqbeg, pred);
+				begin = eqend;
+			}
+		}
+
+		// insertion sort small chunk
+		if (begin != end) insertion_sort(begin, end, pred, &*begin);
+	}
+PUGI__NS_END
+
+// Allocator used for AST and evaluation stacks
+PUGI__NS_BEGIN
+	struct xpath_memory_block
+	{	
+		xpath_memory_block* next;
+
+		char data[
+	#ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
+			PUGIXML_MEMORY_XPATH_PAGE_SIZE
+	#else
+			4096
+	#endif
+		];
+	};
+		
+	class xpath_allocator
+	{
+		xpath_memory_block* _root;
+		size_t _root_size;
+
+	public:
+	#ifdef PUGIXML_NO_EXCEPTIONS
+		jmp_buf* error_handler;
+	#endif
+
+		xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size)
+		{
+		#ifdef PUGIXML_NO_EXCEPTIONS
+			error_handler = 0;
+		#endif
+		}
+		
+		void* allocate_nothrow(size_t size)
+		{
+			const size_t block_capacity = sizeof(_root->data);
+
+			// align size so that we're able to store pointers in subsequent blocks
+			size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+
+			if (_root_size + size <= block_capacity)
+			{
+				void* buf = _root->data + _root_size;
+				_root_size += size;
+				return buf;
+			}
+			else
+			{
+				size_t block_data_size = (size > block_capacity) ? size : block_capacity;
+				size_t block_size = block_data_size + offsetof(xpath_memory_block, data);
+
+				xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));
+				if (!block) return 0;
+				
+				block->next = _root;
+				
+				_root = block;
+				_root_size = size;
+				
+				return block->data;
+			}
+		}
+
+		void* allocate(size_t size)
+		{
+			void* result = allocate_nothrow(size);
+
+			if (!result)
+			{
+			#ifdef PUGIXML_NO_EXCEPTIONS
+				assert(error_handler);
+				longjmp(*error_handler, 1);
+			#else
+				throw std::bad_alloc();
+			#endif
+			}
+
+			return result;
+		}
+
+		void* reallocate(void* ptr, size_t old_size, size_t new_size)
+		{
+			// align size so that we're able to store pointers in subsequent blocks
+			old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+			new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+
+			// we can only reallocate the last object
+			assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _root->data + _root_size);
+
+			// adjust root size so that we have not allocated the object at all
+			bool only_object = (_root_size == old_size);
+
+			if (ptr) _root_size -= old_size;
+
+			// allocate a new version (this will obviously reuse the memory if possible)
+			void* result = allocate(new_size);
+			assert(result);
+
+			// we have a new block
+			if (result != ptr && ptr)
+			{
+				// copy old data
+				assert(new_size > old_size);
+				memcpy(result, ptr, old_size);
+
+				// free the previous page if it had no other objects
+				if (only_object)
+				{
+					assert(_root->data == result);
+					assert(_root->next);
+
+					xpath_memory_block* next = _root->next->next;
+
+					if (next)
+					{
+						// deallocate the whole page, unless it was the first one
+						xml_memory::deallocate(_root->next);
+						_root->next = next;
+					}
+				}
+			}
+
+			return result;
+		}
+
+		void revert(const xpath_allocator& state)
+		{
+			// free all new pages
+			xpath_memory_block* cur = _root;
+
+			while (cur != state._root)
+			{
+				xpath_memory_block* next = cur->next;
+
+				xml_memory::deallocate(cur);
+
+				cur = next;
+			}
+
+			// restore state
+			_root = state._root;
+			_root_size = state._root_size;
+		}
+
+		void release()
+		{
+			xpath_memory_block* cur = _root;
+			assert(cur);
+
+			while (cur->next)
+			{
+				xpath_memory_block* next = cur->next;
+
+				xml_memory::deallocate(cur);
+
+				cur = next;
+			}
+		}
+	};
+
+	struct xpath_allocator_capture
+	{
+		xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc)
+		{
+		}
+
+		~xpath_allocator_capture()
+		{
+			_target->revert(_state);
+		}
+
+		xpath_allocator* _target;
+		xpath_allocator _state;
+	};
+
+	struct xpath_stack
+	{
+		xpath_allocator* result;
+		xpath_allocator* temp;
+	};
+
+	struct xpath_stack_data
+	{
+		xpath_memory_block blocks[2];
+		xpath_allocator result;
+		xpath_allocator temp;
+		xpath_stack stack;
+
+	#ifdef PUGIXML_NO_EXCEPTIONS
+		jmp_buf error_handler;
+	#endif
+
+		xpath_stack_data(): result(blocks + 0), temp(blocks + 1)
+		{
+			blocks[0].next = blocks[1].next = 0;
+
+			stack.result = &result;
+			stack.temp = &temp;
+
+		#ifdef PUGIXML_NO_EXCEPTIONS
+			result.error_handler = temp.error_handler = &error_handler;
+		#endif
+		}
+
+		~xpath_stack_data()
+		{
+			result.release();
+			temp.release();
+		}
+	};
+PUGI__NS_END
+
+// String class
+PUGI__NS_BEGIN
+	class xpath_string
+	{
+		const char_t* _buffer;
+		bool _uses_heap;
+
+		static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc)
+		{
+			char_t* result = static_cast<char_t*>(alloc->allocate((length + 1) * sizeof(char_t)));
+			assert(result);
+
+			memcpy(result, string, length * sizeof(char_t));
+			result[length] = 0;
+
+			return result;
+		}
+
+		static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc)
+		{
+			return duplicate_string(string, strlength(string), alloc);
+		}
+
+	public:
+		xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false)
+		{
+		}
+
+		explicit xpath_string(const char_t* str, xpath_allocator* alloc)
+		{
+			bool empty_ = (*str == 0);
+
+			_buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(str, alloc);
+			_uses_heap = !empty_;
+		}
+
+		explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap)
+		{
+		}
+
+		xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc)
+		{
+			assert(begin <= end);
+
+			bool empty_ = (begin == end);
+
+			_buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast<size_t>(end - begin), alloc);
+			_uses_heap = !empty_;
+		}
+
+		void append(const xpath_string& o, xpath_allocator* alloc)
+		{
+			// skip empty sources
+			if (!*o._buffer) return;
+
+			// fast append for constant empty target and constant source
+			if (!*_buffer && !_uses_heap && !o._uses_heap)
+			{
+				_buffer = o._buffer;
+			}
+			else
+			{
+				// need to make heap copy
+				size_t target_length = strlength(_buffer);
+				size_t source_length = strlength(o._buffer);
+				size_t result_length = target_length + source_length;
+
+				// allocate new buffer
+				char_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t)));
+				assert(result);
+
+				// append first string to the new buffer in case there was no reallocation
+				if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t));
+
+				// append second string to the new buffer
+				memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
+				result[result_length] = 0;
+
+				// finalize
+				_buffer = result;
+				_uses_heap = true;
+			}
+		}
+
+		const char_t* c_str() const
+		{
+			return _buffer;
+		}
+
+		size_t length() const
+		{
+			return strlength(_buffer);
+		}
+		
+		char_t* data(xpath_allocator* alloc)
+		{
+			// make private heap copy
+			if (!_uses_heap)
+			{
+				_buffer = duplicate_string(_buffer, alloc);
+				_uses_heap = true;
+			}
+
+			return const_cast<char_t*>(_buffer);
+		}
+
+		bool empty() const
+		{
+			return *_buffer == 0;
+		}
+
+		bool operator==(const xpath_string& o) const
+		{
+			return strequal(_buffer, o._buffer);
+		}
+
+		bool operator!=(const xpath_string& o) const
+		{
+			return !strequal(_buffer, o._buffer);
+		}
+
+		bool uses_heap() const
+		{
+			return _uses_heap;
+		}
+	};
+
+	PUGI__FN xpath_string xpath_string_const(const char_t* str)
+	{
+		return xpath_string(str, false);
+	}
+PUGI__NS_END
+
+PUGI__NS_BEGIN
+	PUGI__FN bool starts_with(const char_t* string, const char_t* pattern)
+	{
+		while (*pattern && *string == *pattern)
+		{
+			string++;
+			pattern++;
+		}
+
+		return *pattern == 0;
+	}
+
+	PUGI__FN const char_t* find_char(const char_t* s, char_t c)
+	{
+	#ifdef PUGIXML_WCHAR_MODE
+		return wcschr(s, c);
+	#else
+		return strchr(s, c);
+	#endif
+	}
+
+	PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p)
+	{
+	#ifdef PUGIXML_WCHAR_MODE
+		// MSVC6 wcsstr bug workaround (if s is empty it always returns 0)
+		return (*p == 0) ? s : wcsstr(s, p);
+	#else
+		return strstr(s, p);
+	#endif
+	}
+
+	// Converts symbol to lower case, if it is an ASCII one
+	PUGI__FN char_t tolower_ascii(char_t ch)
+	{
+		return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
+	}
+
+	PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
+	{
+		if (na.attribute())
+			return xpath_string_const(na.attribute().value());
+		else
+		{
+			const xml_node& n = na.node();
+
+			switch (n.type())
+			{
+			case node_pcdata:
+			case node_cdata:
+			case node_comment:
+			case node_pi:
+				return xpath_string_const(n.value());
+			
+			case node_document:
+			case node_element:
+			{
+				xpath_string result;
+
+				xml_node cur = n.first_child();
+				
+				while (cur && cur != n)
+				{
+					if (cur.type() == node_pcdata || cur.type() == node_cdata)
+						result.append(xpath_string_const(cur.value()), alloc);
+
+					if (cur.first_child())
+						cur = cur.first_child();
+					else if (cur.next_sibling())
+						cur = cur.next_sibling();
+					else
+					{
+						while (!cur.next_sibling() && cur != n)
+							cur = cur.parent();
+
+						if (cur != n) cur = cur.next_sibling();
+					}
+				}
+				
+				return result;
+			}
+			
+			default:
+				return xpath_string();
+			}
+		}
+	}
+	
+	PUGI__FN unsigned int node_height(xml_node n)
+	{
+		unsigned int result = 0;
+		
+		while (n)
+		{
+			++result;
+			n = n.parent();
+		}
+		
+		return result;
+	}
+	
+	PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh)
+	{
+		// normalize heights
+		for (unsigned int i = rh; i < lh; i++) ln = ln.parent();
+		for (unsigned int j = lh; j < rh; j++) rn = rn.parent();
+		
+		// one node is the ancestor of the other
+		if (ln == rn) return lh < rh;
+		
+		// find common ancestor
+		while (ln.parent() != rn.parent())
+		{
+			ln = ln.parent();
+			rn = rn.parent();
+		}
+
+		// there is no common ancestor (the shared parent is null), nodes are from different documents
+		if (!ln.parent()) return ln < rn;
+
+		// determine sibling order
+		for (; ln; ln = ln.next_sibling())
+			if (ln == rn)
+				return true;
+				
+		return false;
+	}
+
+	PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node)
+	{
+		while (node && node != parent) node = node.parent();
+
+		return parent && node == parent;
+	}
+
+	PUGI__FN const void* document_order(const xpath_node& xnode)
+	{
+		xml_node_struct* node = xnode.node().internal_object();
+
+		if (node)
+		{
+			if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name;
+			if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value;
+			return 0;
+		}
+
+		xml_attribute_struct* attr = xnode.attribute().internal_object();
+
+		if (attr)
+		{
+			if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name;
+			if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value;
+			return 0;
+		}
+
+		return 0;
+	}
+	
+	struct document_order_comparator
+	{
+		bool operator()(const xpath_node& lhs, const xpath_node& rhs) const
+		{
+			// optimized document order based check
+			const void* lo = document_order(lhs);
+			const void* ro = document_order(rhs);
+
+			if (lo && ro) return lo < ro;
+
+			// slow comparison
+			xml_node ln = lhs.node(), rn = rhs.node();
+
+			// compare attributes
+			if (lhs.attribute() && rhs.attribute())
+			{
+				// shared parent
+				if (lhs.parent() == rhs.parent())
+				{
+					// determine sibling order
+					for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
+						if (a == rhs.attribute())
+							return true;
+					
+					return false;
+				}
+				
+				// compare attribute parents
+				ln = lhs.parent();
+				rn = rhs.parent();
+			}
+			else if (lhs.attribute())
+			{
+				// attributes go after the parent element
+				if (lhs.parent() == rhs.node()) return false;
+				
+				ln = lhs.parent();
+			}
+			else if (rhs.attribute())
+			{
+				// attributes go after the parent element
+				if (rhs.parent() == lhs.node()) return true;
+				
+				rn = rhs.parent();
+			}
+
+			if (ln == rn) return false;
+			
+			unsigned int lh = node_height(ln);
+			unsigned int rh = node_height(rn);
+			
+			return node_is_before(ln, lh, rn, rh);
+		}
+	};
+
+	struct duplicate_comparator
+	{
+		bool operator()(const xpath_node& lhs, const xpath_node& rhs) const
+		{
+			if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true;
+			else return rhs.attribute() ? false : lhs.node() < rhs.node();
+		}
+	};
+	
+	PUGI__FN double gen_nan()
+	{
+	#if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
+		union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1];
+		u[0].i = 0x7fc00000;
+		return u[0].f;
+	#else
+		// fallback
+		const volatile double zero = 0.0;
+		return zero / zero;
+	#endif
+	}
+	
+	PUGI__FN bool is_nan(double value)
+	{
+	#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
+		return !!_isnan(value);
+	#elif defined(fpclassify) && defined(FP_NAN)
+		return fpclassify(value) == FP_NAN;
+	#else
+		// fallback
+		const volatile double v = value;
+		return v != v;
+	#endif
+	}
+	
+	PUGI__FN const char_t* convert_number_to_string_special(double value)
+	{
+	#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
+		if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0;
+		if (_isnan(value)) return PUGIXML_TEXT("NaN");
+		return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
+	#elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
+		switch (fpclassify(value))
+		{
+		case FP_NAN:
+			return PUGIXML_TEXT("NaN");
+
+		case FP_INFINITE:
+			return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
+
+		case FP_ZERO:
+			return PUGIXML_TEXT("0");
+
+		default:
+			return 0;
+		}
+	#else
+		// fallback
+		const volatile double v = value;
+
+		if (v == 0) return PUGIXML_TEXT("0");
+		if (v != v) return PUGIXML_TEXT("NaN");
+		if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
+		return 0;
+	#endif
+	}
+	
+	PUGI__FN bool convert_number_to_boolean(double value)
+	{
+		return (value != 0 && !is_nan(value));
+	}
+	
+	PUGI__FN void truncate_zeros(char* begin, char* end)
+	{
+		while (begin != end && end[-1] == '0') end--;
+
+		*end = 0;
+	}
+
+	// gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
+#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
+	PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
+	{
+		// get base values
+		int sign, exponent;
+		_ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign);
+
+		// truncate redundant zeros
+		truncate_zeros(buffer, buffer + strlen(buffer));
+
+		// fill results
+		*out_mantissa = buffer;
+		*out_exponent = exponent;
+	}
+#else
+	PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
+	{
+		// get a scientific notation value with IEEE DBL_DIG decimals
+		sprintf(buffer, "%.*e", DBL_DIG, value);
+		assert(strlen(buffer) < buffer_size);
+		(void)!buffer_size;
+
+		// get the exponent (possibly negative)
+		char* exponent_string = strchr(buffer, 'e');
+		assert(exponent_string);
+
+		int exponent = atoi(exponent_string + 1);
+
+		// extract mantissa string: skip sign
+		char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
+		assert(mantissa[0] != '0' && mantissa[1] == '.');
+
+		// divide mantissa by 10 to eliminate integer part
+		mantissa[1] = mantissa[0];
+		mantissa++;
+		exponent++;
+
+		// remove extra mantissa digits and zero-terminate mantissa
+		truncate_zeros(mantissa, exponent_string);
+
+		// fill results
+		*out_mantissa = mantissa;
+		*out_exponent = exponent;
+	}
+#endif
+
+	PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc)
+	{
+		// try special number conversion
+		const char_t* special = convert_number_to_string_special(value);
+		if (special) return xpath_string_const(special);
+
+		// get mantissa + exponent form
+		char mantissa_buffer[64];
+
+		char* mantissa;
+		int exponent;
+		convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent);
+
+		// make the number!
+		char_t result[512];
+		char_t* s = result;
+
+		// sign
+		if (value < 0) *s++ = '-';
+
+		// integer part
+		if (exponent <= 0)
+		{
+			*s++ = '0';
+		}
+		else
+		{
+			while (exponent > 0)
+			{
+				assert(*mantissa == 0 || static_cast<unsigned int>(*mantissa - '0') <= 9);
+				*s++ = *mantissa ? *mantissa++ : '0';
+				exponent--;
+			}
+		}
+
+		// fractional part
+		if (*mantissa)
+		{
+			// decimal point
+			*s++ = '.';
+
+			// extra zeroes from negative exponent
+			while (exponent < 0)
+			{
+				*s++ = '0';
+				exponent++;
+			}
+
+			// extra mantissa digits
+			while (*mantissa)
+			{
+				assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
+				*s++ = *mantissa++;
+			}
+		}
+
+		// zero-terminate
+		assert(s < result + sizeof(result) / sizeof(result[0]));
+		*s = 0;
+
+		return xpath_string(result, alloc);
+	}
+	
+	PUGI__FN bool check_string_to_number_format(const char_t* string)
+	{
+		// parse leading whitespace
+		while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
+
+		// parse sign
+		if (*string == '-') ++string;
+
+		if (!*string) return false;
+
+		// if there is no integer part, there should be a decimal part with at least one digit
+		if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false;
+
+		// parse integer part
+		while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
+
+		// parse decimal part
+		if (*string == '.')
+		{
+			++string;
+
+			while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
+		}
+
+		// parse trailing whitespace
+		while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
+
+		return *string == 0;
+	}
+
+	PUGI__FN double convert_string_to_number(const char_t* string)
+	{
+		// check string format
+		if (!check_string_to_number_format(string)) return gen_nan();
+
+		// parse string
+	#ifdef PUGIXML_WCHAR_MODE
+		return wcstod(string, 0);
+	#else
+		return atof(string);
+	#endif
+	}
+
+	PUGI__FN bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result)
+	{
+		char_t buffer[32];
+
+		size_t length = static_cast<size_t>(end - begin);
+		char_t* scratch = buffer;
+
+		if (length >= sizeof(buffer) / sizeof(buffer[0]))
+		{
+			// need to make dummy on-heap copy
+			scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
+			if (!scratch) return false;
+		}
+
+		// copy string to zero-terminated buffer and perform conversion
+		memcpy(scratch, begin, length * sizeof(char_t));
+		scratch[length] = 0;
+
+		*out_result = convert_string_to_number(scratch);
+
+		// free dummy buffer
+		if (scratch != buffer) xml_memory::deallocate(scratch);
+
+		return true;
+	}
+	
+	PUGI__FN double round_nearest(double value)
+	{
+		return floor(value + 0.5);
+	}
+
+	PUGI__FN double round_nearest_nzero(double value)
+	{
+		// same as round_nearest, but returns -0 for [-0.5, -0]
+		// ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)
+		return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
+	}
+	
+	PUGI__FN const char_t* qualified_name(const xpath_node& node)
+	{
+		return node.attribute() ? node.attribute().name() : node.node().name();
+	}
+	
+	PUGI__FN const char_t* local_name(const xpath_node& node)
+	{
+		const char_t* name = qualified_name(node);
+		const char_t* p = find_char(name, ':');
+		
+		return p ? p + 1 : name;
+	}
+
+	struct namespace_uri_predicate
+	{
+		const char_t* prefix;
+		size_t prefix_length;
+
+		namespace_uri_predicate(const char_t* name)
+		{
+			const char_t* pos = find_char(name, ':');
+
+			prefix = pos ? name : 0;
+			prefix_length = pos ? static_cast<size_t>(pos - name) : 0;
+		}
+
+		bool operator()(const xml_attribute& a) const
+		{
+			const char_t* name = a.name();
+
+			if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false;
+
+			return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
+		}
+	};
+
+	PUGI__FN const char_t* namespace_uri(const xml_node& node)
+	{
+		namespace_uri_predicate pred = node.name();
+		
+		xml_node p = node;
+		
+		while (p)
+		{
+			xml_attribute a = p.find_attribute(pred);
+			
+			if (a) return a.value();
+			
+			p = p.parent();
+		}
+		
+		return PUGIXML_TEXT("");
+	}
+
+	PUGI__FN const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent)
+	{
+		namespace_uri_predicate pred = attr.name();
+		
+		// Default namespace does not apply to attributes
+		if (!pred.prefix) return PUGIXML_TEXT("");
+		
+		xml_node p = parent;
+		
+		while (p)
+		{
+			xml_attribute a = p.find_attribute(pred);
+			
+			if (a) return a.value();
+			
+			p = p.parent();
+		}
+		
+		return PUGIXML_TEXT("");
+	}
+
+	PUGI__FN const char_t* namespace_uri(const xpath_node& node)
+	{
+		return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
+	}
+
+	PUGI__FN void normalize_space(char_t* buffer)
+	{
+		char_t* write = buffer;
+
+		for (char_t* it = buffer; *it; )
+		{
+			char_t ch = *it++;
+
+			if (PUGI__IS_CHARTYPE(ch, ct_space))
+			{
+				// replace whitespace sequence with single space
+				while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
+
+				// avoid leading spaces
+				if (write != buffer) *write++ = ' ';
+			}
+			else *write++ = ch;
+		}
+
+		// remove trailing space
+		if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
+
+		// zero-terminate
+		*write = 0;
+	}
+
+	PUGI__FN void translate(char_t* buffer, const char_t* from, const char_t* to)
+	{
+		size_t to_length = strlength(to);
+
+		char_t* write = buffer;
+
+		while (*buffer)
+		{
+			PUGI__DMC_VOLATILE char_t ch = *buffer++;
+
+			const char_t* pos = find_char(from, ch);
+
+			if (!pos)
+				*write++ = ch; // do not process
+			else if (static_cast<size_t>(pos - from) < to_length)
+				*write++ = to[pos - from]; // replace
+		}
+
+		// zero-terminate
+		*write = 0;
+	}
+
+	struct xpath_variable_boolean: xpath_variable
+	{
+		xpath_variable_boolean(): value(false)
+		{
+		}
+
+		bool value;
+		char_t name[1];
+	};
+
+	struct xpath_variable_number: xpath_variable
+	{
+		xpath_variable_number(): value(0)
+		{
+		}
+
+		double value;
+		char_t name[1];
+	};
+
+	struct xpath_variable_string: xpath_variable
+	{
+		xpath_variable_string(): value(0)
+		{
+		}
+
+		~xpath_variable_string()
+		{
+			if (value) xml_memory::deallocate(value);
+		}
+
+		char_t* value;
+		char_t name[1];
+	};
+
+	struct xpath_variable_node_set: xpath_variable
+	{
+		xpath_node_set value;
+		char_t name[1];
+	};
+
+	static const xpath_node_set dummy_node_set;
+
+	PUGI__FN unsigned int hash_string(const char_t* str)
+	{
+		// Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
+		unsigned int result = 0;
+
+		while (*str)
+		{
+			result += static_cast<unsigned int>(*str++);
+			result += result << 10;
+			result ^= result >> 6;
+		}
+	
+		result += result << 3;
+		result ^= result >> 11;
+		result += result << 15;
+	
+		return result;
+	}
+
+	template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name)
+	{
+		size_t length = strlength(name);
+		if (length == 0) return 0; // empty variable names are invalid
+
+		// $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
+		void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));
+		if (!memory) return 0;
+
+		T* result = new (memory) T();
+
+		memcpy(result->name, name, (length + 1) * sizeof(char_t));
+
+		return result;
+	}
+
+	PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
+	{
+		switch (type)
+		{
+		case xpath_type_node_set:
+			return new_xpath_variable<xpath_variable_node_set>(name);
+
+		case xpath_type_number:
+			return new_xpath_variable<xpath_variable_number>(name);
+
+		case xpath_type_string:
+			return new_xpath_variable<xpath_variable_string>(name);
+
+		case xpath_type_boolean:
+			return new_xpath_variable<xpath_variable_boolean>(name);
+
+		default:
+			return 0;
+		}
+	}
+
+	template <typename T> PUGI__FN void delete_xpath_variable(T* var)
+	{
+		var->~T();
+		xml_memory::deallocate(var);
+	}
+
+	PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
+	{
+		switch (type)
+		{
+		case xpath_type_node_set:
+			delete_xpath_variable(static_cast<xpath_variable_node_set*>(var));
+			break;
+
+		case xpath_type_number:
+			delete_xpath_variable(static_cast<xpath_variable_number*>(var));
+			break;
+
+		case xpath_type_string:
+			delete_xpath_variable(static_cast<xpath_variable_string*>(var));
+			break;
+
+		case xpath_type_boolean:
+			delete_xpath_variable(static_cast<xpath_variable_boolean*>(var));
+			break;
+
+		default:
+			assert(!"Invalid variable type");
+		}
+	}
+
+	PUGI__FN xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end)
+	{
+		char_t buffer[32];
+
+		size_t length = static_cast<size_t>(end - begin);
+		char_t* scratch = buffer;
+
+		if (length >= sizeof(buffer) / sizeof(buffer[0]))
+		{
+			// need to make dummy on-heap copy
+			scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
+			if (!scratch) return 0;
+		}
+
+		// copy string to zero-terminated buffer and perform lookup
+		memcpy(scratch, begin, length * sizeof(char_t));
+		scratch[length] = 0;
+
+		xpath_variable* result = set->get(scratch);
+
+		// free dummy buffer
+		if (scratch != buffer) xml_memory::deallocate(scratch);
+
+		return result;
+	}
+PUGI__NS_END
+
+// Internal node set class
+PUGI__NS_BEGIN
+	PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
+	{
+		xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
+
+		if (type == xpath_node_set::type_unsorted)
+		{
+			sort(begin, end, document_order_comparator());
+
+			type = xpath_node_set::type_sorted;
+		}
+		
+		if (type != order) reverse(begin, end);
+			
+		return order;
+	}
+
+	PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
+	{
+		if (begin == end) return xpath_node();
+
+		switch (type)
+		{
+		case xpath_node_set::type_sorted:
+			return *begin;
+
+		case xpath_node_set::type_sorted_reverse:
+			return *(end - 1);
+
+		case xpath_node_set::type_unsorted:
+			return *min_element(begin, end, document_order_comparator());
+
+		default:
+			assert(!"Invalid node set type");
+			return xpath_node();
+		}
+	}
+
+	class xpath_node_set_raw
+	{
+		xpath_node_set::type_t _type;
+
+		xpath_node* _begin;
+		xpath_node* _end;
+		xpath_node* _eos;
+
+	public:
+		xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0)
+		{
+		}
+
+		xpath_node* begin() const
+		{
+			return _begin;
+		}
+
+		xpath_node* end() const
+		{
+			return _end;
+		}
+
+		bool empty() const
+		{
+			return _begin == _end;
+		}
+
+		size_t size() const
+		{
+			return static_cast<size_t>(_end - _begin);
+		}
+
+		xpath_node first() const
+		{
+			return xpath_first(_begin, _end, _type);
+		}
+
+		void push_back(const xpath_node& node, xpath_allocator* alloc)
+		{
+			if (_end == _eos)
+			{
+				size_t capacity = static_cast<size_t>(_eos - _begin);
+
+				// get new capacity (1.5x rule)
+				size_t new_capacity = capacity + capacity / 2 + 1;
+
+				// reallocate the old array or allocate a new one
+				xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
+				assert(data);
+
+				// finalize
+				_begin = data;
+				_end = data + capacity;
+				_eos = data + new_capacity;
+			}
+
+			*_end++ = node;
+		}
+
+		void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)
+		{
+			size_t size_ = static_cast<size_t>(_end - _begin);
+			size_t capacity = static_cast<size_t>(_eos - _begin);
+			size_t count = static_cast<size_t>(end_ - begin_);
+
+			if (size_ + count > capacity)
+			{
+				// reallocate the old array or allocate a new one
+				xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
+				assert(data);
+
+				// finalize
+				_begin = data;
+				_end = data + size_;
+				_eos = data + size_ + count;
+			}
+
+			memcpy(_end, begin_, count * sizeof(xpath_node));
+			_end += count;
+		}
+
+		void sort_do()
+		{
+			_type = xpath_sort(_begin, _end, _type, false);
+		}
+
+		void truncate(xpath_node* pos)
+		{
+			assert(_begin <= pos && pos <= _end);
+
+			_end = pos;
+		}
+
+		void remove_duplicates()
+		{
+			if (_type == xpath_node_set::type_unsorted)
+				sort(_begin, _end, duplicate_comparator());
+		
+			_end = unique(_begin, _end);
+		}
+
+		xpath_node_set::type_t type() const
+		{
+			return _type;
+		}
+
+		void set_type(xpath_node_set::type_t value)
+		{
+			_type = value;
+		}
+	};
+PUGI__NS_END
+
+PUGI__NS_BEGIN
+	struct xpath_context
+	{
+		xpath_node n;
+		size_t position, size;
+
+		xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_)
+		{
+		}
+	};
+
+	enum lexeme_t
+	{
+		lex_none = 0,
+		lex_equal,
+		lex_not_equal,
+		lex_less,
+		lex_greater,
+		lex_less_or_equal,
+		lex_greater_or_equal,
+		lex_plus,
+		lex_minus,
+		lex_multiply,
+		lex_union,
+		lex_var_ref,
+		lex_open_brace,
+		lex_close_brace,
+		lex_quoted_string,
+		lex_number,
+		lex_slash,
+		lex_double_slash,
+		lex_open_square_brace,
+		lex_close_square_brace,
+		lex_string,
+		lex_comma,
+		lex_axis_attribute,
+		lex_dot,
+		lex_double_dot,
+		lex_double_colon,
+		lex_eof
+	};
+
+	struct xpath_lexer_string
+	{
+		const char_t* begin;
+		const char_t* end;
+
+		xpath_lexer_string(): begin(0), end(0)
+		{
+		}
+
+		bool operator==(const char_t* other) const
+		{
+			size_t length = static_cast<size_t>(end - begin);
+
+			return strequalrange(other, begin, length);
+		}
+	};
+
+	class xpath_lexer
+	{
+		const char_t* _cur;
+		const char_t* _cur_lexeme_pos;
+		xpath_lexer_string _cur_lexeme_contents;
+
+		lexeme_t _cur_lexeme;
+
+	public:
+		explicit xpath_lexer(const char_t* query): _cur(query)
+		{
+			next();
+		}
+		
+		const char_t* state() const
+		{
+			return _cur;
+		}
+		
+		void next()
+		{
+			const char_t* cur = _cur;
+
+			while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
+
+			// save lexeme position for error reporting
+			_cur_lexeme_pos = cur;
+
+			switch (*cur)
+			{
+			case 0:
+				_cur_lexeme = lex_eof;
+				break;
+			
+			case '>':
+				if (*(cur+1) == '=')
+				{
+					cur += 2;
+					_cur_lexeme = lex_greater_or_equal;
+				}
+				else
+				{
+					cur += 1;
+					_cur_lexeme = lex_greater;
+				}
+				break;
+
+			case '<':
+				if (*(cur+1) == '=')
+				{
+					cur += 2;
+					_cur_lexeme = lex_less_or_equal;
+				}
+				else
+				{
+					cur += 1;
+					_cur_lexeme = lex_less;
+				}
+				break;
+
+			case '!':
+				if (*(cur+1) == '=')
+				{
+					cur += 2;
+					_cur_lexeme = lex_not_equal;
+				}
+				else
+				{
+					_cur_lexeme = lex_none;
+				}
+				break;
+
+			case '=':
+				cur += 1;
+				_cur_lexeme = lex_equal;
+
+				break;
+			
+			case '+':
+				cur += 1;
+				_cur_lexeme = lex_plus;
+
+				break;
+
+			case '-':
+				cur += 1;
+				_cur_lexeme = lex_minus;
+
+				break;
+
+			case '*':
+				cur += 1;
+				_cur_lexeme = lex_multiply;
+
+				break;
+
+			case '|':
+				cur += 1;
+				_cur_lexeme = lex_union;
+
+				break;
+			
+			case '$':
+				cur += 1;
+
+				if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
+				{
+					_cur_lexeme_contents.begin = cur;
+
+					while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
+
+					if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
+					{
+						cur++; // :
+
+						while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
+					}
+
+					_cur_lexeme_contents.end = cur;
+				
+					_cur_lexeme = lex_var_ref;
+				}
+				else
+				{
+					_cur_lexeme = lex_none;
+				}
+
+				break;
+
+			case '(':
+				cur += 1;
+				_cur_lexeme = lex_open_brace;
+
+				break;
+
+			case ')':
+				cur += 1;
+				_cur_lexeme = lex_close_brace;
+
+				break;
+			
+			case '[':
+				cur += 1;
+				_cur_lexeme = lex_open_square_brace;
+
+				break;
+
+			case ']':
+				cur += 1;
+				_cur_lexeme = lex_close_square_brace;
+
+				break;
+
+			case ',':
+				cur += 1;
+				_cur_lexeme = lex_comma;
+
+				break;
+
+			case '/':
+				if (*(cur+1) == '/')
+				{
+					cur += 2;
+					_cur_lexeme = lex_double_slash;
+				}
+				else
+				{
+					cur += 1;
+					_cur_lexeme = lex_slash;
+				}
+				break;
+		
+			case '.':
+				if (*(cur+1) == '.')
+				{
+					cur += 2;
+					_cur_lexeme = lex_double_dot;
+				}
+				else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
+				{
+					_cur_lexeme_contents.begin = cur; // .
+
+					++cur;
+
+					while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
+
+					_cur_lexeme_contents.end = cur;
+					
+					_cur_lexeme = lex_number;
+				}
+				else
+				{
+					cur += 1;
+					_cur_lexeme = lex_dot;
+				}
+				break;
+
+			case '@':
+				cur += 1;
+				_cur_lexeme = lex_axis_attribute;
+
+				break;
+
+			case '"':
+			case '\'':
+			{
+				char_t terminator = *cur;
+
+				++cur;
+
+				_cur_lexeme_contents.begin = cur;
+				while (*cur && *cur != terminator) cur++;
+				_cur_lexeme_contents.end = cur;
+				
+				if (!*cur)
+					_cur_lexeme = lex_none;
+				else
+				{
+					cur += 1;
+					_cur_lexeme = lex_quoted_string;
+				}
+
+				break;
+			}
+
+			case ':':
+				if (*(cur+1) == ':')
+				{
+					cur += 2;
+					_cur_lexeme = lex_double_colon;
+				}
+				else
+				{
+					_cur_lexeme = lex_none;
+				}
+				break;
+
+			default:
+				if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
+				{
+					_cur_lexeme_contents.begin = cur;
+
+					while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
+				
+					if (*cur == '.')
+					{
+						cur++;
+
+						while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
+					}
+
+					_cur_lexeme_contents.end = cur;
+
+					_cur_lexeme = lex_number;
+				}
+				else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
+				{
+					_cur_lexeme_contents.begin = cur;
+
+					while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
+
+					if (cur[0] == ':')
+					{
+						if (cur[1] == '*') // namespace test ncname:*
+						{
+							cur += 2; // :*
+						}
+						else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
+						{
+							cur++; // :
+
+							while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
+						}
+					}
+
+					_cur_lexeme_contents.end = cur;
+				
+					_cur_lexeme = lex_string;
+				}
+				else
+				{
+					_cur_lexeme = lex_none;
+				}
+			}
+
+			_cur = cur;
+		}
+
+		lexeme_t current() const
+		{
+			return _cur_lexeme;
+		}
+
+		const char_t* current_pos() const
+		{
+			return _cur_lexeme_pos;
+		}
+
+		const xpath_lexer_string& contents() const
+		{
+			assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
+
+			return _cur_lexeme_contents;
+		}
+	};
+
+	enum ast_type_t
+	{
+		ast_op_or,						// left or right
+		ast_op_and,						// left and right
+		ast_op_equal,					// left = right
+		ast_op_not_equal,				// left != right
+		ast_op_less,					// left < right
+		ast_op_greater,					// left > right
+		ast_op_less_or_equal,			// left <= right
+		ast_op_greater_or_equal,		// left >= right
+		ast_op_add,						// left + right
+		ast_op_subtract,				// left - right
+		ast_op_multiply,				// left * right
+		ast_op_divide,					// left / right
+		ast_op_mod,						// left % right
+		ast_op_negate,					// left - right
+		ast_op_union,					// left | right
+		ast_predicate,					// apply predicate to set; next points to next predicate
+		ast_filter,						// select * from left where right
+		ast_filter_posinv,				// select * from left where right; proximity position invariant
+		ast_string_constant,			// string constant
+		ast_number_constant,			// number constant
+		ast_variable,					// variable
+		ast_func_last,					// last()
+		ast_func_position,				// position()
+		ast_func_count,					// count(left)
+		ast_func_id,					// id(left)
+		ast_func_local_name_0,			// local-name()
+		ast_func_local_name_1,			// local-name(left)
+		ast_func_namespace_uri_0,		// namespace-uri()
+		ast_func_namespace_uri_1,		// namespace-uri(left)
+		ast_func_name_0,				// name()
+		ast_func_name_1,				// name(left)
+		ast_func_string_0,				// string()
+		ast_func_string_1,				// string(left)
+		ast_func_concat,				// concat(left, right, siblings)
+		ast_func_starts_with,			// starts_with(left, right)
+		ast_func_contains,				// contains(left, right)
+		ast_func_substring_before,		// substring-before(left, right)
+		ast_func_substring_after,		// substring-after(left, right)
+		ast_func_substring_2,			// substring(left, right)
+		ast_func_substring_3,			// substring(left, right, third)
+		ast_func_string_length_0,		// string-length()
+		ast_func_string_length_1,		// string-length(left)
+		ast_func_normalize_space_0,		// normalize-space()
+		ast_func_normalize_space_1,		// normalize-space(left)
+		ast_func_translate,				// translate(left, right, third)
+		ast_func_boolean,				// boolean(left)
+		ast_func_not,					// not(left)
+		ast_func_true,					// true()
+		ast_func_false,					// false()
+		ast_func_lang,					// lang(left)
+		ast_func_number_0,				// number()
+		ast_func_number_1,				// number(left)
+		ast_func_sum,					// sum(left)
+		ast_func_floor,					// floor(left)
+		ast_func_ceiling,				// ceiling(left)
+		ast_func_round,					// round(left)
+		ast_step,						// process set left with step
+		ast_step_root					// select root node
+	};
+
+	enum axis_t
+	{
+		axis_ancestor,
+		axis_ancestor_or_self,
+		axis_attribute,
+		axis_child,
+		axis_descendant,
+		axis_descendant_or_self,
+		axis_following,
+		axis_following_sibling,
+		axis_namespace,
+		axis_parent,
+		axis_preceding,
+		axis_preceding_sibling,
+		axis_self
+	};
+	
+	enum nodetest_t
+	{
+		nodetest_none,
+		nodetest_name,
+		nodetest_type_node,
+		nodetest_type_comment,
+		nodetest_type_pi,
+		nodetest_type_text,
+		nodetest_pi,
+		nodetest_all,
+		nodetest_all_in_namespace
+	};
+
+	template <axis_t N> struct axis_to_type
+	{
+		static const axis_t axis;
+	};
+
+	template <axis_t N> const axis_t axis_to_type<N>::axis = N;
+		
+	class xpath_ast_node
+	{
+	private:
+		// node type
+		char _type;
+		char _rettype;
+
+		// for ast_step / ast_predicate
+		char _axis;
+		char _test;
+
+		// tree node structure
+		xpath_ast_node* _left;
+		xpath_ast_node* _right;
+		xpath_ast_node* _next;
+
+		union
+		{
+			// value for ast_string_constant
+			const char_t* string;
+			// value for ast_number_constant
+			double number;
+			// variable for ast_variable
+			xpath_variable* variable;
+			// node test for ast_step (node name/namespace/node type/pi target)
+			const char_t* nodetest;
+		} _data;
+
+		xpath_ast_node(const xpath_ast_node&);
+		xpath_ast_node& operator=(const xpath_ast_node&);
+
+		template <class Comp> static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
+		{
+			xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
+
+			if (lt != xpath_type_node_set && rt != xpath_type_node_set)
+			{
+				if (lt == xpath_type_boolean || rt == xpath_type_boolean)
+					return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
+				else if (lt == xpath_type_number || rt == xpath_type_number)
+					return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
+				else if (lt == xpath_type_string || rt == xpath_type_string)
+				{
+					xpath_allocator_capture cr(stack.result);
+
+					xpath_string ls = lhs->eval_string(c, stack);
+					xpath_string rs = rhs->eval_string(c, stack);
+
+					return comp(ls, rs);
+				}
+			}
+			else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
+				xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
+
+				for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
+					for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
+					{
+						xpath_allocator_capture cri(stack.result);
+
+						if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
+							return true;
+					}
+
+				return false;
+			}
+			else
+			{
+				if (lt == xpath_type_node_set)
+				{
+					swap(lhs, rhs);
+					swap(lt, rt);
+				}
+
+				if (lt == xpath_type_boolean)
+					return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
+				else if (lt == xpath_type_number)
+				{
+					xpath_allocator_capture cr(stack.result);
+
+					double l = lhs->eval_number(c, stack);
+					xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
+
+					for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
+					{
+						xpath_allocator_capture cri(stack.result);
+
+						if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
+							return true;
+					}
+
+					return false;
+				}
+				else if (lt == xpath_type_string)
+				{
+					xpath_allocator_capture cr(stack.result);
+
+					xpath_string l = lhs->eval_string(c, stack);
+					xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
+
+					for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
+					{
+						xpath_allocator_capture cri(stack.result);
+
+						if (comp(l, string_value(*ri, stack.result)))
+							return true;
+					}
+
+					return false;
+				}
+			}
+
+			assert(!"Wrong types");
+			return false;
+		}
+
+		template <class Comp> static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
+		{
+			xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
+
+			if (lt != xpath_type_node_set && rt != xpath_type_node_set)
+				return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
+			else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
+				xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
+
+				for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
+				{
+					xpath_allocator_capture cri(stack.result);
+
+					double l = convert_string_to_number(string_value(*li, stack.result).c_str());
+
+					for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
+					{
+						xpath_allocator_capture crii(stack.result);
+
+						if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
+							return true;
+					}
+				}
+
+				return false;
+			}
+			else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				double l = lhs->eval_number(c, stack);
+				xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
+
+				for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
+				{
+					xpath_allocator_capture cri(stack.result);
+
+					if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
+						return true;
+				}
+
+				return false;
+			}
+			else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
+				double r = rhs->eval_number(c, stack);
+
+				for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
+				{
+					xpath_allocator_capture cri(stack.result);
+
+					if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
+						return true;
+				}
+
+				return false;
+			}
+			else
+			{
+				assert(!"Wrong types");
+				return false;
+			}
+		}
+
+		void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)
+		{
+			assert(ns.size() >= first);
+
+			size_t i = 1;
+			size_t size = ns.size() - first;
+				
+			xpath_node* last = ns.begin() + first;
+				
+			// remove_if... or well, sort of
+			for (xpath_node* it = last; it != ns.end(); ++it, ++i)
+			{
+				xpath_context c(*it, i, size);
+			
+				if (expr->rettype() == xpath_type_number)
+				{
+					if (expr->eval_number(c, stack) == i)
+						*last++ = *it;
+				}
+				else if (expr->eval_boolean(c, stack))
+					*last++ = *it;
+			}
+			
+			ns.truncate(last);
+		}
+
+		void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack)
+		{
+			if (ns.size() == first) return;
+			
+			for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
+			{
+				apply_predicate(ns, first, pred->_left, stack);
+			}
+		}
+
+		void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc)
+		{
+			if (!a) return;
+
+			const char_t* name = a.name();
+
+			// There are no attribute nodes corresponding to attributes that declare namespaces
+			// That is, "xmlns:..." or "xmlns"
+			if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return;
+			
+			switch (_test)
+			{
+			case nodetest_name:
+				if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc);
+				break;
+				
+			case nodetest_type_node:
+			case nodetest_all:
+				ns.push_back(xpath_node(a, parent), alloc);
+				break;
+				
+			case nodetest_all_in_namespace:
+				if (starts_with(name, _data.nodetest))
+					ns.push_back(xpath_node(a, parent), alloc);
+				break;
+			
+			default:
+				;
+			}
+		}
+		
+		void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc)
+		{
+			if (!n) return;
+
+			switch (_test)
+			{
+			case nodetest_name:
+				if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc);
+				break;
+				
+			case nodetest_type_node:
+				ns.push_back(n, alloc);
+				break;
+				
+			case nodetest_type_comment:
+				if (n.type() == node_comment)
+					ns.push_back(n, alloc);
+				break;
+				
+			case nodetest_type_text:
+				if (n.type() == node_pcdata || n.type() == node_cdata)
+					ns.push_back(n, alloc);
+				break;
+				
+			case nodetest_type_pi:
+				if (n.type() == node_pi)
+					ns.push_back(n, alloc);
+				break;
+									
+			case nodetest_pi:
+				if (n.type() == node_pi && strequal(n.name(), _data.nodetest))
+					ns.push_back(n, alloc);
+				break;
+				
+			case nodetest_all:
+				if (n.type() == node_element)
+					ns.push_back(n, alloc);
+				break;
+				
+			case nodetest_all_in_namespace:
+				if (n.type() == node_element && starts_with(n.name(), _data.nodetest))
+					ns.push_back(n, alloc);
+				break;
+
+			default:
+				assert(!"Unknown axis");
+			} 
+		}
+
+		template <class T> void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T)
+		{
+			const axis_t axis = T::axis;
+
+			switch (axis)
+			{
+			case axis_attribute:
+			{
+				for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute())
+					step_push(ns, a, n, alloc);
+				
+				break;
+			}
+			
+			case axis_child:
+			{
+				for (xml_node c = n.first_child(); c; c = c.next_sibling())
+					step_push(ns, c, alloc);
+					
+				break;
+			}
+			
+			case axis_descendant:
+			case axis_descendant_or_self:
+			{
+				if (axis == axis_descendant_or_self)
+					step_push(ns, n, alloc);
+					
+				xml_node cur = n.first_child();
+				
+				while (cur && cur != n)
+				{
+					step_push(ns, cur, alloc);
+					
+					if (cur.first_child())
+						cur = cur.first_child();
+					else if (cur.next_sibling())
+						cur = cur.next_sibling();
+					else
+					{
+						while (!cur.next_sibling() && cur != n)
+							cur = cur.parent();
+					
+						if (cur != n) cur = cur.next_sibling();
+					}
+				}
+				
+				break;
+			}
+			
+			case axis_following_sibling:
+			{
+				for (xml_node c = n.next_sibling(); c; c = c.next_sibling())
+					step_push(ns, c, alloc);
+				
+				break;
+			}
+			
+			case axis_preceding_sibling:
+			{
+				for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling())
+					step_push(ns, c, alloc);
+				
+				break;
+			}
+			
+			case axis_following:
+			{
+				xml_node cur = n;
+
+				// exit from this node so that we don't include descendants
+				while (cur && !cur.next_sibling()) cur = cur.parent();
+				cur = cur.next_sibling();
+
+				for (;;)
+				{
+					step_push(ns, cur, alloc);
+
+					if (cur.first_child())
+						cur = cur.first_child();
+					else if (cur.next_sibling())
+						cur = cur.next_sibling();
+					else
+					{
+						while (cur && !cur.next_sibling()) cur = cur.parent();
+						cur = cur.next_sibling();
+
+						if (!cur) break;
+					}
+				}
+
+				break;
+			}
+
+			case axis_preceding:
+			{
+				xml_node cur = n;
+
+				while (cur && !cur.previous_sibling()) cur = cur.parent();
+				cur = cur.previous_sibling();
+
+				for (;;)
+				{
+					if (cur.last_child())
+						cur = cur.last_child();
+					else
+					{
+						// leaf node, can't be ancestor
+						step_push(ns, cur, alloc);
+
+						if (cur.previous_sibling())
+							cur = cur.previous_sibling();
+						else
+						{
+							do 
+							{
+								cur = cur.parent();
+								if (!cur) break;
+
+								if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc);
+							}
+							while (!cur.previous_sibling());
+
+							cur = cur.previous_sibling();
+
+							if (!cur) break;
+						}
+					}
+				}
+
+				break;
+			}
+			
+			case axis_ancestor:
+			case axis_ancestor_or_self:
+			{
+				if (axis == axis_ancestor_or_self)
+					step_push(ns, n, alloc);
+
+				xml_node cur = n.parent();
+				
+				while (cur)
+				{
+					step_push(ns, cur, alloc);
+					
+					cur = cur.parent();
+				}
+				
+				break;
+			}
+
+			case axis_self:
+			{
+				step_push(ns, n, alloc);
+
+				break;
+			}
+
+			case axis_parent:
+			{
+				if (n.parent()) step_push(ns, n.parent(), alloc);
+
+				break;
+			}
+				
+			default:
+				assert(!"Unimplemented axis");
+			}
+		}
+		
+		template <class T> void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v)
+		{
+			const axis_t axis = T::axis;
+
+			switch (axis)
+			{
+			case axis_ancestor:
+			case axis_ancestor_or_self:
+			{
+				if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test
+					step_push(ns, a, p, alloc);
+
+				xml_node cur = p;
+				
+				while (cur)
+				{
+					step_push(ns, cur, alloc);
+					
+					cur = cur.parent();
+				}
+				
+				break;
+			}
+
+			case axis_descendant_or_self:
+			case axis_self:
+			{
+				if (_test == nodetest_type_node) // reject attributes based on principal node type test
+					step_push(ns, a, p, alloc);
+
+				break;
+			}
+
+			case axis_following:
+			{
+				xml_node cur = p;
+				
+				for (;;)
+				{
+					if (cur.first_child())
+						cur = cur.first_child();
+					else if (cur.next_sibling())
+						cur = cur.next_sibling();
+					else
+					{
+						while (cur && !cur.next_sibling()) cur = cur.parent();
+						cur = cur.next_sibling();
+						
+						if (!cur) break;
+					}
+
+					step_push(ns, cur, alloc);
+				}
+
+				break;
+			}
+
+			case axis_parent:
+			{
+				step_push(ns, p, alloc);
+
+				break;
+			}
+
+			case axis_preceding:
+			{
+				// preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding
+				step_fill(ns, p, alloc, v);
+				break;
+			}
+			
+			default:
+				assert(!"Unimplemented axis");
+			}
+		}
+		
+		template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v)
+		{
+			const axis_t axis = T::axis;
+			bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
+
+			xpath_node_set_raw ns;
+			ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted);
+
+			if (_left)
+			{
+				xpath_node_set_raw s = _left->eval_node_set(c, stack);
+
+				// self axis preserves the original order
+				if (axis == axis_self) ns.set_type(s.type());
+
+				for (const xpath_node* it = s.begin(); it != s.end(); ++it)
+				{
+					size_t size = ns.size();
+
+					// in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes
+					if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
+					
+					if (it->node())
+						step_fill(ns, it->node(), stack.result, v);
+					else if (attributes)
+						step_fill(ns, it->attribute(), it->parent(), stack.result, v);
+						
+					apply_predicates(ns, size, stack);
+				}
+			}
+			else
+			{
+				if (c.n.node())
+					step_fill(ns, c.n.node(), stack.result, v);
+				else if (attributes)
+					step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v);
+				
+				apply_predicates(ns, 0, stack);
+			}
+
+			// child, attribute and self axes always generate unique set of nodes
+			// for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice
+			if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)
+				ns.remove_duplicates();
+
+			return ns;
+		}
+		
+	public:
+		xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value):
+			_type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
+		{
+			assert(type == ast_string_constant);
+			_data.string = value;
+		}
+
+		xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value):
+			_type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
+		{
+			assert(type == ast_number_constant);
+			_data.number = value;
+		}
+		
+		xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):
+			_type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
+		{
+			assert(type == ast_variable);
+			_data.variable = value;
+		}
+		
+		xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0):
+			_type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
+		{
+		}
+
+		xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents):
+			_type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(0), _next(0)
+		{
+			_data.nodetest = contents;
+		}
+
+		void set_next(xpath_ast_node* value)
+		{
+			_next = value;
+		}
+
+		void set_right(xpath_ast_node* value)
+		{
+			_right = value;
+		}
+
+		bool eval_boolean(const xpath_context& c, const xpath_stack& stack)
+		{
+			switch (_type)
+			{
+			case ast_op_or:
+				return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
+				
+			case ast_op_and:
+				return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
+				
+			case ast_op_equal:
+				return compare_eq(_left, _right, c, stack, equal_to());
+
+			case ast_op_not_equal:
+				return compare_eq(_left, _right, c, stack, not_equal_to());
+	
+			case ast_op_less:
+				return compare_rel(_left, _right, c, stack, less());
+			
+			case ast_op_greater:
+				return compare_rel(_right, _left, c, stack, less());
+
+			case ast_op_less_or_equal:
+				return compare_rel(_left, _right, c, stack, less_equal());
+			
+			case ast_op_greater_or_equal:
+				return compare_rel(_right, _left, c, stack, less_equal());
+
+			case ast_func_starts_with:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_string lr = _left->eval_string(c, stack);
+				xpath_string rr = _right->eval_string(c, stack);
+
+				return starts_with(lr.c_str(), rr.c_str());
+			}
+
+			case ast_func_contains:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_string lr = _left->eval_string(c, stack);
+				xpath_string rr = _right->eval_string(c, stack);
+
+				return find_substring(lr.c_str(), rr.c_str()) != 0;
+			}
+
+			case ast_func_boolean:
+				return _left->eval_boolean(c, stack);
+				
+			case ast_func_not:
+				return !_left->eval_boolean(c, stack);
+				
+			case ast_func_true:
+				return true;
+				
+			case ast_func_false:
+				return false;
+
+			case ast_func_lang:
+			{
+				if (c.n.attribute()) return false;
+				
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_string lang = _left->eval_string(c, stack);
+				
+				for (xml_node n = c.n.node(); n; n = n.parent())
+				{
+					xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
+					
+					if (a)
+					{
+						const char_t* value = a.value();
+						
+						// strnicmp / strncasecmp is not portable
+						for (const char_t* lit = lang.c_str(); *lit; ++lit)
+						{
+							if (tolower_ascii(*lit) != tolower_ascii(*value)) return false;
+							++value;
+						}
+						
+						return *value == 0 || *value == '-';
+					}
+				}
+				
+				return false;
+			}
+
+			case ast_variable:
+			{
+				assert(_rettype == _data.variable->type());
+
+				if (_rettype == xpath_type_boolean)
+					return _data.variable->get_boolean();
+
+				// fallthrough to type conversion
+			}
+
+			default:
+			{
+				switch (_rettype)
+				{
+				case xpath_type_number:
+					return convert_number_to_boolean(eval_number(c, stack));
+					
+				case xpath_type_string:
+				{
+					xpath_allocator_capture cr(stack.result);
+
+					return !eval_string(c, stack).empty();
+				}
+					
+				case xpath_type_node_set:				
+				{
+					xpath_allocator_capture cr(stack.result);
+
+					return !eval_node_set(c, stack).empty();
+				}
+
+				default:
+					assert(!"Wrong expression for return type boolean");
+					return false;
+				}
+			}
+			}
+		}
+
+		double eval_number(const xpath_context& c, const xpath_stack& stack)
+		{
+			switch (_type)
+			{
+			case ast_op_add:
+				return _left->eval_number(c, stack) + _right->eval_number(c, stack);
+				
+			case ast_op_subtract:
+				return _left->eval_number(c, stack) - _right->eval_number(c, stack);
+
+			case ast_op_multiply:
+				return _left->eval_number(c, stack) * _right->eval_number(c, stack);
+
+			case ast_op_divide:
+				return _left->eval_number(c, stack) / _right->eval_number(c, stack);
+
+			case ast_op_mod:
+				return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
+
+			case ast_op_negate:
+				return -_left->eval_number(c, stack);
+
+			case ast_number_constant:
+				return _data.number;
+
+			case ast_func_last:
+				return static_cast<double>(c.size);
+			
+			case ast_func_position:
+				return static_cast<double>(c.position);
+
+			case ast_func_count:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				return static_cast<double>(_left->eval_node_set(c, stack).size());
+			}
+			
+			case ast_func_string_length_0:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				return static_cast<double>(string_value(c.n, stack.result).length());
+			}
+			
+			case ast_func_string_length_1:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				return static_cast<double>(_left->eval_string(c, stack).length());
+			}
+			
+			case ast_func_number_0:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				return convert_string_to_number(string_value(c.n, stack.result).c_str());
+			}
+			
+			case ast_func_number_1:
+				return _left->eval_number(c, stack);
+
+			case ast_func_sum:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				double r = 0;
+				
+				xpath_node_set_raw ns = _left->eval_node_set(c, stack);
+				
+				for (const xpath_node* it = ns.begin(); it != ns.end(); ++it)
+				{
+					xpath_allocator_capture cri(stack.result);
+
+					r += convert_string_to_number(string_value(*it, stack.result).c_str());
+				}
+			
+				return r;
+			}
+
+			case ast_func_floor:
+			{
+				double r = _left->eval_number(c, stack);
+				
+				return r == r ? floor(r) : r;
+			}
+
+			case ast_func_ceiling:
+			{
+				double r = _left->eval_number(c, stack);
+				
+				return r == r ? ceil(r) : r;
+			}
+
+			case ast_func_round:
+				return round_nearest_nzero(_left->eval_number(c, stack));
+			
+			case ast_variable:
+			{
+				assert(_rettype == _data.variable->type());
+
+				if (_rettype == xpath_type_number)
+					return _data.variable->get_number();
+
+				// fallthrough to type conversion
+			}
+
+			default:
+			{
+				switch (_rettype)
+				{
+				case xpath_type_boolean:
+					return eval_boolean(c, stack) ? 1 : 0;
+					
+				case xpath_type_string:
+				{
+					xpath_allocator_capture cr(stack.result);
+
+					return convert_string_to_number(eval_string(c, stack).c_str());
+				}
+					
+				case xpath_type_node_set:
+				{
+					xpath_allocator_capture cr(stack.result);
+
+					return convert_string_to_number(eval_string(c, stack).c_str());
+				}
+					
+				default:
+					assert(!"Wrong expression for return type number");
+					return 0;
+				}
+				
+			}
+			}
+		}
+		
+		xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack)
+		{
+			assert(_type == ast_func_concat);
+
+			xpath_allocator_capture ct(stack.temp);
+
+			// count the string number
+			size_t count = 1;
+			for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
+
+			// gather all strings
+			xpath_string static_buffer[4];
+			xpath_string* buffer = static_buffer;
+
+			// allocate on-heap for large concats
+			if (count > sizeof(static_buffer) / sizeof(static_buffer[0]))
+			{
+				buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string)));
+				assert(buffer);
+			}
+
+			// evaluate all strings to temporary stack
+			xpath_stack swapped_stack = {stack.temp, stack.result};
+
+			buffer[0] = _left->eval_string(c, swapped_stack);
+
+			size_t pos = 1;
+			for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
+			assert(pos == count);
+
+			// get total length
+			size_t length = 0;
+			for (size_t i = 0; i < count; ++i) length += buffer[i].length();
+
+			// create final string
+			char_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t)));
+			assert(result);
+
+			char_t* ri = result;
+
+			for (size_t j = 0; j < count; ++j)
+				for (const char_t* bi = buffer[j].c_str(); *bi; ++bi)
+					*ri++ = *bi;
+
+			*ri = 0;
+
+			return xpath_string(result, true);
+		}
+
+		xpath_string eval_string(const xpath_context& c, const xpath_stack& stack)
+		{
+			switch (_type)
+			{
+			case ast_string_constant:
+				return xpath_string_const(_data.string);
+			
+			case ast_func_local_name_0:
+			{
+				xpath_node na = c.n;
+				
+				return xpath_string_const(local_name(na));
+			}
+
+			case ast_func_local_name_1:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_node_set_raw ns = _left->eval_node_set(c, stack);
+				xpath_node na = ns.first();
+				
+				return xpath_string_const(local_name(na));
+			}
+
+			case ast_func_name_0:
+			{
+				xpath_node na = c.n;
+				
+				return xpath_string_const(qualified_name(na));
+			}
+
+			case ast_func_name_1:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_node_set_raw ns = _left->eval_node_set(c, stack);
+				xpath_node na = ns.first();
+				
+				return xpath_string_const(qualified_name(na));
+			}
+
+			case ast_func_namespace_uri_0:
+			{
+				xpath_node na = c.n;
+				
+				return xpath_string_const(namespace_uri(na));
+			}
+
+			case ast_func_namespace_uri_1:
+			{
+				xpath_allocator_capture cr(stack.result);
+
+				xpath_node_set_raw ns = _left->eval_node_set(c, stack);
+				xpath_node na = ns.first();
+				
+				return xpath_string_const(namespace_uri(na));
+			}
+
+			case ast_func_string_0:
+				return string_value(c.n, stack.result);
+
+			case ast_func_string_1:
+				return _left->eval_string(c, stack);
+
+			case ast_func_concat:
+				return eval_string_concat(c, stack);
+
+			case ast_func_substring_before:
+			{
+				xpath_allocator_capture cr(stack.temp);
+
+				xpath_stack swapped_stack = {stack.temp, stack.result};
+
+				xpath_string s = _left->eval_string(c, swapped_stack);
+				xpath_string p = _right->eval_string(c, swapped_stack);
+
+				const char_t* pos = find_substring(s.c_str(), p.c_str());
+				
+				return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string();
+			}
+			
+			case ast_func_substring_after:
+			{
+				xpath_allocator_capture cr(stack.temp);
+
+				xpath_stack swapped_stack = {stack.temp, stack.result};
+
+				xpath_string s = _left->eval_string(c, swapped_stack);
+				xpath_string p = _right->eval_string(c, swapped_stack);
+				
+				const char_t* pos = find_substring(s.c_str(), p.c_str());
+				if (!pos) return xpath_string();
+
+				const char_t* result = pos + p.length();
+
+				return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result);
+			}
+
+			case ast_func_substring_2:
+			{
+				xpath_allocator_capture cr(stack.temp);
+
+				xpath_stack swapped_stack = {stack.temp, stack.result};
+
+				xpath_string s = _left->eval_string(c, swapped_stack);
+				size_t s_length = s.length();
+
+				double first = round_nearest(_right->eval_number(c, stack));
+				
+				if (is_nan(first)) return xpath_string(); // NaN
+				else if (first >= s_length + 1) return xpath_string();
+				
+				size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
+				assert(1 <= pos && pos <= s_length + 1);
+
+				const char_t* rbegin = s.c_str() + (pos - 1);
+				
+				return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin);
+			}
+			
+			case ast_func_substring_3:
+			{
+				xpath_allocator_capture cr(stack.temp);
+
+				xpath_stack swapped_stack = {stack.temp, stack.result};
+
+				xpath_string s = _left->eval_string(c, swapped_stack);
+				size_t s_length = s.length();
+
+				double first = round_nearest(_right->eval_number(c, stack));
+				double last = first + round_nearest(_right->_next->eval_number(c, stack));
+				
+				if (is_nan(first) || is_nan(last)) return xpath_string();
+				else if (first >= s_length + 1) return xpath_string();
+				else if (first >= last) return xpath_string();
+				else if (last < 1) return xpath_string();
+				
+				size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
+				size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last);
+
+				assert(1 <= pos && pos <= end && end <= s_length + 1);
+				const char_t* rbegin = s.c_str() + (pos - 1);
+				const char_t* rend = s.c_str() + (end - 1);
+
+				return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result);
+			}
+
+			case ast_func_normalize_space_0:
+			{
+				xpath_string s = string_value(c.n, stack.result);
+
+				normalize_space(s.data(stack.result));
+
+				return s;
+			}
+
+			case ast_func_normalize_space_1:
+			{
+				xpath_string s = _left->eval_string(c, stack);
+
+				normalize_space(s.data(stack.result));
+			
+				return s;
+			}
+
+			case ast_func_translate:
+			{
+				xpath_allocator_capture cr(stack.temp);
+
+				xpath_stack swapped_stack = {stack.temp, stack.result};
+
+				xpath_string s = _left->eval_string(c, stack);
+				xpath_string from = _right->eval_string(c, swapped_stack);
+				xpath_string to = _right->_next->eval_string(c, swapped_stack);
+
+				translate(s.data(stack.result), from.c_str(), to.c_str());
+
+				return s;
+			}
+
+			case ast_variable:
+			{
+				assert(_rettype == _data.variable->type());
+
+				if (_rettype == xpath_type_string)
+					return xpath_string_const(_data.variable->get_string());
+
+				// fallthrough to type conversion
+			}
+
+			default:
+			{
+				switch (_rettype)
+				{
+				case xpath_type_boolean:
+					return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
+					
+				case xpath_type_number:
+					return convert_number_to_string(eval_number(c, stack), stack.result);
+					
+				case xpath_type_node_set:
+				{
+					xpath_allocator_capture cr(stack.temp);
+
+					xpath_stack swapped_stack = {stack.temp, stack.result};
+
+					xpath_node_set_raw ns = eval_node_set(c, swapped_stack);
+					return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
+				}
+				
+				default:
+					assert(!"Wrong expression for return type string");
+					return xpath_string();
+				}
+			}
+			}
+		}
+
+		xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack)
+		{
+			switch (_type)
+			{
+			case ast_op_union:
+			{
+				xpath_allocator_capture cr(stack.temp);
+
+				xpath_stack swapped_stack = {stack.temp, stack.result};
+
+				xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack);
+				xpath_node_set_raw rs = _right->eval_node_set(c, stack);
+				
+				// we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
+				rs.set_type(xpath_node_set::type_unsorted);
+
+				rs.append(ls.begin(), ls.end(), stack.result);
+				rs.remove_duplicates();
+				
+				return rs;
+			}
+
+			case ast_filter:
+			case ast_filter_posinv:
+			{
+				xpath_node_set_raw set = _left->eval_node_set(c, stack);
+
+				// either expression is a number or it contains position() call; sort by document order
+				if (_type == ast_filter) set.sort_do();
+
+				apply_predicate(set, 0, _right, stack);
+			
+				return set;
+			}
+			
+			case ast_func_id:
+				return xpath_node_set_raw();
+			
+			case ast_step:
+			{
+				switch (_axis)
+				{
+				case axis_ancestor:
+					return step_do(c, stack, axis_to_type<axis_ancestor>());
+					
+				case axis_ancestor_or_self:
+					return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());
+
+				case axis_attribute:
+					return step_do(c, stack, axis_to_type<axis_attribute>());
+
+				case axis_child:
+					return step_do(c, stack, axis_to_type<axis_child>());
+				
+				case axis_descendant:
+					return step_do(c, stack, axis_to_type<axis_descendant>());
+
+				case axis_descendant_or_self:
+					return step_do(c, stack, axis_to_type<axis_descendant_or_self>());
+
+				case axis_following:
+					return step_do(c, stack, axis_to_type<axis_following>());
+				
+				case axis_following_sibling:
+					return step_do(c, stack, axis_to_type<axis_following_sibling>());
+				
+				case axis_namespace:
+					// namespaced axis is not supported
+					return xpath_node_set_raw();
+				
+				case axis_parent:
+					return step_do(c, stack, axis_to_type<axis_parent>());
+				
+				case axis_preceding:
+					return step_do(c, stack, axis_to_type<axis_preceding>());
+
+				case axis_preceding_sibling:
+					return step_do(c, stack, axis_to_type<axis_preceding_sibling>());
+				
+				case axis_self:
+					return step_do(c, stack, axis_to_type<axis_self>());
+
+				default:
+					assert(!"Unknown axis");
+					return xpath_node_set_raw();
+				}
+			}
+
+			case ast_step_root:
+			{
+				assert(!_right); // root step can't have any predicates
+
+				xpath_node_set_raw ns;
+
+				ns.set_type(xpath_node_set::type_sorted);
+
+				if (c.n.node()) ns.push_back(c.n.node().root(), stack.result);
+				else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);
+
+				return ns;
+			}
+
+			case ast_variable:
+			{
+				assert(_rettype == _data.variable->type());
+
+				if (_rettype == xpath_type_node_set)
+				{
+					const xpath_node_set& s = _data.variable->get_node_set();
+
+					xpath_node_set_raw ns;
+
+					ns.set_type(s.type());
+					ns.append(s.begin(), s.end(), stack.result);
+
+					return ns;
+				}
+
+				// fallthrough to type conversion
+			}
+
+			default:
+				assert(!"Wrong expression for return type node set");
+				return xpath_node_set_raw();
+			}
+		}
+		
+		bool is_posinv()
+		{
+			switch (_type)
+			{
+			case ast_func_position:
+				return false;
+
+			case ast_string_constant:
+			case ast_number_constant:
+			case ast_variable:
+				return true;
+
+			case ast_step:
+			case ast_step_root:
+				return true;
+
+			case ast_predicate:
+			case ast_filter:
+			case ast_filter_posinv:
+				return true;
+
+			default:
+				if (_left && !_left->is_posinv()) return false;
+				
+				for (xpath_ast_node* n = _right; n; n = n->_next)
+					if (!n->is_posinv()) return false;
+					
+				return true;
+			}
+		}
+
+		xpath_value_type rettype() const
+		{
+			return static_cast<xpath_value_type>(_rettype);
+		}
+	};
+
+	struct xpath_parser
+	{
+		xpath_allocator* _alloc;
+		xpath_lexer _lexer;
+
+		const char_t* _query;
+		xpath_variable_set* _variables;
+
+		xpath_parse_result* _result;
+
+	#ifdef PUGIXML_NO_EXCEPTIONS
+		jmp_buf _error_handler;
+	#endif
+
+		void throw_error(const char* message)
+		{
+			_result->error = message;
+			_result->offset = _lexer.current_pos() - _query;
+
+		#ifdef PUGIXML_NO_EXCEPTIONS
+			longjmp(_error_handler, 1);
+		#else
+			throw xpath_exception(*_result);
+		#endif
+		}
+
+		void throw_error_oom()
+		{
+		#ifdef PUGIXML_NO_EXCEPTIONS
+			throw_error("Out of memory");
+		#else
+			throw std::bad_alloc();
+		#endif
+		}
+
+		void* alloc_node()
+		{
+			void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node));
+
+			if (!result) throw_error_oom();
+
+			return result;
+		}
+
+		const char_t* alloc_string(const xpath_lexer_string& value)
+		{
+			if (value.begin)
+			{
+				size_t length = static_cast<size_t>(value.end - value.begin);
+
+				char_t* c = static_cast<char_t*>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t)));
+				if (!c) throw_error_oom();
+
+				memcpy(c, value.begin, length * sizeof(char_t));
+				c[length] = 0;
+
+				return c;
+			}
+			else return 0;
+		}
+
+		xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2])
+		{
+			assert(argc <= 1);
+
+			if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
+
+			return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
+		}
+
+		xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2])
+		{
+			switch (name.begin[0])
+			{
+			case 'b':
+				if (name == PUGIXML_TEXT("boolean") && argc == 1)
+					return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]);
+					
+				break;
+			
+			case 'c':
+				if (name == PUGIXML_TEXT("count") && argc == 1)
+				{
+					if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
+					return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]);
+				}
+				else if (name == PUGIXML_TEXT("contains") && argc == 2)
+					return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]);
+				else if (name == PUGIXML_TEXT("concat") && argc >= 2)
+					return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]);
+				else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
+					return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]);
+					
+				break;
+			
+			case 'f':
+				if (name == PUGIXML_TEXT("false") && argc == 0)
+					return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean);
+				else if (name == PUGIXML_TEXT("floor") && argc == 1)
+					return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]);
+					
+				break;
+			
+			case 'i':
+				if (name == PUGIXML_TEXT("id") && argc == 1)
+					return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]);
+					
+				break;
+			
+			case 'l':
+				if (name == PUGIXML_TEXT("last") && argc == 0)
+					return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number);
+				else if (name == PUGIXML_TEXT("lang") && argc == 1)
+					return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]);
+				else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
+					return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args);
+			
+				break;
+			
+			case 'n':
+				if (name == PUGIXML_TEXT("name") && argc <= 1)
+					return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args);
+				else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1)
+					return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args);
+				else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
+					return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);
+				else if (name == PUGIXML_TEXT("not") && argc == 1)
+					return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]);
+				else if (name == PUGIXML_TEXT("number") && argc <= 1)
+					return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
+			
+				break;
+			
+			case 'p':
+				if (name == PUGIXML_TEXT("position") && argc == 0)
+					return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number);
+				
+				break;
+			
+			case 'r':
+				if (name == PUGIXML_TEXT("round") && argc == 1)
+					return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]);
+
+				break;
+			
+			case 's':
+				if (name == PUGIXML_TEXT("string") && argc <= 1)
+					return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
+				else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
+					return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]);
+				else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
+					return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
+				else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
+					return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
+				else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
+					return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
+				else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
+					return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
+				else if (name == PUGIXML_TEXT("sum") && argc == 1)
+				{
+					if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
+					return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]);
+				}
+
+				break;
+			
+			case 't':
+				if (name == PUGIXML_TEXT("translate") && argc == 3)
+					return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]);
+				else if (name == PUGIXML_TEXT("true") && argc == 0)
+					return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean);
+					
+				break;
+
+			default:
+				break;
+			}
+
+			throw_error("Unrecognized function or wrong parameter count");
+
+			return 0;
+		}
+
+		axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified)
+		{
+			specified = true;
+
+			switch (name.begin[0])
+			{
+			case 'a':
+				if (name == PUGIXML_TEXT("ancestor"))
+					return axis_ancestor;
+				else if (name == PUGIXML_TEXT("ancestor-or-self"))
+					return axis_ancestor_or_self;
+				else if (name == PUGIXML_TEXT("attribute"))
+					return axis_attribute;
+				
+				break;
+			
+			case 'c':
+				if (name == PUGIXML_TEXT("child"))
+					return axis_child;
+				
+				break;
+			
+			case 'd':
+				if (name == PUGIXML_TEXT("descendant"))
+					return axis_descendant;
+				else if (name == PUGIXML_TEXT("descendant-or-self"))
+					return axis_descendant_or_self;
+				
+				break;
+			
+			case 'f':
+				if (name == PUGIXML_TEXT("following"))
+					return axis_following;
+				else if (name == PUGIXML_TEXT("following-sibling"))
+					return axis_following_sibling;
+				
+				break;
+			
+			case 'n':
+				if (name == PUGIXML_TEXT("namespace"))
+					return axis_namespace;
+				
+				break;
+			
+			case 'p':
+				if (name == PUGIXML_TEXT("parent"))
+					return axis_parent;
+				else if (name == PUGIXML_TEXT("preceding"))
+					return axis_preceding;
+				else if (name == PUGIXML_TEXT("preceding-sibling"))
+					return axis_preceding_sibling;
+				
+				break;
+			
+			case 's':
+				if (name == PUGIXML_TEXT("self"))
+					return axis_self;
+				
+				break;
+
+			default:
+				break;
+			}
+
+			specified = false;
+			return axis_child;
+		}
+
+		nodetest_t parse_node_test_type(const xpath_lexer_string& name)
+		{
+			switch (name.begin[0])
+			{
+			case 'c':
+				if (name == PUGIXML_TEXT("comment"))
+					return nodetest_type_comment;
+
+				break;
+
+			case 'n':
+				if (name == PUGIXML_TEXT("node"))
+					return nodetest_type_node;
+
+				break;
+
+			case 'p':
+				if (name == PUGIXML_TEXT("processing-instruction"))
+					return nodetest_type_pi;
+
+				break;
+
+			case 't':
+				if (name == PUGIXML_TEXT("text"))
+					return nodetest_type_text;
+
+				break;
+			
+			default:
+				break;
+			}
+
+			return nodetest_none;
+		}
+
+		// PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
+		xpath_ast_node* parse_primary_expression()
+		{
+			switch (_lexer.current())
+			{
+			case lex_var_ref:
+			{
+				xpath_lexer_string name = _lexer.contents();
+
+				if (!_variables)
+					throw_error("Unknown variable: variable set is not provided");
+
+				xpath_variable* var = get_variable(_variables, name.begin, name.end);
+
+				if (!var)
+					throw_error("Unknown variable: variable set does not contain the given name");
+
+				_lexer.next();
+
+				return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
+			}
+
+			case lex_open_brace:
+			{
+				_lexer.next();
+
+				xpath_ast_node* n = parse_expression();
+
+				if (_lexer.current() != lex_close_brace)
+					throw_error("Unmatched braces");
+
+				_lexer.next();
+
+				return n;
+			}
+
+			case lex_quoted_string:
+			{
+				const char_t* value = alloc_string(_lexer.contents());
+
+				xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value);
+				_lexer.next();
+
+				return n;
+			}
+
+			case lex_number:
+			{
+				double value = 0;
+
+				if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value))
+					throw_error_oom();
+
+				xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value);
+				_lexer.next();
+
+				return n;
+			}
+
+			case lex_string:
+			{
+				xpath_ast_node* args[2] = {0};
+				size_t argc = 0;
+				
+				xpath_lexer_string function = _lexer.contents();
+				_lexer.next();
+				
+				xpath_ast_node* last_arg = 0;
+				
+				if (_lexer.current() != lex_open_brace)
+					throw_error("Unrecognized function call");
+				_lexer.next();
+
+				if (_lexer.current() != lex_close_brace)
+					args[argc++] = parse_expression();
+
+				while (_lexer.current() != lex_close_brace)
+				{
+					if (_lexer.current() != lex_comma)
+						throw_error("No comma between function arguments");
+					_lexer.next();
+					
+					xpath_ast_node* n = parse_expression();
+					
+					if (argc < 2) args[argc] = n;
+					else last_arg->set_next(n);
+
+					argc++;
+					last_arg = n;
+				}
+				
+				_lexer.next();
+
+				return parse_function(function, argc, args);
+			}
+
+			default:
+				throw_error("Unrecognizable primary expression");
+
+				return 0;
+			}
+		}
+		
+		// FilterExpr ::= PrimaryExpr | FilterExpr Predicate
+		// Predicate ::= '[' PredicateExpr ']'
+		// PredicateExpr ::= Expr
+		xpath_ast_node* parse_filter_expression()
+		{
+			xpath_ast_node* n = parse_primary_expression();
+
+			while (_lexer.current() == lex_open_square_brace)
+			{
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_expression();
+
+				if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set");
+
+				bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv();
+
+				n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr);
+
+				if (_lexer.current() != lex_close_square_brace)
+					throw_error("Unmatched square brace");
+			
+				_lexer.next();
+			}
+			
+			return n;
+		}
+		
+		// Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
+		// AxisSpecifier ::= AxisName '::' | '@'?
+		// NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
+		// NameTest ::= '*' | NCName ':' '*' | QName
+		// AbbreviatedStep ::= '.' | '..'
+		xpath_ast_node* parse_step(xpath_ast_node* set)
+		{
+			if (set && set->rettype() != xpath_type_node_set)
+				throw_error("Step has to be applied to node set");
+
+			bool axis_specified = false;
+			axis_t axis = axis_child; // implied child axis
+
+			if (_lexer.current() == lex_axis_attribute)
+			{
+				axis = axis_attribute;
+				axis_specified = true;
+				
+				_lexer.next();
+			}
+			else if (_lexer.current() == lex_dot)
+			{
+				_lexer.next();
+				
+				return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0);
+			}
+			else if (_lexer.current() == lex_double_dot)
+			{
+				_lexer.next();
+				
+				return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0);
+			}
+		
+			nodetest_t nt_type = nodetest_none;
+			xpath_lexer_string nt_name;
+			
+			if (_lexer.current() == lex_string)
+			{
+				// node name test
+				nt_name = _lexer.contents();
+				_lexer.next();
+
+				// was it an axis name?
+				if (_lexer.current() == lex_double_colon)
+				{
+					// parse axis name
+					if (axis_specified) throw_error("Two axis specifiers in one step");
+
+					axis = parse_axis_name(nt_name, axis_specified);
+
+					if (!axis_specified) throw_error("Unknown axis");
+
+					// read actual node test
+					_lexer.next();
+
+					if (_lexer.current() == lex_multiply)
+					{
+						nt_type = nodetest_all;
+						nt_name = xpath_lexer_string();
+						_lexer.next();
+					}
+					else if (_lexer.current() == lex_string)
+					{
+						nt_name = _lexer.contents();
+						_lexer.next();
+					}
+					else throw_error("Unrecognized node test");
+				}
+				
+				if (nt_type == nodetest_none)
+				{
+					// node type test or processing-instruction
+					if (_lexer.current() == lex_open_brace)
+					{
+						_lexer.next();
+						
+						if (_lexer.current() == lex_close_brace)
+						{
+							_lexer.next();
+
+							nt_type = parse_node_test_type(nt_name);
+
+							if (nt_type == nodetest_none) throw_error("Unrecognized node type");
+							
+							nt_name = xpath_lexer_string();
+						}
+						else if (nt_name == PUGIXML_TEXT("processing-instruction"))
+						{
+							if (_lexer.current() != lex_quoted_string)
+								throw_error("Only literals are allowed as arguments to processing-instruction()");
+						
+							nt_type = nodetest_pi;
+							nt_name = _lexer.contents();
+							_lexer.next();
+							
+							if (_lexer.current() != lex_close_brace)
+								throw_error("Unmatched brace near processing-instruction()");
+							_lexer.next();
+						}
+						else
+							throw_error("Unmatched brace near node type test");
+
+					}
+					// QName or NCName:*
+					else
+					{
+						if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:*
+						{
+							nt_name.end--; // erase *
+							
+							nt_type = nodetest_all_in_namespace;
+						}
+						else nt_type = nodetest_name;
+					}
+				}
+			}
+			else if (_lexer.current() == lex_multiply)
+			{
+				nt_type = nodetest_all;
+				_lexer.next();
+			}
+			else throw_error("Unrecognized node test");
+			
+			xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name));
+			
+			xpath_ast_node* last = 0;
+			
+			while (_lexer.current() == lex_open_square_brace)
+			{
+				_lexer.next();
+				
+				xpath_ast_node* expr = parse_expression();
+
+				xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr);
+				
+				if (_lexer.current() != lex_close_square_brace)
+					throw_error("Unmatched square brace");
+				_lexer.next();
+				
+				if (last) last->set_next(pred);
+				else n->set_right(pred);
+				
+				last = pred;
+			}
+			
+			return n;
+		}
+		
+		// RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
+		xpath_ast_node* parse_relative_location_path(xpath_ast_node* set)
+		{
+			xpath_ast_node* n = parse_step(set);
+			
+			while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
+			{
+				lexeme_t l = _lexer.current();
+				_lexer.next();
+
+				if (l == lex_double_slash)
+					n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+				
+				n = parse_step(n);
+			}
+			
+			return n;
+		}
+		
+		// LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
+		// AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
+		xpath_ast_node* parse_location_path()
+		{
+			if (_lexer.current() == lex_slash)
+			{
+				_lexer.next();
+				
+				xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
+
+				// relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path
+				lexeme_t l = _lexer.current();
+
+				if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
+					return parse_relative_location_path(n);
+				else
+					return n;
+			}
+			else if (_lexer.current() == lex_double_slash)
+			{
+				_lexer.next();
+				
+				xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
+				n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+				
+				return parse_relative_location_path(n);
+			}
+
+			// else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1
+			return parse_relative_location_path(0);
+		}
+		
+		// PathExpr ::= LocationPath
+		//				| FilterExpr
+		//				| FilterExpr '/' RelativeLocationPath
+		//				| FilterExpr '//' RelativeLocationPath
+		xpath_ast_node* parse_path_expression()
+		{
+			// Clarification.
+			// PathExpr begins with either LocationPath or FilterExpr.
+			// FilterExpr begins with PrimaryExpr
+			// PrimaryExpr begins with '$' in case of it being a variable reference,
+			// '(' in case of it being an expression, string literal, number constant or
+			// function call.
+
+			if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || 
+				_lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
+				_lexer.current() == lex_string)
+			{
+				if (_lexer.current() == lex_string)
+				{
+					// This is either a function call, or not - if not, we shall proceed with location path
+					const char_t* state = _lexer.state();
+					
+					while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
+					
+					if (*state != '(') return parse_location_path();
+
+					// This looks like a function call; however this still can be a node-test. Check it.
+					if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path();
+				}
+				
+				xpath_ast_node* n = parse_filter_expression();
+
+				if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
+				{
+					lexeme_t l = _lexer.current();
+					_lexer.next();
+					
+					if (l == lex_double_slash)
+					{
+						if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set");
+
+						n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+					}
+	
+					// select from location path
+					return parse_relative_location_path(n);
+				}
+
+				return n;
+			}
+			else return parse_location_path();
+		}
+
+		// UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
+		xpath_ast_node* parse_union_expression()
+		{
+			xpath_ast_node* n = parse_path_expression();
+
+			while (_lexer.current() == lex_union)
+			{
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_union_expression();
+
+				if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set)
+					throw_error("Union operator has to be applied to node sets");
+
+				n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr);
+			}
+
+			return n;
+		}
+
+		// UnaryExpr ::= UnionExpr | '-' UnaryExpr
+		xpath_ast_node* parse_unary_expression()
+		{
+			if (_lexer.current() == lex_minus)
+			{
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_unary_expression();
+
+				return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr);
+			}
+			else return parse_union_expression();
+		}
+		
+		// MultiplicativeExpr ::= UnaryExpr
+		//						  | MultiplicativeExpr '*' UnaryExpr
+		//						  | MultiplicativeExpr 'div' UnaryExpr
+		//						  | MultiplicativeExpr 'mod' UnaryExpr
+		xpath_ast_node* parse_multiplicative_expression()
+		{
+			xpath_ast_node* n = parse_unary_expression();
+
+			while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string &&
+				   (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div"))))
+			{
+				ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply :
+					_lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod;
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_unary_expression();
+
+				n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr);
+			}
+
+			return n;
+		}
+
+		// AdditiveExpr ::= MultiplicativeExpr
+		//					| AdditiveExpr '+' MultiplicativeExpr
+		//					| AdditiveExpr '-' MultiplicativeExpr
+		xpath_ast_node* parse_additive_expression()
+		{
+			xpath_ast_node* n = parse_multiplicative_expression();
+
+			while (_lexer.current() == lex_plus || _lexer.current() == lex_minus)
+			{
+				lexeme_t l = _lexer.current();
+
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_multiplicative_expression();
+
+				n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr);
+			}
+
+			return n;
+		}
+
+		// RelationalExpr ::= AdditiveExpr
+		//					  | RelationalExpr '<' AdditiveExpr
+		//					  | RelationalExpr '>' AdditiveExpr
+		//					  | RelationalExpr '<=' AdditiveExpr
+		//					  | RelationalExpr '>=' AdditiveExpr
+		xpath_ast_node* parse_relational_expression()
+		{
+			xpath_ast_node* n = parse_additive_expression();
+
+			while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal || 
+				   _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal)
+			{
+				lexeme_t l = _lexer.current();
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_additive_expression();
+
+				n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater :
+								l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr);
+			}
+
+			return n;
+		}
+		
+		// EqualityExpr ::= RelationalExpr
+		//					| EqualityExpr '=' RelationalExpr
+		//					| EqualityExpr '!=' RelationalExpr
+		xpath_ast_node* parse_equality_expression()
+		{
+			xpath_ast_node* n = parse_relational_expression();
+
+			while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal)
+			{
+				lexeme_t l = _lexer.current();
+
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_relational_expression();
+
+				n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr);
+			}
+
+			return n;
+		}
+		
+		// AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
+		xpath_ast_node* parse_and_expression()
+		{
+			xpath_ast_node* n = parse_equality_expression();
+
+			while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and"))
+			{
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_equality_expression();
+
+				n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr);
+			}
+
+			return n;
+		}
+
+		// OrExpr ::= AndExpr | OrExpr 'or' AndExpr
+		xpath_ast_node* parse_or_expression()
+		{
+			xpath_ast_node* n = parse_and_expression();
+
+			while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or"))
+			{
+				_lexer.next();
+
+				xpath_ast_node* expr = parse_and_expression();
+
+				n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr);
+			}
+
+			return n;
+		}
+		
+		// Expr ::= OrExpr
+		xpath_ast_node* parse_expression()
+		{
+			return parse_or_expression();
+		}
+
+		xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result)
+		{
+		}
+
+		xpath_ast_node* parse()
+		{
+			xpath_ast_node* result = parse_expression();
+			
+			if (_lexer.current() != lex_eof)
+			{
+				// there are still unparsed tokens left, error
+				throw_error("Incorrect query");
+			}
+			
+			return result;
+		}
+
+		static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)
+		{
+			xpath_parser parser(query, variables, alloc, result);
+
+		#ifdef PUGIXML_NO_EXCEPTIONS
+			int error = setjmp(parser._error_handler);
+
+			return (error == 0) ? parser.parse() : 0;
+		#else
+			return parser.parse();
+		#endif
+		}
+	};
+
+	struct xpath_query_impl
+	{
+		static xpath_query_impl* create()
+		{
+			void* memory = xml_memory::allocate(sizeof(xpath_query_impl));
+
+			return new (memory) xpath_query_impl();
+		}
+
+		static void destroy(void* ptr)
+		{
+			if (!ptr) return;
+			
+			// free all allocated pages
+			static_cast<xpath_query_impl*>(ptr)->alloc.release();
+
+			// free allocator memory (with the first page)
+			xml_memory::deallocate(ptr);
+		}
+
+		xpath_query_impl(): root(0), alloc(&block)
+		{
+			block.next = 0;
+		}
+
+		xpath_ast_node* root;
+		xpath_allocator alloc;
+		xpath_memory_block block;
+	};
+
+	PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd)
+	{
+		if (!impl) return xpath_string();
+
+	#ifdef PUGIXML_NO_EXCEPTIONS
+		if (setjmp(sd.error_handler)) return xpath_string();
+	#endif
+
+		xpath_context c(n, 1, 1);
+
+		return impl->root->eval_string(c, sd.stack);
+	}
+PUGI__NS_END
+
+namespace pugi
+{
+#ifndef PUGIXML_NO_EXCEPTIONS
+	PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_)
+	{
+		assert(_result.error);
+	}
+	
+	PUGI__FN const char* xpath_exception::what() const throw()
+	{
+		return _result.error;
+	}
+
+	PUGI__FN const xpath_parse_result& xpath_exception::result() const
+	{
+		return _result;
+	}
+#endif
+	
+	PUGI__FN xpath_node::xpath_node()
+	{
+	}
+		
+	PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_)
+	{
+	}
+		
+	PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
+	{
+	}
+
+	PUGI__FN xml_node xpath_node::node() const
+	{
+		return _attribute ? xml_node() : _node;
+	}
+		
+	PUGI__FN xml_attribute xpath_node::attribute() const
+	{
+		return _attribute;
+	}
+	
+	PUGI__FN xml_node xpath_node::parent() const
+	{
+		return _attribute ? _node : _node.parent();
+	}
+
+	PUGI__FN static void unspecified_bool_xpath_node(xpath_node***)
+	{
+	}
+
+	PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const
+	{
+		return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
+	}
+	
+	PUGI__FN bool xpath_node::operator!() const
+	{
+		return !(_node || _attribute);
+	}
+
+	PUGI__FN bool xpath_node::operator==(const xpath_node& n) const
+	{
+		return _node == n._node && _attribute == n._attribute;
+	}
+	
+	PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const
+	{
+		return _node != n._node || _attribute != n._attribute;
+	}
+
+#ifdef __BORLANDC__
+	PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs)
+	{
+		return (bool)lhs && rhs;
+	}
+
+	PUGI__FN bool operator||(const xpath_node& lhs, bool rhs)
+	{
+		return (bool)lhs || rhs;
+	}
+#endif
+
+	PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_)
+	{
+		assert(begin_ <= end_);
+
+		size_t size_ = static_cast<size_t>(end_ - begin_);
+
+		if (size_ <= 1)
+		{
+			// deallocate old buffer
+			if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
+
+			// use internal buffer
+			if (begin_ != end_) _storage = *begin_;
+
+			_begin = &_storage;
+			_end = &_storage + size_;
+		}
+		else
+		{
+			// make heap copy
+			xpath_node* storage = static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
+
+			if (!storage)
+			{
+			#ifdef PUGIXML_NO_EXCEPTIONS
+				return;
+			#else
+				throw std::bad_alloc();
+			#endif
+			}
+
+			memcpy(storage, begin_, size_ * sizeof(xpath_node));
+			
+			// deallocate old buffer
+			if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
+
+			// finalize
+			_begin = storage;
+			_end = storage + size_;
+		}
+	}
+
+	PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage)
+	{
+	}
+
+	PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage)
+	{
+		_assign(begin_, end_);
+	}
+
+	PUGI__FN xpath_node_set::~xpath_node_set()
+	{
+		if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
+	}
+		
+	PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage)
+	{
+		_assign(ns._begin, ns._end);
+	}
+	
+	PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
+	{
+		if (this == &ns) return *this;
+		
+		_type = ns._type;
+		_assign(ns._begin, ns._end);
+
+		return *this;
+	}
+
+	PUGI__FN xpath_node_set::type_t xpath_node_set::type() const
+	{
+		return _type;
+	}
+		
+	PUGI__FN size_t xpath_node_set::size() const
+	{
+		return _end - _begin;
+	}
+		
+	PUGI__FN bool xpath_node_set::empty() const
+	{
+		return _begin == _end;
+	}
+		
+	PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const
+	{
+		assert(index < size());
+		return _begin[index];
+	}
+
+	PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const
+	{
+		return _begin;
+	}
+		
+	PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const
+	{
+		return _end;
+	}
+	
+	PUGI__FN void xpath_node_set::sort(bool reverse)
+	{
+		_type = impl::xpath_sort(_begin, _end, _type, reverse);
+	}
+
+	PUGI__FN xpath_node xpath_node_set::first() const
+	{
+		return impl::xpath_first(_begin, _end, _type);
+	}
+
+	PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
+	{
+	}
+
+	PUGI__FN xpath_parse_result::operator bool() const
+	{
+		return error == 0;
+	}
+
+	PUGI__FN const char* xpath_parse_result::description() const
+	{
+		return error ? error : "No error";
+	}
+
+	PUGI__FN xpath_variable::xpath_variable()
+	{
+	}
+
+	PUGI__FN const char_t* xpath_variable::name() const
+	{
+		switch (_type)
+		{
+		case xpath_type_node_set:
+			return static_cast<const impl::xpath_variable_node_set*>(this)->name;
+
+		case xpath_type_number:
+			return static_cast<const impl::xpath_variable_number*>(this)->name;
+
+		case xpath_type_string:
+			return static_cast<const impl::xpath_variable_string*>(this)->name;
+
+		case xpath_type_boolean:
+			return static_cast<const impl::xpath_variable_boolean*>(this)->name;
+
+		default:
+			assert(!"Invalid variable type");
+			return 0;
+		}
+	}
+
+	PUGI__FN xpath_value_type xpath_variable::type() const
+	{
+		return _type;
+	}
+
+	PUGI__FN bool xpath_variable::get_boolean() const
+	{
+		return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
+	}
+
+	PUGI__FN double xpath_variable::get_number() const
+	{
+		return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();
+	}
+
+	PUGI__FN const char_t* xpath_variable::get_string() const
+	{
+		const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0;
+		return value ? value : PUGIXML_TEXT("");
+	}
+
+	PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const
+	{
+		return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
+	}
+
+	PUGI__FN bool xpath_variable::set(bool value)
+	{
+		if (_type != xpath_type_boolean) return false;
+
+		static_cast<impl::xpath_variable_boolean*>(this)->value = value;
+		return true;
+	}
+
+	PUGI__FN bool xpath_variable::set(double value)
+	{
+		if (_type != xpath_type_number) return false;
+
+		static_cast<impl::xpath_variable_number*>(this)->value = value;
+		return true;
+	}
+
+	PUGI__FN bool xpath_variable::set(const char_t* value)
+	{
+		if (_type != xpath_type_string) return false;
+
+		impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);
+
+		// duplicate string
+		size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
+
+		char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));
+		if (!copy) return false;
+
+		memcpy(copy, value, size);
+
+		// replace old string
+		if (var->value) impl::xml_memory::deallocate(var->value);
+		var->value = copy;
+
+		return true;
+	}
+
+	PUGI__FN bool xpath_variable::set(const xpath_node_set& value)
+	{
+		if (_type != xpath_type_node_set) return false;
+
+		static_cast<impl::xpath_variable_node_set*>(this)->value = value;
+		return true;
+	}
+
+	PUGI__FN xpath_variable_set::xpath_variable_set()
+	{
+		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0;
+	}
+
+	PUGI__FN xpath_variable_set::~xpath_variable_set()
+	{
+		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
+		{
+			xpath_variable* var = _data[i];
+
+			while (var)
+			{
+				xpath_variable* next = var->_next;
+
+				impl::delete_xpath_variable(var->_type, var);
+
+				var = next;
+			}
+		}
+	}
+
+	PUGI__FN xpath_variable* xpath_variable_set::find(const char_t* name) const
+	{
+		const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
+		size_t hash = impl::hash_string(name) % hash_size;
+
+		// look for existing variable
+		for (xpath_variable* var = _data[hash]; var; var = var->_next)
+			if (impl::strequal(var->name(), name))
+				return var;
+
+		return 0;
+	}
+
+	PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
+	{
+		const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
+		size_t hash = impl::hash_string(name) % hash_size;
+
+		// look for existing variable
+		for (xpath_variable* var = _data[hash]; var; var = var->_next)
+			if (impl::strequal(var->name(), name))
+				return var->type() == type ? var : 0;
+
+		// add new variable
+		xpath_variable* result = impl::new_xpath_variable(type, name);
+
+		if (result)
+		{
+			result->_type = type;
+			result->_next = _data[hash];
+
+			_data[hash] = result;
+		}
+
+		return result;
+	}
+
+	PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value)
+	{
+		xpath_variable* var = add(name, xpath_type_boolean);
+		return var ? var->set(value) : false;
+	}
+
+	PUGI__FN bool xpath_variable_set::set(const char_t* name, double value)
+	{
+		xpath_variable* var = add(name, xpath_type_number);
+		return var ? var->set(value) : false;
+	}
+
+	PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value)
+	{
+		xpath_variable* var = add(name, xpath_type_string);
+		return var ? var->set(value) : false;
+	}
+
+	PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
+	{
+		xpath_variable* var = add(name, xpath_type_node_set);
+		return var ? var->set(value) : false;
+	}
+
+	PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name)
+	{
+		return find(name);
+	}
+
+	PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
+	{
+		return find(name);
+	}
+
+	PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
+	{
+		impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
+
+		if (!qimpl)
+		{
+		#ifdef PUGIXML_NO_EXCEPTIONS
+			_result.error = "Out of memory";
+		#else
+			throw std::bad_alloc();
+		#endif
+		}
+		else
+		{
+			impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy);
+
+			qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
+
+			if (qimpl->root)
+			{
+				_impl = static_cast<impl::xpath_query_impl*>(impl_holder.release());
+				_result.error = 0;
+			}
+		}
+	}
+
+	PUGI__FN xpath_query::~xpath_query()
+	{
+		impl::xpath_query_impl::destroy(_impl);
+	}
+
+	PUGI__FN xpath_value_type xpath_query::return_type() const
+	{
+		if (!_impl) return xpath_type_none;
+
+		return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();
+	}
+
+	PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const
+	{
+		if (!_impl) return false;
+		
+		impl::xpath_context c(n, 1, 1);
+		impl::xpath_stack_data sd;
+
+	#ifdef PUGIXML_NO_EXCEPTIONS
+		if (setjmp(sd.error_handler)) return false;
+	#endif
+		
+		return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
+	}
+	
+	PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
+	{
+		if (!_impl) return impl::gen_nan();
+		
+		impl::xpath_context c(n, 1, 1);
+		impl::xpath_stack_data sd;
+
+	#ifdef PUGIXML_NO_EXCEPTIONS
+		if (setjmp(sd.error_handler)) return impl::gen_nan();
+	#endif
+
+		return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
+	}
+
+#ifndef PUGIXML_NO_STL
+	PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const
+	{
+		impl::xpath_stack_data sd;
+
+		return impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd).c_str();
+	}
+#endif
+
+	PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
+	{
+		impl::xpath_stack_data sd;
+
+		impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd);
+
+		size_t full_size = r.length() + 1;
+		
+		if (capacity > 0)
+		{
+			size_t size = (full_size < capacity) ? full_size : capacity;
+			assert(size > 0);
+
+			memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
+			buffer[size - 1] = 0;
+		}
+		
+		return full_size;
+	}
+
+	PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const
+	{
+		if (!_impl) return xpath_node_set();
+
+		impl::xpath_ast_node* root = static_cast<impl::xpath_query_impl*>(_impl)->root;
+
+		if (root->rettype() != xpath_type_node_set)
+		{
+		#ifdef PUGIXML_NO_EXCEPTIONS
+			return xpath_node_set();
+		#else
+			xpath_parse_result res;
+			res.error = "Expression does not evaluate to node set";
+
+			throw xpath_exception(res);
+		#endif
+		}
+		
+		impl::xpath_context c(n, 1, 1);
+		impl::xpath_stack_data sd;
+
+	#ifdef PUGIXML_NO_EXCEPTIONS
+		if (setjmp(sd.error_handler)) return xpath_node_set();
+	#endif
+
+		impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack);
+
+		return xpath_node_set(r.begin(), r.end(), r.type());
+	}
+
+	PUGI__FN const xpath_parse_result& xpath_query::result() const
+	{
+		return _result;
+	}
+
+	PUGI__FN static void unspecified_bool_xpath_query(xpath_query***)
+	{
+	}
+
+	PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
+	{
+		return _impl ? unspecified_bool_xpath_query : 0;
+	}
+
+	PUGI__FN bool xpath_query::operator!() const
+	{
+		return !_impl;
+	}
+
+	PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const
+	{
+		xpath_query q(query, variables);
+		return select_single_node(q);
+	}
+
+	PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const
+	{
+		xpath_node_set s = query.evaluate_node_set(*this);
+		return s.empty() ? xpath_node() : s.first();
+	}
+
+	PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const
+	{
+		xpath_query q(query, variables);
+		return select_nodes(q);
+	}
+
+	PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const
+	{
+		return query.evaluate_node_set(*this);
+	}
+}
+
+#endif
+
+#ifdef __BORLANDC__
+#	pragma option pop
+#endif
+
+// Intel C++ does not properly keep warning state for function templates,
+// so popping warning state at the end of translation unit leads to warnings in the middle.
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#	pragma warning(pop)
+#endif
+
+// Undefine all local macros (makes sure we're not leaking macros in header-only mode)
+#undef PUGI__NO_INLINE
+#undef PUGI__STATIC_ASSERT
+#undef PUGI__DMC_VOLATILE
+#undef PUGI__MSVC_CRT_VERSION
+#undef PUGI__NS_BEGIN
+#undef PUGI__NS_END
+#undef PUGI__FN
+#undef PUGI__FN_NO_INLINE
+#undef PUGI__IS_CHARTYPE_IMPL
+#undef PUGI__IS_CHARTYPE
+#undef PUGI__IS_CHARTYPEX
+#undef PUGI__SKIPWS
+#undef PUGI__OPTSET
+#undef PUGI__PUSHNODE
+#undef PUGI__POPNODE
+#undef PUGI__SCANFOR
+#undef PUGI__SCANWHILE
+#undef PUGI__ENDSEG
+#undef PUGI__THROW_ERROR
+#undef PUGI__CHECK_ERROR
+
+#endif
+
+/**
+ * Copyright (c) 2006-2012 Arseny Kapoulkine
+ *
+ * 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.
+ */
Index: XmlTools2/trunk/XmlTools/libs/pugixml.hpp
===================================================================
--- XmlTools2/trunk/XmlTools/libs/pugixml.hpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/pugixml.hpp	(revision 905)
@@ -0,0 +1,1265 @@
+/**
+ * pugixml parser - version 1.2
+ * --------------------------------------------------------
+ * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
+ * Report bugs and download new versions at http://pugixml.org/
+ *
+ * This library is distributed under the MIT License. See notice at the end
+ * of this file.
+ *
+ * This work is based on the pugxml parser, which is:
+ * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
+ */
+
+#ifndef PUGIXML_VERSION
+// Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons
+#	define PUGIXML_VERSION 120
+#endif
+
+// Include user configuration file (this can define various configuration macros)
+#include "pugiconfig.hpp"
+
+#ifndef HEADER_PUGIXML_HPP
+#define HEADER_PUGIXML_HPP
+
+// Include stddef.h for size_t and ptrdiff_t
+#include <stddef.h>
+
+// Include exception header for XPath
+#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS)
+#	include <exception>
+#endif
+
+// Include STL headers
+#ifndef PUGIXML_NO_STL
+#	include <iterator>
+#	include <iosfwd>
+#	include <string>
+#endif
+
+// Macro for deprecated features
+#ifndef PUGIXML_DEPRECATED
+#	if defined(__GNUC__)
+#		define PUGIXML_DEPRECATED __attribute__((deprecated))
+#	elif defined(_MSC_VER) && _MSC_VER >= 1300
+#		define PUGIXML_DEPRECATED __declspec(deprecated)
+#	else
+#		define PUGIXML_DEPRECATED
+#	endif
+#endif
+
+// If no API is defined, assume default
+#ifndef PUGIXML_API
+#	define PUGIXML_API
+#endif
+
+// If no API for classes is defined, assume default
+#ifndef PUGIXML_CLASS
+#	define PUGIXML_CLASS PUGIXML_API
+#endif
+
+// If no API for functions is defined, assume default
+#ifndef PUGIXML_FUNCTION
+#	define PUGIXML_FUNCTION PUGIXML_API
+#endif
+
+// Character interface macros
+#ifdef PUGIXML_WCHAR_MODE
+#	define PUGIXML_TEXT(t) L ## t
+#	define PUGIXML_CHAR wchar_t
+#else
+#	define PUGIXML_TEXT(t) t
+#	define PUGIXML_CHAR char
+#endif
+
+namespace pugi
+{
+	// Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE
+	typedef PUGIXML_CHAR char_t;
+
+#ifndef PUGIXML_NO_STL
+	// String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE
+	typedef std::basic_string<PUGIXML_CHAR, std::char_traits<PUGIXML_CHAR>, std::allocator<PUGIXML_CHAR> > string_t;
+#endif
+}
+
+// The PugiXML namespace
+namespace pugi
+{
+	// Tree node types
+	enum xml_node_type
+	{
+		node_null,			// Empty (null) node handle
+		node_document,		// A document tree's absolute root
+		node_element,		// Element tag, i.e. '<node/>'
+		node_pcdata,		// Plain character data, i.e. 'text'
+		node_cdata,			// Character data, i.e. '<![CDATA[text]]>'
+		node_comment,		// Comment tag, i.e. '<!-- text -->'
+		node_pi,			// Processing instruction, i.e. '<?name?>'
+		node_declaration,	// Document declaration, i.e. '<?xml version="1.0"?>'
+		node_doctype		// Document type declaration, i.e. '<!DOCTYPE doc>'
+	};
+
+	// Parsing options
+
+	// Minimal parsing mode (equivalent to turning all other flags off).
+	// Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed.
+	const unsigned int parse_minimal = 0x0000;
+
+	// This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default.
+	const unsigned int parse_pi = 0x0001;
+
+	// This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default.
+	const unsigned int parse_comments = 0x0002;
+
+	// This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default.
+	const unsigned int parse_cdata = 0x0004;
+
+	// This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree.
+	// This flag is off by default; turning it on usually results in slower parsing and more memory consumption.
+	const unsigned int parse_ws_pcdata = 0x0008;
+
+	// This flag determines if character and entity references are expanded during parsing. This flag is on by default.
+	const unsigned int parse_escapes = 0x0010;
+
+	// This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default.
+	const unsigned int parse_eol = 0x0020;
+	
+	// This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default.
+	const unsigned int parse_wconv_attribute = 0x0040;
+
+	// This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default.
+	const unsigned int parse_wnorm_attribute = 0x0080;
+	
+	// This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default.
+	const unsigned int parse_declaration = 0x0100;
+
+	// This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default.
+	const unsigned int parse_doctype = 0x0200;
+
+	// This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only
+	// of whitespace is added to the DOM tree.
+	// This flag is off by default; turning it on may result in slower parsing and more memory consumption.
+	const unsigned int parse_ws_pcdata_single = 0x0400;
+
+	// The default parsing mode.
+	// Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded,
+	// End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
+	const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol;
+
+	// The full parsing mode.
+	// Nodes of all types are added to the DOM tree, character/reference entities are expanded,
+	// End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
+	const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype;
+
+	// These flags determine the encoding of input data for XML document
+	enum xml_encoding
+	{
+		encoding_auto,		// Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found
+		encoding_utf8,		// UTF8 encoding
+		encoding_utf16_le,	// Little-endian UTF16
+		encoding_utf16_be,	// Big-endian UTF16
+		encoding_utf16,		// UTF16 with native endianness
+		encoding_utf32_le,	// Little-endian UTF32
+		encoding_utf32_be,	// Big-endian UTF32
+		encoding_utf32,		// UTF32 with native endianness
+		encoding_wchar,		// The same encoding wchar_t has (either UTF16 or UTF32)
+		encoding_latin1
+	};
+
+	// Formatting flags
+	
+	// Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default.
+	const unsigned int format_indent = 0x01;
+	
+	// Write encoding-specific BOM to the output stream. This flag is off by default.
+	const unsigned int format_write_bom = 0x02;
+
+	// Use raw output mode (no indentation and no line breaks are written). This flag is off by default.
+	const unsigned int format_raw = 0x04;
+	
+	// Omit default XML declaration even if there is no declaration in the document. This flag is off by default.
+	const unsigned int format_no_declaration = 0x08;
+
+	// Don't escape attribute values and PCDATA contents. This flag is off by default.
+	const unsigned int format_no_escapes = 0x10;
+
+	// Open file using text mode in xml_document::save_file. This enables special character (i.e. new-line) conversions on some systems. This flag is off by default.
+	const unsigned int format_save_file_text = 0x20;
+
+	// The default set of formatting flags.
+	// Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.
+	const unsigned int format_default = format_indent;
+		
+	// Forward declarations
+	struct xml_attribute_struct;
+	struct xml_node_struct;
+
+	class xml_node_iterator;
+	class xml_attribute_iterator;
+	class xml_named_node_iterator;
+
+	class xml_tree_walker;
+
+	class xml_node;
+
+	class xml_text;
+	
+	#ifndef PUGIXML_NO_XPATH
+	class xpath_node;
+	class xpath_node_set;
+	class xpath_query;
+	class xpath_variable_set;
+	#endif
+
+	// Range-based for loop support
+	template <typename It> class xml_object_range
+	{
+	public:
+		typedef It const_iterator;
+
+		xml_object_range(It b, It e): _begin(b), _end(e)
+		{
+		}
+
+		It begin() const { return _begin; }
+		It end() const { return _end; }
+
+	private:
+		It _begin, _end;
+	};
+
+	// Writer interface for node printing (see xml_node::print)
+	class PUGIXML_CLASS xml_writer
+	{
+	public:
+		virtual ~xml_writer() {}
+
+		// Write memory chunk into stream/file/whatever
+		virtual void write(const void* data, size_t size) = 0;
+	};
+
+	// xml_writer implementation for FILE*
+	class PUGIXML_CLASS xml_writer_file: public xml_writer
+	{
+	public:
+		// Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio
+		xml_writer_file(void* file);
+
+		virtual void write(const void* data, size_t size);
+
+	private:
+		void* file;
+	};
+
+	#ifndef PUGIXML_NO_STL
+	// xml_writer implementation for streams
+	class PUGIXML_CLASS xml_writer_stream: public xml_writer
+	{
+	public:
+		// Construct writer from an output stream object
+		xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream);
+		xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream);
+
+		virtual void write(const void* data, size_t size);
+
+	private:
+		std::basic_ostream<char, std::char_traits<char> >* narrow_stream;
+		std::basic_ostream<wchar_t, std::char_traits<wchar_t> >* wide_stream;
+	};
+	#endif
+
+	// A light-weight handle for manipulating attributes in DOM tree
+	class PUGIXML_CLASS xml_attribute
+	{
+		friend class xml_attribute_iterator;
+		friend class xml_node;
+
+	private:
+		xml_attribute_struct* _attr;
+	
+		typedef void (*unspecified_bool_type)(xml_attribute***);
+
+	public:
+		// Default constructor. Constructs an empty attribute.
+		xml_attribute();
+		
+		// Constructs attribute from internal pointer
+		explicit xml_attribute(xml_attribute_struct* attr);
+
+		// Safe bool conversion operator
+		operator unspecified_bool_type() const;
+
+		// Borland C++ workaround
+		bool operator!() const;
+
+		// Comparison operators (compares wrapped attribute pointers)
+		bool operator==(const xml_attribute& r) const;
+		bool operator!=(const xml_attribute& r) const;
+		bool operator<(const xml_attribute& r) const;
+		bool operator>(const xml_attribute& r) const;
+		bool operator<=(const xml_attribute& r) const;
+		bool operator>=(const xml_attribute& r) const;
+
+		// Check if attribute is empty
+		bool empty() const;
+
+		// Get attribute name/value, or "" if attribute is empty
+		const char_t* name() const;
+		const char_t* value() const;
+
+		// Get attribute value, or the default value if attribute is empty
+		const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const;
+
+		// Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty
+		int as_int(int def = 0) const;
+		unsigned int as_uint(unsigned int def = 0) const;
+		double as_double(double def = 0) const;
+		float as_float(float def = 0) const;
+
+		// Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty
+		bool as_bool(bool def = false) const;
+
+		// Set attribute name/value (returns false if attribute is empty or there is not enough memory)
+		bool set_name(const char_t* rhs);
+		bool set_value(const char_t* rhs);
+
+		// Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
+		bool set_value(int rhs);
+		bool set_value(unsigned int rhs);
+		bool set_value(double rhs);
+		bool set_value(bool rhs);
+
+		// Set attribute value (equivalent to set_value without error checking)
+		xml_attribute& operator=(const char_t* rhs);
+		xml_attribute& operator=(int rhs);
+		xml_attribute& operator=(unsigned int rhs);
+		xml_attribute& operator=(double rhs);
+		xml_attribute& operator=(bool rhs);
+
+		// Get next/previous attribute in the attribute list of the parent node
+		xml_attribute next_attribute() const;
+		xml_attribute previous_attribute() const;
+
+		// Get hash value (unique for handles to the same object)
+		size_t hash_value() const;
+
+		// Get internal pointer
+		xml_attribute_struct* internal_object() const;
+	};
+
+#ifdef __BORLANDC__
+	// Borland C++ workaround
+	bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs);
+	bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs);
+#endif
+
+	// A light-weight handle for manipulating nodes in DOM tree
+	class PUGIXML_CLASS xml_node
+	{
+		friend class xml_attribute_iterator;
+		friend class xml_node_iterator;
+		friend class xml_named_node_iterator;
+
+	protected:
+		xml_node_struct* _root;
+
+		typedef void (*unspecified_bool_type)(xml_node***);
+
+	public:
+		// Default constructor. Constructs an empty node.
+		xml_node();
+
+		// Constructs node from internal pointer
+		explicit xml_node(xml_node_struct* p);
+
+		// Safe bool conversion operator
+		operator unspecified_bool_type() const;
+
+		// Borland C++ workaround
+		bool operator!() const;
+	
+		// Comparison operators (compares wrapped node pointers)
+		bool operator==(const xml_node& r) const;
+		bool operator!=(const xml_node& r) const;
+		bool operator<(const xml_node& r) const;
+		bool operator>(const xml_node& r) const;
+		bool operator<=(const xml_node& r) const;
+		bool operator>=(const xml_node& r) const;
+
+		// Check if node is empty.
+		bool empty() const;
+
+		// Get node type
+		xml_node_type type() const;
+
+		// Get node name/value, or "" if node is empty or it has no name/value
+		const char_t* name() const;
+		const char_t* value() const;
+	
+		// Get attribute list
+		xml_attribute first_attribute() const;
+		xml_attribute last_attribute() const;
+
+		// Get children list
+		xml_node first_child() const;
+		xml_node last_child() const;
+
+		// Get next/previous sibling in the children list of the parent node
+		xml_node next_sibling() const;
+		xml_node previous_sibling() const;
+		
+		// Get parent node
+		xml_node parent() const;
+
+		// Get root of DOM tree this node belongs to
+		xml_node root() const;
+
+		// Get text object for the current node
+		xml_text text() const;
+
+		// Get child, attribute or next/previous sibling with the specified name
+		xml_node child(const char_t* name) const;
+		xml_attribute attribute(const char_t* name) const;
+		xml_node next_sibling(const char_t* name) const;
+		xml_node previous_sibling(const char_t* name) const;
+
+		// Get child value of current node; that is, value of the first child node of type PCDATA/CDATA
+		const char_t* child_value() const;
+
+		// Get child value of child with specified name. Equivalent to child(name).child_value().
+		const char_t* child_value(const char_t* name) const;
+
+		// Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value)
+		bool set_name(const char_t* rhs);
+		bool set_value(const char_t* rhs);
+		
+		// Add attribute with specified name. Returns added attribute, or empty attribute on errors.
+		xml_attribute append_attribute(const char_t* name);
+		xml_attribute prepend_attribute(const char_t* name);
+		xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr);
+		xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);
+
+		// Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors.
+		xml_attribute append_copy(const xml_attribute& proto);
+		xml_attribute prepend_copy(const xml_attribute& proto);
+		xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr);
+		xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);
+
+		// Add child node with specified type. Returns added node, or empty node on errors.
+		xml_node append_child(xml_node_type type = node_element);
+		xml_node prepend_child(xml_node_type type = node_element);
+		xml_node insert_child_after(xml_node_type type, const xml_node& node);
+		xml_node insert_child_before(xml_node_type type, const xml_node& node);
+
+		// Add child element with specified name. Returns added node, or empty node on errors.
+		xml_node append_child(const char_t* name);
+		xml_node prepend_child(const char_t* name);
+		xml_node insert_child_after(const char_t* name, const xml_node& node);
+		xml_node insert_child_before(const char_t* name, const xml_node& node);
+
+		// Add a copy of the specified node as a child. Returns added node, or empty node on errors.
+		xml_node append_copy(const xml_node& proto);
+		xml_node prepend_copy(const xml_node& proto);
+		xml_node insert_copy_after(const xml_node& proto, const xml_node& node);
+		xml_node insert_copy_before(const xml_node& proto, const xml_node& node);
+
+		// Remove specified attribute
+		bool remove_attribute(const xml_attribute& a);
+		bool remove_attribute(const char_t* name);
+
+		// Remove specified child
+		bool remove_child(const xml_node& n);
+		bool remove_child(const char_t* name);
+
+		// Find attribute using predicate. Returns first attribute for which predicate returned true.
+		template <typename Predicate> xml_attribute find_attribute(Predicate pred) const
+		{
+			if (!_root) return xml_attribute();
+			
+			for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute())
+				if (pred(attrib))
+					return attrib;
+		
+			return xml_attribute();
+		}
+
+		// Find child node using predicate. Returns first child for which predicate returned true.
+		template <typename Predicate> xml_node find_child(Predicate pred) const
+		{
+			if (!_root) return xml_node();
+	
+			for (xml_node node = first_child(); node; node = node.next_sibling())
+				if (pred(node))
+					return node;
+		
+			return xml_node();
+		}
+
+		// Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true.
+		template <typename Predicate> xml_node find_node(Predicate pred) const
+		{
+			if (!_root) return xml_node();
+
+			xml_node cur = first_child();
+			
+			while (cur._root && cur._root != _root)
+			{
+				if (pred(cur)) return cur;
+
+				if (cur.first_child()) cur = cur.first_child();
+				else if (cur.next_sibling()) cur = cur.next_sibling();
+				else
+				{
+					while (!cur.next_sibling() && cur._root != _root) cur = cur.parent();
+
+					if (cur._root != _root) cur = cur.next_sibling();
+				}
+			}
+
+			return xml_node();
+		}
+
+		// Find child node by attribute name/value
+		xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
+		xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;
+
+	#ifndef PUGIXML_NO_STL
+		// Get the absolute node path from root as a text string.
+		string_t path(char_t delimiter = '/') const;
+	#endif
+
+		// Search for a node by path consisting of node names and . or .. elements.
+		xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const;
+
+		// Recursively traverse subtree with xml_tree_walker
+		bool traverse(xml_tree_walker& walker);
+	
+	#ifndef PUGIXML_NO_XPATH
+		// Select single node by evaluating XPath query. Returns first node from the resulting node set.
+		xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
+		xpath_node select_single_node(const xpath_query& query) const;
+
+		// Select node set by evaluating XPath query
+		xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
+		xpath_node_set select_nodes(const xpath_query& query) const;
+	#endif
+		
+		// Print subtree using a writer object
+		void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
+
+	#ifndef PUGIXML_NO_STL
+		// Print subtree to stream
+		void print(std::basic_ostream<char, std::char_traits<char> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
+		void print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const;
+	#endif
+
+		// Child nodes iterators
+		typedef xml_node_iterator iterator;
+
+		iterator begin() const;
+		iterator end() const;
+
+		// Attribute iterators
+		typedef xml_attribute_iterator attribute_iterator;
+
+		attribute_iterator attributes_begin() const;
+		attribute_iterator attributes_end() const;
+
+		// Range-based for support
+		xml_object_range<xml_node_iterator> children() const;
+		xml_object_range<xml_named_node_iterator> children(const char_t* name) const;
+		xml_object_range<xml_attribute_iterator> attributes() const;
+
+		// Get node offset in parsed file/string (in char_t units) for debugging purposes
+		ptrdiff_t offset_debug() const;
+
+		// Get hash value (unique for handles to the same object)
+		size_t hash_value() const;
+
+		// Get internal pointer
+		xml_node_struct* internal_object() const;
+	};
+
+#ifdef __BORLANDC__
+	// Borland C++ workaround
+	bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs);
+	bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs);
+#endif
+
+	// A helper for working with text inside PCDATA nodes
+	class PUGIXML_CLASS xml_text
+	{
+		friend class xml_node;
+
+		xml_node_struct* _root;
+
+		typedef void (*unspecified_bool_type)(xml_text***);
+
+		explicit xml_text(xml_node_struct* root);
+
+		xml_node_struct* _data_new();
+		xml_node_struct* _data() const;
+
+	public:
+		// Default constructor. Constructs an empty object.
+		xml_text();
+
+		// Safe bool conversion operator
+		operator unspecified_bool_type() const;
+
+		// Borland C++ workaround
+		bool operator!() const;
+
+		// Check if text object is empty
+		bool empty() const;
+
+		// Get text, or "" if object is empty
+		const char_t* get() const;
+
+		// Get text, or the default value if object is empty
+		const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const;
+
+		// Get text as a number, or the default value if conversion did not succeed or object is empty
+		int as_int(int def = 0) const;
+		unsigned int as_uint(unsigned int def = 0) const;
+		double as_double(double def = 0) const;
+		float as_float(float def = 0) const;
+
+		// Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty
+		bool as_bool(bool def = false) const;
+
+		// Set text (returns false if object is empty or there is not enough memory)
+		bool set(const char_t* rhs);
+
+		// Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
+		bool set(int rhs);
+		bool set(unsigned int rhs);
+		bool set(double rhs);
+		bool set(bool rhs);
+
+		// Set text (equivalent to set without error checking)
+		xml_text& operator=(const char_t* rhs);
+		xml_text& operator=(int rhs);
+		xml_text& operator=(unsigned int rhs);
+		xml_text& operator=(double rhs);
+		xml_text& operator=(bool rhs);
+
+		// Get the data node (node_pcdata or node_cdata) for this object
+		xml_node data() const;
+	};
+
+#ifdef __BORLANDC__
+	// Borland C++ workaround
+	bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs);
+	bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs);
+#endif
+
+	// Child node iterator (a bidirectional iterator over a collection of xml_node)
+	class PUGIXML_CLASS xml_node_iterator
+	{
+		friend class xml_node;
+
+	private:
+		mutable xml_node _wrap;
+		xml_node _parent;
+
+		xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent);
+
+	public:
+		// Iterator traits
+		typedef ptrdiff_t difference_type;
+		typedef xml_node value_type;
+		typedef xml_node* pointer;
+		typedef xml_node& reference;
+
+	#ifndef PUGIXML_NO_STL
+		typedef std::bidirectional_iterator_tag iterator_category;
+	#endif
+
+		// Default constructor
+		xml_node_iterator();
+
+		// Construct an iterator which points to the specified node
+		xml_node_iterator(const xml_node& node);
+
+		// Iterator operators
+		bool operator==(const xml_node_iterator& rhs) const;
+		bool operator!=(const xml_node_iterator& rhs) const;
+
+		xml_node& operator*() const;
+		xml_node* operator->() const;
+
+		const xml_node_iterator& operator++();
+		xml_node_iterator operator++(int);
+
+		const xml_node_iterator& operator--();
+		xml_node_iterator operator--(int);
+	};
+
+	// Attribute iterator (a bidirectional iterator over a collection of xml_attribute)
+	class PUGIXML_CLASS xml_attribute_iterator
+	{
+		friend class xml_node;
+
+	private:
+		mutable xml_attribute _wrap;
+		xml_node _parent;
+
+		xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent);
+
+	public:
+		// Iterator traits
+		typedef ptrdiff_t difference_type;
+		typedef xml_attribute value_type;
+		typedef xml_attribute* pointer;
+		typedef xml_attribute& reference;
+
+	#ifndef PUGIXML_NO_STL
+		typedef std::bidirectional_iterator_tag iterator_category;
+	#endif
+
+		// Default constructor
+		xml_attribute_iterator();
+
+		// Construct an iterator which points to the specified attribute
+		xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent);
+
+		// Iterator operators
+		bool operator==(const xml_attribute_iterator& rhs) const;
+		bool operator!=(const xml_attribute_iterator& rhs) const;
+
+		xml_attribute& operator*() const;
+		xml_attribute* operator->() const;
+
+		const xml_attribute_iterator& operator++();
+		xml_attribute_iterator operator++(int);
+
+		const xml_attribute_iterator& operator--();
+		xml_attribute_iterator operator--(int);
+	};
+
+	// Named node range helper
+	class xml_named_node_iterator
+	{
+	public:
+		// Iterator traits
+		typedef ptrdiff_t difference_type;
+		typedef xml_node value_type;
+		typedef xml_node* pointer;
+		typedef xml_node& reference;
+
+	#ifndef PUGIXML_NO_STL
+		typedef std::forward_iterator_tag iterator_category;
+	#endif
+
+		// Default constructor
+		xml_named_node_iterator();
+
+		// Construct an iterator which points to the specified node
+		xml_named_node_iterator(const xml_node& node, const char_t* name);
+
+		// Iterator operators
+		bool operator==(const xml_named_node_iterator& rhs) const;
+		bool operator!=(const xml_named_node_iterator& rhs) const;
+
+		xml_node& operator*() const;
+		xml_node* operator->() const;
+
+		const xml_named_node_iterator& operator++();
+		xml_named_node_iterator operator++(int);
+
+	private:
+		mutable xml_node _node;
+		const char_t* _name;
+	};
+
+	// Abstract tree walker class (see xml_node::traverse)
+	class PUGIXML_CLASS xml_tree_walker
+	{
+		friend class xml_node;
+
+	private:
+		int _depth;
+	
+	protected:
+		// Get current traversal depth
+		int depth() const;
+	
+	public:
+		xml_tree_walker();
+		virtual ~xml_tree_walker();
+
+		// Callback that is called when traversal begins
+		virtual bool begin(xml_node& node);
+
+		// Callback that is called for each node traversed
+		virtual bool for_each(xml_node& node) = 0;
+
+		// Callback that is called when traversal ends
+		virtual bool end(xml_node& node);
+	};
+
+	// Parsing status, returned as part of xml_parse_result object
+	enum xml_parse_status
+	{
+		status_ok = 0,				// No error
+
+		status_file_not_found,		// File was not found during load_file()
+		status_io_error,			// Error reading from file/stream
+		status_out_of_memory,		// Could not allocate memory
+		status_internal_error,		// Internal error occurred
+
+		status_unrecognized_tag,	// Parser could not determine tag type
+
+		status_bad_pi,				// Parsing error occurred while parsing document declaration/processing instruction
+		status_bad_comment,			// Parsing error occurred while parsing comment
+		status_bad_cdata,			// Parsing error occurred while parsing CDATA section
+		status_bad_doctype,			// Parsing error occurred while parsing document type declaration
+		status_bad_pcdata,			// Parsing error occurred while parsing PCDATA section
+		status_bad_start_element,	// Parsing error occurred while parsing start element tag
+		status_bad_attribute,		// Parsing error occurred while parsing element attribute
+		status_bad_end_element,		// Parsing error occurred while parsing end element tag
+		status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag)
+	};
+
+	// Parsing result
+	struct PUGIXML_CLASS xml_parse_result
+	{
+		// Parsing status (see xml_parse_status)
+		xml_parse_status status;
+
+		// Last parsed offset (in char_t units from start of input data)
+		ptrdiff_t offset;
+
+		// Source document encoding
+		xml_encoding encoding;
+
+		// Default constructor, initializes object to failed state
+		xml_parse_result();
+
+		// Cast to bool operator
+		operator bool() const;
+
+		// Get error description
+		const char* description() const;
+	};
+
+	// Document class (DOM tree root)
+	class PUGIXML_CLASS xml_document: public xml_node
+	{
+	private:
+		char_t* _buffer;
+
+		char _memory[192];
+		
+		// Non-copyable semantics
+		xml_document(const xml_document&);
+		const xml_document& operator=(const xml_document&);
+
+		void create();
+		void destroy();
+
+		xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own);
+
+	public:
+		// Default constructor, makes empty document
+		xml_document();
+
+		// Destructor, invalidates all node/attribute handles to this document
+		~xml_document();
+
+		// Removes all nodes, leaving the empty document
+		void reset();
+
+		// Removes all nodes, then copies the entire contents of the specified document
+		void reset(const xml_document& proto);
+
+	#ifndef PUGIXML_NO_STL
+		// Load document from stream.
+		xml_parse_result load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+		xml_parse_result load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options = parse_default);
+	#endif
+
+		// Load document from zero-terminated string. No encoding conversions are applied.
+		xml_parse_result load(const char_t* contents, unsigned int options = parse_default);
+
+		// Load document from file
+		xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+		xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+
+		// Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns.
+		xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+
+		// Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).
+		// You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed.
+		xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+
+		// Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).
+		// You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore).
+		xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+
+		// Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details).
+		void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
+
+	#ifndef PUGIXML_NO_STL
+		// Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details).
+		void save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
+		void save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const;
+	#endif
+
+		// Save XML to file
+		bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
+		bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
+
+		// Get document element
+		xml_node document_element() const;
+	};
+
+#ifndef PUGIXML_NO_XPATH
+	// XPath query return type
+	enum xpath_value_type
+	{
+		xpath_type_none,	  // Unknown type (query failed to compile)
+		xpath_type_node_set,  // Node set (xpath_node_set)
+		xpath_type_number,	  // Number
+		xpath_type_string,	  // String
+		xpath_type_boolean	  // Boolean
+	};
+
+	// XPath parsing result
+	struct PUGIXML_CLASS xpath_parse_result
+	{
+		// Error message (0 if no error)
+		const char* error;
+
+		// Last parsed offset (in char_t units from string start)
+		ptrdiff_t offset;
+
+		// Default constructor, initializes object to failed state
+		xpath_parse_result();
+
+		// Cast to bool operator
+		operator bool() const;
+
+		// Get error description
+		const char* description() const;
+	};
+
+	// A single XPath variable
+	class PUGIXML_CLASS xpath_variable
+	{
+		friend class xpath_variable_set;
+
+	protected:
+		xpath_value_type _type;
+		xpath_variable* _next;
+
+		xpath_variable();
+
+		// Non-copyable semantics
+		xpath_variable(const xpath_variable&);
+		xpath_variable& operator=(const xpath_variable&);
+		
+	public:
+		// Get variable name
+		const char_t* name() const;
+
+		// Get variable type
+		xpath_value_type type() const;
+
+		// Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error
+		bool get_boolean() const;
+		double get_number() const;
+		const char_t* get_string() const;
+		const xpath_node_set& get_node_set() const;
+
+		// Set variable value; no type conversion is performed, false is returned on type mismatch error
+		bool set(bool value);
+		bool set(double value);
+		bool set(const char_t* value);
+		bool set(const xpath_node_set& value);
+	};
+
+	// A set of XPath variables
+	class PUGIXML_CLASS xpath_variable_set
+	{
+	private:
+		xpath_variable* _data[64];
+
+		// Non-copyable semantics
+		xpath_variable_set(const xpath_variable_set&);
+		xpath_variable_set& operator=(const xpath_variable_set&);
+
+		xpath_variable* find(const char_t* name) const;
+
+	public:
+		// Default constructor/destructor
+		xpath_variable_set();
+		~xpath_variable_set();
+
+		// Add a new variable or get the existing one, if the types match
+		xpath_variable* add(const char_t* name, xpath_value_type type);
+
+		// Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch
+		bool set(const char_t* name, bool value);
+		bool set(const char_t* name, double value);
+		bool set(const char_t* name, const char_t* value);
+		bool set(const char_t* name, const xpath_node_set& value);
+
+		// Get existing variable by name
+		xpath_variable* get(const char_t* name);
+		const xpath_variable* get(const char_t* name) const;
+	};
+
+	// A compiled XPath query object
+	class PUGIXML_CLASS xpath_query
+	{
+	private:
+		void* _impl;
+		xpath_parse_result _result;
+
+		typedef void (*unspecified_bool_type)(xpath_query***);
+
+		// Non-copyable semantics
+		xpath_query(const xpath_query&);
+		xpath_query& operator=(const xpath_query&);
+
+	public:
+		// Construct a compiled object from XPath expression.
+		// If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors.
+		explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0);
+
+		// Destructor
+		~xpath_query();
+
+		// Get query expression return type
+		xpath_value_type return_type() const;
+		
+		// Evaluate expression as boolean value in the specified context; performs type conversion if necessary.
+		// If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
+		bool evaluate_boolean(const xpath_node& n) const;
+		
+		// Evaluate expression as double value in the specified context; performs type conversion if necessary.
+		// If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
+		double evaluate_number(const xpath_node& n) const;
+		
+	#ifndef PUGIXML_NO_STL
+		// Evaluate expression as string value in the specified context; performs type conversion if necessary.
+		// If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
+		string_t evaluate_string(const xpath_node& n) const;
+	#endif
+		
+		// Evaluate expression as string value in the specified context; performs type conversion if necessary.
+		// At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero).
+		// If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
+		// If PUGIXML_NO_EXCEPTIONS is defined, returns empty  set instead.
+		size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const;
+
+		// Evaluate expression as node set in the specified context.
+		// If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
+		// If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead.
+		xpath_node_set evaluate_node_set(const xpath_node& n) const;
+
+		// Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode)
+		const xpath_parse_result& result() const;
+
+		// Safe bool conversion operator
+		operator unspecified_bool_type() const;
+
+		// Borland C++ workaround
+		bool operator!() const;
+	};
+	
+	#ifndef PUGIXML_NO_EXCEPTIONS
+	// XPath exception class
+	class PUGIXML_CLASS xpath_exception: public std::exception
+	{
+	private:
+		xpath_parse_result _result;
+
+	public:
+		// Construct exception from parse result
+		explicit xpath_exception(const xpath_parse_result& result);
+
+		// Get error message
+		virtual const char* what() const throw();
+
+		// Get parse result
+		const xpath_parse_result& result() const;
+	};
+	#endif
+	
+	// XPath node class (either xml_node or xml_attribute)
+	class PUGIXML_CLASS xpath_node
+	{
+	private:
+		xml_node _node;
+		xml_attribute _attribute;
+	
+		typedef void (*unspecified_bool_type)(xpath_node***);
+
+	public:
+		// Default constructor; constructs empty XPath node
+		xpath_node();
+		
+		// Construct XPath node from XML node/attribute
+		xpath_node(const xml_node& node);
+		xpath_node(const xml_attribute& attribute, const xml_node& parent);
+
+		// Get node/attribute, if any
+		xml_node node() const;
+		xml_attribute attribute() const;
+		
+		// Get parent of contained node/attribute
+		xml_node parent() const;
+
+		// Safe bool conversion operator
+		operator unspecified_bool_type() const;
+		
+		// Borland C++ workaround
+		bool operator!() const;
+
+		// Comparison operators
+		bool operator==(const xpath_node& n) const;
+		bool operator!=(const xpath_node& n) const;
+	};
+
+#ifdef __BORLANDC__
+	// Borland C++ workaround
+	bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs);
+	bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs);
+#endif
+
+	// A fixed-size collection of XPath nodes
+	class PUGIXML_CLASS xpath_node_set
+	{
+	public:
+		// Collection type
+		enum type_t
+		{
+			type_unsorted,			// Not ordered
+			type_sorted,			// Sorted by document order (ascending)
+			type_sorted_reverse		// Sorted by document order (descending)
+		};
+		
+		// Constant iterator type
+		typedef const xpath_node* const_iterator;
+	
+		// Default constructor. Constructs empty set.
+		xpath_node_set();
+
+		// Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful
+		xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted);
+
+		// Destructor
+		~xpath_node_set();
+		
+		// Copy constructor/assignment operator
+		xpath_node_set(const xpath_node_set& ns);
+		xpath_node_set& operator=(const xpath_node_set& ns);
+
+		// Get collection type
+		type_t type() const;
+		
+		// Get collection size
+		size_t size() const;
+
+		// Indexing operator
+		const xpath_node& operator[](size_t index) const;
+		
+		// Collection iterators
+		const_iterator begin() const;
+		const_iterator end() const;
+
+		// Sort the collection in ascending/descending order by document order
+		void sort(bool reverse = false);
+		
+		// Get first node in the collection by document order
+		xpath_node first() const;
+		
+		// Check if collection is empty
+		bool empty() const;
+	
+	private:
+		type_t _type;
+		
+		xpath_node _storage;
+		
+		xpath_node* _begin;
+		xpath_node* _end;
+
+		void _assign(const_iterator begin, const_iterator end);
+	};
+#endif
+
+#ifndef PUGIXML_NO_STL
+	// Convert wide string to UTF8
+	std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const wchar_t* str);
+	std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >& str);
+	
+	// Convert UTF8 to wide string
+	std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const char* str);
+	std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const std::basic_string<char, std::char_traits<char>, std::allocator<char> >& str);
+#endif
+
+	// Memory allocation function interface; returns pointer to allocated memory or NULL on failure
+	typedef void* (*allocation_function)(size_t size);
+	
+	// Memory deallocation function interface
+	typedef void (*deallocation_function)(void* ptr);
+
+	// Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions.
+	void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
+	
+	// Get current memory management functions
+	allocation_function PUGIXML_FUNCTION get_memory_allocation_function();
+	deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function();
+}
+
+#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
+namespace std
+{
+	// Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
+	std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&);
+	std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&);
+	std::forward_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&);
+}
+#endif
+
+#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
+namespace std
+{
+	// Workarounds for (non-standard) iterator category detection
+	std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&);
+	std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&);
+	std::forward_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&);
+}
+#endif
+
+#endif
+
+/**
+ * Copyright (c) 2006-2012 Arseny Kapoulkine
+ *
+ * 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.
+ */
Index: XmlTools2/trunk/XmlTools/libs/rexml.js
===================================================================
--- XmlTools2/trunk/XmlTools/libs/rexml.js	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/rexml.js	(revision 905)
@@ -0,0 +1,150 @@
+//////     JSXML XML Tools - REXML                /////////////
+//////     Regular Expression-based XML parser    /////////////
+//////     Ver 1.2 Jun 18 2001                    /////////////
+//////     Copyright 2000 Peter Tracey            /////////////
+//////     http://jsxml.homestead.com/            /////////////
+
+function REXML(XML) {
+	this.XML = XML;
+
+	this.rootElement = null;
+
+	this.parse = REXML_parse;
+	if (this.XML && this.XML != "") this.parse();
+}
+
+	function REXML_parse() {
+		var reTag = new RegExp("<([^>/ ]*)([^>]*)>","g"); // matches that tag name $1 and attribute string $2
+		var reTagText = new RegExp("<([^>/ ]*)([^>]*)>([^<]*)","g"); // matches tag name $1, attribute string $2, and text $3
+		var strType = "";
+		var strTag = "";
+		var strText = "";
+		var strAttributes = "";
+		var strOpen = "";
+		var strClose = "";
+		var iElements = 0;
+		var xmleLastElement = null;
+		if (this.XML.length == 0) return;
+		var arrElementsUnparsed = this.XML.match(reTag);
+		var arrElementsUnparsedText = this.XML.match(reTagText);
+		var i=0;
+		if (arrElementsUnparsed[0].replace(reTag, "$1") == "?xml") i++;
+
+		for (; i<arrElementsUnparsed.length; i++) {
+			strTag = arrElementsUnparsed[i].replace(reTag,"$1");
+			strAttributes = arrElementsUnparsed[i].replace(reTag,"$2");
+			strText = arrElementsUnparsedText[i].replace(reTagText,"$3").replace(/[\r\n\t ]+/g, " "); // remove white space
+			strClose = "";
+			if (strTag.indexOf("![CDATA[") == 0) {
+				strOpen = "<![CDATA[";
+				strClose = "]]>";
+				strType = "cdata";
+			} else if (strTag.indexOf("!--") == 0) {
+				strOpen = "<!--";
+				strClose = "-->";
+				strType = "comment";
+			} else if (strTag.indexOf("?") == 0) {
+				strOpen = "<?";
+				strClose = "?>";
+				strType = "pi";
+			} else strType = "element";
+			if (strClose != "") {
+				strText = "";
+				if (arrElementsUnparsedText[i].indexOf(strClose) > -1) strText = arrElementsUnparsedText[i];
+				else {
+					for (; i<arrElementsUnparsed.length && arrElementsUnparsedText[i].indexOf(strClose) == -1; i++) {
+						strText += arrElementsUnparsedText[i];
+					}
+					strText += arrElementsUnparsedText[i];
+				}
+				if (strText.substring(strOpen.length, strText.indexOf(strClose)) != "")	{
+					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, "","",xmleLastElement,strText.substring(strOpen.length, strText.indexOf(strClose)));
+					if (strType == "cdata") xmleLastElement.text += strText.substring(strOpen.length, strText.indexOf(strClose));
+				}
+				if (strText.indexOf(strClose)+ strClose.length < strText.length) {
+					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText.substring(strText.indexOf(strClose)+ strClose.length, strText.length));
+					if (strType == "cdata") xmleLastElement.text += strText.substring(strText.indexOf(strClose)+ strClose.length, strText.length);
+				}
+				continue;
+			}
+			if (strText.replace(/ */, "") == "") strText = "";
+			if (arrElementsUnparsed[i].substring(1,2) != "/") {
+				if (iElements == 0) {
+					xmleLastElement = this.rootElement = new REXML_XMLElement(strType, strTag,strAttributes,null,strText);
+					iElements++;
+					if (strText != "") xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
+				} else if (arrElementsUnparsed[i].substring(arrElementsUnparsed[i].length-2,arrElementsUnparsed[i].length-1) != "/") {
+					xmleLastElement = xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, strTag,strAttributes,xmleLastElement,strText);
+					iElements++;
+					if (strText != "") xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
+				} else {
+					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement(strType, strTag,strAttributes,xmleLastElement,strText);
+					if (strText != "") xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
+				}
+			} else {
+				xmleLastElement = xmleLastElement.parentElement;
+				iElements--;
+				if (xmleLastElement && strText != "") {
+					xmleLastElement.text += strText;
+					xmleLastElement.childElements[xmleLastElement.childElements.length] = new REXML_XMLElement("text", "","",xmleLastElement,strText);
+				}
+			}
+		}
+	}
+
+	function REXML_XMLElement(strType, strName, strAttributes, xmlParent, strText) {
+		this.type = strType;
+		this.name = strName;
+		this.attributeString = strAttributes;
+		this.attributes = null;
+		this.childElements = new Array();
+		this.parentElement = xmlParent;
+		this.text = strText; // text of element
+
+		this.getText = REXML_XMLElement_getText; // text of element and child elements
+		this.childElement = REXML_XMLElement_childElement;
+		this.attribute = REXML_XMLElement_attribute;
+	}
+
+		function REXML_XMLElement_getText() {
+			if (this.type == "text" || this.type == "cdata") {
+				return this.text;
+			} else if (this.childElements.length) {
+				var L = "";
+				for (var i=0; i<this.childElements.length; i++) {
+					L += this.childElements[i].getText();
+				}
+				return L;
+			} else return "";
+		}
+		
+		function REXML_XMLElement_childElement(strElementName) {
+			for (var i=0; i<this.childElements.length; i++) if (this.childElements[i].name == strElementName) return this.childElements[i];
+			return null;
+		}
+
+		function REXML_XMLElement_attribute(strAttributeName) {
+			if (!this.attributes) {
+				var reAttributes = new RegExp(" ([^= ]*)=","g"); // matches attributes
+				if (this.attributeString.match(reAttributes) && this.attributeString.match(reAttributes).length) {
+					var arrAttributes = this.attributeString.match(reAttributes);
+					if (!arrAttributes.length) arrAttributes = null;
+					else for (var j=0; j<arrAttributes.length; j++) {
+						arrAttributes[j] = new Array(
+							(arrAttributes[j]+"").replace(/[= ]/g,""),
+							ParseAttribute(this.attributeString, (arrAttributes[j]+"").replace(/[= ]/g,""))
+										);
+					}
+					this.attributes = arrAttributes;
+				}
+			}
+			if (this.attributes) for (var i=0; i<this.attributes.length; i++) if (this.attributes[i][0] == strAttributeName) return this.attributes[i][1];
+			return "";
+		}
+
+function ParseAttribute(str,Attribute) {
+	var str = str +  ">";
+	if (str.indexOf(Attribute + "='")>-1) var Attr = new RegExp(".*" + Attribute + "='([^']*)'.*>");
+	else if (str.indexOf(Attribute + '="')>-1) var Attr = new RegExp(".*" + Attribute + '="([^"]*)".*>');
+	return str.replace(Attr, "$1");
+}
Index: XmlTools2/trunk/XmlTools/libs/time_logger.h
===================================================================
--- XmlTools2/trunk/XmlTools/libs/time_logger.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/libs/time_logger.h	(revision 905)
@@ -0,0 +1,128 @@
+/*
+ * 42TinyJS
+ *
+ * A fork of TinyJS with the goal to makes a more JavaScript/ECMA compliant engine
+ *
+ * Authored By Armin Diedering <armin@diedering.de>
+ *
+ * Copyright (C) 2010-2013 ardisoft
+ *
+ *
+ * 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 time_logger_h__
+#define time_logger_h__
+#if defined(WITH_TIME_LOGGER)
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string>
+#ifdef _WIN32
+#include <Windows.h>
+#else
+#include <time.h>
+#endif
+class TimeLogger {
+public:
+	TimeLogger(const char *Name, bool Started=false, const char *extName=0) 
+		: 
+	name(Name), start_time(gettime()), sum_time(0), calls(0), started(Started) {
+		if(extName) {
+			name+="[";
+			name+=extName;
+			name+="]";
+		}
+	}
+	TimeLogger(const char *Name, const char *extName, bool Started=false) 
+		: 
+	name(Name), start_time(gettime()), sum_time(0), calls(0), started(Started) {
+		if(extName) {
+			name+="[";
+			name+=extName;
+			name+="]";
+		}
+	}
+	~TimeLogger() {
+		printLog();
+//		getchar();
+	}
+	void startTimer() {
+		start_time = gettime();
+		started = true;
+	}
+	void stopTimer() {
+		if(!started) return;
+		sum_time += gettime()-start_time;
+		calls++;
+		started = false;
+	}
+	void printLog() {
+		if(started) stopTimer();
+		if(calls == 1)
+			printf("Timer( %s ) = %d,%06d sec \n",
+			name.c_str(), (int)(sum_time / 1000000LL), (int)(sum_time % 1000000LL));
+		else if(calls>1)
+		printf("Timer( %s ) = %d,%06d sec (called %d times) -> %.d microsec per call\n",
+		name.c_str(), (int)(sum_time / 1000000LL), (int)(sum_time % 1000000LL),
+		calls, (int)(sum_time/calls));
+		calls = 0; sum_time = 0;
+	}
+private:
+//	static int64_t frequenzy = 0;
+	std::string name;
+	int64_t start_time, sum_time;
+	uint32_t calls;
+	bool started;
+	int64_t gettime() {	// set out to time in millisec
+#ifdef _WIN32
+		static LARGE_INTEGER fr = {0};
+		LARGE_INTEGER li;
+		if(fr.QuadPart == 0) QueryPerformanceFrequency(&fr);
+		QueryPerformanceCounter(&li);
+		return (li.QuadPart * 1000000LL) / fr.QuadPart;
+#else
+		return (clock() * 1000000LL) / CLOCKS_PER_SEC;
+#endif
+	};
+};
+class _TimeLoggerHelper {
+public:
+	_TimeLoggerHelper(TimeLogger &Tl) : tl(Tl) { tl.startTimer(); }
+	~_TimeLoggerHelper() { tl.stopTimer(); }
+private:
+	TimeLogger &tl;
+};
+#	define TimeLoggerCreate(a, ...) TimeLogger a##_TimeLogger(#a,##__VA_ARGS__)
+#	define TimeLoggerStart(a) a##_TimeLogger.startTimer()
+#	define TimeLoggerStop(a) a##_TimeLogger.stopTimer()
+#	define TimeLoggerLogprint(a) a##_TimeLogger.printLog()
+#	define TimeLoggerHelper(a) _TimeLoggerHelper a##_helper(a##_TimeLogger)
+#else /* _DEBUG */
+#	define TimeLoggerCreate(...)
+#	define TimeLoggerStart(...) do{}while(0)
+#	define TimeLoggerStop(...) do{}while(0)
+#	define TimeLoggerLogprint(a) do{}while(0)
+#	define TimeLoggerHelper(a)  do{}while(0)
+#endif /* _DEBUG */
+
+
+
+#endif // time_logger_h__
Index: XmlTools2/trunk/XmlTools/main.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/main.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/main.cpp	(revision 905)
@@ -0,0 +1,215 @@
+#include "main.h"
+
+int main(int argc, char *argv[])
+{
+
+    QCoreApplication app(argc, argv);
+
+    QCoreApplication::setApplicationName(GlobalVars::AppName);
+    QCoreApplication::setApplicationVersion(GlobalVars::AppVersion);
+
+    QCommandLineParser parser;
+    parser.setApplicationDescription("Additional documentation can be found at: http://wiki.oni2.net/XmlTools");
+
+    QString filesWildCard, patchFilesWildCard, forceTargetFilesWildcard;
+    QString currentVal, newVal, diffOldNewVal, positions;
+    XmlFilter filters; // Filters
+    bool noBackups=false;
+
+
+    QCommandLineOption addValuesOption(QStringList() << "a" << "add-values", "Add values to a set of XML elements.");
+    QCommandLineOption removeValuesOption(QStringList() << "remove-values", "Removes values from a set of XML elements.");
+    QCommandLineOption replaceValueOption(QStringList() << "replace-value", "Replaces 1 value in a set of XML elements.");
+    QCommandLineOption replaceAllValuesOption(QStringList() << "replace-all-values", "Replaces all values in a set of XML elements.");
+    QCommandLineOption updateElementsOption(QStringList() << "u" << "update-elements", "Updates all values in a set of XML elements.");
+    QCommandLineOption invertElementsOption(QStringList() << "i" << "invert-elements", "Inverts a set of XML elements.");
+
+    QCommandLineOption currentValOption(QStringList() << "c" << "current-val", "Current value(s) [use space as separator].","current-val");
+    QCommandLineOption newValOption(QStringList() << "n" << "new-val", "New value(s) [use space as separator]","new-val.");
+    QCommandLineOption diffOldNewValueOption(QStringList() << "d" << "diff-old-new-val", "Difference between old and new value.","diff-old-new-val");
+    QCommandLineOption positionsValueOption(QStringList() << "positions", "Positions [use space as separator] [0-index based].","positions");
+
+    QCommandLineOption filesOption(QStringList() << "f" << "files", "XML files to process [wildcards supported].", "files");
+    QCommandLineOption patchFilesOption(QStringList() << "p" << "patch-files" , "Patch files to process [wildcards supported].", "patch-files");
+    QCommandLineOption forceTargetFilesOption(QStringList() << "force-target-files" , "Force the patch-files operation in the specified XML files. [wildcards supported].", "force-target-files");
+    QCommandLineOption elementNameOption(QStringList() << "e" << "element-name", "Name of the XML element(s) where processing will occur.", "element-name");
+    QCommandLineOption parentElementNameOption(QStringList() << "parent-element-name", "Name of the XML parent element of <element-name> [used as filter].", "parent-element-name");
+    QCommandLineOption attributeNameOption("attribute-name", "Attribute name of <element-name>  [used as filter].", "attribute-name");
+    QCommandLineOption attributeValueOption("attribute-value", "Attribute value of <attribute-name>  [used as filter].", "attribute-value");
+    QCommandLineOption noBackupsOption(QStringList()  << "no-backups", "No backups [faster processing].");
+
+    parser.addOption(addValuesOption);
+    parser.addOption(removeValuesOption);
+    parser.addOption(replaceValueOption);
+    parser.addOption(replaceAllValuesOption);
+    parser.addOption(updateElementsOption);
+    parser.addOption(invertElementsOption);
+
+    parser.addOption(currentValOption);
+    parser.addOption(newValOption);
+    parser.addOption(diffOldNewValueOption);
+    parser.addOption(positionsValueOption);
+
+    parser.addOption(filesOption);
+    parser.addOption(patchFilesOption);
+    parser.addOption(forceTargetFilesOption);
+    parser.addOption(elementNameOption);
+    parser.addOption(parentElementNameOption);
+    parser.addOption(attributeNameOption);
+    parser.addOption(attributeValueOption);
+    parser.addOption(noBackupsOption);
+
+    parser.addVersionOption();
+    parser.addHelpOption();
+
+    // Process the actual command line arguments given by the user
+    parser.process(app);
+
+    // If no arguments show help option
+    if(app.arguments().size()==1){
+        parser.showHelp();
+    }
+
+    // Check if the user doesn't want backups (it boost XmlTools peformance, lower disk output)
+    if(parser.isSet(noBackupsOption)){
+        noBackups=true;
+    }
+
+    // Get patch files wildcard if available
+    if(parser.isSet(patchFilesOption)){
+        patchFilesWildCard=parser.value(patchFilesOption);
+
+        // Never reached
+        //        if(patchFilesWildCard==""){
+        //            UtilXmlTools::displayErrorMessage("Parameter Parsing", "patch-files option requires 1 value: <patch-files> the patch files to process (wildcards supported).");
+        //        }
+
+        forceTargetFilesWildcard=parser.value(forceTargetFilesOption);
+
+
+        XmlPatch myXmlPatch(patchFilesWildCard,forceTargetFilesWildcard,noBackups);
+        myXmlPatch.readAndProcessPatchFile(); // beging file patch processing
+
+        return 0;
+    }
+
+    // Get element name if available
+    if(parser.isSet(elementNameOption)){
+        filters.setElementName(parser.value(elementNameOption));
+    }
+
+    if(filters.getElementName()==""){
+        UtilXmlTools::displayErrorMessage("Parameter Parsing","element-name option is required if not using patch-files option.");
+    }
+
+    // Get current value(s) if avaialabe
+    if(parser.isSet(currentValOption)){
+        currentVal=parser.value(currentValOption);
+    }
+
+    // Get new value(s) if avaialabe
+    if(parser.isSet(newValOption)){
+        newVal=parser.value(newValOption);
+    }
+
+    // Get difference between old and new value if avaialabe
+    if(parser.isSet(diffOldNewValueOption)){
+        diffOldNewVal=parser.value(diffOldNewValueOption);
+    }
+
+    // Get positions if avaialabe
+    if(parser.isSet(positionsValueOption)){
+        positions=parser.value(positionsValueOption);
+    }
+
+    // Get parent element name if available
+    if(parser.isSet(parentElementNameOption)){
+        filters.setParentElementName(parser.value(parentElementNameOption));
+    }
+
+    // Get attribute name if available
+    if(parser.isSet(attributeNameOption)){
+        filters.setAttributeName(parser.value(attributeNameOption));
+    }
+
+    // Get attribute value if available
+    if(parser.isSet(attributeValueOption)){
+        filters.setAttributeValue(parser.value(attributeValueOption));
+    }
+
+    // Check attribute filters
+    if(filters.getAttributeName()!="" && filters.getAttributeValue()==""){
+        UtilXmlTools::displayErrorMessage("Parameter Parsing","attribute-value option is required if using attribute-name option.");
+    }
+
+    if(filters.getAttributeValue()!="" && filters.getAttributeName()==""){
+        UtilXmlTools::displayErrorMessage("Parameter Parsing","attribute-name option is required if using attribute-value option.");
+    }
+
+    // Get files wildcard if available
+    if(parser.isSet(filesOption)){
+        filesWildCard=parser.value(filesOption);
+    }
+    else{
+        UtilXmlTools::displayErrorMessage("Parameter Parsing", "files option requires 1 value: <files> the XML files to process (wildcards supported).");
+    }
+
+    XmlTools myXmlTools(filesWildCard,filters,noBackups);
+
+
+    // Users wants an add-option?
+    if(parser.isSet(addValuesOption)){
+
+        if(newVal==""){
+            UtilXmlTools::displayErrorMessage("Parameter Parsing", "add-value option requires 1 value: <new-val> the new values to add (space separated).");
+        }
+
+        myXmlTools.addValues(newVal);
+    }
+    else if(parser.isSet(removeValuesOption)){ // Or remove-values option?
+
+        if(currentVal==""){
+            UtilXmlTools::displayErrorMessage("Parameter Parsing","remove-values option requires 1 value: <current-val> the current values to remove (space separated).");
+        }
+
+        myXmlTools.removeValues(currentVal);
+    }
+    else if(parser.isSet(replaceValueOption)){ // Or replace-value option?
+
+        if(currentVal=="" || newVal==""){
+            UtilXmlTools::displayErrorMessage("Parameter Parsing","replace-value option requires 2 values: <current-val> the current value and <new-val> the new value.");
+        }
+
+        myXmlTools.replaceValue(currentVal,newVal);
+    }
+    else if(parser.isSet(replaceAllValuesOption)){ // Or replace-all-values option?
+
+        if(newVal=="" && positions==""){
+            UtilXmlTools::displayErrorMessage("Parameter Parsing","replace-all-values option requires 1 value: <new-val> the new value.\n" +
+                                              Util::toQString("It has also 1 optional value: <positions> the positions to replace (space separated and 0-index based)."));
+        }
+
+        myXmlTools.replaceAll(newVal,positions);
+    }
+    else if(parser.isSet(updateElementsOption)){ // Or update-elements option?
+
+        if(diffOldNewVal==""){
+            UtilXmlTools::displayErrorMessage("Parameter Parsing","update-elements option requires 1 value: <diff-old-new-val> the difference between one current element "+
+                                              Util::toQString("value and one new element value (current value and new value must have the same position)."));
+        }
+
+        myXmlTools.updateElements(diffOldNewVal);
+    }
+    else if(parser.isSet(invertElementsOption)){ // Or invert-elements option?
+        myXmlTools.invertElements();
+    }
+    else{
+        UtilXmlTools::displayErrorMessage("Parameter Parsing","One operation is required to XmlTools continue. Possible operations are:\n"+
+                                          Util::toQString("--patch-files\n--add-values\n--remove-values\n--replace-value\n--replace-all-values\n--update-elements\n--invert-elements"));
+    }
+
+    //std::cout << "Started" << std::endl;
+
+    //app.exec();
+    return 0;
+}
Index: XmlTools2/trunk/XmlTools/main.h
===================================================================
--- XmlTools2/trunk/XmlTools/main.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/main.h	(revision 905)
@@ -0,0 +1,20 @@
+#ifndef MAIN_H
+#define MAIN_H
+
+#include "xmlpatch.h"
+
+#ifdef __MINGW32__
+// Turns off globbing for MingW, this is the same as that
+// CRT_noglob.o, but avoids having to locate CRT_nogob.o in the
+// filesystem.
+// http://mingw-users.1079350.n2.nabble.com/Problems-with-expanding-wildcards-to-a-program-td1358555.html
+unsigned long _CRT_glob = 0; // Magic variable to disable wildcards expansion in mingw
+// in our case fixes param parser crashes on windows
+#endif
+
+int main(int argc, char *argv[]);
+
+void invert(std::string elementName, std::string parElementName);
+
+
+#endif // MAIN_H
Index: XmlTools2/trunk/XmlTools/multidimvar.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/multidimvar.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/multidimvar.cpp	(revision 905)
@@ -0,0 +1,63 @@
+#include "multidimvar.h"
+
+// Receives a string with a value with multiple dimensions separated by space
+// Example of input "5 4 6". Variable with dim1=5, dim2=4, dim3=6.
+MultiDimVar::MultiDimVar(QString multiDimValue)
+{
+    this->multiDimValue=Util::qListDoubleFromSpacedString(multiDimValue);
+}
+
+// Inicializes a new MultiDimVar with the dimensions specified with all zero values
+MultiDimVar::MultiDimVar(int dim){
+
+    for(int i=0; i<dim; i++){
+        this->multiDimValue.append(0);
+    }
+
+}
+
+// Sums 2 MultiDimVar values
+MultiDimVar MultiDimVar::sum(const MultiDimVar &val1, const MultiDimVar &val2){
+    MultiDimVar result(val1.multiDimValue.size());
+
+    if(val1.multiDimValue.size()!=val2.multiDimValue.size()){
+        UtilXmlTools::displayErrorMessage("MultiDimVar sum","Error summing MultiDimVar, variables don't have the same dimensions.");
+    }
+
+    for(int i=0; i<result.multiDimValue.size(); i++){
+        result.multiDimValue[i]=val1.multiDimValue[i]+val2.multiDimValue[i];
+    }
+
+    return result;
+}
+
+// Subtract 2 MultiDimVar values
+MultiDimVar MultiDimVar::sub(const MultiDimVar &val1, const MultiDimVar &val2){
+    MultiDimVar result(val1.multiDimValue.size());
+
+    if(val1.multiDimValue.size()!=val2.multiDimValue.size()){
+        UtilXmlTools::displayErrorMessage("MultiDimVar subtraction","Error subtracting MultiDimVar, variables don't have the same dimensions.");
+    }
+
+    for(int i=0; i<result.multiDimValue.size(); i++){
+        result.multiDimValue[i]=val1.multiDimValue[i]-val2.multiDimValue[i];
+    }
+
+    return result;
+}
+
+// Returns a string representation of this multidimensional value as string.
+// Each dimension is separated by a space.
+QString MultiDimVar::toString(){
+
+    QString result;
+
+    for(int i=0; i<this->multiDimValue.size()-1; i++){
+        result += QString::number(this->multiDimValue[i],'G',9) + " "; // G is the option used by onisplit
+    }
+
+    result += QString::number(this->multiDimValue.size()-1,'G',9); // last one does not have a space at the end
+
+    return result;
+
+}
Index: XmlTools2/trunk/XmlTools/multidimvar.h
===================================================================
--- XmlTools2/trunk/XmlTools/multidimvar.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/multidimvar.h	(revision 905)
@@ -0,0 +1,17 @@
+#ifndef MULTIDIMVAR_H
+#define MULTIDIMVAR_H
+
+#include "utilxmltools.h"
+
+class MultiDimVar
+{
+public:
+    QList<double> multiDimValue; // current this class only supports doubles.
+    MultiDimVar(QString multiDimValue);
+    MultiDimVar(int dim);
+    static MultiDimVar sum(const MultiDimVar &val1, const MultiDimVar &val2);
+    static MultiDimVar sub(const MultiDimVar &val1, const MultiDimVar &val2);
+    QString toString();
+};
+
+#endif // MULTIDIMVAR_H
Index: XmlTools2/trunk/XmlTools/readme.txt
===================================================================
--- XmlTools2/trunk/XmlTools/readme.txt	(revision 905)
+++ XmlTools2/trunk/XmlTools/readme.txt	(revision 905)
@@ -0,0 +1,76 @@
+Readme.txt
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+XmlTools v2.0
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+----------------------------------
+Description:
+----------------------------------
+
+XmlTools is a command-line modding tool that operates on XML files. 
+
+It supports many operations in XML files and even non implemented operations using custom javascript code.
+
+It is developed in C++ and works in both Mac OS and Windows.
+
+An additional guide with examples can be read here: http://wiki.oni2.net/XmlTools
+
+----------------------------------
+Full Features:
+----------------------------------
+
+-Update a xml node (for example, to reposition an OBAN animation or adjust pelvis height for a TRAM).
+
+-Invert a xml node (for example, invert an OBAN animation).
+
+-Add new values to XML elements (for example, add the 'unkillable' flag to some characters in a level).
+
+-Remove values from XML elements (for example, remove boss shields from characters in a level).
+
+-Replace values in XML elements (for example, increase the health of characters by replacing the old HP value).
+
+-Patch file support allows the modder to list multiple commands in a file, to all be performed at once.
+
+-Add custom XML to existing files (patch only).
+
+-Remove XML from existing files (patch only).
+
+-Powerful custom XML editing using javascript (for what you can't do with native operations) (patch only). 
+
+----------------------------------
+Installation (standalone version):
+----------------------------------
+
+Extract XmlTools folder to any place in your computer. Open it with command line on windows or terminal in Mac OS.
+
+----------------------------------
+Contacts:
+----------------------------------
+
+Script10k, "faob2@hotmail.com"
+
+Oni Central Forum:
+http://oni.bungie.org
+->Select forum
+
+Oni Wiki:
+http://wiki.oni2.net
+
+----------------------------------
+Change Log:
+----------------------------------
+2.0, 25-01-2014
+-Rewrite XmlTools fom the scratch from C# to C++ in order to increase (much!) the performance of the program
+-The program now uses the following libraries: Qt5, pugixml, 
+Qt5 Google V8 javascript engine and jsxml js library
+-The commands were simplified (they now use the unix like syntax)
+-Update node operation (old updatechainvalues) it now receives the DIFFERENCE between the old value 
+and the new value instead of the new value
+-Update node operation (old updatechainvalues) relation parameter was removed
+-The program now only edits files with .xml extension
+-The patch files now have a XmlTools minimum version
+-The program now only reads patches files with .patch or .oni-patch extensions
+-Some patch files operations were renamed:
+ADDTO -> ADD_INSIDE_NODE
+REMOVE -> REMOVE_NODE
+CUSTOMCODE -> CUSTOM_CODE
Index: XmlTools2/trunk/XmlTools/resources.qrc
===================================================================
--- XmlTools2/trunk/XmlTools/resources.qrc	(revision 905)
+++ XmlTools2/trunk/XmlTools/resources.qrc	(revision 905)
@@ -0,0 +1,6 @@
+<RCC>
+    <qresource prefix="/resources">
+        <file>libs/jsxml.js</file>
+        <file>libs/rexml.js</file>
+    </qresource>
+</RCC>
Index: XmlTools2/trunk/XmlTools/util.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/util.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/util.cpp	(revision 905)
@@ -0,0 +1,195 @@
+#include "util.h"
+
+namespace GlobalVars{
+QString AppName="XmlTools";
+QString AppVersion="2.0";
+}
+
+namespace Util{
+
+QString normalizePath(QString path){
+    return path.replace("\\","/");
+}
+
+QString cutName(QString path){
+    return path.remove(0,path.lastIndexOf('/')).remove('"');
+}
+
+QString insertQuotes(QString path){
+    return "\""+path+"\"";
+}
+
+QString normalizeAndQuote(QString path){
+    return insertQuotes(normalizePath(path));
+}
+
+bool checkEmptySpaces(QStringList toCheck){
+    foreach (QString current, toCheck){
+        if(current.trimmed().isEmpty()){
+            return true; //There are empty spaces
+        }
+    }
+    return false;
+}
+
+bool checkIfIntegers(QStringList toCheck){
+    foreach (QString current, toCheck){
+        if(!isStringInteger(current)){
+            return true; // Some aren't valid integers
+        }
+    }
+    return false;
+}
+
+bool checkIfDoubles(QStringList toCheck){
+    foreach (QString current, toCheck){
+        if(!isStringDouble(current)){
+            return true; // Some aren't valid doubles
+        }
+    }
+    return false;
+}
+
+bool isStringInteger(QString myString){
+    bool isNumber;
+
+    myString.toInt(&isNumber); //convert to int and see if it succeeds
+
+    return isNumber;
+}
+
+bool isStringDouble(QString myString){
+    bool isDouble;
+
+    myString.toDouble(&isDouble); //convert to double and see if it succeeds
+
+    return isDouble;
+}
+
+QString fullTrim(QString str) {
+
+    str = str.simplified(); //convert all invisible chars in normal whitespaces
+    str.replace( " ", "" );
+
+    return str;
+}
+
+//Searches for the QString "toSearch" in the "myString" variable backward
+//Returns the index of the first match or -1 if not found
+int indexOfBackward(const QString &myString, const QString &toSearch, int from){
+    int myStringSize=myString.size();
+    int toSearchSize=toSearch.size();
+
+    if(from==-1){
+        from=myStringSize;
+    }
+
+    int i=from;
+
+    while(i>=0){
+        for(int j=toSearchSize-1; j>=0; j--){
+            i--;
+            if(myString.at(i)!=toSearch.at(j)){
+                break;
+            }
+            if(j==0){
+                return i;
+            }
+        }
+    }
+
+    return -1;
+}
+
+QStringList substring(const QString &myString,const QString &separator, Qt::CaseSensitivity cs){
+    QStringList result = QStringList();
+    int currIdx=0, nextIdx=0;
+
+    while(true){
+        nextIdx=myString.indexOf(separator,currIdx,cs);
+        result << myString.mid(currIdx,nextIdx-currIdx);
+        if(nextIdx==-1) break;
+        currIdx=nextIdx+1;
+    }
+
+    return result;
+}
+
+QStringList qStringListFromSpacedString(const QString &mySpacedString){
+    return Util::substring(mySpacedString," ");
+}
+
+QList<int> qListIntFromSpacedString(const QString &mySpacedString){
+    QStringList stringList;
+    QList<int> intList;
+
+    stringList = Util::substring(mySpacedString," ");
+
+    foreach(QString value, stringList){
+        intList << value.toInt();
+    }
+
+    return intList;
+}
+
+QList<double> qListDoubleFromSpacedString(const QString &mySpacedString){
+    QStringList stringList;
+    QList<double> doubleList;
+
+    stringList = Util::substring(mySpacedString," ");
+
+    foreach(QString value, stringList){
+        doubleList << value.toDouble();
+    }
+
+    return doubleList;
+}
+
+QString normalizeDecimalSeparator(QString value){
+    return value.replace(',','.');
+}
+
+bool backupFile(QString file){
+    return copyFile(file,file+".bak");
+}
+
+bool copyFile(QString src, QString dest){
+    return QFile::copy(src, dest);
+}
+
+
+// Supports wildcards, and directory with wildcard e.g.:
+// *.xml
+// C:/myXmls/*.xml
+QStringList getAllFilesByWildcard(const QString &wildcard){
+
+    QString pathNormalized;
+    QStringList nameWildCard; // entryList requires a QStringList
+    int endOfPathIdx;
+    QDir directory;
+
+    if(wildcard==""){
+        std::cout << "You need to specify a wildcard! Aborting..." << std::endl;
+        exit(1);
+    }
+
+    pathNormalized=Util::normalizePath(wildcard); // Convert slashes to work in both mac and windows
+
+    if(pathNormalized.contains("/")){
+        endOfPathIdx=Util::indexOfBackward(pathNormalized,"/"); // get last slash
+
+        nameWildCard.append(pathNormalized.right(pathNormalized.size()-1-endOfPathIdx)); // get the names wildcard // -1 because starts with zeo
+
+        pathNormalized=pathNormalized.left(endOfPathIdx); // get the complete path
+
+        directory=QDir(pathNormalized);
+
+        return directory.entryList(nameWildCard);
+    }
+
+    nameWildCard << wildcard;
+
+    return directory.entryList(nameWildCard);
+}
+
+}
Index: XmlTools2/trunk/XmlTools/util.h
===================================================================
--- XmlTools2/trunk/XmlTools/util.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/util.h	(revision 905)
@@ -0,0 +1,53 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <QFile>
+#include <QDir>
+#include <QString>
+#include <QStringList>
+#include <iostream> // cout, cin etc.
+
+namespace GlobalVars{
+extern QString AppName;
+extern QString AppVersion;
+}
+
+/**
+  Utilities functions (global)
+  **/
+namespace Util{
+QString normalizePath(QString path);
+QString cutName(QString path);
+QString insertQuotes(QString path);
+QString normalizeAndQuote(QString path);
+QString fullTrim(QString str);
+QString normalizeDecimalSeparator(QString value);
+QStringList substring(const QString &myString, const QString &separator, Qt::CaseSensitivity cs = Qt::CaseSensitive);
+QStringList qStringListFromSpacedString(const QString &mySpacedString);
+QStringList getAllFilesByWildcard(const QString &wildcard);
+QList<int> qListIntFromSpacedString(const QString &mySpacedString);
+QList<double> qListDoubleFromSpacedString(const QString &mySpacedString);
+int indexOfBackward(const QString &myString, const QString &toSearch, int from = -1);
+bool checkEmptySpaces(QStringList toCheck);
+bool checkIfIntegers(QStringList toCheck);
+bool checkIfDoubles(QStringList toCheck);
+bool isStringInteger(QString myString);
+bool isStringDouble(QString myString);
+bool backupFile(QString file);
+bool copyFile(QString src, QString dest);
+// The commented code bellow is a big mistake because toLatin1() creates a temp object that gets
+// destroyed after the semicolon: https://qt-project.org/forums/viewthread/12885 (Volker answer)
+//// Convert a QString to a c string
+//// Caution don't use as for example: std::cout << toCstr(a) << " " << toCstr(b);
+//// as the result will be always a.
+//inline const char* toCstr(const QString &myString){
+//    return myString.toLatin1().constData();
+//}
+// Converts a std::string to QString
+inline QString toQString(std::string myString){
+    return QString::fromStdString(myString);
+}
+
+}
+
+#endif // UTIL_H
Index: XmlTools2/trunk/XmlTools/utilxmltools.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/utilxmltools.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/utilxmltools.cpp	(revision 905)
@@ -0,0 +1,110 @@
+#include "utilxmltools.h"
+
+namespace UtilXmlTools{
+
+QStringList getAllXmlFilesByWildcard(const QString &wildcard){
+    QStringList validFilesMatching;
+    QStringList filesMatching;
+
+    // Get all files matching the wildcard
+
+    filesMatching=Util::getAllFilesByWildcard(wildcard);
+
+    // Check if all are XmlFiles, only return valid XmlFiles
+
+    for(int i=0; i<filesMatching.size(); i++){
+        if(filesMatching[i].endsWith(".xml",Qt::CaseInsensitive)){
+            validFilesMatching << filesMatching[i];
+        }
+    }
+
+    return validFilesMatching;
+
+}
+
+QStringList getAllPatchFilesByWildcard(const QString &wildcard){
+    QStringList validFilesMatching;
+    QStringList filesMatching;
+
+    // Get all files matching the wildcard
+
+    filesMatching=Util::getAllFilesByWildcard(wildcard);
+
+    // Check if all are PatchFiles, only return valid PatchFiles
+
+    for(int i=0; i<filesMatching.size(); i++){
+        if(filesMatching[i].endsWith(".patch",Qt::CaseInsensitive) || filesMatching[i].endsWith(".oni-patch",Qt::CaseInsensitive)){
+            validFilesMatching << filesMatching[i];
+        }
+    }
+
+    return validFilesMatching;
+
+}
+
+void backupFile(const QString &file){
+    if(!QFile::exists(file+".bak")){
+        if(!Util::backupFile(file)){
+            std::cerr << "Couldn't backup file '" << file.toLatin1().constData() << "'. Aborting." << std::endl;
+            exit(1);
+        }
+    }
+    else{
+        std::cout << "Backup file '" << file.toLatin1().constData() << "'' already exists. Skipping..." << std::endl;
+    }
+}
+
+void getAllNamedElements(pugi::xml_node &node, QList<pugi::xml_node> &result, XmlFilter &filters){
+    for (pugi::xml_node_iterator currNode = node.begin(); currNode != node.end(); ++currNode)
+    {
+
+        if ((*currNode).name() == filters.getElementName() && (filters.getParentElementName() == "" || filters.getParentElementName() == (*currNode).parent().name())
+                && (filters.getAttributeName() == "" ||
+                    Util::toQString((*currNode).attribute(filters.getAttributeName().toLatin1().constData()).value()) == filters.getAttributeValue()) ){ // Seems node attribute must be converted to qtsring to remove \r\n needs to check in future!
+
+            result << *currNode;
+            continue;
+        }
+        getAllNamedElements(*currNode,result,filters);
+    }
+}
+
+pugi::xml_node getFirstNamedElements(pugi::xml_node &node, XmlFilter &filters){
+
+    pugi::xml_node foundNode;
+
+    for (pugi::xml_node_iterator currNode = node.begin(); currNode != node.end(); ++currNode)
+    {
+        if ((*currNode).name() == filters.getElementName() && (filters.getParentElementName() == "" || filters.getParentElementName() == (*currNode).parent().name())
+                && (filters.getAttributeName() == "" ||
+                    Util::toQString((*currNode).attribute(filters.getAttributeName().toLatin1().constData()).value()) == filters.getAttributeValue()) ){
+            return *currNode;
+        }
+
+        foundNode=getFirstNamedElements(*currNode,filters);
+
+        if(foundNode.type()!=pugi::node_null){
+            return foundNode;
+        }
+
+    }
+
+    return foundNode;
+}
+
+void displaySuccessMessage(const int numberOperations, const QString &operation){
+    std::cout << "------------------------------------------------------------------------" << std::endl;
+    std::cout << numberOperations << " " << operation.toLatin1().constData() << " operation(s) completed with success!" << std::endl;
+    std::cout << "------------------------------------------------------------------------" << std::endl;
+}
+
+void displayErrorMessage(const QString& operation, const QString &message, bool exitProgram){
+    std::cerr << "************************************************************************" << std::endl;
+    std::cerr << operation.toLatin1().constData() << " operation failed!" << std::endl << std::endl;
+    std::cerr << message.toLatin1().constData() << std::endl << std::endl;
+    if(exitProgram) std::cerr << "Aborting..." << std::endl;
+    std::cerr << "************************************************************************" << std::endl;
+    if(exitProgram) exit(1);
+}
+
+}
Index: XmlTools2/trunk/XmlTools/utilxmltools.h
===================================================================
--- XmlTools2/trunk/XmlTools/utilxmltools.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/utilxmltools.h	(revision 905)
@@ -0,0 +1,55 @@
+#ifndef UTILXMLTOOLS_H
+#define UTILXMLTOOLS_H
+
+// Utilities functions specific used for Xml Tools (not general functions)
+
+#include "util.h"
+#include "xmlfilter.h"
+#include "libs/pugixml.hpp"
+
+namespace UtilXmlTools{
+
+QStringList getAllXmlFilesByWildcard(const QString &wildcard);
+QStringList getAllPatchFilesByWildcard(const QString &wildcard);
+void backupFile(const QString &file);
+void getAllNamedElements(pugi::xml_node &node, QList<pugi::xml_node> &result, XmlFilter &filters);
+void displaySuccessMessage(const int numberOperations, const QString &operation);
+void displayErrorMessage(const QString& operation, const QString &message, bool exitProgram=true);
+pugi::xml_node getFirstNamedElements(pugi::xml_node &node, XmlFilter &filters);
+
+//// inline functions
+
+inline void loadXmlFile(const QString &file, pugi::xml_document &document, pugi::xml_node &rootNode, bool backupsEnabled, const QString &operationForErrorMessage){
+
+    pugi::xml_parse_result result = document.load_file(file.toLatin1().constData());
+    rootNode=document.root();
+
+    if(result.status==pugi::status_ok){
+        std::cout << "File '" << file.toLatin1().constData() << "' loaded with sucess." << std::endl;
+    }
+    else{
+        UtilXmlTools::displayErrorMessage(operationForErrorMessage,"An error ocurred while loading '" +file + "' XML file\n" + result.description());
+    }
+
+    if(backupsEnabled){
+        UtilXmlTools::backupFile(file); // bake a backup of the file.
+    }
+
+}
+
+inline void saveXmlFile(const QString &file, pugi::xml_document &document, const QString &operationForErrorMessage){
+    if(!document.save_file(file.toLatin1().constData(), "\t", pugi::format_indent | pugi::format_save_file_text | pugi::format_no_escapes)){ // output as the system new lines ending
+        UtilXmlTools::displayErrorMessage(operationForErrorMessage,"An error ocurred while saving '" + file + "' XML file");
+    }
+}
+
+//inline void checkIfValidXmlFile(const QString &file){
+//    if(!file.endsWith(".xml",Qt::CaseInsensitive)){
+//        std::cout << "Tried to load a non xml file: '" << Util::toCstr(file) << "'. XmlTools only work over XmlFiles." << std::endl;
+//        exit(1);
+//    }
+//}
+
+}
+
+#endif // UTILXMLTOOLS_H
Index: XmlTools2/trunk/XmlTools/xmlfilter.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/xmlfilter.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/xmlfilter.cpp	(revision 905)
@@ -0,0 +1,47 @@
+#include "xmlfilter.h"
+
+XmlFilter::XmlFilter()
+{
+
+}
+
+XmlFilter::XmlFilter(QString elementName, QString parentElementName, QString attributeName, QString attributeValue){
+    this->elementName=elementName;
+    this->parentElementName=parentElementName;
+    this->attributeName=attributeName;
+    this->attributeValue=attributeValue;
+}
+
+// QStrings
+
+QString XmlFilter::getElementName(){
+    return this->elementName;
+}
+
+QString XmlFilter::getParentElementName(){
+    return this->parentElementName;
+}
+
+QString XmlFilter::getAttributeName(){
+    return this->attributeName;
+}
+
+QString XmlFilter::getAttributeValue(){
+    return this->attributeValue;
+}
+
+void XmlFilter::setElementName(QString elementName){
+    this->elementName=elementName;
+}
+
+void XmlFilter::setParentElementName(QString parentElementName){
+    this->parentElementName=parentElementName;
+}
+
+void XmlFilter::setAttributeName(QString attributeName){
+    this->attributeName=attributeName;
+}
+
+void XmlFilter::setAttributeValue(QString attributeValue){
+    this->attributeValue=attributeValue;
+}
Index: XmlTools2/trunk/XmlTools/xmlfilter.h
===================================================================
--- XmlTools2/trunk/XmlTools/xmlfilter.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/xmlfilter.h	(revision 905)
@@ -0,0 +1,30 @@
+#ifndef XMLFILTER_H
+#define XMLFILTER_H
+
+#include <QString>
+
+//class to simplify XML filtering
+class XmlFilter
+{
+public:
+
+    XmlFilter();
+    XmlFilter(QString elementName, QString parentElementName, QString attributeName, QString attributeValue);
+
+    QString getElementName();
+    QString getParentElementName();
+    QString getAttributeName();
+    QString getAttributeValue();
+
+    void setElementName(QString elementName);
+    void setParentElementName(QString parentElementName);
+    void setAttributeName(QString attributeName);
+    void setAttributeValue(QString attributeValue);
+private:
+    QString elementName;
+    QString parentElementName;
+    QString attributeName;
+    QString attributeValue;
+};
+
+#endif // XMLFILTER_H
Index: XmlTools2/trunk/XmlTools/xmlpatch.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/xmlpatch.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/xmlpatch.cpp	(revision 905)
@@ -0,0 +1,413 @@
+#include "xmlpatch.h"
+
+XmlPatch::XmlPatch(QString patchFilesWildcard, QString forceTargetFilesWildcard, bool noBackups)
+{
+    this->patchFilesToProcess=UtilXmlTools::getAllPatchFilesByWildcard(patchFilesWildcard);
+    this->forceTargetFilesWildcard=forceTargetFilesWildcard;
+    this->backupsEnabled=!noBackups;
+
+    if(forceTargetFilesWildcard!=""){
+        std::cout << "User forced patch in the target file(s): " << this->forceTargetFilesWildcard.toLatin1().constData() << std::endl;
+    }
+
+    if(this->patchFilesToProcess.size()==0){
+        UtilXmlTools::displayErrorMessage("Loading patch files","No .patch or .oni-patch files were found for the wildcard: "+patchFilesWildcard);
+    }
+
+}
+
+void XmlPatch::readAndProcessPatchFile(){
+
+    // Process all PatchFiles
+    for(int i=0; i<this->patchFilesToProcess.size(); i++){
+
+        QFile inputFile(this->patchFilesToProcess[i]);
+
+        if (inputFile.open(QIODevice::ReadOnly))
+        {
+
+            QTextStream fileStream(&inputFile);
+
+            checkPatchVersion(this->patchFilesToProcess[i], fileStream);
+            checkAndProcessValidCommands(fileStream);
+
+            inputFile.close();
+        }
+        else{
+            UtilXmlTools::displayErrorMessage("Read patch file", "Error opening patch file: '" + this->patchFilesToProcess[i] + "'.\n" + inputFile.errorString());
+        }
+
+    }
+
+    UtilXmlTools::displaySuccessMessage(this->patchFilesToProcess.size(),"Patch File(s)");
+
+}
+
+void XmlPatch::addToOperation(const QString &xmlString, XmlFilter &filters, const QString &filesWildcard){
+
+    QStringList filesToProcess;
+
+    filesToProcess=UtilXmlTools::getAllXmlFilesByWildcard(filesWildcard);
+
+    pugi::xml_node nodeToInsertion;
+    pugi::xml_document newNode;
+    pugi::xml_parse_result result;
+
+    result=newNode.load(xmlString.toLatin1().constData()); // load xml to insert
+
+    if(result.status!=pugi::status_ok){
+        UtilXmlTools::displayErrorMessage("@ADD_INSIDE_NODE", "The xml node to insert is invalid.\n" + Util::toQString(result.description()));
+    }
+
+    // Process all XmlFiles
+    for(int i=0; i<filesToProcess.size(); i++){
+
+        UtilXmlTools::loadXmlFile(filesToProcess[i],this->document,this->rootNode,this->backupsEnabled,"@ADD_INSIDE_NODE");
+
+        nodeToInsertion=UtilXmlTools::getFirstNamedElements(this->rootNode,filters);
+
+        if(nodeToInsertion.type()==pugi::node_null){
+
+            QString errMessage;
+
+            errMessage = "It wasn't found a node with a ElementName: '" + filters.getElementName() + "'";
+            if(filters.getParentElementName()!=""){
+                errMessage += " and a ParentElementName: '" + filters.getParentElementName() + "'";
+            }
+            if(filters.getAttributeName()!=""){
+                errMessage += " and an AttributeName: '" + filters.getAttributeName() + "' and an AttributeValue: '" + filters.getAttributeValue() + "'";
+            }
+
+            UtilXmlTools::displayErrorMessage("@ADD_INSIDE_NODE",errMessage);
+        }
+
+        nodeToInsertion.prepend_copy(newNode.first_child()); // append the new node
+
+
+        UtilXmlTools::saveXmlFile(filesToProcess[i],this->document, "@ADD_INSIDE_NODE");
+    }
+
+    UtilXmlTools::displaySuccessMessage(filesToProcess.size(),"@ADD_INSIDE_NODE");
+}
+
+void XmlPatch::removeNodeOperation(XmlFilter &filters, const QString &filesWildcard){
+
+    QStringList filesToProcess;
+
+    filesToProcess=UtilXmlTools::getAllXmlFilesByWildcard(filesWildcard);
+
+    pugi::xml_node nodeToDeletion;
+    pugi::xml_parse_result result;
+
+    // Process all XmlFiles
+    for(int i=0; i<filesToProcess.size(); i++){
+
+        UtilXmlTools::loadXmlFile(filesToProcess[i],this->document,this->rootNode,this->backupsEnabled,"@REMOVE_NODE");
+
+        nodeToDeletion=UtilXmlTools::getFirstNamedElements(this->rootNode,filters);
+
+        if(nodeToDeletion.type()==pugi::node_null){
+            QString errMessage;
+
+            errMessage = "It wasn't found a node with a ElementName: '" + filters.getElementName() + "'";
+            if(filters.getParentElementName()!=""){
+                errMessage += " and a ParentElementName: '" + filters.getParentElementName() + "'";
+            }
+            if(filters.getAttributeName()!=""){
+                errMessage += " and an AttributeName: '" + filters.getAttributeName() + "' and an AttributeValue: '" + filters.getAttributeValue() + "'";
+            }
+
+            UtilXmlTools::displayErrorMessage("@REMOVE_NODE",errMessage);
+        }
+
+        if(!nodeToDeletion.parent().remove_child(nodeToDeletion)){  // remove the node
+
+            QString errMessage;
+
+            errMessage = "Couldn't remove the node with Element '" + filters.getElementName() + "'";
+
+            if(filters.getParentElementName()!=""){
+                errMessage += " and a ParentElement: '" + filters.getParentElementName() + "'";
+            }
+
+            UtilXmlTools::displayErrorMessage("@REMOVE_NODE",errMessage);
+        }
+
+        UtilXmlTools::saveXmlFile(filesToProcess[i],this->document, "@REMOVE_NODE");
+    }
+
+    UtilXmlTools::displaySuccessMessage(filesToProcess.size(), "@REMOVE_NODE");
+}
+
+void XmlPatch::executeCommandOperation(const QString &commandString){
+
+    QProcess newXmlToolsInstance;
+    QString resultOutput;
+
+    // Avoid infinite fork loops
+    if(commandString.contains("-p") || commandString.contains("--patch-files")){
+        UtilXmlTools::displayErrorMessage("@COMMAND","Use of --patch-files option is not allowed inside a patch file");
+    }
+
+    newXmlToolsInstance.start(GlobalVars::AppName + " " + commandString);
+    newXmlToolsInstance.waitForFinished(-1); // wait for new instance to finish
+
+    resultOutput=newXmlToolsInstance.readAll();
+
+    if(newXmlToolsInstance.exitCode()!=0){
+        UtilXmlTools::displayErrorMessage("@COMMAND", "An error ocurred:\n" + resultOutput);
+        exit(1);
+    }
+
+    std::cout << "@COMMAND patch operation output:\n" << resultOutput.toLatin1().constData() << std::endl;
+
+    UtilXmlTools::displaySuccessMessage(1,"@COMMAND");
+}
+
+void XmlPatch::executeCustomCommandOperation(const QString &jsString, const QString &filesWildcard){
+
+    QStringList filesToProcess;
+#ifdef _USE_OLD_JS_ENGINE
+    QScriptEngine engine;
+    QScriptValue engineResult; // variable to check for js_errors
+#else
+    QJSEngine engine;
+    QJSValue engineResult; // variable to check for js_errors
+#endif
+
+    QString rexmlString, jsxmlString, currXmlFileString;
+
+
+    QFile rexmlfile(":/resources/libs/rexml.js");
+    QFile jsxmlfile(":/resources/libs/jsxml.js");
+
+    filesToProcess=UtilXmlTools::getAllXmlFilesByWildcard(filesWildcard);
+
+    rexmlfile.open(QFile::ReadOnly | QFile::Text);
+    jsxmlfile.open(QFile::ReadOnly | QFile::Text);
+
+    rexmlString=QTextStream(&rexmlfile).readAll();
+    jsxmlString=QTextStream(&jsxmlfile).readAll();
+
+    engine.evaluate(rexmlString); // load js libraries
+    engine.evaluate(jsxmlString);
+
+    // Process all XmlFiles
+    for(int i=0; i<filesToProcess.size(); i++){
+
+        if(this->backupsEnabled){
+            UtilXmlTools::backupFile(filesToProcess[i]);
+        }
+
+        QFile currXmlFile(filesToProcess[i]);
+
+        if(!currXmlFile.open(QFile::ReadOnly | QFile::Text)){
+            UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Error loading '" + filesToProcess[i] + "' file for read operation.");
+        }
+
+        currXmlFileString=QTextStream(&currXmlFile).readAll();
+
+        currXmlFile.close(); // close reading
+
+        engine.globalObject().setProperty("$xmlData",currXmlFileString);
+
+        engineResult=engine.evaluate(jsString);
+
+#ifdef _USE_OLD_JS_ENGINE
+        if (engine.hasUncaughtException()) {
+            displayJsException(engine,engineResult);
+        }
+#else
+        checkForJsException(engineResult);
+#endif
+
+        if(!currXmlFile.open(QFile::WriteOnly | QFile::Text | QIODevice::Truncate)){
+            UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Error loading '" + filesToProcess[i] + "' file for @CUSTOM_CODE write operation.");
+        }
+
+        engineResult=engine.globalObject().property("$xmlData");
+
+#ifdef _USE_OLD_JS_ENGINE
+        if (engine.hasUncaughtException()) {
+            displayJsException(engine,engineResult);
+        }
+#else
+        checkForJsException(engineResult);
+#endif
+
+        QTextStream(&currXmlFile) << engineResult.toString(); // retreive the modified xml by javascript and save it to the file
+    }
+
+    UtilXmlTools::displaySuccessMessage(filesToProcess.size(), "@CUSTOM_CODE");
+}
+
+void XmlPatch::checkPatchVersion(const QString &file, QTextStream &fileStream){
+
+    QString line, patchVersion="";
+
+    // First get the patch version and check it validity
+    while ( !fileStream.atEnd() ){
+        line = fileStream.readLine();
+
+        if(line.startsWith('#')){ // Ignore comments
+            continue;
+        }
+        else if(line.startsWith("@XML_TOOLS")){
+
+            patchVersion=getPatchParameterValue(line,"Version");
+
+            if(!patchVersion.startsWith("2.0")){
+                QString errMessage;
+
+                errMessage = "The current patch version is incompatible with this XmlTools version:\n";
+                errMessage += "Patch file name: '" + file + "'\n";
+                errMessage += "XmlTools version:  " + GlobalVars::AppVersion + "\n" + "CurrPatch version: " + patchVersion + "";
+                UtilXmlTools::displayErrorMessage("@XML_TOOLS",errMessage);
+            }
+            break; // We have got what we wanted
+        }
+    }
+
+    if(patchVersion==""){
+        UtilXmlTools::displayErrorMessage("@XML_TOOLS","Patch version not found.");
+    }
+
+}
+
+void XmlPatch::checkAndProcessValidCommands(QTextStream &fileStream){
+
+    QString line;
+    QString filesWildcard;
+    QString xmlToInsert, command, jsCode;
+    XmlFilter filters;
+
+    // Process the rest of the commands in patch file
+    while ( !fileStream.atEnd() ){
+        line = fileStream.readLine();
+
+        if(line.startsWith('#')){ // Ignore comments
+            continue;
+        }
+        else if(line.startsWith("@ADD_INSIDE_NODE")){
+            filters.setElementName(getPatchParameterValue(line,"ElementName"));
+            filters.setParentElementName(getPatchParameterValue(line,"ParentElementName"));
+            filters.setAttributeName(getPatchParameterValue(line,"AttributeName"));
+            filters.setAttributeValue(getPatchParameterValue(line,"AttributeValue"));
+            if(this->forceTargetFilesWildcard==""){
+                filesWildcard=getPatchParameterValue(line,"Files");
+            }
+            else{
+                filesWildcard=this->forceTargetFilesWildcard;
+            }
+
+            // Check attribute filters
+            if(filters.getAttributeName()!="" && filters.getAttributeValue()==""){
+                UtilXmlTools::displayErrorMessage("@ADD_INSIDE_NODE","attribute-value option is required if using attribute-name option.");
+            }
+
+            if(filters.getAttributeValue()!="" && filters.getAttributeName()==""){
+                UtilXmlTools::displayErrorMessage("@ADD_INSIDE_NODE","attribute-name option is required if using attribute-value option.");
+            }
+
+            while ( !fileStream.atEnd() && !line.startsWith("</xml>")){
+                line = fileStream.readLine();
+
+                if(!line.startsWith("<xml>") && !line.startsWith("</xml>")){
+                    xmlToInsert += line + "\n";
+                }
+            }
+
+            addToOperation(xmlToInsert,filters,filesWildcard);
+
+        }
+        else if(line.startsWith("@REMOVE_NODE")){
+
+            filters.setElementName(getPatchParameterValue(line,"ElementName"));
+            filters.setParentElementName(getPatchParameterValue(line,"ParentElementName"));
+            filters.setAttributeName(getPatchParameterValue(line,"AttributeName"));
+            filters.setAttributeValue(getPatchParameterValue(line,"AttributeValue"));
+            if(this->forceTargetFilesWildcard==""){
+                filesWildcard=getPatchParameterValue(line,"Files");
+            }
+            else{
+                filesWildcard=this->forceTargetFilesWildcard;
+            }
+
+            // Check attribute filters
+            if(filters.getAttributeName()!="" && filters.getAttributeValue()==""){
+                UtilXmlTools::displayErrorMessage("@REMOVE_NODE","attribute-value option is required if using attribute-name option.");
+            }
+
+            if(filters.getAttributeValue()!="" && filters.getAttributeName()==""){
+                UtilXmlTools::displayErrorMessage("@REMOVE_NODE","attribute-name option is required if using attribute-value option.");
+            }
+
+            removeNodeOperation(filters,filesWildcard);
+
+        }
+        else if(line.startsWith("@COMMAND")){
+
+            command=getPatchParameterValue(line,"");
+
+            executeCommandOperation(command);
+        }
+        else if(line.startsWith("@CUSTOM_CODE")){
+
+            if(this->forceTargetFilesWildcard==""){
+                filesWildcard=getPatchParameterValue(line,"Files");
+            }
+            else{
+                filesWildcard=this->forceTargetFilesWildcard;
+            }
+
+            while ( !fileStream.atEnd() && !line.startsWith("</code>")){
+
+                line = fileStream.readLine();
+
+                if(!line.startsWith("<code>") && !line.startsWith("</code>")){
+                    jsCode += line + "\n";
+                }
+            }
+
+            executeCustomCommandOperation(jsCode,filesWildcard);
+        }
+    }
+}
+
+QString XmlPatch::getPatchParameterValue(const QString& line, QString parameter){
+
+    int startValueIdx, endValueIdx;
+
+    parameter+=" "; // Parameters include a space before it's value.
+
+    if(!line.contains(parameter)){
+        if(parameter=="ParentElementName " || parameter=="AttributeName " || parameter=="AttributeValue "){
+            return ""; // not mandatory
+        }
+        parameter.remove(" "); // just remove the space added so it doesn't look weird when outputted to the user
+
+        UtilXmlTools::displayErrorMessage("Read patch file parameter","Couldn't retreive '" + parameter + "' parameter.");
+    }
+
+    startValueIdx=line.indexOf(parameter); // get the position where parameter is defined
+    endValueIdx=line.indexOf("\"",startValueIdx)+1; // get the position where parameter value begins (+1 to ignore mandotory quote)
+
+    startValueIdx=endValueIdx;
+    endValueIdx=line.indexOf("\"",startValueIdx); // get the last mandatory quote of the value
+
+    return line.mid(startValueIdx,endValueIdx-startValueIdx); // return the value of the parameter (is in the middle of the mandatory quotes)
+}
+
+#ifdef _USE_OLD_JS_ENGINE
+void XmlPatch::displayJsException(QScriptEngine &engine, QScriptValue &engineResult){
+    if (engine.hasUncaughtException()) {
+        UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code) at line " +QString::number(engine.uncaughtExceptionLineNumber()) + ":\n" + engineResult.toString());
+    }
+}
+#else
+void XmlPatch::checkForJsException(QJSValue &engineResult){
+    if (engineResult.isError()) {
+        UtilXmlTools::displayErrorMessage("@CUSTOM_CODE","Uncaught js exception (user code):\n" + engineResult.toString());
+    }
+}
+#endif
Index: XmlTools2/trunk/XmlTools/xmlpatch.h
===================================================================
--- XmlTools2/trunk/XmlTools/xmlpatch.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/xmlpatch.h	(revision 905)
@@ -0,0 +1,31 @@
+#ifndef XMLPATCH_H
+#define XMLPATCH_H
+
+#include "xmltools.h"
+
+class XmlPatch
+{
+public:
+    XmlPatch(QString patchFilesWildcard, QString forceTargetFilesWildcard="", bool backupsEnabled=true);
+    void readAndProcessPatchFile();
+private:
+    QStringList patchFilesToProcess;
+    QString forceTargetFilesWildcard;
+    pugi::xml_document document;
+    pugi::xml_node rootNode;
+    bool backupsEnabled;
+    QString getPatchParameterValue(const QString& line, QString parameter);
+    void addToOperation(const QString &xmlString, XmlFilter &filters, const QString &filesWildcard="");
+    void removeNodeOperation(XmlFilter &filters, const QString &filesWildcard="");
+    void executeCommandOperation(const QString &commandString);
+    void executeCustomCommandOperation(const QString &jsString, const QString &filesWildcard="");
+    void checkPatchVersion(const QString &file, QTextStream &fileStream);
+    void checkAndProcessValidCommands(QTextStream &fileStream);
+#ifdef _USE_OLD_JS_ENGINE
+    void displayJsException(QScriptEngine &engine, QScriptValue &engineResult);
+#else
+    void checkForJsException(QJSValue &engineResult);
+#endif
+};
+
+#endif // XMLPATCH_H
Index: XmlTools2/trunk/XmlTools/xmltools.cpp
===================================================================
--- XmlTools2/trunk/XmlTools/xmltools.cpp	(revision 905)
+++ XmlTools2/trunk/XmlTools/xmltools.cpp	(revision 905)
@@ -0,0 +1,257 @@
+#include "xmltools.h"
+
+XmlTools::XmlTools(QString filesWildcard, XmlFilter filter, bool noBackups)
+{
+    this->filesToProcess=UtilXmlTools::getAllXmlFilesByWildcard(filesWildcard);
+    this->filters=filter;
+    this->backupsEnabled=!noBackups;
+
+    if(this->filesToProcess.size()==0){
+        UtilXmlTools::displayErrorMessage("Loading xml files","No XML files were found for the wildcard: "+filesWildcard);
+    }
+}
+
+// Adds new values to an element
+void XmlTools::addValues(QString newValues){
+
+    // Process all XmlFiles
+    for(int i=0; i<this->filesToProcess.size(); i++){
+
+        QStringList newValuesList, currValuesList;
+        QList<pugi::xml_node> elements;
+
+        UtilXmlTools::loadXmlFile(this->filesToProcess[i],this->document,this->rootNode,this->backupsEnabled,"add-values");
+
+        newValuesList=Util::qStringListFromSpacedString(newValues);
+        UtilXmlTools::getAllNamedElements(this->rootNode,elements,this->filters);
+
+        for(int j=0; j<elements.size(); j++){
+
+            currValuesList=Util::qStringListFromSpacedString(Util::toQString(elements[j].text().as_string())); // convert each element in a list (uses space as separator)
+
+            for(int k=0; k<newValuesList.size(); k++){
+                if(currValuesList.contains(newValuesList[k])){ // If the current element already contains this value proceed to the next
+                    continue;
+                }
+
+                elements[j].text()=QString(Util::toQString(elements[j].text().as_string()) + " " + newValuesList[k]).toLatin1().constData(); // If it doesn't exists yet let's add it
+            }
+        }
+
+        UtilXmlTools::saveXmlFile(this->filesToProcess[i],this->document,"add-values");
+    }
+
+    UtilXmlTools::displaySuccessMessage(this->filesToProcess.size(), "add-values");
+
+}
+
+void XmlTools::removeValues(QString valuesToRemove){
+
+    // Process all XmlFiles
+    for(int i=0; i<this->filesToProcess.size(); i++){
+
+        QList<pugi::xml_node> elements;
+        QStringList valuesToRemoveList, currValuesList;
+        bool elementChanged=false;
+
+        UtilXmlTools::loadXmlFile(this->filesToProcess[i],this->document,this->rootNode,this->backupsEnabled, "remove-values");
+
+        UtilXmlTools::getAllNamedElements(this->rootNode,elements,this->filters);
+
+        valuesToRemoveList=Util::qStringListFromSpacedString(valuesToRemove);
+
+        for(int j=0; j<elements.size(); j++){ // O(3)... Optimization may be necessary.
+            currValuesList=Util::qStringListFromSpacedString(Util::toQString(elements[j].text().as_string())); // convert each element in a list (uses space as separator)
+
+            for(int k=0; k<currValuesList.size(); k++){
+                for(int m=0; m<valuesToRemoveList.size(); m++){
+                    if(currValuesList[k]==valuesToRemoveList[m]){
+                        currValuesList[k]=""; // remove it
+                        elementChanged=true;
+                    }
+                }
+            }
+
+            if(elementChanged){ // If curr element changed update the XML
+                elements[j].text()=currValuesList.join(' ').toLatin1().constData();
+                elementChanged=false;
+            }
+        }
+
+        UtilXmlTools::saveXmlFile(this->filesToProcess[i],this->document, "remove-values");
+    }
+
+
+    UtilXmlTools::displaySuccessMessage(this->filesToProcess.size(),"remove-values");
+}
+
+void XmlTools::replaceValue(QString oldValue, QString newValue){
+
+    // Process all XmlFiles
+    for(int i=0; i<this->filesToProcess.size(); i++){
+
+        QList<pugi::xml_node> elements;
+        QStringList currValuesList;
+        bool elementChanged=false;
+
+        UtilXmlTools::loadXmlFile(this->filesToProcess[i],this->document,this->rootNode,this->backupsEnabled, "replace-value");
+
+        UtilXmlTools::getAllNamedElements(this->rootNode,elements,this->filters);
+
+        for(int j=0; j<elements.size(); j++){
+            currValuesList=Util::qStringListFromSpacedString(Util::toQString(elements[j].text().as_string())); // convert each element in a list (uses space as separator)
+
+            for(int k=0; k<currValuesList.size(); k++){
+                if(currValuesList[k]==oldValue){ // Found a match with the old value?
+                    currValuesList[k]=newValue; // If found replace it with the new value
+                    elementChanged=true;
+                }
+            }
+
+            if(elementChanged){ // If curr element changed update the XML
+                elements[j].text()=currValuesList.join(" ").toLatin1().constData();
+            }
+            elementChanged=false;
+        }
+
+        UtilXmlTools::saveXmlFile(this->filesToProcess[i],this->document, "replace-value");
+    }
+
+    UtilXmlTools::displaySuccessMessage(this->filesToProcess.size(), "replace-value");
+}
+
+// Replaces all current values of an element by another (can be specified only specific positions)
+void XmlTools::replaceAll(QString value, QString valuePositions){
+
+    // Process all XmlFiles
+    for(int i=0; i<this->filesToProcess.size(); i++){
+
+        QList<pugi::xml_node> elements;
+
+        UtilXmlTools::loadXmlFile(this->filesToProcess[i],this->document,this->rootNode,this->backupsEnabled, "replace-all");
+
+        UtilXmlTools::getAllNamedElements(this->rootNode,elements,this->filters);
+
+
+        // Let's start the override
+        for(int j=0; j<elements.size(); j++){
+            if(valuePositions!=""){
+                elements[j].text()=replaceSpecificPositions(value, Util::toQString(elements[j].text().as_string()),valuePositions).toLatin1().constData();
+            }
+            else{
+                elements[j].text()=value.toLatin1().constData();
+            }
+        }
+
+        UtilXmlTools::saveXmlFile(this->filesToProcess[i],this->document, "replace-all");
+    }
+
+    UtilXmlTools::displaySuccessMessage(this->filesToProcess.size(), "replace-all");
+}
+
+// Update a set of XML elements values based in the difference between the old and new value
+// This can be used in multiple files if the difference between one file and other are the same e.g. increment to all current object positions 100 in y (A difference of -100).
+// E.g. oldValue=5 , newValue=7; diffBetweenOldAndNewValue=-2
+void XmlTools::updateElements(QString diffBetweenOldAndNewValue){
+
+    // Process all XmlFiles
+    for(int i=0; i<this->filesToProcess.size(); i++){
+
+        QList<pugi::xml_node> elements;
+        MultiDimVar lastXmlValue(0); // inicialize with any value or dimension
+        MultiDimVar currXmlValue(0);
+        MultiDimVar newXmlValue(0); // value that will update currValue
+
+        UtilXmlTools::loadXmlFile(this->filesToProcess[i],this->document,this->rootNode,this->backupsEnabled, "update-elements");
+
+        UtilXmlTools::getAllNamedElements(this->rootNode,elements,this->filters);
+
+
+        if(elements.size()>1){
+            lastXmlValue=MultiDimVar(Util::toQString(elements[0].text().as_string())); // the lastXmlValue will begin to be the first one of the node
+            currXmlValue=MultiDimVar(Util::toQString(elements[1].text().as_string())); // the currXmlValue will begin to be the second one of the node
+            newXmlValue=MultiDimVar::sub(lastXmlValue, MultiDimVar(diffBetweenOldAndNewValue));
+            elements[0].text() = newXmlValue.toString().toLatin1().constData(); // update the first eblement with the new one already
+        }
+
+        // Let's start the node update
+        for(int j=1; j<elements.size()-1; j++){ // We start in 1 because the 0 is already saved in lastXmlValue // -1 because we will also work with the next one in the current
+
+            newXmlValue=MultiDimVar::sum(newXmlValue,MultiDimVar::sub(currXmlValue,lastXmlValue));
+            elements[j].text() = newXmlValue.toString().toLatin1().constData(); // update element with the new value
+            lastXmlValue=currXmlValue;
+            currXmlValue=MultiDimVar(Util::toQString(elements[j+1].text().as_string()));
+
+        }
+
+        // To update too last element (avoid out of bound because i+1)
+        newXmlValue=MultiDimVar::sum(newXmlValue,MultiDimVar::sub(currXmlValue,lastXmlValue));
+        elements[elements.size()-1].text() = newXmlValue.toString().toLatin1().constData(); // update element with the new value
+
+        UtilXmlTools::saveXmlFile(this->filesToProcess[i],this->document, "update-elements");
+    }
+
+    UtilXmlTools::displaySuccessMessage(this->filesToProcess.size(),"updateNode");
+
+}
+
+// Invert a set of XML elements with specified name (and optionally a parent name)
+void XmlTools::invertElements(){
+
+    // Process all XmlFiles
+    for(int i=0; i<this->filesToProcess.size(); i++){
+        UtilXmlTools::loadXmlFile(this->filesToProcess[i],this->document,this->rootNode,this->backupsEnabled, "invert-elements");
+
+        QList<pugi::xml_node> elements;
+        QStringList invertedElements; //Inverting the element order
+
+        UtilXmlTools::getAllNamedElements(this->rootNode,elements,this->filters);
+
+        // Read all elements and save to the list
+        for(int j=elements.size()-1; j>=0; j--){
+            invertedElements << Util::toQString(elements[j].text().as_string());
+        }
+
+        // Override the tree with the inverted order
+        for(int j=0; j<elements.size(); j++){
+            elements[j].text()= invertedElements[j].toLatin1().constData();
+        }
+
+        UtilXmlTools::saveXmlFile(this->filesToProcess[i],this->document, "invert-elements");
+    }
+
+    UtilXmlTools::displaySuccessMessage(this->filesToProcess.size(),"invert-elements");
+
+}
+
+// Replaces specific values (given the position) for a new value
+// [ currValues / positionsToReplaced are strings with composed by another strings space separated ]
+// Returns a new string (space separated) will values replaced
+QString XmlTools::replaceSpecificPositions(const QString &newValue, const QString &currValues, const QString &positionsToReplace){
+
+    QList<int> positionsToReplaceList;
+    QStringList currValuesList;
+
+    positionsToReplaceList=Util::qListIntFromSpacedString(positionsToReplace);
+    currValuesList=Util::qStringListFromSpacedString(currValues);
+
+    // Make some validation before the replacing
+    if(currValuesList.size()<positionsToReplaceList.size()){
+        UtilXmlTools::displayErrorMessage("replaceSpecificPositions","There are more positions to replace than the current xml values.");
+    }
+
+    foreach(int pos, positionsToReplaceList){
+        if(pos>currValuesList.size()-1 || pos < 0){ //Are positions valid for the current values? //-1 because starts at 0
+            UtilXmlTools::displayErrorMessage("replaceSpecificPositions","One or more of the specified positions to replace are out of range.");
+        }
+    }
+    //
+
+    // Finally replace the specified values
+    foreach(int pos, positionsToReplaceList){
+        currValuesList[pos]=newValue;
+    }
+
+    return currValuesList.join(" ");
+
+}
Index: XmlTools2/trunk/XmlTools/xmltools.h
===================================================================
--- XmlTools2/trunk/XmlTools/xmltools.h	(revision 905)
+++ XmlTools2/trunk/XmlTools/xmltools.h	(revision 905)
@@ -0,0 +1,43 @@
+#ifndef XMLTOOLS_H
+#define XMLTOOLS_H
+
+#define _USE_OLD_JS_ENGINE
+
+#include <string>
+#include <QtCore>
+#include <stdio.h>
+#ifdef _USE_OLD_JS_ENGINE // Needs to test each one in terms of performance... At first look seems old engine is faster for the xml parsing method used!
+#include <QScriptEngine>
+#else
+#include <QJSEngine>
+#endif
+
+#include "utilxmltools.h"
+#include "multidimvar.h"
+
+// Template got from here:
+// http://www.lubby.org/ebooks/qtconsoleapp2/qtconsoleapp2.html
+
+// The xml library used was pugixml:
+// https://code.google.com/p/pugixml/
+
+class XmlTools
+{
+public:
+    XmlTools(QString filesWildcard, XmlFilter filter, bool noBackups);
+    void addValues(QString newValues);
+    void removeValues(QString valuesToRemove);
+    void replaceValue(QString oldValue, QString newValue);
+    void replaceAll(QString value, QString valuePositions = "");
+    void updateElements(QString diffBetweenOldAndNewValue);
+    void invertElements();
+private:
+    QString replaceSpecificPositions(const QString &newValue, const QString &currValues, const QString &positionsToReplace);
+    pugi::xml_document document;
+    pugi::xml_node rootNode;
+    QStringList filesToProcess;
+    XmlFilter filters;
+    bool backupsEnabled;
+};
+
+#endif // XMLTOOLS_H
