#ifndef AL4_HEADER
#define AL4_HEADER
#define GCC_COMPILER
//#define WRITE_DIRECT
//#define _GNU_SOURCE

//------------------ do not remove this comment:
//#define TEST_STAGE
//------------------ do not remove this comment:
//#define MSVSTUDIO
//------------------ do not remove this comment:
//#define LOG_METHODS
#define LOG_METHODS_PATH
//----------------------------------------------
	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>

#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>

#ifdef MSWINDOWS
	#define WIN_GDI
	#include <windows.h>
#else
	#include <linux/limits.h>
	#define MAX_PATH PATH_MAX
	
	#include <unistd.h>
	#include <sys/types.h>
#endif

#ifdef MSVSTUDIO
	#define snprintf _snprintf
#endif


//------------------------------------------------------------------------------

typedef unsigned char byte;

class Ref_obj;
class AL4_object;
class Methods_AL4_object;

class Ref_obj
{
public:
    static int Total_Ref_obj_Count;
    AL4_object * Obj;
    int Count;

    // Is calling from New_owned() when an object is created with its 
    // exclusive owner but without a counter in its hard_link.
    //---------------------------------------------------{}
    
    Ref_obj() {}
    
    Ref_obj(AL4_object * obj, int count);

    void Ref_dec_weak();
    void Ref_dec_hard();
};

class Methods_AL4_object
{
public:

    AL4_object * THIS_OBJ;
    
    Methods_AL4_object() 
    {
    }
    
    Methods_AL4_object(AL4_object * This_obj)
    {
        THIS_OBJ = This_obj;
    }
    
    virtual void Erase();

    virtual void CONSTRUCT()
    {
    }

    virtual void DESTRUCT()
    {
    }
};

class AL4_object 
{
public:
    Methods_AL4_object* DO;
    
    Methods_AL4_object* Do()
    {
        return DO;
    }

    //just for debugging:
    static int total_obj_counter;
    int TOTAL_obj_index;
    
    // Fastest way to check if a variable is referencing the NONE
    bool Is_NONE_object;

    // Back reference to a Ref_obj, containing a hard link onto the object
    Ref_obj* hard_link;

    // Back reference to a Ref_obj, containing a weak link to the object
    Ref_obj* weak_link;

    // Additional link onto the object itself to make changes in fields.
    // For the NONE object, it is referencing the dummy_obj, so NONE is never
    // changed (though it is not necessary to check value for NONE).
    AL4_object * write;

    // Object NONE instance (single for a class)
    static Ref_obj* None_obj;

    // Object Dummy instance (single for a class)
    static Ref_obj* Dummy_obj;

    AL4_object()
    {
        Is_NONE_object = false;
        DO = new Methods_AL4_object(this);
        TOTAL_obj_index = ++total_obj_counter;
        if (TOTAL_obj_index == 999) // == 999
        {
        	int stop_by_object = 0; 
        }
    }
    
    virtual ~AL4_object() {}

    //------------- for OWNED BY children:
    std::vector<Ref_obj*> children;

    virtual Ref_obj* NONE_obj_instance()
    {
        return None_obj;
    }

    virtual AL4_object* NONE_base_obj()
    {
        return nullptr;
    }
    
    static void Object_assign_hard(Ref_obj** Dest, AL4_object* Src)
    {
        if (*Dest == NULL) return;
        Src->hard_link->Count += 2;
        (*Dest)->Ref_dec_hard();
        *Dest = Src->hard_link;
    }
    
    static void Object_assign_weak(Ref_obj** Dest, AL4_object* Src)
    {
        if (*Dest == NULL) return;
        Src->weak_link->Count += 2;
        (*Dest)->Ref_dec_weak();
        *Dest = Src->weak_link;
    }
    
    static void Object_assign_hard_noincref(Ref_obj** Dest, AL4_object* Src)
    {
        if (*Dest == NULL) return;
        (*Dest)->Ref_dec_hard();
        *Dest = Src->hard_link;
    }
    
    static void Object_assign_weak_noincref(Ref_obj** Dest, AL4_object* Src)
    {
        if (*Dest == NULL) return;
        (*Dest)->Ref_dec_weak();
        *Dest = Src->weak_link;
    }
    
    Ref_obj* Owned_by(Ref_obj* owner)
    {
        if (owner->Obj->Is_NONE_object) return hard_link;
        //if (owner->Obj->children == nullptr)
        //    owner->Obj->children = new std::vector<Ref_obj>();
        owner->Obj->children.push_back(hard_link);
        hard_link->Count |= 1;
        return hard_link;
    }
    
    static AL4_object* NoneObj_AL4_object;
    static AL4_object* DummyObj_AL4_object;
    
    static void init_class_AL4_object();
    static Ref_obj* New_nofields();
};

class Noneclass_AL4_object: public Methods_AL4_object
{
public:

    Noneclass_AL4_object()
    { }

    Noneclass_AL4_object(AL4_object* obj_this) :
          Methods_AL4_object((AL4_object*)obj_this)
    { }

};


class Any_structure : public AL4_object
{
public:
	Any_structure()
	{ }
	
	virtual Any_structure* Clone()
	{ return nullptr; }
};


class StopException : public std::exception
{
public:
    std::string Message;
	StopException(std::string msg)
	{
		Message = msg;
	}
	
	~StopException() throw()
	{
		Message = "";
	}
};

class TooDeepRecursionException : public std::exception
{
public:
    std::string Message;
    
    ~TooDeepRecursionException() throw()
    {
    	Message = "";
    }
};

typedef unsigned int INDEX;
//------------------------------------------------------------------------------

class ArrayObjHard
{
public:
	static int total_ArrayObj;
	int index_ArrayObj;
	
	static void check_index_array_obj(int index)
	{
		if (index == 4)
		{ int dummy_stop = 0; }
	}
	
	ArrayObjHard()
	{
 		index_ArrayObj = ++total_ArrayObj;
 		check_index_array_obj(index_ArrayObj);
 		none_obj = nullptr;
	}
	
	Ref_obj* none_obj;
    
    ArrayObjHard(Ref_obj* none)
    {
    	index_ArrayObj = ++total_ArrayObj;
 		check_index_array_obj(index_ArrayObj);
        none_obj = none;
    }

    virtual Ref_obj* get(INDEX index) { if (index) {} return nullptr; }
    virtual void set(INDEX index, Ref_obj* value) { if (index && value) {} }
    virtual void Add(Ref_obj* X) { if(X){} }
    virtual void Insert(INDEX index, Ref_obj* X) { if (index && X){} }
    virtual void Release_objects() { }
    virtual void Delete(INDEX index, int count_delete)
    { if((int)index < count_delete){} }
    virtual void Remove(Ref_obj* value) { if(value){} }
    virtual void Clear() { }
    virtual int Count() { return 0; }
    virtual int IndexOf(Ref_obj* value) { if(value){} return -1; }
    void Swap(INDEX e1, INDEX e2) 
    {
    	Ref_obj* v1 = get(e1);
    	Ref_obj* v2 = get(e2);
    	set(e1, v2);
    	set(e2, v1);
    }
    
    void Dispose() { Clear(); }
    bool Contains(Ref_obj* value) { return IndexOf(value) >= 0; }
    virtual ~ArrayObjHard()
    { 
        Dispose();
        none_obj = nullptr;
    }
    
    void assign_array(ArrayObjHard src)
    {
        Clear();
        int count = src.Count();
        for (int i = 0; i < count; i++)
            Add(src.get(i));
    }
    
