diff --git a/src/TNL/Config/iniparser.hpp b/src/TNL/Config/iniparser.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f6a4bae1ded0f1a66b448751dc5c2cf03cdc194e
--- /dev/null
+++ b/src/TNL/Config/iniparser.hpp
@@ -0,0 +1,1504 @@
+/*==============================================================================================================/
+|                   _         _                  _   ___ _   _ ___ ____                                         |
+|                  | |    ___| | _____ _   _ ___( ) |_ _| \ | |_ _|  _ \ __ _ _ __ ___  ___ _ __                |
+|                  | |   / _ \ |/ / __| | | / __|/   | ||  \| || || |_) / _` | '__/ __|/ _ \ '__|               |
+|                  | |__|  __/   <\__ \ |_| \__ \    | || |\  || ||  __/ (_| | |  \__ \  __/ |                  |
+|                  |_____\___|_|\_\___/\__, |___/   |___|_| \_|___|_|   \__,_|_|  |___/\___|_|                  |
+|                                      |___/                                                                    |
+/===============================================================================================================/
+| All-in-one INI file parser                                                                                    |
+| Provides convenient cross-platform class to load and save .INI files                                          |
+| Extends classic INI-file format with                                                                          |
+| -> arrays (comma (',') separated values: |val1, val2, val3|)                                                  |
+| -> maps (declared as |key1:val1, key2:val2, ... , keyN:valN|)                                                 |
+| -> nested sections (Section2 is considered child of Section1, if Section2 is defined as [Section1.Section2])  |
+| -> file includes (use ";#include <file_path>" to include file with relative or full system path <file_path>)  |
+| Please look in provided file ini-test/test1.ini for extended ini examples, in test_app.cpp for usage examples |
+| Language: C++, STL used                                                                                       |
+| Version:  1.1                                                                                                 |
+/===============================================================================================================/
+| Copyright (c) 2015 by Borovik Alexey
+| MIT License
+|
+| 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 _INIPARSER_H
+#define _INIPARSER_H
+
+/*---------------------------------------------------------------------------------------------------------------/
+/ Includes
+/---------------------------------------------------------------------------------------------------------------*/
+#include <string>     // for std::string
+#include <vector>     // for std::vector
+#include <map>        // for std::map
+#include <sstream>    // for std::stringstream
+#include <algorithm>  // for std::transform
+#include <functional> // for std::not1, std::ptr_fun
+#include <cctype>     // for std::isspace()
+#include <ctype.h>    // for tolower() and toupper()
+#include <fstream>    // for std::fstream
+#include <string.h>   // for strlen()
+#include <iomanip>    // for std::setprecision
+/*---------------------------------------------------------------------------------------------------------------/
+/ Defines & Settings
+/---------------------------------------------------------------------------------------------------------------*/
+
+// Error codes
+#define INI_ERR_INVALID_FILENAME  -1   // Can't open file for reading or writing
+#define INI_ERR_PARSING_ERROR     -2   // File parse error
+
+// INI file syntax can be changed here
+// NOTE: When saving INI files first characters of provided arrays are used
+
+/// Each of the characters in this string opens section
+#define INI_SECTION_OPEN_CHARS   "[{"
+/// Each of the characters in this string closes section
+#define INI_SECTION_CLOSE_CHARS  "]}"
+/// Each of the characters in this string starts comment
+#define INI_COMMENT_CHARS         ";#"
+/// Each of the characters in this string separates entry's name from entry's value
+#define INI_NAME_VALUE_SEP_CHARS "=:"
+/// Each of the characters in this string when found last in input line tells that next line
+/// should be considered as current line's continuation
+#define INI_MULTILINE_CHARS         "\\/"
+
+// Delimiter of values in array
+#define INI_ARRAY_DELIMITER         ','
+// Symbol, opening the segment of array (INI_ARRAY_DELIMITER in segment is not considered as delimiter)
+#define INI_ARRAY_SEGMENT_OPEN      '{'
+// Symbol, closing the segment of array
+#define INI_ARRAY_SEGMENT_CLOSE     '}'
+// Escape character in INI file (INI_ARRAY_SEGMENT_OPEN and INI_ARRAY_SEGMENT_CLOSE if found inside
+// elements of array and maps should be escaped for proper parsing)
+#define INI_ESCAPE_CHARACTER        '\\'
+// Symbol, separating key from value in map
+#define INI_MAP_KEY_VAL_DELIMETER   ':'
+// Delimiter, separating parent name from child name in section full name
+#define INI_SUBSECTION_DELIMETER    '.'
+// Delimiter to separate section name from value name when getting value directly from file
+#define INI_SECTION_VALUE_DELIMETER ':'
+
+// Inclusion line
+// Please note, that inclusion command must appear in comment section (i.e. ;INI_INCLUDE_SEQ)
+#define INI_INCLUDE_SEQ "#include "
+
+// Path delimiter
+#ifdef WIN32
+#    define SYSTEM_PATH_DELIM '\\'
+#else
+#    define SYSTEM_PATH_DELIM '/'
+#endif
+
+/*---------------------------------------------------------------------------------------------------------------/
+/ Auxiliaries
+/---------------------------------------------------------------------------------------------------------------*/
+
+// All parser-related stuff is in INI namespace
+namespace INI
+{
+    /// String to lower case
+    static inline void string_to_lower(std::string& str)
+    {
+        std::transform(str.begin(), str.end(), str.begin(), ::tolower);
+    }
+
+    /// String to upper case
+    static inline void string_to_upper(std::string& str)
+    {
+        std::transform(str.begin(), str.end(), str.begin(), ::toupper);
+    }
+
+    /// stream to be used for conversions
+    class convstream: public std::stringstream
+    {
+    public:
+        convstream() {*this << std::setprecision(17) << std::boolalpha;}
+    };
+
+    /// Convert anything (int, double etc) to string
+    template<class T> std::string t_to_string(const T& i)
+    {
+        convstream ss;
+        std::string s;
+        ss << i;
+        s = ss.str();
+        return s;
+    }
+    /// Special case for string (to avoid overheat)
+    template<> inline std::string t_to_string<std::string>(const std::string& i)
+    { 
+        return i; 
+    }
+
+    /// Convert string to anything (int, double, etc)
+    template<class T> T string_to_t(const std::string& v)
+    {
+        convstream ss;
+        T out;
+        ss << v;
+        ss >> out;
+        return out;
+    }
+    /// Special case for string
+    template<> inline std::string string_to_t<std::string>(const std::string& v)
+    {
+        return v;
+    }
+    /// Special case for boolean value
+    /// std::boolalpha only covers 'true' or 'false', while we have more cases
+    template<> inline bool string_to_t<bool>(const std::string& v)
+    {
+        if (!v.size())
+            return false;
+        if (v[0] == '1' || v[0] == 't' || v[0] == 'T' || v[0] == 'Y' || v[0] == 'y')
+            return true;
+        return false;
+    }
+
+    // Calling isspace with signed chars in Visual Studio causes assert failure in DEBUG builds
+    // This hack is approved by MS itself
+#if defined (_MSC_VER)
+    static inline int __in_isspace(int ch) {return std::isspace((unsigned char)ch);}
+#else
+#    define __in_isspace std::isspace
+#endif
+
+    // Trim string from start
+    static inline std::string &ltrim(std::string &s) {
+        s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(__in_isspace))));
+        return s;
+    }
+
+    // Trim string from end
+    static inline std::string &rtrim(std::string &s) {
+        s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(__in_isspace))).base(), s.end());
+        return s;
+    }
+
+    // Trim string from both ends
+    static inline std::string &trim(std::string &s) {
+        return ltrim(rtrim(s));
+    }
+
+    /// Split strings (and trim result) based on the provided separator
+    /// Strings in the vector would be trimmed as well
+    static inline std::vector<std::string> split_string(const std::string& str, const std::string& sep)
+    {
+        std::vector<std::string> lst;
+        if (str.empty())
+            return lst;
+        size_t cur_pos = 0;
+        size_t prev_pos = 0;
+        for (; ; cur_pos+=sep.size(),prev_pos = cur_pos)
+        {
+            cur_pos = str.find(sep,cur_pos);
+            if (cur_pos == std::string::npos)
+                break;
+            std::string out = str.substr(prev_pos,cur_pos-prev_pos);
+            trim(out);
+            lst.push_back(out);
+        }
+        std::string out = str.substr(prev_pos);
+        trim(out);
+        lst.push_back(out);
+        return lst;
+    }
+
+    /// Join array of strings into one with specified separator
+    static inline std::string join_string(const std::vector<std::string>& array, const std::string& sep)
+    {
+        std::string ret;
+        if (!array.size())
+            return ret;
+        for (size_t i = 0; i < array.size()-1; i++)
+            ret += array.at(i) + sep;
+        ret += array.at(array.size()-1);
+        return ret;
+    }
+
+    /// Test whether provided char is in the charset
+    static inline bool char_is_one_of(int ch, const char* charset)
+    {
+        for (const char* it = charset; *it != '\0'; ++it)
+            if (ch == *it)
+                return true;
+        return false;
+    }
+
+    // Replace every occurrence of @param what to @param ret in @param str
+    static inline std::string& str_replace(std::string& str, const std::string& what, const std::string& rep)
+    {
+        int diff = rep.size() - what.size() + 1;
+        for (size_t pos = 0; ;pos += diff)
+        {
+            pos = str.find(what.c_str(),pos);
+            if (pos == std::string::npos)
+                break;
+            str.replace(pos,what.size(),rep);
+        }
+        return str;
+    }
+
+    // normalize path (for relative path to be system-independent)
+    static inline void normalize_path(std::string& path)
+    {
+#ifdef WIN32
+        str_replace(path,"/","\\");
+#else
+        str_replace(path,"\\","/");
+#endif
+    }
+
+    // get file path (excluding file name)
+    static inline std::string file_path(const std::string& file_fullname)
+    {
+        size_t pos = file_fullname.rfind(SYSTEM_PATH_DELIM);
+        if (pos == std::string::npos)
+            return std::string();
+        return file_fullname.substr(0,pos);
+    }
+
+    // get file name (excluding file path)
+    static inline std::string file_name(const std::string& file_fullname)
+    {
+        size_t pos = file_fullname.rfind(SYSTEM_PATH_DELIM);
+        if (pos == std::string::npos)
+            return file_fullname;
+        return file_fullname.substr(pos+1);
+    }
+
+    // check whether path is absolute
+    static inline bool path_is_absolute(const std::string& path)
+    {
+#ifdef WIN32
+        if (path.size() < 2)
+            return false;
+        // absolute filenames should start with drive letter (i.e. c:) 
+        // or network path (\\)
+        if (path[1] == ':' || (path[0] == '\\' && path[1] == '\\'))
+            return true;
+        return false;
+#else
+        // everything is simple under POSIX: absolute path should start with /
+        if (path.size() < 1)
+            return false;
+        if (path[0] == '/')
+            return true;
+        return false;
+#endif
+    }
+
+    // check whether path is relative
+    static inline bool path_is_relative(const std::string& path) {return !path_is_absolute(path);}
+
+    /*---------------------------------------------------------------------------------------------------------------/
+    / INI-related classes
+    /---------------------------------------------------------------------------------------------------------------*/
+
+    // forward declarations
+    class Value;
+    class Array;
+    class Map;
+    class Section;
+    class File;
+    typedef std::vector<Section*> SectionVector;
+    
+    /**
+      * Reference-counting helper class
+      * This should be used as a member in reference-counting classes Value, Array and Map
+    **/
+    template<class T> class RefCountPtr
+    {
+    public:
+        RefCountPtr():_ptr(NULL){}
+        RefCountPtr(const RefCountPtr& cp):_ptr(cp._ptr) {Increment();}
+        RefCountPtr(const T& val):_ptr(NULL){_ptr = new refcont(val);}
+        virtual ~RefCountPtr() {Decrement();}
+        RefCountPtr& operator= (const RefCountPtr& rt)
+        {
+            Decrement();
+            _ptr = rt._ptr;
+            Increment();
+            return *this;
+        }
+        bool operator== (const RefCountPtr& val) const
+        {
+            if (_ptr == val._ptr)
+                return true;
+            if (!_ptr || !val._ptr)
+                return false;
+            return _ptr->val == val._ptr->val;
+        }
+        bool operator!= (const Value& val) const { return !(*this == val);}
+        bool IsValid() const {return (_ptr != NULL);}
+        T* DataPtr() {return (_ptr==NULL?NULL:&_ptr->val);}
+        const T* DataPtr() const { return (_ptr==NULL?NULL:&_ptr->val);}
+        T& Data() {return _ptr->val;}
+        const T& Data() const {return _ptr->val;}
+        T DataObj(const T& defval = T()) const {return (_ptr==NULL?defval:_ptr->val);}
+        T* operator->() {return DataPtr();}
+        const T* operator->() const {return DataPtr();}
+        void Copy()
+        {
+            if (!_ptr)
+                _ptr = new refcont();
+            else if (_ptr->count > 1)
+            {
+                refcont* cp = new refcont(_ptr->val);
+                Decrement();
+                _ptr = cp;
+            }
+        }
+    private:
+        void Decrement()
+        {
+            if (!_ptr)
+                return;
+            _ptr->count--;
+            if (!_ptr->count)
+            {
+                delete(_ptr);
+                _ptr = NULL;
+            }
+        }
+        void Increment()
+        {
+            if (_ptr)
+                _ptr->count++;
+        }
+        struct refcont
+        {
+            refcont() :count(1) {}
+            refcont(const T& pval) :val(pval), count(1) {}
+            T val;
+            size_t count;
+        };
+        refcont* _ptr;
+    };
+
+    /**
+      * Value to be stored in INI-file
+      * This is a simple reference-counting class, storing a pointer to original string
+      * It has some functions for easy converting to\from other types
+      * Value can contain array (in string representation) and be converted to\from it 
+    **/
+    class Value
+    {
+    public:
+        Value(){}
+        Value(const Value& cp):_val(cp._val){}
+        template<class T> Value(const T& val){Set(val);}
+        Value(const char* value){Set(value);}
+        virtual ~Value(){}
+
+        Value& operator= (const Value& rt) {_val = rt._val; return *this;}
+        template<class T> Value& operator= (const T& value) { Set(value); return *this;}
+        bool operator== (const Value& rgh) const { return _val == rgh._val;}
+        bool operator!= (const Value& val) const { return !(*this == val);}
+        bool operator< (const Value& rgh) const
+        {
+            if (!_val.IsValid())
+                return true;
+            if (!rgh._val.IsValid())
+                return false;
+            return (_val.Data() < rgh._val.Data());
+        }
+
+        /// Template function to convert value to any type
+        template<class T> T Get() const { return string_to_t<T>(_val.DataObj());}
+        void Set(const std::string& str) { _val = RefCountPtr<std::string>(str); }
+        /// Template function to set value
+        template<class T> void Set(const T& value) { Set(t_to_string(value)); }
+        // const char* (as any pointer) is defaulting in template to int or bool, which is not what we want
+        void Set(const char* value) { _val = RefCountPtr<std::string>(std::string(value)); }
+
+        /// Converts Value to std::string
+        std::string AsString() const { return _val.DataObj();}
+        /// Converts Value to integer
+        int AsInt() const {return Get<int>();}
+        /// Converts Value to double
+        double AsDouble() const {return Get<double>();}
+        /// Converts Value to boolean
+        bool AsBool() const {return Get<bool>();}
+        /// Converts Value to Array
+        Array AsArray() const;
+        /// Converts Value to Map
+        Map AsMap() const;
+        /// Converts Value to specified type T
+        template<class T> T AsT() const {return Get<T>();}
+
+    private:
+        RefCountPtr<std::string> _val;
+    };
+
+    /**
+      * Array of Values
+      * Reference-counting class
+    **/
+    class Array
+    {
+    public:
+        Array(){}
+        Array(const Array& cp) :_val(cp._val){}
+        Array(const std::string& str, char sep = INI_ARRAY_DELIMITER, char seg_open = INI_ARRAY_SEGMENT_OPEN,
+              char seg_close = INI_ARRAY_SEGMENT_CLOSE, char esc = INI_ESCAPE_CHARACTER)
+        {
+            FromString(str,sep,seg_open,seg_close,esc);
+        }
+        template<class T> Array(const std::vector<T>& vect){FromVector(vect);} 
+        virtual ~Array() {}
+
+        Array& operator= (const Array& rt) {_val = rt._val; return *this;}
+        Array& operator<< (const Value & val) { return PushBack(val);}
+        /// Returns reference to value on specified position @param pos
+        /// Array is automatically widen (if needed) for that operation to always succeed
+        Value& operator[] (size_t pos)
+        {
+            _val.Copy();
+            if (pos >= _val->size())
+                _val->insert(_val->end(),pos-_val->size()+1,Value());
+            return _val.Data()[pos];
+        }
+
+        /// Gets value with specified position @param pos
+        /// If @param pos is >= Size() returns @param def_val
+        Value GetValue(size_t pos, const Value& def_val = Value()) const
+        {
+            if (!_val.IsValid())
+                return def_val;
+            if (pos >= _val->size())
+                return def_val;
+            return _val->at(pos);
+        }
+        /// Sets value @param value to specified position @param pos
+        /// Array is automatically widen (if needed) to allow this operation 
+        void SetValue(size_t pos, const Value& value)
+        {
+            _val.Copy();
+            if (pos >= _val->size())
+            {
+                _val->insert(_val->end(),pos-_val->size(),Value());
+                _val->push_back(value);
+            }
+            else
+                _val->at(pos) = value;
+        }
+        /// Adds @param val to the end of the Array
+        Array& PushBack(const Value& val) 
+        {
+            _val.Copy();
+            _val->push_back(val); 
+            return *this;
+        }
+        /// Returns array size
+        size_t Size() const { if (!_val.IsValid()) return 0; return _val->size(); }
+        
+        /// Formats string with all values of this array represented as strings, separated by @param sep
+        std::string ToString(char sep = INI_ARRAY_DELIMITER, char seg_open = INI_ARRAY_SEGMENT_OPEN,
+                             char seg_close = INI_ARRAY_SEGMENT_CLOSE, char esc = INI_ESCAPE_CHARACTER) const
+        {
+            std::string ret;
+            if (!_val.IsValid())
+                return ret;
+            for (size_t i = 0; i < _val->size(); i++)
+            {
+                std::string tmp = _val->at(i).AsString();
+                std::string out;
+                bool has_delim = false;
+                for (size_t j = 0; j < tmp.size(); j++)
+                {
+                    if (tmp[j] == seg_open || tmp[j] == seg_close)
+                        out.push_back(esc);
+                    else if (tmp[j] == sep)
+                        has_delim = true;
+                    out.push_back(tmp[j]);
+                }
+                if (has_delim)
+                    ret += seg_open + out + seg_close;
+                else
+                    ret += out;
+                if (i != _val->size()-1)
+                    ret += sep;
+            }
+            return ret;
+        }
+        /// Fills array with values from string @param str, separated by @param sep
+        void FromString(const std::string& str, char sep = INI_ARRAY_DELIMITER, 
+                        char seg_open  = INI_ARRAY_SEGMENT_OPEN,
+                        char seg_close = INI_ARRAY_SEGMENT_CLOSE, char esc = INI_ESCAPE_CHARACTER)
+        {
+            _val.Copy();
+            _val->clear();
+            if (str.empty())
+                return;
+            std::string cur_str;
+            int segm_cnt = 0;
+            bool escaped = false;
+            int preesc = 0;
+            for (size_t i = 0; i <= str.size(); ++i)
+            {
+                if (escaped && i < str.size())
+                {
+                    cur_str.push_back(str[i]);
+                    escaped = false;
+                    if (str[i] == esc)
+                        preesc = 2;
+                }
+                else if ((i == str.size()) || (str[i] == sep && !segm_cnt))
+                {
+                    trim(cur_str);
+                    _val->push_back(cur_str);
+                    cur_str.clear();
+                }
+                else if (str[i] == seg_open && !preesc)
+                {
+                    if (segm_cnt)
+                        cur_str.push_back(str[i]);
+                    segm_cnt++;
+                }
+                else if (str[i] == seg_close && !preesc)
+                {
+                    segm_cnt--;
+                    if (segm_cnt < 0)
+                        segm_cnt = 0;
+                    if (segm_cnt)
+                        cur_str.push_back(str[i]);
+                }
+                else if (str[i] == esc)
+                    escaped = true;
+                else
+                    cur_str.push_back(str[i]);
+                if (preesc)
+                    preesc--;
+            }
+        }
+        template<class T> std::vector<T> ToVector() const
+        {
+            std::vector<T> ret;
+            if (!_val.IsValid())
+                return ret;
+            for (size_t i = 0; i < _val->size(); ++i)
+                ret.push_back(_val->at(i).AsT<T>());
+            return ret;
+        }
+        template<class T> void FromVector(const std::vector<T>& vect)
+        {
+            _val.Copy();
+            _val->clear();
+            for (size_t i = 0; i < vect.size(); ++i)
+                _val->push_back(Value(vect.at(i)));
+        }
+        /// Converts Array to Value
+        Value ToValue() const
+        {
+            return Value(ToString());
+        }
+        /// Gets Array from Value
+        void FromValue(const Value& val)
+        {
+            FromString(val.AsString());
+        }
+    private:
+        RefCountPtr<std::vector<Value> > _val;
+    };
+
+    template<> inline void Value::Set<Array> (const Array& value)
+    {
+        Set(value.ToString());
+    }
+    template<> inline Array Value::Get<Array>() const
+    {
+        if (!_val.IsValid())
+            return Array();
+        return Array(_val.Data());
+    }
+    inline Array Value::AsArray() const {return Get<Array>();}
+
+    /**
+      * Map of Values
+      * Reference-counting class
+    **/
+    class Map
+    {
+    public:
+        Map(){}
+        Map(const Map& cp) :_val(cp._val){}
+        Map(const std::string& str, char sep = INI_ARRAY_DELIMITER, char seg_open = INI_ARRAY_SEGMENT_OPEN,
+              char seg_close = INI_ARRAY_SEGMENT_CLOSE, char kval = INI_MAP_KEY_VAL_DELIMETER,
+              char esc = INI_ESCAPE_CHARACTER)
+        {
+            FromString(str,sep,seg_open,seg_close,kval,esc);
+        }
+        template<class T, class M> Map(const std::map<T,M>& mp){FromMap(mp);} 
+        virtual ~Map(){}
+        Map& operator= (const Map& rt) {_val = rt._val; return *this;}
+        /// Returns reference to value of the specified key @param key
+        /// Map is automatically inserts entry for this operation to always succeed
+        Value& operator[] (const Value& key)
+        {
+            _val.Copy();
+            return _val.Data()[key];
+        }
+
+        /// Gets value for specified key @param key
+        /// If there is no specified key - returns @param def_val
+        Value GetValue(const Value& key, const Value& def_val = Value()) const
+        {
+            if (!_val.IsValid())
+                return def_val;
+            std::map<Value,Value>::const_iterator it = _val->find(key);
+            if (it == _val->end())
+                return def_val;
+            return it->second;
+        }
+        /// Sets value @param value to specified key @param key
+        void SetValue(const Value& key, const Value& value)
+        {
+            _val.Copy();
+            std::pair<std::map<Value,Value>::iterator,bool> res = 
+                _val->insert(std::pair<Value,Value>(key,value));
+            if (!res.second)
+                res.first->second = value;
+        }
+        /// Returns map size
+        size_t Size() const { if (!_val.IsValid()) return 0; return _val->size();}
+
+
+        /// Formats string with all values of this map
+        std::string ToString(char sep = INI_ARRAY_DELIMITER, char seg_open = INI_ARRAY_SEGMENT_OPEN,
+                             char seg_close = INI_ARRAY_SEGMENT_CLOSE, char kval = INI_MAP_KEY_VAL_DELIMETER, 
+                             char esc = INI_ESCAPE_CHARACTER) const
+        {
+            std::string ret;
+            if (!_val.IsValid())
+                return ret;
+            for (std::map<Value,Value>::const_iterator it = _val->begin(); it != _val->end(); ++it)
+            {
+                if (it != _val->begin())
+                    ret += sep;
+                std::string key = it->first.AsString();
+                std::string out_key;
+                std::string val = it->second.AsString();
+                std::string out_val;
+                // key
+                bool has_delim = false;
+                for (size_t j = 0; j < key.size(); j++)
+                {
+                    if (key[j] == seg_open || key[j] == seg_close)
+                        out_key.push_back(esc);
+                    else if (key[j] == kval || key[j] == sep)
+                        has_delim = true;
+                    out_key.push_back(key[j]);
+                }
+                if (has_delim)
+                    out_key = seg_open + out_key + seg_close;
+                // value
+                has_delim = false;
+                for (size_t j = 0; j < val.size(); j++)
+                {
+                    if (val[j] == seg_open || val[j] == seg_close)
+                        out_val.push_back(esc);
+                    else if (val[j] == kval || val[j] == sep)
+                        has_delim = true;
+                    out_val.push_back(val[j]);
+                }
+                if (has_delim)
+                    out_val = seg_open + out_val + seg_close;
+                // pair
+                ret += out_key + kval + out_val;
+            }
+            return ret;
+        }
+        /// Fills map with values from string @param str
+        void FromString(const std::string& str, char sep = INI_ARRAY_DELIMITER, 
+                        char seg_open  = INI_ARRAY_SEGMENT_OPEN,
+                        char seg_close = INI_ARRAY_SEGMENT_CLOSE, char kval = INI_MAP_KEY_VAL_DELIMETER,
+                        char esc = INI_ESCAPE_CHARACTER)
+        {
+            _val.Copy();
+            _val->clear();
+            if (str.empty())
+                return;
+            std::string cur_str;
+            std::string cur_key;
+            int segm_cnt = 0;
+            bool escaped = false;
+            int preesc = 0;
+            for (size_t i = 0; i <= str.size(); ++i)
+            {
+                if (escaped && i < str.size())
+                {
+                    cur_str.push_back(str[i]);
+                    escaped = false;
+                    if (str[i] == esc)
+                        preesc = 2;
+                }
+                else if ((i==str.size()) || (str[i] == sep && !segm_cnt))
+                {
+                    trim(cur_str);
+                    std::pair<std::map<Value,Value>::iterator,bool> res = 
+                        _val->insert(std::pair<Value,Value>(Value(cur_key),Value(cur_str)));
+                    if (!res.second)
+                        res.first->second = cur_str;
+                    cur_str.clear();
+                    cur_key.clear();
+                }
+                else if (str[i] == kval && !segm_cnt)
+                {
+                    trim(cur_str);
+                    cur_key = cur_str;
+                    cur_str.clear();
+                }
+                else if (str[i] == seg_open && !preesc)
+                {
+                    if (segm_cnt)
+                        cur_str.push_back(str[i]);
+                    segm_cnt++;
+                }
+                else if (str[i] == seg_close && !preesc)
+                {
+                    segm_cnt--;
+                    if (segm_cnt < 0)
+                        segm_cnt = 0;
+                    if (segm_cnt)
+                        cur_str.push_back(str[i]);
+                }
+                else if (str[i] == esc)
+                    escaped = true;
+                else
+                    cur_str.push_back(str[i]);
+                if (preesc)
+                    preesc--;
+            }
+        }
+        template<class T, class M> std::map<T,M> ToMap() const
+        {
+            std::map<T,M> ret;
+            if (!_val.IsValid())
+                return ret;
+            for (std::map<Value,Value>::iterator it = _val->begin(); it != _val->end(); ++it)
+                ret.insert(std::pair<T,M>(it->first.AsT<T>(),it->second.AsT<M>()));
+            return ret;
+        }
+        template<class T, class M> void FromMap(const std::map<T,M>& mp)
+        {
+            _val.Copy();
+            _val->clear();
+            for (typename std::map<T,M>::const_iterator it = mp.begin(); it != mp.end(); ++it)
+                _val->insert(std::pair<Value,Value>(Value(it->first),Value(it->second)));
+        }
+        /// Converts Array to Value
+        Value ToValue() const
+        {
+            return Value(ToString());
+        }
+        /// Gets Array from Value
+        void FromValue(const Value& val)
+        {
+            FromString(val.AsString());
+        }
+    private:
+        RefCountPtr<std::map<Value,Value> > _val;
+    };
+
+    template<> inline void Value::Set<Map> (const Map& value)
+    {
+        Set(value.ToString());
+    }
+    template<> inline Map Value::Get<Map>() const
+    {
+        if (!_val.IsValid())
+            return Map();
+        return Map(_val.Data());
+    }
+    inline Map Value::AsMap() const {return Get<Map>();}
+
+    /*---------------------------------------------------------------------------------------------------------------/
+    / INI file creation and parsing
+    /---------------------------------------------------------------------------------------------------------------*/
+
+    /**
+      * One section of the ini-file
+      * This can be created by INIFile class only
+    **/
+    class Section
+    {
+        friend class File;
+        typedef std::map<std::string, Value> EntryMap;
+        typedef std::pair<std::string,Value> EntryPair;
+        typedef std::map<std::string, std::string> CommentMap;
+        typedef std::pair<std::string, std::string> CommentPair;
+    /*-----------------------------------------------------------------------------------------------------------/
+    / General functions & iterators
+    /-----------------------------------------------------------------------------------------------------------*/
+    public:
+        typedef EntryMap::iterator values_iter;
+        typedef EntryMap::const_iterator const_values_iter;
+        values_iter ValuesBegin() {return _entries.begin();}
+        const_values_iter ValuesBegin() const {return _entries.begin();}
+        values_iter ValuesEnd() {return _entries.end();}
+        const_values_iter ValuesEnd() const {return _entries.end();}
+        size_t ValuesSize() const {return _entries.size();}
+
+        /// Returns full section name (subsection name will contain '.', separating subsection part)
+        const std::string& FullName() const { return _name;}
+        /// Return section name (will be parsed to get individual section name)
+        std::string Name() const
+        {
+            return _name.substr(_name.rfind(INI_SUBSECTION_DELIMETER)+1);
+        }
+        /// Get comment, associated with this section (written before the line with the section, or after it)
+        std::string Comment() const {return _comment;}
+        /// Return all keys in this section
+        std::vector<std::string> GetSectionKeys() const
+        {
+            std::vector<std::string> keys;
+            for (EntryMap::const_iterator it = _entries.begin(); it != _entries.end(); it++)
+                keys.push_back(it->first);
+            return keys;
+        }
+        /// Get Value
+        Value GetValue(const std::string& key, const Value& def_value = Value()) const
+        {
+            EntryMap::const_iterator it = _entries.find(key);
+            if (it == _entries.end())
+                return def_value;
+            return it->second;
+        }
+        /// Set Value
+        void SetValue(const std::string& key, const Value& val, const std::string& comment = std::string())
+        {
+            _entries[key] = val;
+            if (!comment.empty())
+                _comments[key] = comment;
+        }
+        /// Set Value to array
+        void SetArrayValue(const std::string& key, size_t pos, const Value& val)
+        {
+            Array ar = GetValue(key).AsArray();
+            ar.SetValue(pos,val);
+            SetValue(key,ar);
+        }
+        /// Remove value
+        void RemoveValue(const std::string& key)
+        {
+            EntryMap::iterator it = _entries.find(key);
+            if (it == _entries.end())
+                return;
+            _entries.erase(it);
+        }
+        /// Get comment, associated with provided value
+        std::string GetComment(const std::string& key) const
+        {
+            CommentMap::const_iterator it = _comments.find(key);
+            if (it == _comments.end())
+                return std::string();
+            return it->second;
+        }
+        /// Set comment for specified key
+        void SetComment(const std::string& key, const std::string& comment)
+        {
+            _comments[key] = comment;
+        }
+        /// Save the section's contents to specified stream
+        void Save(std::ostream& stream) const;
+    /*-----------------------------------------------------------------------------------------------------------/
+    / Parent & child parsing
+    /-----------------------------------------------------------------------------------------------------------*/
+    public:
+        Section* FindParent() const;
+        Section* GetParent();
+        Section* FindSubSection(const std::string& name) const;
+        Section* GetSubSection(const std::string& name);
+        SectionVector FindSubSections() const;
+    /*-----------------------------------------------------------------------------------------------------------/
+    / Internal contents
+    /-----------------------------------------------------------------------------------------------------------*/
+    private:
+        /// Only INI::File can create sections
+        Section(File* file, const std::string& name, const std::string& comment = std::string()):
+           _file(file),_name(name),_comment(comment){}
+        /// Class should be copied only by File class to properly handle _file
+        Section(const Section& cp):_file(cp._file),_name(cp._name),_comment(cp._comment),_entries(cp._entries),
+            _comments(cp._comments){}
+        File*       _file;                   // file, this section is associated with
+        std::string _name;                 // name of the section
+        std::string _comment;              // comment to the section
+        EntryMap    _entries;              // all entries in the section
+        CommentMap  _comments;             // all comments, associated with values in the section
+    };
+
+    /**
+      * Main class of the parser
+      * Provides way to load and save ini-files, as well as
+      * setting specific values in them
+    **/
+    class File
+    {
+    public:
+        /// Sections stores all values and comments inside them
+        typedef std::map<std::string, Section*> SectionMap;
+        typedef std::pair<std::string, Section*> SectionPair;
+        typedef SectionMap::iterator          sections_iter;
+        typedef SectionMap::const_iterator    const_sections_iter;
+        /// Result of previous parse operation
+        struct PResult
+        {
+            PResult():error_code(0),error_line_num(0){}
+            void Set(int code, int line_num = 0, const std::string& line = std::string())
+            {
+                error_code = code;
+                error_line_num = line_num;
+                error_line = line;
+            }
+            void Invalidate() {error_code = 0; error_line_num = 0; error_line.clear();}
+            std::string GetErrorDesc() const
+            {
+                if (!error_code)
+                    return "No error";
+                if (error_code == INI_ERR_INVALID_FILENAME)
+                    return std::string("Failed to open file ") + file_name + "!";
+                if (error_code == INI_ERR_PARSING_ERROR)
+                    return std::string("Parse error in file ") + file_name + " on line ą" 
+                    + t_to_string(error_line) + ": \"" + error_line + "\""; 
+                return "Unknown error!";
+            }
+            int error_code;         // code of the error. 0 if no error
+            int error_line_num;     // number of line with the error
+            std::string error_line; // line with error
+            std::string file_name;  // name of the file with error (will be empty for stream)
+            operator bool() const {return !error_code;}
+        };
+    public:
+        File(){}
+        File(const std::string& fname) { Load(fname);}
+        File(const File& lf) { CopyFrom(lf); }
+        File& operator= (const File& lf) { Unload(); CopyFrom(lf); return *this; }
+        void CopyFrom(const File& lf)
+        {
+            for (SectionMap::const_iterator it = lf._sections.begin(); it != lf._sections.end(); it++)
+            {
+                Section* sect = new Section(*it->second);
+                sect->_file = this;
+                _sections.insert(SectionPair(it->first,sect));
+            }
+            _result = lf._result;
+        }
+        virtual ~File() {Unload();}
+    /*---------------------------------------------------------------------------------------------------------------/
+    / Section & values manipulations
+    /---------------------------------------------------------------------------------------------------------------*/
+    public:
+        /// A way to iterate through all sections
+        /// Section pointer can be accesed as SectionMap::iterator::second, section name - as ::first
+        size_t SectionsSize() const {return _sections.size();}
+        sections_iter SectionsBegin() {return _sections.begin();}
+        const_sections_iter SectionsBegin() const {return _sections.begin();}
+        sections_iter SectionsEnd() {return _sections.end();}
+        const_sections_iter SectionsEnd() const {return _sections.end();}
+
+        /// Get value from the file
+        /// Use INI_SECTION_VALUE_DELIMETER to separate section name from value name
+        Value GetValue(const std::string& name, const Value& def_val = Value())
+        {
+            size_t pos = name.rfind(INI_SECTION_VALUE_DELIMETER);
+            std::string nm;
+            if (pos != std::string::npos)
+                nm = name.substr(0,pos);
+            SectionMap::iterator it = _sections.find(nm);
+            if (it == _sections.end())
+                return def_val;
+            return it->second->GetValue(name.substr(pos+1),def_val);
+        }
+
+        /// Set value to the file
+        /// Use INI_SECTION_VALUE_DELIMETER to separate section name from value name
+        void SetValue(const std::string& name, const Value& value, const std::string& comment = std::string())
+        {
+            size_t pos = name.rfind(INI_SECTION_VALUE_DELIMETER);
+            std::string nm;
+            if (pos != std::string::npos)
+                nm = name.substr(0,pos);
+            Section* sect = GetSection(nm);
+            sect->SetValue(name.substr(pos+1),value,comment);
+        }
+
+        /// Set array Value to array
+        void SetArrayValue(const std::string& key, size_t pos, const Value& val)
+        {
+            Array ar = GetValue(key).AsArray();
+            ar.SetValue(pos,val);
+            SetValue(key,ar);
+        }
+
+        /// Returns pointer to section with specified name
+        /// If section does not exists - creates it
+        Section* GetSection(const std::string& name)
+        {
+            SectionMap::iterator it = _sections.find(name);
+            if (it != _sections.end())
+                return it->second;
+            Section* sc = new Section(this,name);
+            _sections.insert(SectionPair(name,sc));
+            return sc;
+        }
+
+        /// Find existing section by name
+        /// @return pointer to existing section or NULL
+        Section* FindSection(const std::string& name) const
+        {
+            SectionMap::const_iterator it = _sections.find(name);
+            if (it == _sections.end())
+                return NULL;
+            return it->second;
+        }
+
+        /// Deletes section with specified name
+        void DeleteSection(const std::string& name)
+        {
+            SectionMap::iterator it = _sections.find(name);
+            if (it != _sections.end())
+                _sections.erase(it);
+        }
+
+        /// Get subsection of specified section with specified name
+        Section* FindSubSection(const Section* sect, const std::string& name) const
+        {
+            return FindSection(sect->FullName() + INI_SUBSECTION_DELIMETER + name);
+        }
+
+        /// If subsection does not exists, creates it
+        Section* GetSubSection(Section* sect, const std::string& name)
+        {
+            return GetSection(sect->FullName() + INI_SUBSECTION_DELIMETER + name);
+        }
+
+        /// Get parent section of the specified section
+        Section* FindParentSection(const Section* sect) const
+        {
+            size_t pos = sect->FullName().rfind(INI_SUBSECTION_DELIMETER);
+            std::string nm;
+            if (pos != std::string::npos)
+                nm = sect->FullName().substr(0,pos);
+            return FindSection(nm);
+        }
+        /// Get parent section (created if needed)
+        Section* GetParentSection(const Section* sect)
+        {
+            size_t pos = sect->FullName().rfind(INI_SUBSECTION_DELIMETER);
+            std::string nm;
+            if (pos != std::string::npos)
+                nm = sect->FullName().substr(0,pos);
+            return GetSection(nm);
+        }
+        /// Find subsections of the specified section
+        SectionVector FindSubSections(const Section* sect) const
+        {
+            SectionVector ret;
+            if (sect->_file != this)
+                return ret;
+            for (SectionMap::const_iterator it = _sections.begin(); it != _sections.end(); ++it)
+            {
+                if (it->second == sect)
+                    continue;
+                if (it->first.find(sect->FullName() + INI_SUBSECTION_DELIMETER) != std::string::npos)
+                    ret.push_back(it->second);
+            }
+            return ret;
+        }
+        // Get top-level sections (not child of any other sections)
+        SectionVector GetTopLevelSections() const
+        {
+            SectionVector ret;
+            for (SectionMap::const_iterator it = _sections.begin(); it != _sections.end(); ++it)
+            {
+                if (it->first.find(INI_SUBSECTION_DELIMETER) == std::string::npos)
+                    ret.push_back(it->second);
+            }
+            return ret;
+        }
+    /*---------------------------------------------------------------------------------------------------------------/
+    / Load & Save functions
+    /---------------------------------------------------------------------------------------------------------------*/
+    public:
+        /// Load file from input stream, that must be properly opened and prepared for reading
+        /// Set @param unload_prev to true for unloading any stuff currently in memory before loading 
+        /// Set @param rpath to be used as relative path when searching for inclusions in files
+        /// @return 1 if load succeeds, 0 if not
+        /// in case load was not succesfull you can access extended information by calling ParseResult()
+        int Load(std::istream& stream, bool unload_prev = false, const std::string& rpath = std::string())
+        {
+            if (unload_prev)
+                DeleteSections(_sections);
+            return ParseStream(stream,"",rpath,_sections);
+        }
+        /// Load ini from file in system
+        /// Set @param unload_prev to false for not unloading any stuff currently in memory before loading 
+        int Load(const std::string& fname, bool unload_prev = true)
+        {
+            _result.file_name = fname;
+            normalize_path(_result.file_name);
+            std::ifstream file(_result.file_name.c_str(), std::ios::in);
+            if (!file.is_open())
+            {
+                _result.Set(INI_ERR_INVALID_FILENAME);
+                return 0;
+            }
+            return Load(file,unload_prev,file_path(_result.file_name));
+        }
+
+        /// Save ini file to stream
+        void Save(std::ostream& stream) const
+        {
+            SaveStream(stream,_sections); 
+        }
+
+        /// Save ini file to file
+        int Save(const std::string& fname)
+        {
+            _result.file_name = fname;
+            normalize_path(_result.file_name);
+            std::ofstream file(_result.file_name.c_str(), std::ios::out);
+            if (!file.is_open())
+            {
+                _result.Set(INI_ERR_INVALID_FILENAME);
+                return 0;
+            }
+            SaveStream(file,_sections);
+            return 1;
+        }
+
+        /// Save only one section to specifed stream
+        void Save(std::ostream& stream, const Section* sect) const
+        {
+            SectionMap mp;
+            mp.insert(SectionPair(sect->FullName(),const_cast<Section*>(sect)));
+            SaveStream(stream,mp);
+        }
+
+        /// Adds comment line to provided stream
+        /// For it to be not associated with anything you should add newline after it
+        static void AddCommentToStream(std::ostream& stream, const std::string& str)
+        {
+            std::vector<std::string> ar = split_string(str,"\n");
+            for (size_t i = 0; i < ar.size(); i++)
+                stream << INI_COMMENT_CHARS[0] << ar.at(i) << std::endl;
+        }
+
+        /// Adds inclusion line to stream
+        static void AddIncludeToStream(std::ostream& stream, const std::string& path)
+        {
+            stream << INI_COMMENT_CHARS[0] << INI_INCLUDE_SEQ << path << std::endl;
+        }
+
+        /// Unload memory
+        void Unload()
+        {
+            DeleteSections(_sections);
+        }
+        /// Return last operation result
+        const PResult& LastResult() {return _result;}
+    /*---------------------------------------------------------------------------------------------------------------/
+    / Parsing & Saving internals
+    /---------------------------------------------------------------------------------------------------------------*/
+    protected:
+        enum LineType
+        {
+            EMPTY,
+            SECTION,
+            ENTRY,
+            COMMENT,
+            ERROR
+        };
+
+        /**
+          * Parse input line
+          * Line must be concatenated (if needed) and trimmed before passing to this function
+          * @param input_line - Line to parse
+          * @param section - will contain section name in case SECTION return
+          * @param key - will contain key in case ENTRY return
+          * @param value - will contain value in case ENTRY return
+          * @param comment - will contain comment in case of return != EMPTY and != ERROR
+          * @return type of the parsed line
+        **/
+        LineType ParseLine(const std::string& input_line, std::string& section, 
+                           std::string& key, std::string& value, std::string& comment) const
+        {
+            LineType ret = EMPTY;
+            size_t last_pos = input_line.npos;
+            if (input_line.empty())
+                return ret;
+            // comment parsing
+            if (char_is_one_of(input_line.at(0),INI_COMMENT_CHARS))
+            {
+                ret = COMMENT;
+                // Can't do it that way, cause of 'initialization of non-const reference of type from a temporary of type'
+                // stupid GCC rule
+                //comment = trim(input_line.substr(1));
+                comment = input_line.substr(1);
+                trim(comment);
+                return ret;
+            }
+            // section parsing
+            else if (char_is_one_of(input_line.at(0),INI_SECTION_OPEN_CHARS))
+            {
+                last_pos = input_line.find_first_of(INI_SECTION_CLOSE_CHARS);
+                if (last_pos == input_line.npos)
+                    return ERROR;
+                ret = SECTION;
+                section = input_line.substr(1,last_pos-1);
+                trim(section);
+                last_pos++;
+            }
+            // key-value pair parsing
+            else
+            {
+                size_t pos = input_line.find_first_of(INI_NAME_VALUE_SEP_CHARS);
+                // not section, not comment, not empty - error
+                if (pos == input_line.npos || pos == input_line.size()-1)
+                    return ERROR;
+                ret = ENTRY;
+                key = input_line.substr(0,pos);
+                trim(key);
+                last_pos = input_line.find_first_of(INI_COMMENT_CHARS,pos+1);
+                value = input_line.substr(pos+1,last_pos-pos-1);
+                trim(value);
+                if (last_pos != input_line.npos)
+                    last_pos--;
+            }
+            // get associated comment
+            last_pos = input_line.find_first_of(INI_COMMENT_CHARS,last_pos);
+            if (last_pos != input_line.npos)
+            {
+                comment = input_line.substr(last_pos+1);
+                trim(comment);
+            }
+            return ret;
+        }
+
+        /// Parse provided input stream to specified section map
+        /// Comments separated from closest section or key-value pair by 1 or more empty strings
+        /// would be ignored
+        /// Default section will be created if needed
+        int ParseStream(std::istream& stream, const std::string& def_section, 
+                        const std::string& rpath, SectionMap& pmap)
+        {
+            Section* cur_sect = NULL;
+            std::string pcomment;
+            std::string prev_line;
+            _result.Invalidate();
+
+            // Find whether default section already exists in provided map
+            // if not - it will be created later if needed
+            SectionMap::iterator it = pmap.find(def_section);
+            if (it != pmap.end())
+                cur_sect = it->second;
+
+            for (int lnc = 1; !stream.eof(); lnc++)
+            {
+                std::string line;
+                std::getline(stream,line);
+                trim(line);
+                if (line.empty())
+                {
+                    pcomment.clear();
+                    continue;
+                }
+                // Handle multiline strings
+                if (char_is_one_of(line.at(line.size()-1),INI_MULTILINE_CHARS))
+                {
+                    prev_line = prev_line + line.substr(0,line.size()-1);
+                    continue;
+                }
+                else if (!prev_line.empty())
+                {
+                    line = prev_line + line;
+                    prev_line.clear();
+                }
+                std::string section_key, value, comment;
+                LineType lt = ParseLine(line,section_key,section_key,value,comment);
+                if (lt == EMPTY)
+                {
+                    pcomment.clear();
+                    continue;
+                }
+                else if (lt == ERROR)
+                {
+                    _result.Set(INI_ERR_PARSING_ERROR,lnc,line);
+                    return 0;
+                }
+                // Handle inclusion
+                else if (lt == COMMENT && comment.substr(0,strlen(INI_INCLUDE_SEQ)) == INI_INCLUDE_SEQ)
+                {
+                    std::string incname = comment.substr(strlen(INI_INCLUDE_SEQ));
+                    trim(incname);
+                    normalize_path(incname);
+                    // try to open file
+                    std::string fpath;
+                    if (path_is_relative(incname) && !rpath.empty())
+                        fpath = rpath + SYSTEM_PATH_DELIM + incname;
+                    else
+                        fpath = incname;
+                    std::ifstream file(fpath.c_str(), std::ios::in);
+                    std::string prevfn = _result.file_name;
+                    _result.file_name = fpath;
+                    if (!file.is_open())
+                    {
+                        _result.Set(INI_ERR_INVALID_FILENAME,lnc,line);
+                        return 0;
+                    }
+                    std::string scname; 
+                    if (cur_sect)
+                        scname = cur_sect->FullName();
+                    else
+                        scname = def_section;
+                    if (!ParseStream(file,scname,file_path(fpath),pmap))
+                        return 0;
+                    _result.file_name = prevfn;
+                    continue;
+                }
+                // Add comment (it can be set with any string type, other than EMPTY and ERROR)
+                pcomment += comment;
+                // Add section (or modify comment of existing one if needed)
+                if (lt == SECTION)
+                {
+                    SectionMap::iterator it = pmap.find(section_key);
+                    if (it == pmap.end())
+                    {
+                        cur_sect = new Section(this,section_key,pcomment);
+                        pmap.insert(SectionPair(section_key, cur_sect));
+                    }
+                    else
+                    {
+                        cur_sect = it->second;
+                        if (!pcomment.empty())
+                        {
+                            if (!it->second->_comment.empty())
+                                it->second->_comment += stream.widen('\n') + pcomment;
+                            else
+                                it->second->_comment = pcomment;
+                        }
+                    }
+                    pcomment.clear();
+                }
+                else if (lt == ENTRY)
+                {
+                    // Try to create default section if it is not already in the array
+                    if (!cur_sect)
+                    {
+                        cur_sect = new Section(this,def_section);
+                        pmap.insert(SectionPair(def_section, cur_sect));
+                    }
+                    cur_sect->SetValue(section_key,value,pcomment);
+                    pcomment.clear();
+                }
+            }
+            // Clears eof flag for future usage of stream
+            stream.clear();
+            return 1;
+        }
+        /// Save provided section map to stream
+        void SaveStream(std::ostream& stream, const SectionMap& pmap) const
+        {
+            for (SectionMap::const_iterator it = pmap.begin(); it != pmap.end(); ++it)
+            {
+                if (it->second->ValuesSize() == 0)
+                    continue;
+                if (!it->second->Comment().empty())
+                    AddCommentToStream(stream,it->second->Comment());
+                if (!it->first.empty())
+                    stream << INI_SECTION_OPEN_CHARS[0] << it->first << INI_SECTION_CLOSE_CHARS[0] << std::endl;
+                for (Section::values_iter vit = it->second->ValuesBegin(); vit != it->second->ValuesEnd(); vit++)
+                {
+                    stream << vit->first << " " << INI_NAME_VALUE_SEP_CHARS[0] << " " << vit->second.AsString();
+                    std::string cmn = it->second->GetComment(vit->first);
+                    if (!cmn.empty())
+                        stream << " " << INI_COMMENT_CHARS[0] << cmn;
+                    stream << std::endl;
+                }
+                stream << std::endl;
+            }
+        }
+    private:
+        void DeleteSections(SectionMap& mp)
+        {
+            for (SectionMap::iterator it = mp.begin(); it != mp.end(); ++it)
+                delete(it->second);
+            mp.clear();
+        }
+        // All sections (including subsections) in one map
+        SectionMap        _sections;
+        PResult       _result;
+    };
+
+    /*-----------------------------------------------------------------------------------------------------------/
+    / Some functions left unimplemented
+    /-----------------------------------------------------------------------------------------------------------*/
+    inline Section* Section::GetParent() {return _file->GetParentSection(this);}
+    inline Section* Section::FindParent() const {return _file->FindParentSection(this);}
+    inline Section* Section::GetSubSection(const std::string& name) {return _file->GetSubSection(this,name);}
+    inline Section* Section::FindSubSection(const std::string& name) const {return _file->FindSubSection(this,name);}
+    inline SectionVector Section::FindSubSections() const {return _file->FindSubSections(this);}
+    inline void Section::Save(std::ostream& stream) const {return _file->Save(stream,this);}
+}
+/*---------------------------------------------------------------------------------------------------------------/
+/ Stream operators
+/---------------------------------------------------------------------------------------------------------------*/
+static inline std::ostream& operator<< (std::ostream& stream, const INI::File& file)
+{
+    file.Save(stream);
+    return stream;
+}
+static inline std::ostream& operator<< (std::ostream& stream, const INI::Section* sect)
+{
+    sect->Save(stream);
+    return stream;
+}
+static inline std::ostream& operator<< (std::ostream& stream, const INI::Array& ar)
+{
+    stream << ar.ToValue().AsString();
+    return stream;
+}
+static inline std::istream& operator>> (std::istream& stream, INI::File& file)
+{
+    file.Load(stream,false);
+    return stream;
+}
+
+/*---------------------------------------------------------------------------------------------------------------/
+/ Little tidying up
+/---------------------------------------------------------------------------------------------------------------*/
+#undef INI_SECTION_OPEN_CHARS
+#undef INI_SECTION_CLOSE_CHARS
+#undef INI_COMMENT_CHARS
+#undef INI_NAME_VALUE_SEP_CHARS
+#undef INI_MULTILINE_CHARS
+#undef INI_ARRAY_DELIMITER
+#undef INI_ARRAY_SEGMENT_OPEN
+#undef INI_ARRAY_SEGMENT_CLOSE
+#undef INI_ESCAPE_CHARACTER
+#undef INI_MAP_KEY_VAL_DELIMETER
+#undef INI_SUBSECTION_DELIMETER
+#undef INI_SECTION_VALUE_DELIMETER
+#undef INI_INCLUDE_SEQ
+#undef SYSTEM_PATH_DELIM
+// Note: error definitions are left
+
+#endif