    virtual ArrayObjHard* Clone_array()
    {
    	return nullptr;
    }
    
    
    
};

template <typename T> class AL4Array
{
protected:
    INDEX count;
    INDEX capacity;
    T * items;
    T dummy;
    bool shared;
    
    void set_capacity(INDEX new_cap)
    {
        if (new_cap < capacity) return;
        new_cap = (new_cap + 31) & ~31;
        if (items == nullptr)
        {
            items = (T *)malloc(sizeof(T) * new_cap);
            if (items == nullptr) return;
            capacity = new_cap;
            return;
        }
        T * old = items;
        items = (T *)malloc(sizeof(T) * new_cap);
        if (old == nullptr) return;
        if (items == nullptr)
        {
            items = old; return;
        }
        for (INDEX i = 0; i < count; i++)
            items[i] = old[i];
        capacity = new_cap;
        free(old);
    }
    
    void shrink()
    {
        //TODO
    }
    
public:

    AL4Array<T>() 
    { 
        items = nullptr; 
        count = 0; 
        capacity = 0; 
        dummy = (T)0; 
        shared = false;
    }
    
    AL4Array<T>( T array[], INDEX from, INDEX items_count ) //???????????????????
    {
        items = &array[from]; 
        count = items_count; 
        capacity = items_count; 
        dummy = (T)0; 
        shared = true;
    }
    
    inline T get(INDEX index)
    {
        if (index >= count) return (T)0;
        return items[index];
    }
    
    inline void set(INDEX index, T value)
    {
        if (index >= count) return;
        items[index] = value;
    }
    
    
    inline INDEX size() 
    {
    	return count;
    }
    
    void push_back(T value)
    { 
        if (count >= capacity)
        	set_capacity((capacity + 32) * 3 / 2);
        items[count++] = value;
    }
    
    void insert_direct(INDEX at_index, T value)
    {
        if (count >= capacity) set_capacity((capacity + 32) * 3 / 2);
        for (int i = count; i > (int)at_index; i--)
            items[i] = items[i-1];
        items[at_index] = value;
        count++;
    }
    
    void delete_direct(INDEX at_index, int count_delete)
    {
        for (int i = at_index; i < (int)count-count_delete; i++)
            items[i] = items[i+count_delete];
        count -= count_delete;
        if (count < capacity / 2) shrink();
    }
    
    void clear()
    {
        count = 0;
        capacity = 0;
        if (!shared) free(items);
        items = nullptr;
    }
    
    void reserve(INDEX N)
    {
        set_capacity(N);
    }
    
};

class DynAObjHard : public ArrayObjHard
{
public:
    AL4Array<Ref_obj*> List;
    
    DynAObjHard() {}
    
    DynAObjHard(Ref_obj* none) : ArrayObjHard(none)
    {
        //none_obj = none;
    }
   
    Ref_obj* get(INDEX index) override
    {
        if (index >= List.size()) return none_obj;
        return List.get(index);
    }
    
    void set(INDEX index, Ref_obj* value) override
    {
        if (index >= List.size()) return;
        Ref_obj* r = List.get(index);
        AL4_object::Object_assign_hard(&r, value->Obj);
        List.set(index, r);
    }

    void Add(Ref_obj* X) override
    {
        List.push_back(X);
        X->Obj->hard_link->Count += 2;
    }
    
    virtual void Insert_obj(INDEX index, Ref_obj* X)
    {
        if (index > List.size()) return;
        List.insert_direct(index, X);
        X->Obj->hard_link->Count += 2;
    }
    
    void Insert(INDEX index, Ref_obj* X) override
    {
        Insert_obj(index, X);
    }
    
    // Used only in case when new object is added to an array
    // of hard links, to provide correct usage Count value
    void Ref_dec_last()
    {
        if (Count() == 0) return;
        get(Count() - 1)->Ref_dec_hard();
    }

    void Release_objects() override
    {
        for (int i = (int)List.size()-1; i >= 0; i--)
        {
            Ref_obj* obj = List.get(i);
            List.set(i, nullptr);
            
            if (obj != nullptr)
                obj->Ref_dec_hard();
        }
        List.clear();
    }
    
    void Delete(INDEX index, int count_delete) override
    {
    	if (index >= List.size()) return;
    	if (index + count_delete > List.size())
    		count_delete = List.size() - index;
        if (count_delete > 0)
        {
            Ref_obj* obj = List.get(index);
            List.delete_direct(index, count_delete);
            obj->Ref_dec_hard();
        }
    }
    
    void Remove(Ref_obj* value) override
    {
        AL4_object* obj = value->Obj;
        for (int i = (int)List.size()-1; i >= 0; i--)
        {
            Ref_obj* x = List.get(i);
            if (x == nullptr) continue;
            if (x->Obj == obj)
                Delete(i, 1);
        }
    }

    void Clear() override
    {
        Release_objects();
    }

    int Count() override
    {
        return (int)List.size();
    }
    
    int IndexOf(Ref_obj* value) override
    {
        int size = (int)List.size();
        AL4_object * obj = value->Obj;
        for (int i = 0; i < size; i++)
            if (List.get(i)->Obj == obj) return i;
        return -1;
    }
    
    void Allocate(int New_size) {
    	List.reserve(New_size);
    	while ((INDEX)Count() < (INDEX)New_size)
            Add(none_obj);
    	Delete(New_size, Count() - New_size);
    }
    
    Ref_obj* Dismiss_array_item(int Index) {
    	Ref_obj* m = get(Index);
    	m->Count+=2;
    	set(Index, none_obj);
    	return m;
    }

};

class DynAObjWeak : public DynAObjHard
{
public:
    DynAObjWeak(Ref_obj* none) : DynAObjHard(none)
    {
    }

    void set(INDEX index, Ref_obj* value) override
    {
        if (index >= List.size()) return;
        Ref_obj* r = List.get(index);
        AL4_object::Object_assign_weak(&r, value->Obj);
        List.set(index, r);
    }

    void Add(Ref_obj* X) override
    {
        List.push_back(X);
        X->Obj->weak_link->Count += 2;
    }
    
    void Insert_obj(INDEX index, Ref_obj* X) override
    {
        if (index > List.size()) return;
        List.insert_direct(index, X);
        X->Obj->weak_link->Count += 2;
    }
    
    // Used only in case when new object is added to an array
    // of hard links, to provide correct usage Count value
    void Ref_dec_last()
    {
        if (Count() == 0) return;
        get(Count() - 1)->Ref_dec_hard();
    }

    void Release_objects() override
    {
        for (int i = (int)List.size()-1; i >= 0; i--)
        {
            Ref_obj* obj = List.get(i);
            List.set(i, nullptr);
            obj->Ref_dec_weak();
        }
        List.clear();
    }
    
    void Delete(INDEX index, int count_delete) override
    {
    	if (index >= List.size()) return;
    	if (index + count_delete > List.size())
    		count_delete = List.size() - index;
        if (count_delete > 0)
        {
            Ref_obj* obj = List.get(index);
            List.delete_direct(index, count_delete);
            obj->Ref_dec_weak();
        }
    }
    
    virtual ArrayObjHard* Clone_array() override
    {
    	DynAObjWeak* Result = new DynAObjWeak(none_obj);
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->Add(get(i));
    	}
    	return Result;
    }
    
};

class FixAObj : public ArrayObjHard
{
public:
    DynAObjHard* BaseList;
    int Starting;
    int Count_items;
    bool Is_slice;

    FixAObj() : ArrayObjHard() {}

    FixAObj(Ref_obj* none) : ArrayObjHard(none)
    {
        BaseList = new DynAObjHard(none);
        Starting = 0;
        Count_items = 0;
    }

    FixAObj(DynAObjHard* base_list, int From_idx, int To_idx) 
        : ArrayObjHard(base_list->none_obj)
    {
        Is_slice = true;
        BaseList = base_list;
        Starting = From_idx;
        Count_items = To_idx + 1 - From_idx;
    }

    FixAObj(FixAObj* base_list, int From_idx, int To_idx)
        : ArrayObjHard(base_list->none_obj)
    {
        Is_slice = true;
        BaseList = base_list->BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list->Starting;
    }

    ~FixAObj()
    {
        if (!Is_slice) BaseList->Clear();
        BaseList = nullptr;
    }
    
    Ref_obj* get(INDEX index) override
    {
        if (index >= (INDEX)Count_items) return BaseList->none_obj;
        return BaseList->get(Starting + index);
    }

    void set(INDEX index, Ref_obj* value) override
    {
        if (index >= (INDEX)Count_items) return;
        BaseList->set(Starting + index, value);
    }
    
    void Unref()
    {
        if (Is_slice) return;
        for (int i = Starting; i < Starting + Count_items; i++)
            set(i, BaseList->none_obj);
    }

    int Count() override 
    { 
        return Count_items;
    }

    int IndexOf(Ref_obj* Obj) override
    {
        int last = Starting + Count_items;
        for (int i = Starting; i < last; i++)
            if (BaseList->get(i)->Obj == Obj->Obj) return i;
        return -1;
    }

    void Clear() override
    {
        if (!Is_slice)
            BaseList->Clear();
        Count_items = 0;
    }

    virtual ArrayObjHard* Clone_array() override
    {
    	ArrayObjHard* Result = new FixAObj(this, 0, Count()-1);
    	return Result;
    }
    
};

//------------------------------------------------------------------------------
class ArrayInt
{
public:
    virtual int get(INDEX index) { if(index){} return 0; }
    virtual void set(INDEX index, int value) { if(index || value){} }
    virtual void Add(int X) { if(X){} }
    virtual void Insert(INDEX index, int X) { if (index || X){} }
    virtual void Release_objects() { }
    virtual void Delete(INDEX index, int count_delete)
    { if((int)index<count_delete){} }
    virtual void Remove(int value) { if(value){} }
    virtual void Clear() { }
    virtual int Count() { return 0; }
    virtual int IndexOf(int value) { if(value){} return -1; }
    void Swap(INDEX e1, INDEX e2) 
    {
    	int v1 = get(e1);
    	int v2 = get(e2);
    	set(e1, v2);
    	set(e2, v1); 
    }
    
    void Dispose() { Clear(); }
    bool Contains(int value) { return IndexOf(value) >= 0; }
    virtual ~ArrayInt()
    { 
        Dispose();        
    }
    
    void assign_array(ArrayInt src)
    {
        Clear();
        int count = src.Count();
        for (int i = 0; i < count; i++)
            Add(src.get(i));
    }
    
    virtual ArrayInt* Clone_array()
    {
    	return nullptr;
    }
    
};

class DynAInt : public ArrayInt
{
public: 
    AL4Array<int> List;

    int get(INDEX index) override
    {
        return List.get(index);
    }

    void set(INDEX index, int value) override
    {
        List.set(index, value);
    }

    void Clear() override
    {
        List.clear();
    }

    int Count() override
    {
        return List.size();
    }
    
    void Add(int value) override
    {
        List.push_back(value);
    }
    
    void Insert(INDEX index, int value) override
    {
        List.insert_direct(index, value);
    }
    
    void Delete(INDEX index, int count_delete) override
    {
    	if (index >= List.size()) return;
    	if (index + count_delete > List.size())
    		count_delete = List.size() - index;
        if (count_delete > 0)
        	List.delete_direct(index, count_delete);
    }

    void Remove(int value) override 
    { 
    	for (int i = List.size()-1; i >= 0; i--)
    		if(value == List.get(i))
    			Delete(i, 1);
    }

    int IndexOf(int value) override
    {
        int last = (int)List.size();
        for (int i = 0; i < last; i++)
            if (List.get((INDEX)i) == value)
                return i;
        return -1;
    }
    
    virtual ArrayInt* Clone_array() override
    {
    	DynAInt* Result = new DynAInt();
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->Add(get(i));
    	}
    	return Result;
    }
    
    void Allocate(int New_size) {
    	List.reserve(New_size);
    	while ((INDEX)Count() < (INDEX)New_size)
            Add(0);
    	Delete(New_size, Count() - New_size);
    }
    
};

class FixAInt : public ArrayInt
{
public:
    DynAInt* BaseList;
    INDEX Starting;
    int Count_items;
    bool Is_slice;

    FixAInt() {}

    FixAInt(INDEX N)
    {
        if (N < 0) N = 0;
        BaseList = new DynAInt();
        BaseList->List.reserve((unsigned int)N);
        for (INDEX i = 0; i < N; i++)
            BaseList->Add(0);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixAInt(int Array[], int N)
    {
        if (N < 0) N = 0;
        BaseList = new DynAInt();
        
        AL4Array<int> ints(Array, 0, N);
        
        BaseList->List = ints;
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixAInt(std::vector<int> A)
    {
        BaseList = new DynAInt();
        BaseList->List.reserve(A.size());
        int size = (int)A.size();
        for(int i = 0; i < size; i++)
            BaseList->Add(A[(unsigned int)i]);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixAInt(DynAInt* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    FixAInt(FixAInt* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list->BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list->Starting;
    }

    FixAInt(ArrayInt* base_list, int From_idx, int To_idx)
    {
        if (dynamic_cast<FixAInt*>(base_list))
        {
            Is_slice = true;
            BaseList = ((FixAInt*)base_list)->BaseList;
            Count_items = To_idx + 1 - From_idx;
            Starting = From_idx + ((FixAInt*)base_list)->Starting;
        }
        else
        {
            Is_slice = true;
            BaseList = (DynAInt*)base_list;
            Count_items = To_idx + 1 - From_idx;
            Starting = From_idx;
        }
    }

    int get(INDEX index) override
    {                
        if (index >= (INDEX)Count_items)
            return 0;
        return BaseList->get(Starting + index);
    }

    void set(INDEX index, int value) override
    {
        if (index >= (INDEX)Count_items)
            return;
        BaseList->set(Starting + index, value);
    }
    
    int Count() override 
    { return Count_items; }

    int IndexOf(int Value) override
    {
        int last = Starting + Count_items;
        for (int i = Starting; i < last; i++)
            if (BaseList->get(i) == Value) return i;
        return -1;
    }

    void Clear() override
    {
        if (!Is_slice)
            BaseList->Clear();
        Count_items = 0;
    }

    virtual ArrayInt* Clone_array() override
    {
    	FixAInt* Result = new FixAInt(Count());
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->set(i, get(i));
    	}
    	return Result;
    }
    
};

//------------------------------------------------------------------------------
class ArrayReal
{
public:
    virtual double get(INDEX index) { if(index){} return 0; }
    virtual void set(INDEX index, double value) { if (index||value){} }
    virtual void Add(double X) { if(X){} }
    virtual void Insert(INDEX index, double X) { if(index||X){} }
    virtual void Release_objects() { }
    virtual void Delete(INDEX index, int count_delete)
    { if((int)index<count_delete){} }
    //virtual void Remove(double value) { if(value){} }
    virtual void Clear() { }
    virtual int Count() { return 0; }
    virtual int IndexOf(double value) { if(value){} return -1; }
    void Swap(INDEX e1, INDEX e2) 
    {
    	double v1 = get(e1);
    	double v2 = get(e2);
    	set(e1, v2);
    	set(e2, v1); 
    }
    
    void Dispose() { Clear(); }
    bool Contains(double value) { return IndexOf(value) >= 0; }
    virtual ~ArrayReal()
    { 
        Dispose();        
    }
    
    void assign_array(ArrayReal src)
    {
        Clear();
        int count = src.Count();
        for (int i = 0; i < count; i++)
            Add(src.get(i));
    }
    
    virtual ArrayReal* Clone_array()
    {
    	return nullptr;
    }
    
};

class DynAReal : public ArrayReal
{
public:

    std::vector<double> List;
    
    double get(INDEX index) override
    {
        if (index >= (INDEX)Count()) return 0;
        return List[index];
    }
    
    void set(INDEX index, double value) override
    {
        if (index >= (INDEX)Count()) return;
        List[index] = value;
    }

    void Clear() override
    {
        List.clear();
    }

    int Count() override
    {
        return List.size();
    }
    
    void Delete(INDEX index, int count_delete) override
    {
    	if (index >= List.size()) return;
    	if (index + count_delete > List.size())
    		count_delete = List.size() - index;
        if (count_delete > 0)
            List.erase(List.begin() + index,
            		   List.begin() + index + count_delete);
    }

    void Add(double value) override
    {
        List.push_back(value);
    }
    
    void Insert(INDEX index, double value) override
    {
        if (index > List.size()) return;
        List.insert(List.begin() + index, value);
    }
    
    int IndexOf(double value) override
    {
        int last = (int)List.size();
        for (int i = 0; i < last; i++)
            if (List[(unsigned int)i] == value) return i;
        return -1;
    }
    
    virtual ArrayReal* Clone_array() override
    {
    	DynAReal* Result = new DynAReal();
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->Add(get(i));
    	}
    	return Result;
    }
    
    void Allocate(int New_size) {
    	List.reserve(New_size);
    	while ((INDEX)Count() < (INDEX)New_size)
            Add(0);
    	Delete(New_size, Count() - New_size);
    }
    
};

class FixAReal : public ArrayReal
{
public:

    DynAReal* BaseList;
    int Starting;
    int Count_items;
    bool Is_slice;

    FixAReal() 
    {
        Starting = 0;
        Count_items = 0;
        BaseList = new DynAReal();
    }

    FixAReal(int N)
    {
        if (N < 0) N = 0;
        BaseList = new DynAReal();
        BaseList->List.reserve((unsigned int)N);
        for (int i = 0; i < N; i++)
            BaseList->Add(0);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixAReal(double A[], int N)
    {
        if (N < 0) N = 0;
        BaseList = new DynAReal();
        BaseList->List.reserve((unsigned int)N);
        for (int i = 0; i < N; i++)
            BaseList->Add(A[(unsigned int)i]);
        Count_items = BaseList->Count();
        Starting = 0;
    }
    
    FixAReal(std::vector<double> A)
    {
        BaseList = new DynAReal();
        BaseList->List.reserve(A.size());
        int size = (int)A.size();
        for(int i= 0; i < size; i++)
            BaseList->Add(A[i]);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixAReal(DynAReal* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    FixAReal(FixAReal* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list->BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list->Starting;
    }

    FixAReal(ArrayReal* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
    	if (dynamic_cast<FixAReal*>(base_list))
    	{
    		BaseList = ((FixAReal*)base_list)->BaseList;
	        Count_items = To_idx + 1 - From_idx;
	        Starting = From_idx + ((FixAReal*)base_list)->Starting;
    	}
    	else
    	{
	        BaseList = (DynAReal*)base_list;
	        Count_items = To_idx + 1 - From_idx;
	        Starting = From_idx;
    	}	
    }

    double get(INDEX index) override
    {
        if (index >= (INDEX)Count_items) return 0;
        return BaseList->get(Starting + index);
    }
        
    void set(INDEX index, double value) override
    {
        if (index >= (INDEX)Count_items) return;
        BaseList->set(Starting + index, value);
    }
    
    int Count() override
    { return Count_items; }

    int IndexOf(double Value) override
    {
        int last = Starting + Count_items;
        for (int i = Starting; i < last; i++)
            if (BaseList->get(i) == Value) return i;
        return -1;
    }

    void Clear() override
    {
        if (!Is_slice)
            BaseList->Clear();
        Count_items = 0;
    }
    
    virtual ArrayReal* Clone_array() override
    {
    	FixAReal* Result = new FixAReal(Count());
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->set(i, get(i));
    	}
    	return Result;
    }
    
};

//------------------------------------------------------------------------------
class ArrayBool
{
public:
    virtual bool get(INDEX index) { if(index){} return 0; }
    virtual void set(INDEX index, bool value) { if(index||value){}  }
    virtual void Add(bool X) { if(X){} }
    virtual void Insert(INDEX index, bool X) { if(index||X){} }
    virtual void Release_objects() { }
    virtual void Delete(INDEX index, int count_delete)
    { if((int)index<count_delete){} }
    virtual void Remove(bool value) { if(value){} }
    virtual void Clear() { }
    virtual int Count() { return 0; }
    virtual int IndexOf(bool value) { if(value){} return -1; }
    void Swap(INDEX e1, INDEX e2) 
    {
    	bool v1 = get(e1);
    	bool v2 = get(e2);
    	set(e1, v2);
    	set(e2, v1); 
    }
    
    void Dispose() { Clear(); }
    bool Contains(bool value) { return IndexOf(value) >= 0; }
    virtual ~ArrayBool()
    { 
        Dispose();        
    }
    
    void assign_array(ArrayBool src)
    {
        Clear();
        int count = src.Count();
        for (int i = 0; i < count; i++)
            Add(src.get(i));
    }
    
    virtual ArrayBool* Clone_array()
    {
    	return nullptr;
    }
    
};

class DynABool : public ArrayBool
{
public:

    std::vector<bool> List;

    bool get(INDEX index) override
    {
        if (index >= (INDEX)Count()) return false;
        return List[index];
    }

    void set(INDEX index, bool value) override
    {
        if (index >= (INDEX)Count()) return;
        List[index] = value;
    }

    void Clear() override
    {
        List.clear();
    }

    int Count() override
    {
        return List.size();
    }
    
    void Delete(INDEX index, int count_delete) override
    {
    	if (index >= List.size()) return;
    	if (index + count_delete > List.size())
    		count_delete = List.size() - index;
        if (count_delete > 0)
            List.erase(List.begin() + index, 
            		   List.begin() + index + count_delete);
    }

    void Remove(bool value) override 
    { 
    	for (int i = List.size()-1; i >= 0; i--)
    		if(value == List[i])
    			Delete(i, 1);
    }

    void Add(bool value) override
    {
        List.push_back(value);
    }
    
    void Insert(INDEX index, bool value) override
    {
        if (index > List.size()) return;
        List.insert(List.begin() + index, value);
    }
    
    int IndexOf(bool value) override
    {
        int last = (int)List.size();
        for (int i = 0; i < last; i++)
            if (List[(unsigned int)i] == value) return i;
        return -1;
    }
    
    virtual ArrayBool* Clone_array() override
    {
    	DynABool* Result = new DynABool();
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->Add(get(i));
    	}
    	return Result;
    }
    
};

class FixABool : public ArrayBool
{
public:
    DynABool* BaseList;
    int Starting;
    int Count_items;
    bool Is_slice;

    FixABool() {}

    FixABool(int N)
    {
        if (N < 0) N = 0;
        BaseList = new DynABool();
        BaseList->List.reserve((unsigned int)N);
        for (int i = 0; i < N; i++)
            BaseList->Add(false);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixABool(bool A[], int N)
    {
        if (N < 0) N = 0;
        BaseList = new DynABool();
        BaseList->List.reserve((unsigned int)N);
        for (int i = 0; i < N; i++)
            BaseList->Add(A[(unsigned int)i]);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixABool(std::vector<bool> A)
    {
        BaseList = new DynABool();
        BaseList->List.reserve(A.size());
        for (int i = 0; i < (int)A.size(); i++)
            BaseList->Add(A[(unsigned int)i]);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixABool(DynABool* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    FixABool(FixABool* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list->BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list->Starting;
    }

    bool get(INDEX index) override
    {
        if (index >= (INDEX)Count_items) return false;
        return BaseList->get(Starting + index);
    }

    void set(INDEX index, bool value) override
    {
        if (index >= (INDEX)Count_items) return;
        BaseList->set(Starting + index, value);
    }
    
    int Count() override
    { 
        return Count_items; 
    }

    int IndexOf(bool Value) override
    {
        int last = Starting + Count_items;
        for (int i = Starting; i < last; i++)
            if (BaseList->get(i) == Value) return i;
        return -1;
    }

    void Clear() override
    {
        if (!Is_slice)
            BaseList->Clear();
        Count_items = 0;
    }
    
    virtual ArrayBool* Clone_array() override
    {
    	FixABool* Result = new FixABool(Count());
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->set(i, get(i));
    	}
    	return Result;
    }
    
};

//------------------------------------------------------------------------------
class ArrayByte
{
public:
    virtual byte get(INDEX index) { if(index){} return 0; }
    virtual void set(INDEX index, byte value) { if(index||value){} }
    virtual void Add(byte X) { if(X){} }
    virtual void Insert(INDEX index, byte X) { if(index||X){} }
    virtual void Release_objects() { }
    virtual void Delete(INDEX index, int count_delete)
    { if((int)index<count_delete){} }
    virtual void Remove(byte value) { if(value){} }
    virtual void Clear() { }
    virtual void Reallocate(INDEX New_size) { if(New_size){} }
    virtual int Count() { return 0; }
    virtual int IndexOf(byte value) { if(value){}  return -1; }
    void Swap(INDEX e1, INDEX e2) 
    {
    	byte v1 = get(e1);
    	byte v2 = get(e2);
    	set(e1, v2);
    	set(e2, v1); 
    }
    
    void Dispose() { Clear(); }
    bool Contains(byte value) { return IndexOf(value) >= 0; }
    virtual ~ArrayByte()
    { 
        Dispose();        
    }
    
    virtual byte* FirstByte() { return nullptr; }
    
    void assign_array(ArrayByte src)
    {
        Clear();
        int count = src.Count();
        for (int i = 0; i < count; i++)
            Add(src.get(i));
    }
    
    virtual ArrayByte* Clone_array()
    {
    	return nullptr;
    }
    
};

class DynAByte : public ArrayByte
{
public:

    std::vector<byte> List;

    virtual byte get(INDEX index) override
    {
        if (index >= (INDEX)Count())
            return 0;
        return List[index];
    }
    
    virtual void set(INDEX index, byte value) override
    {
        if (index >= (INDEX)Count()) return;
        List[index] = value;
    }

    virtual void Clear() override
    {
        List.clear();
    }
    
    void Reallocate(INDEX New_size) override
    {
        if ((INDEX)Count() >= New_size) return;
        List.reserve(New_size);
        while ((INDEX)Count() < New_size)
            List.push_back((byte)0);
    }
    
    virtual int Count() override
    {
        return List.size();
    }
    
    void Add(byte value) override
    {
        List.push_back(value);
    }

    void Insert(INDEX index, byte value) override
    {
        if (index > List.size()) return;
        List.insert(List.begin() + index, value);
    }

    void Delete(INDEX index, int count_delete) override
    {
    	if (index >= List.size()) return;
    	if (index + count_delete > List.size())
    		count_delete = List.size() - index;
        if (count_delete > 0)
            List.erase(List.begin() + index,
            		   List.begin() + index + count_delete);
    }

    void Remove(byte value) override 
    { 
    	for (int i = List.size()-1; i >= 0; i--)
    		if(value == List[i])
    			Delete(i, 1);
    }

    virtual int IndexOf(byte value) override
    {
        int last = (int)List.size();
        for (int i = 0; i < last; i++)
            if (List[(unsigned int)i] == value) return i;
        return -1;
    }
    
    byte* FirstByte() override 
    { 
        return &List[0];
    }
    
    virtual ArrayByte* Clone_array() override
    {
    	DynAByte* Result = new DynAByte();
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->Add(get(i));
    	}
    	return Result;
    }
    
    void Allocate(int New_size) {
    	List.reserve(New_size);
    	while ((INDEX)Count() < (INDEX)New_size)
            Add((byte)0);
    	Delete(New_size, Count() - New_size);
    }
    
};

class FixAByte_OnArray : public DynAByte
{
public:

    byte* Array;
    INDEX Array_size;
    
    FixAByte_OnArray() {}
    
    FixAByte_OnArray(byte* A, INDEX size) 
    {
        Array = A;
        Array_size = size;
    }

    byte get(INDEX index) override
    {
        if (index >= (INDEX)Count()) return 0;
        return Array[index];
    }
    
    void set(INDEX index, byte value) override
    {
        if (index >= (INDEX)Count()) return;
        Array[index] = value;
    }

    void Clear() override
    {
        Array_size = 0;
    }
    
    int Count() override
    {
        return Array_size;
    }
    
    int IndexOf(byte value) override
    {
        int size = Count();
        for (int i = 0; i < size; i++)
            if (Array[(unsigned int)i] == value) return i;
        return -1;
    }
    
    byte* FirstByte() override 
    { 
        return Array;
    }
    
};

class FixAByte : public ArrayByte
{
public: 
    DynAByte* BaseList;
    INDEX Starting;
    int Count_items;
    bool Is_slice;

    FixAByte() {}

    FixAByte(int N)
    {
        if (N < 0) N = 0;
        BaseList = new DynAByte();
        BaseList->List.reserve((unsigned int)N);
        for (int i = 0; i < N; i++)
            BaseList->Add(0);
        Count_items = BaseList->Count();
        Starting = 0;
    }
    
    FixAByte(byte* Array, int size)
    {
        if (size < 0) size = 0;
        BaseList = new FixAByte_OnArray(Array, size);
        Starting = 0;
        Count_items = size;
        Is_slice = true;
    }
    
    FixAByte(std::vector<byte> A)
    {
        BaseList = new DynAByte();
        BaseList->List.reserve(A.size());
        for (int i = 0; i < (int)A.size(); i++)
            BaseList->Add(A[(unsigned int)i]);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixAByte(ArrayByte* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
        if (dynamic_cast<DynAByte*>(base_list))
            BaseList = (DynAByte*)base_list;
        else
        {
            BaseList = ((FixAByte*)base_list) -> BaseList;
            Starting += ((FixAByte*)base_list) -> Starting;
        }
    }

    byte get(INDEX index) override
    {
        if (index >= (INDEX)Count_items) return 0;
        return BaseList->get(Starting + index);
    }
        
    void set(INDEX index, byte value) override
    {
        if (index >= (INDEX)Count_items) return;
        BaseList->set(Starting + index, value);
    }
    
    int Count() override
    { 
        return Count_items; 
    }

    int IndexOf(byte Value) override
    {
        int last = Starting + Count_items;
        for (int i = Starting; i < last; i++)
            if (BaseList->get(i) == Value) return i;
        return -1;
    }

    void Clear() override
    {
        if (!Is_slice)
            BaseList->Clear();
        Count_items = 0;
    }
    
    byte* FirstByte() override 
    { 
        return &BaseList->FirstByte()[Starting];
    }
    
    virtual ArrayByte* Clone_array() override
    {
    	FixAByte* Result = new FixAByte(Count());
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->set(i, get(i));
    	}
    	return Result;
    }
    
};

//------------------------------------------------------------------------------
class ArrayStr
{
public:
	static int total_ArrayStr;
	int index_ArrayStr;
	ArrayStr()
	{
		index_ArrayStr = ++total_ArrayStr;
	}
	
public:
    virtual std::string get(INDEX index) { if(index){} return std::string(""); }
    virtual void set(INDEX index, std::string value) 
    { if(index||(value == std::string(""))){} }
    virtual void Add(std::string X) { if(X == std::string("")){} }
    virtual void Insert(INDEX index, std::string X) 
    { if(index||(X == std::string(""))){} }
    virtual void Release_objects() { }
    virtual void Delete(INDEX index, int count_delete)
    { if((int)index<count_delete){} }
    virtual void Remove(std::string value) { if(value == std::string("")){} }
    virtual void Clear() { }
    virtual int Count() { return 0; }
    virtual int IndexOf(std::string value) 
    { if(value == std::string("")){} return -1; }
    void Swap(INDEX e1, INDEX e2) 
    {
    	std::string v1 = get(e1);
    	std::string v2 = get(e2);
    	set(e1, v2);
    	set(e2, v1); 
    }
    
    void Dispose() { Clear(); }
    bool Contains(std::string value) { return IndexOf(value) >= 0; }
    virtual ~ArrayStr()
    { 
        Dispose();      
    }
    
    void assign_array(ArrayStr src)
    {
        Clear();
        for (int i = 0; i < src.Count(); i++)
            Add(src.get(i));
    }
    
    virtual ArrayStr* Clone_array()
    {
    	return nullptr;
    }
    
};

class DynAStr : public ArrayStr
{
public:

    std::vector<std::string> Array;
    int fCount;
    
	DynAStr()
	{
		fCount = 0;
	}
	
    std::string get(INDEX index) override
    {
        if (index >= (INDEX)Count())
        	return std::string("");
        return Array[index];
    }
    
    void set(INDEX index, std::string value) override
    {
        if (index >= (INDEX)Count()) return;
        Array[index] = value;
    }

    void Clear() override
    {
        Array.clear();
        fCount = 0;
    }

    int Count() override
    {
        return fCount;
    }
    
    void Add(std::string value) override
    {
        if (fCount >= (int)Array.size())
        	Insert(fCount, value);
        else
        {
        	Array[fCount++] = value;
        }
    }

    void Insert(INDEX index, std::string value) override
    {
        if (index > (INDEX)fCount) return;
    	if ((INDEX)fCount == Array.size())
    	{
    		int n = fCount / 4;
    		if (n == 0) n = 1;
    		if (n > 1024) n = 1024;
    		Array.reserve(n);
    	}
        Array.insert(Array.begin() + index, value);
    	fCount++;
    }

    void Delete(INDEX index, int count_delete) override
    {
    	if (index >= Array.size()) return;
    	if (index + count_delete > Array.size())
    		count_delete = Array.size() - index;
        if (count_delete > 0)
        {
	        Array.erase(Array.begin() + index,
	        			Array.begin() + index + count_delete);
	    	fCount -= count_delete;
        }
    }
    
    void Remove(std::string value) override 
    { 
    	for (int i = fCount-1; i >= 0; i--)
    		if(value == Array[i])
    			Delete(i, 1);
    }

    int IndexOf(std::string value) override
    {
    	for (int i = 0; i < fCount; i++)
    		if (Array[i] == value) return i;
        return -1;
    }
    
    virtual ArrayStr* Clone_array() override
    {
    	DynAStr* Result = new DynAStr();
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->Add(get(i));
    	}
    	return Result;
    }
    
    void Allocate(int New_size) {
    	Array.reserve(New_size);
    	while ((INDEX)Count() < (INDEX)New_size)
            Add("");
    	Delete(New_size, Count() - New_size);
    }
    
};

class FixAStr : public ArrayStr
{
public:
    DynAStr* BaseList;
    INDEX Starting;
    int Count_items;
    bool Is_slice;

    FixAStr(int N)
    {
        if (N < 0) N = 0;
        BaseList = new DynAStr();
        BaseList->Array.reserve(N);
        for (int i = 0; i < N; i++)
        	BaseList->Add(std::string(""));
        Starting = 0;
        Count_items = BaseList->Count();
    }

    FixAStr(std::string A[], int N)
    {
        if (N < 0) N = 0;
        BaseList = new DynAStr();
        BaseList->Array.reserve(N);
        for (int i = 0; i < N; i++)
            BaseList->Add(A[i]);
        Starting = 0;
        Count_items = BaseList->Count();
    }

    FixAStr(std::vector<std::string> A)
    {
        BaseList = new DynAStr();
        BaseList->Array.reserve(A.size());
        int size = (int)A.size();
        for (int i = 0; i < size; i++)
            BaseList->Add(A[i]);
        Starting = 0;
        Count_items = BaseList->Count();
    }

    FixAStr(DynAStr* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    FixAStr(ArrayStr* base_list, int From_idx, int To_idx)
    {
    	if (dynamic_cast<FixAStr*>(base_list)) {
	        Is_slice = true;
	        BaseList = ((FixAStr*)base_list)->BaseList;
	        Count_items = To_idx + 1 - From_idx;
	        Starting = From_idx + ((FixAStr*)base_list)->Starting;
    	}
    	else {
	        Is_slice = true;
	        BaseList = (DynAStr*)base_list;
	        Count_items = To_idx + 1 - From_idx;
	        Starting = From_idx;
    	}
    }

    FixAStr(FixAStr* base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list->BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list->Starting;
    }

    std::string get(INDEX index) override
    {
        if (index >= (INDEX)Count_items)
        return std::string("");
        return BaseList->get(Starting + index);
    }
    
    void set(INDEX index, std::string value) override
    {
        if (index >= (INDEX)Count_items) return;
        BaseList->set(Starting + index, value);
    }

    int Count() override
    { 
        return Count_items;
    }

    int IndexOf(std::string Value) override
    {
        int last = Starting + Count_items;
        for (int i = Starting; i < last; i++)
            if (BaseList->get(i) == Value) return i;
        return -1;
    }

    void Set_strings(const char** Values)
    {
        int last = Starting + Count_items;
        for (int i = Starting; i < last; i++)
        {
        	std:: string s = *Values;
        	BaseList->Array[i] = s;
            Values++;
        }
    }
    
    void Clear() override
    {
        if (!Is_slice)
            BaseList->Clear();
        Count_items = 0;
    }
    
    virtual ArrayStr* Clone_array() override
    {
    	FixAStr* Result = new FixAStr(Count());
    	for (int i = 0; i < Count(); i++)
    	{
    		Result->set(i, get(i));
    	}
    	return Result;
    }
    
};

//------------------------------------------------------------------------------
class ArrayRec
{
public:
    INDEX rec_size;
    byte* dummy_rec;
    
    ArrayRec()
    {
        rec_size = 0;
        dummy_rec = nullptr; //(byte *)malloc(1);
    }
    
    ArrayRec(INDEX r_size)
    {
        rec_size = r_size;
        dummy_rec = (byte *)malloc(r_size);
    }

    virtual byte* get(INDEX index) { if(index){} return nullptr; }
    virtual void set(INDEX index, byte* value) { if(index||value){} }
    virtual void Add(byte* X) { if(X){} }
    virtual void Insert(INDEX index, byte* X) { if(index||X){} }
    virtual void Release_objects() { }
    virtual void Delete(INDEX index, int count_delete)
    { if((int)index<count_delete){} }
    //virtual void Remove(byte* value) { if(value){} }
    virtual void Clear() { }
    virtual int Count() { return 0; }
    
    void Dispose() { Clear(); }
    virtual ~ArrayRec()
    {
        Dispose();
        if(dummy_rec != nullptr) free(dummy_rec);
        dummy_rec = nullptr;
    }
    
    void assign_array(ArrayRec src)
    {
        Clear();
        if (src.rec_size != rec_size) return;
        int count = src.Count();
        for (int i = 0; i < count; i++)
            Add(src.get(i));
    }
    
};

class DynARec : public ArrayRec
{
public:

    std::vector<byte*> List;
    
    DynARec() : ArrayRec()
    {
    }
    
    DynARec(INDEX r_size) : ArrayRec(r_size)
    {
        rec_size = r_size;
        dummy_rec = (byte *)malloc(r_size);
    }
    
    byte* get(INDEX index) override
    {
        if (index >= (INDEX)Count()) return dummy_rec;
        return List[index];
    }
    
    void set(INDEX index, byte* value) override
    {
        if (index >= (INDEX)Count()) return;
        memmove(List[index], value, rec_size);
    }

    int Count() override
    {
        return List.size();
    }
    
    void Add(byte* value) override
    {
        byte* rec = (byte*)malloc(rec_size);
        memmove(rec, value, rec_size);
        List.push_back(rec);
    }

    void Insert(INDEX index, byte* value) override
    {
        if (index > List.size()) return;
        byte* rec = (byte*)malloc(rec_size);
        memmove(rec, value, rec_size);
        List.insert(List.begin() + index, rec);
    }

	void Delete(INDEX index, int count_delete) override
    {
    	if (index >= List.size()) return;
    	if (index + count_delete > List.size())
    		count_delete = List.size() - index;
    	for (int i = index+count_delete-1; i>=(int)index; i--)
    	{
        	free(List[i]);
            List.erase(List.begin() + i);
    	}
    }    

    virtual void Clear() override
    {
        int size = (int)List.size();
        for(int i = 0; i < size; i++)
        {
            free(List[(unsigned int)i]);
        }
        List.clear();
    }
    
    byte* Dismiss_array_item(int Index) {
    	byte* m = get(Index);
    	set(Index, dummy_rec);
    	return m;
    }
    
};

class FixARec : public ArrayRec
{
public:
    DynARec* BaseList;
    INDEX Starting;
    int Count_items;
    bool Is_slice;

    FixARec()
    {
        BaseList = new DynARec(1);
        Starting = 0;
        Count_items = 0;
        }
    
    FixARec(INDEX rec_size) : ArrayRec(rec_size)
    {
        BaseList = new DynARec(rec_size);
        Starting = 0;
        Count_items = rec_size;
    }

    FixARec(std::vector<byte*> A, INDEX rec_size) : ArrayRec(rec_size)
    {
        BaseList = new DynARec(rec_size);
        BaseList->List.reserve(A.size());
        int size = (int)A.size();
        for (int i = 0; i < size; i++)
            BaseList->Add(A[i]);
        Count_items = BaseList->Count();
        Starting = 0;
    }

    FixARec(DynARec* base_list, INDEX From_idx, INDEX To_idx)
        : ArrayRec(base_list->rec_size)
    {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    FixARec(FixARec* base_list, INDEX From_idx, INDEX To_idx)
        : ArrayRec(base_list->rec_size)
    {
        Is_slice = true;
        BaseList = base_list->BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list->Starting;
    }
    
    FixARec(ArrayRec* base_list, INDEX From_idx, INDEX To_idx)
        : ArrayRec(base_list->rec_size)
    {
        if (dynamic_cast<FixARec*>(base_list))
        {
            Is_slice = true;
            BaseList = ((FixARec*)base_list)->BaseList;
            Count_items = To_idx + 1 - From_idx;
            Starting = From_idx + ((FixARec*)base_list)->Starting;
            return;
        }
        Is_slice = true;
        BaseList = (DynARec*)base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }
    
    byte* get(INDEX index) override
    {
        if (index >= (INDEX)Count_items)
            return BaseList->dummy_rec;
        return BaseList->get(Starting + index);
    }
        
    void set(INDEX index, byte* value) override
    {
        if (index >= (INDEX)Count_items) return;
        BaseList->set(Starting + index, value);
    }
    
    int Count() override
    { return Count_items; }

    void Clear() override
    {
        if (!Is_slice)
            BaseList->Clear();
        Count_items = 0;
    }
};
//------------------------------------------------------------------------------


    
class Errors_store
{
public:

	char* Messages[10];
	int Count_messages;

	void Add_error(const std::string& Message)
	{
		char* msg_text = (char *)malloc(Message.length()+1);
        strcpy(msg_text, &Message[0]);
		if (Count_messages < 10)
		{
			Messages[Count_messages++] = msg_text;
			return;
		}
		free(Messages[4]);
		Messages[4] = NULL;
		for (int i = 5; i < Count_messages-1; i++)
			Messages[i] = Messages[i+1];
		Messages[Count_messages-1] = msg_text;
	}
};

class AL4_handler
{
public:
	virtual void Handler()
	{
	}
};




class AL4_system
{
public:
	static std::vector<std :: string> Parameters;
	
    static FixABool* Native_array_to_fixed_array_var(FixABool* Dest, bool* Bools,
        int size)
    {
        Dest = new FixABool(Bools, size);
        return Dest;
    }

    static FixAByte* Native_array_to_fixed_array_var(FixAByte* Dest, byte* Bytes,
        int size)
    {
        Dest = new FixAByte(Bytes, size);
        return Dest;
    }
    
    static FixAInt* Native_array_to_fixed_array_var(FixAInt* Dest, int* Ints,
        int size)
    {
        Dest = new FixAInt(Ints, size);
        return Dest;
    }
    
    static FixAReal* Native_array_to_fixed_array_var(
    FixAReal* Dest, double* Reals, int size)
    {
        Dest = new FixAReal(Reals, size);
        return Dest;
    }
    
    static boolean Array_item_bool(const bool* A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return false;
    	return A[Index];
    }

    static byte Array_item_byte(const byte* A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return 0;
    	return A[Index];
    }

    static int Array_item_int(const int* A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return 0;
    	return A[Index];
    }

    static double Array_item_double(const double* A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return 0;
    	return A[Index];
    }

    static std::string Array_item_string(const std::string* A, int Size, 
    int Index) {
    	if (Index < 0 || Index >= Size) return "";
    	return A[Index];
    }
    
    static void* Dismiss_structure(void *struc_item) {
    	return( struc_item );
    }
    
    static void* Clone_structure(void* struc_item, int size_struct) {
    	byte* result = (byte*)malloc(size_struct);
    	memmove((void*)result, struc_item, size_struct);
    	return (void*) result;
    }
    
    static int Recursion_counter;
    static long long Test_caller;
                // lower 6 decimal digits = #of source code line in test function
                //    calling ordinary code and test functions of level 2
                // next 6 decimal digits = #of source code line in secondary test
                //    functions calling ordinary functions.
    
    
    //-------------------------------------
    // Safe operation S[i] (string S, int i)
    static std::string Single_symbol(std::string S, int Pos);

    //---------------------------
    // Safe Substring() of string
    static std::string Substring(std::string S, int from, int to);
    
    //---------------------------
    // Optimized comparison of two sub-strings
    static int CompareSubstrings(std::string S1, std::string S2, 
        int from1, int to1, int from2, int to2);

    //---------------------------
    // Optimized comparison of a sub-string with a string
    static int CompareSubstrWithStr(std::string S1,  
        int from1, int to1, std::string S2);

    //-----------------------------------------
    // Operation S[i] = c (not available in C#)
    static std::string Replace_symbol(std::string S, int i, std::string r);

    //---------------------------------------------------------
    // Assign value to short string (all chars after MaxLen
    // are ignored)
    //static void Assign_short_str(TCHAR* Dest, std::string Source, int MaxLen);
    
    //static std::string TCHAR_array_to_string(const TCHAR* Src, int MaxLen);

    //static std::string Short_str_as_STR(char* Src);
    
#ifdef MSWINDOWS
    static std::string Wide_string_to_string(std::wstring W);
#endif

	static int utf8len(std::string s);
	
	static int utf8char(const char *cur);
	
	static int utf8char(std::string s, int at_index);
	
	static std::string utf8substr(std::string s, int start, int len);
	
	static std::string nullchar();
    
    //----------------------
    // Convert int - > char to std::string
    static std::string AsCharStr(int c);
    
    //----------------------
    // Concatenate 2 strings
    static std::string Concat2Strings(std::string S1, std::string S2);
    
    static bool like_str(std::string S1, std::string S2);

    //----------------------
    // Convert int to string
    static std::string StrFromInt(int x);

    //-------------------------
    // Convert double to string
    static std::string StrFromDouble(double x);

    //-------------------------
    // Convert bool to string
    static std::string StrFromBool(bool x);

    static int Int(std::string s);

    static int RealAsInt(double X);
    static int EnumAsInt(byte X);

    static std::string hex16(int value16);
    static std::string StrHex16(std::string s);

    static int ShiftLeft(int i, int n);

    static int ShiftRight(int i, int n);

    static int RotateLeft(int i, int m);

    static int RotateRight(int i, int m);

    //------------------------------------------
    // Find substring first position in a string
    static int Find_str(std::string S, std::string Pattern);
    
    //--------------------------------------
    // Check if string contains a substring:
    static bool StrContains(std::string S, std::string Pattern);
    
    //--------------------------------------
    // optimized check if an item contained in an array:
    static bool ArrayContainsInt(int* A, int A_count, int Value);
    static bool ArrayContainsByte(byte* A, int A_count, byte Value);
    static bool ArrayContainsStr(std::string A[], int A_count, std::string Value);
    static bool ArrayContainsChar(std::string A[], int A_count, int Value);


    //--------------------------------------
    // Is object variable referencing NONE ?
    static bool Is_none(Ref_obj* obj);

    //---------------------------------------------------------------
    // Safe division of real numbers. Returns INF or NaN in bad cases
    static double Safe_div(double X, double Y);

    //-------------------------------------------------
    // Safe division of int numbers. Returns very large 
    // or negative large integer number in bad cases.
    static int Safe_div_int(int X, int Y);

    //---------------------------------
    // Safe rest of division operation.
    static int Safe_rest(int X, int Y);

    //-----------------------
    // STOP operation
    static void STOP(std::string message);

	static
	#ifndef GCC_COMPILER
    	__declspec(thread)
    #endif
    Errors_store* Errors;
    
    //-------------------------
    // Should be called on any exception to collect errors:
    // maximum 10 errors are stored
    // If there were more then 10, middle errors are removed and 
    // then Errors list contains:
    // 0 to 4 - first 5 errors from Reset_errors
    // 5 - empty (to signal that Errors count > 10)
    // 6 TO 9 - last 4 errors
    static void Any_exception(std::exception E);
    
    static void Reset_errors();
    
    static int Errors_count();
    
    static std::string Errors_info(int index);

    //------------------------------------------------------------
    // Operation X.{Type}. Returns NONE is X is not of type {Type}. 
    static Ref_obj* As_obj(Ref_obj* X, Ref_obj* None_y);

    //----------------------------------------------------------
    // Application startup directory
    static std::string Start_dir();

    //----------------------------------------------------------
    // Application startup directory
    static std::string Startup_path();

    //---------------------------------------------------------
    // Clear test data
    static void Clear_test_data(std::vector<long long> test_lines);

    //---------------------------------------------------------
    // Remove a range from test data
    static void Remove_test_data(std::vector<long long>& test_lines, 
                int from, int to);

    //---------------------------------------------------------
    // Output test data of class
    static void Output_test_data(const std::vector<long long>& test_lines,
        const std::vector<int>& test_assert, 
        const std::vector<std::string>& test_assert_failed_text,
        const std::string& Class_test_file,
        const std::string& Class_path_source);

    // adding an assertion failed to list of failed assertions:
    static void Assertion_failed(int line, 
        std::vector<int>& test_assert,
        std::vector<std::string>& test_assert_failed_text,
        const std::string& assert_failed_text);

    static bool Need_console;
    static void Write(std::string S);
    
    static void Write_direct(std::string);
    static void (*WriteRedirected)(std::string S); // = Write_direct;
    // dumb C++ lang does not allow init ptrs to functions

    static void WriteLine(std::string S);
    static std::string ReadLine();

	static void Save_strings(std::vector<std::string> L, std::string Path);
    
    static bool Is_TEST_stage()
    {
        #ifdef TEST_STAGE
               return true;
        #else
               return false;
        #endif
    }
    
#localize1

    static std::string get_Localize_str(int n);
    
	#ifndef GCC_COMPILER
	__declspec( thread )
	#endif
	static int global_activity_counter;
	
	static std::vector<AL4_handler*> long_operation_handlers; 
		
	static void check_long_operation()
	{
		global_activity_counter = 65535;
		for (int i = long_operation_handlers.size()-1; i >= 0; i--)
			long_operation_handlers[i]->Handler();
	}
    
public:
	static int imin(int a, int b)
    {
    	if (a < b) return a;
    	else return b;
    }

public:
	static int imax(int a, int b)
    {
    	if (a > b) return a;
    	else return b;
    }

}; //end of class AL4_system


#ifdef LOG_METHODS

class AL4_log_methods
{
public:
	static std::vector<std::string> buf_out; 
	static int call_count;
	static void log_method(std::string fun_name);
	
public:
	static int disabled_logging;
	static void disable_log(int d);
	
public:
	static void reset_logging();
};

#endif


#endif //AL4_HEADER

