
native struct int implements ICloneable, IComparableMore, IInspectable includes OperatorModule
{
    native long toLong();
    native short toShort();
    native byte toByte();
    native uint toUInt();
    native float toFloat(); 
    native double toDouble(); 
    native char toChar();
    virtual native String toString();

    int times() with void block(int num) {
        for(int i=0; i<self; i++) {
            bool break_existance = block(i);
            if(break_existance) {
                break;
            }
        }

        return self;
    }
    int times() with void block() {
        for(int i=0; i<self; i++) {
            bool break_existance = block();
            if(break_existance) {
                break;
            }
        }

        return self;
    }

    int toInt() {
        return new int(self);
    }

    bool toBool() {
        return self != 0;
    }

    native virtual void setValue(int value);

    virtual int hashValue() {
        return self;
    }

    virtual int clone() throws Exception{
        int new_object = new int();
        new_object.setValue(self);
        return new_object;
    }

    virtual int dup() {
        return self.clone();
    }
}

native struct byte implements IComparableMore, ICloneable, IInspectable includes OperatorModule
{
    native virtual void setValue(byte value);
    native int toInt();
    native long toLong();

    byte toByte() {
        return new byte(self);
    }

    virtual String toString() {
        return self.toInt().toString();
    }

    virtual int hashValue() {
        return self.toInt();
    }

    virtual byte clone() throws Exception{
        byte new_object = new byte();
        new_object.setValue(self);
        return new_object;
    }

    virtual byte dup() {
        return self.clone();
    }

    byte(int value) {
        self.setValue(value.toByte());
    }
}

native struct short implements ICloneable, IComparableMore, IInspectable includes OperatorModule
{
    native virtual void setValue(short value);
    native int toInt();
    native long toLong();

    short toShort() {
        return new short(self);
    }

    virtual String toString() {
        return self.toInt().toString();
    }

    virtual int hashValue() {
        return self.toInt();
    }

    virtual short clone() throws Exception{
        short new_object = new short();
        new_object.setValue(self);
        return new_object;
    }

    virtual short dup() {
        return self.clone();
    }

    short(int value) {
        self.setValue(value.toShort());
    }
}

native struct uint implements ICloneable, IComparableMore, IInspectable includes OperatorModule
{
    native virtual void setValue(uint value);
    native int toInt();
    native long toLong();
    virtual native String toString();

    uint toUInt() {
        return new uint(self);
    }

    virtual int hashValue() {
        return self.toInt();
    }

    virtual uint clone() throws Exception{
        uint new_object = new uint();
        new_object.setValue(self);
        return new_object;
    }

    virtual uint dup() {
        return self.clone();
    }

    uint(int value) {
        self.setValue(value.toUInt());
    }
}

native struct long implements ICloneable, IComparableMore, IInspectable includes OperatorModule
{
    native virtual void setValue(long value);
    native byte toByte();
    native short toShort();
    native int toInt();
    native uint toUInt();
    native float toFloat(); 
    native double toDouble(); 
    native char toChar();

    long toLong() {
        return new long(self);
    }

    virtual native String toString();

    virtual int hashValue() {
        return self.toInt();
    }

    virtual long clone() throws Exception{
        long new_object = new long();
        new_object.setValue(self);
        return new_object;
    }

    virtual long dup() {
        return self.clone();
    }

    long(int value) {
        self.setValue(value.toLong());
    }
}

native struct char implements ICloneable, IComparableMore, IInspectable 
{
    native virtual void setValue(char value);
    native int toInt();
    virtual native String toString();

    virtual int hashValue() {
        return self.toInt();
    }

    char toChar() {
        return new char(self);
    }

    virtual char clone() throws Exception{
        char new_object = new char();
        new_object.setValue(self);
        return new_object;
    }

    virtual char dup() {
        return self.clone();
    }

    virtual bool operator==(char@Nullable value) {
        if(self.type() == Null || value.type() == Null) {
            return self.type() == Null && value.type() == Null;
        }
        return self.toInt() == value.toInt();
    }
    virtual bool operator!=(char@Nullable value) {
        return !(self == value);
    }
    virtual bool operator <(char value) {
        return self.toInt() < value.toInt();
    }
    virtual bool operator <=(char value) {
        return self.toInt() <= value.toInt();
    }
    virtual bool operator >(char value) {
        return self.toInt() > value.toInt();
    }
    virtual bool operator >=(char value) {
        return self.toInt() >= value.toInt();
    }

    char upcase() {
        char result = 0.toChar();

        if(self >= 'a' && self <= 'z') {
            result = (self.toInt() - 'a'.toInt() + 'A'.toInt()).toChar();
        }
        else {
            result = self;
        }

        return result;
    }
    char downcase() {
        char result = 0.toChar();

        if(self >= 'A' && self <= 'Z') {
            result = (self.toInt() - 'A'.toInt() + 'a'.toInt()).toChar();
        }
        else {
            result = self;
        }

        return result;
    }

    bool isControlCharacter() {
        return self >= 0x00.toChar() && self < ' ' || self == 0x7F.toChar();
    }

    bool isAsciiCharacter() {
        return self >= 0x00.toChar() && self <= 0xFF.toChar();
    }

    bool isDigitCharacter() {
        return self >= '0' && self <= '9';
    }

    bool isAlphabetCharacter() {
        return self >= 'a' && self <= 'z' || self >= 'A' && self <= 'Z';
    }

    bool isNonControlCharacter() {
        return self >= ' ' && self <= '~';
    }
}

native struct float implements ICloneable, IInspectable, IComparableMore includes OperatorModuleForDouble
{ 
    native int toInt();
    native double toDouble();
    virtual native String toString();

    float toFloat() {
        return new float(self);
    }

    float(int value) {
        self.setValue(value.toDouble());
    }

    native virtual void setValue(float value);

    virtual float clone() throws Exception{
        float new_object = new float();
        new_object.setValue(self);
        return new_object;
    }

    virtual float dup() {
        return self.clone();
    }
}

native struct double implements ICloneable, IInspectable, IComparableMore includes OperatorModuleForDouble
{
    native int toInt();
    native float toFloat();
    virtual native String toString();
    native virtual void setValue(double value);

    double(int value) {
        self.setValue(value.toDouble());
    }

    double toDouble() {
        return new double(self);
    }

    virtual double clone() throws Exception{
        double new_object = new double();
        new_object.setValue(self);
        return new_object;
    }

    virtual double dup() {
        return self.clone();
    }
}

native struct bool implements IComparable, ICloneable, IInspectable  
{
    native virtual void setValue(bool value);

    bool toBool() {
        return new bool(self);
    }

    virtual bool clone() throws Exception{
        bool new_object = new bool();
        new_object.setValue(self);
        return new_object;
    }

    virtual bool dup() {
        return self.clone();
    }

    virtual String toString() {
        if(self) {
            return "true";
        }
        else {
            return "false";
        }
    }
    int toInt() {
        if(self) {
            return 1;
        }
        else {
            return 0;
        }
    }
    
    bool operator !() {
        return \!self;
    }
    bool operator &&(bool value) {
        return self \&& value;
    }
    bool operator ||(bool value) {
        return self \|| value;
    }

    virtual bool operator==(bool@Nullable value) {
        return self \== value;
    }
    virtual bool operator !=(bool@Nullable value) {
        return self \!= value;
    }
}

native struct pointer implements IComparable, IInspectable, ICloneable
{
    native virtual void setValue(pointer value);
    native virtual String toString();

    pointer toPointer() {
        return new pointer(self);
    }

    native bool equals(pointer right);

    virtual pointer clone() {
        pointer new_object = new pointer();
        new_object.setValue(self);
        return new_object;
    }

    virtual pointer dup() {
        return self.clone();
    }

    native void forward(int size=1) throws NullPointerException, Exception;
    native void backward(int size=1) throws NullPointerException, Exception;

    native byte getByte() throws NullPointerException;
    native short getShort() throws NullPointerException;
    native uint getUInt() throws NullPointerException;
    native long getLong() throws NullPointerException;

    virtual bool operator==(pointer@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }

        return self.equals(right);
    }

    virtual bool operator!=(pointer@Nullable right) {
        return !(self == right);
    }
}

enum Encoding
{
    Binary, ASCII, Utf8, EucJP, SJIS
}

abstract native class Regex implements IComparable, ICloneable
{
    abstract virtual String source();

    abstract virtual bool ignoreCase();
    abstract virtual bool multiLine();
    abstract virtual bool global();
    abstract virtual Encoding encode();

    abstract virtual void setIgnoreCase(bool ignore_case);
    abstract virtual void setMultiLine(bool mutiline);
    abstract virtual void setGlobal(bool global);
    abstract virtual void setEncode(Encoding encode);

    abstract virtual void compile(String source, bool ignore_case, bool mutiline, bool global, Encoding encode) throws InvalidRegexException;

    virtual bool operator==(Regex@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }

        return self.source() == right.source() && self.ignoreCase() == right.ignoreCase() && self.multiLine() == right.multiLine() && self.global() == right.global() && self.encode() == right.encode();
    }

    virtual bool operator !=(Regex@Nullable right) {
        return !(self == right);
    }

    virtual void setValue(Regex value) {
    }
    virtual Regex dup() {
        return self;
    }
    virtual Regex clone() {
        return self;
    }
}

native class OnigurumaRegex implements ICloneable, IInspectable extends Regex
{
    native virtual String source();
    native virtual bool ignoreCase();
    native virtual bool multiLine();
    native virtual Encoding encode();
    native virtual bool global();

    native virtual void setIgnoreCase(bool ignore_case);
    native virtual void setMultiLine(bool mutiline);
    native virtual void setGlobal(bool global);
    native virtual void setEncode(Encoding encode);

    native virtual void setValue(OnigurumaRegex regex);

    native virtual void compile(String source, bool ignore_case, bool mutiline, bool global, Encoding encode) throws InvalidRegexException;

    OnigurumaRegex(String source, bool ignore_case=false, bool multiline=false, bool global=false, Encoding encode=Encoding.Utf8)
    {
        self.compile(source, ignore_case, multiline, global, encode);
    }

    virtual OnigurumaRegex clone() throws Exception{
        return new OnigurumaRegex(self.source(), self.ignoreCase(), self.multiLine(), self.global(), self.encode());
    }

    virtual OnigurumaRegex dup() {
        OnigurumaRegex regex = new OnigurumaRegex();
        regex.setValue(self);
        return regex;
    }

    virtual String toString() {
        return self.source();
    }
}

native class StringBuffer implements IComparable, ICloneable, IInspectable
{
    native virtual void setValue(StringBuffer value);
    native virtual String toString();
    native int length();
    native virtual void setValue(String value);

    StringBuffer(String value) {
        self.setValue(value);
    }

    virtual StringBuffer clone() {
        return new StringBuffer(self);
    }

    virtual StringBuffer dup() {
        return self.clone();
    }

    native StringBuffer append(String value);

    StringBuffer operator+=(String value) {
        return self.append(value);
    }

    native StringBuffer append(char c);

    StringBuffer operator+=(char value) {
        return self.append(value);
    }

    StringBuffer clear() {
        self.setValue("");
        return self;
    }

    virtual bool operator==(StringBuffer@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() != Null || right.type() != Null;
        }

        return self.toString() == right.toString();
    }
    virtual bool operator!=(StringBuffer@Nullable right) {
        return !(self == right);
    }
}

native class Parser implements IComparable, ICloneable, IInspectable
{
    native virtual void setValue(Parser value);
    native virtual String toString() throws Exception;
    native long point() throws Exception;
    native void setString(String value);
    native void setPoint(long point);
    
    native bool end() throws Exception;
    native char getChar();
    native String getString(int num) throws Exception;
    native Parser forward(int num=1);
    native Parser backward(int num=1);

    Parser(String value) {
        self.setString(value);
    }

    virtual Parser clone() {
        return new Parser(self);
    }

    virtual Parser dup() {
        return self.clone();
    }

    virtual bool operator==(Parser@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() != Null || right.type() != Null;
        }

        return self.toString() == right.toString() && self.point() == right.point();
    }
    virtual bool operator!=(Parser@Nullable right) {
        return !(self == right);
    }
}

native class String implements IComparableMore, ICloneable, IHashKey, IInspectable 
{
    native virtual void setValue(String value);
    native int toInt();
    native double toDouble();

    native int length();

    native char@CheckForNull char(int index);

    native char replace(int index, char character) throws RangeException;

    native Bytes toBytes() throws ConvertingStringCodeException;

    native int cmp(String right, bool ignore_case=false);

    native void match(Regex regex, int@Nullable offset=0, int count=1) with void block(int begin, int end, Array<Range> group_strings);

    native void matchReverse(Regex regex, int@Nullable offset=null, int count=1) with void block(int begin, int end, Array<Range> group_strings);

    virtual void outputValueForInterpreter() {
        ("=> \"" + self.toString().chomp() + "\"").println();
    }

    virtual String toString() {
        return new String(self);
    }

    Parser toParser() {
        return new Parser(self);
    }

    bool operator =~ (Regex regex, Array<String>@Nullable group_strings=null) throws Exception 
    {
        bool result = false;

        if(!(group_strings == null || group_strings.type() == Array<String> && group_strings.length() == 0)) 
        {
            throw new Exception("Invalid group_string parametor");
        }

        self.match(regex, 0, 1) {
            |int begin, int end, Array<Range> group_strings2|

            if(group_strings != null) {
                for(int i=0; i<group_strings2.length(); i++) {
                    Range range = group_strings2[i];

                    String group_string = self[range.head()..range.tail()];

                    group_strings.add(group_string);
                }
            }

            result = true;

            break;
        }

        return result;
    }

    virtual String clone() throws Exception{
        String new_string = new String();
        new_string.setValue(self);
        return new_string;
    }

    virtual String dup() {
        return self.clone();
    }

    virtual int hashValue() {
        int hash_value = 0;

        for(int i=0; i<self.length(); i++) {
            hash_value += self.char(i).toInt();
        }

        return hash_value;
    }

    void print() {
        Clover.print(self);
    }
    void println() {
        Clover.println(self);
    }

    char@CheckForNull operator[] (int index) {
        return self.char(index);
    }

    char operator[]= (int index, char character) throws RangeException {
        return self.replace(index, character);
    }

    String operator[] (Range range) {
        Range corrected_range = new Range();
        range.correct(corrected_range, self.length());

        StringBuffer result = new StringBuffer();

        if(self.length() == 0) {
        }
        else if(corrected_range.head() < corrected_range.tail()) {
            for(int i=corrected_range.head(); i<corrected_range.tail(); i++) {
                result += self[i];
            }
        }
        else {
            for(int i=corrected_range.head()-1; i>=corrected_range.tail(); i--) {
                result += self[i];
            }
        }

        return result.toString();
    }

    String operator +(String value) {
        return self \+ value;
    }

    String operator+= (String string) {
        self.setValue(self + string);
        return self;
    }

    virtual bool operator==(String@Nullable right) {
        return (self \== right);
    }
    virtual bool operator!=(String@Nullable right) {
        return !(self \== right);
    }
    virtual bool operator>(String right) {
        return self.cmp(right) == 1;
    }
    virtual bool operator<(String right) {
        return self.cmp(right) == -1;
    }
    virtual bool operator>=(String right) {
        return self.cmp(right) == 1 || self \== right;
    }
    virtual bool operator<=(String right) {
        return self.cmp(right) == -1 || self \== right;
    }
    String operator *(int num) {
        StringBuffer new_string = new StringBuffer();
        for(int i=0; i<num; i++) {
            new_string += self;
        }
        return new_string.toString();
    }

    bool asciiOnly() {
        for(int i=0; i<self.length(); i++) {
            if(!self[i].isAsciiCharacter()) {
                return false;
            }
        }

        return true;
    }

    String capitalize() {
        StringBuffer result = new StringBuffer();

        if(self.length() > 0) {
            result += self[0].upcase();
        }
        if(self.length() > 1) {
            result += self[1..null];
        }

        return result.toString();
    }

    String each() with void block(char c) {
        for(int i=0; i<self.length(); i++) {
            bool break_existance = block(self[i]);
            if(break_existance) {
                break;
            }
        }

        return self;
    }

    String chomp(String separator=null) {
        String result = "";

        if(separator == null) {
            if(self.length() >= 2) {
                if(self[-2] == '\r' && self[-1] == '\n') {
                    result = self[0..-2];
                }
                else if(self[-1] == '\r' || self[-1] == '\n') {
                    result = self[0..-1];
                }
                else {
                    result = self.clone();
                }
            }
            else if(self.length() >= 1) {
                if(self[-1] == '\r' || self[-1] == '\n') {
                    result = self[0..-1];
                }
                else {
                    result = self.clone();
                }
            }
        }
        else {
            if(self.length() >= separator.length()) {
                if(self[self.length()-separator.length()..null] == separator) {
                    result = self[0..self.length()-separator.length()];
                }
                else {
                    result = self.clone();
                }
            }
        }

        return result;
    }

    String chop() {
        String result = "";
        
        if(self[-2] == '\r' && self[-1] == '\n') {
            result = self[0..-2];
        }
        else {
            result = self[0..-1];
        }

        return result;
    }

    int count(char character) {
        int count = 0;

        for(int i=0; i<self.length(); i++) {
            if(self[i] == character) {
                count++;
            }
        }

        return count;
    }

    int count(Regex regex) {
        int c = 0;

        regex.setGlobal(true);

        self.match(regex, 0, 1) {
            |int begin, int end, Array<Range> group_strings2|

            c++;
        }

        return c;
    }

    String delete(char character) {
        StringBuffer result = new StringBuffer();

        Parser parser = self.toParser();

        while(!parser.end()) {
            char c = parser.getChar();

            if(c != character) {
                result += c;
            }

            parser.forward(1);
        }

        return result.toString();
    }

    String delete(Regex regex) {
        StringBuffer result = new StringBuffer();
        int begin_before = 0;

        //regex.setGlobal(true);

        self.match(regex, 0, 1) {
            |int begin, int end, Array<Range> group_strings2|

            if(begin_before < begin) {
                result += self[begin_before..begin];
            }

            begin_before = end;
        }

        if(begin_before < self.length()) {
            result += self[begin_before..null];
        }

        return result.toString();
    }

    String downcase() {
        StringBuffer result = new StringBuffer();

        Parser parser = self.toParser();

        while(!parser.end()) {
            result += parser.getChar().downcase();

            parser.forward(1);
        }

        return result.toString();
    }

    Array<String> lines(String separator="\n") {
        Array<String> result = new Array<String>();

        StringBuffer line = new StringBuffer();

        Parser parser = self.toParser();

        while(!parser.end()) {
            if(parser.getString(separator.length()) == separator) {
                line.append(separator);
                result.add(line.toString());

                line.clear();
                parser.forward(separator.length());
            }
            else {
                line.append(parser.getChar());
                parser.forward(1);
            }
        }

        if(line.toString() != "") {
            result.add(line.toString());
        }

        return result;
    }

    String sub(Regex regex, String replacement) {
        StringBuffer result = new StringBuffer();
        int begin_before = 0;

        self.match(regex, 0, 1) {
            |int begin, int end, Array<Range> group_strings2|

            if(begin_before < begin) {
                result += self[begin_before..begin];
            }

            result += replacement;

            begin_before = end;
        }

        if(begin_before < self.length()) {
            result += self[begin_before..null];
        }

        return result.toString();
    }

    String sub(Regex regex) with String block(Array<String> group_strings, String prematch, String match, String postmatch)
    {
        StringBuffer result = new StringBuffer();
        int begin_before = 0;

        self.match(regex, 0, 1) {
            |int begin, int end, Array<Range> group_strings|

            if(begin_before < begin) {
                result += self[begin_before..begin];
            }

            /// call block ///
            Array<String> group_strings2 = new Array<String>();

            group_strings.each() { |Range range|
                group_strings2.add(self[range]);
            }

            String prematch = self[0..begin];
            String match = self[begin..end];
            String postmatch = self[end..null];

            Tuple<bool,String> block_result = block(group_strings2, prematch, match, postmatch);

            /// append block result to the string ///
            result += block_result.get2();

            begin_before = end;
        }

        if(begin_before < self.length()) {
            result += self[begin_before..null];
        }

        return result.toString();
    }

    String sub(Regex regex, Hash<String, String> replacement) {
        StringBuffer result = new StringBuffer();
        int begin_before = 0;

        self.match(regex, 0, 1) {
            |int begin, int end, Array<Range> group_strings|

            if(begin_before < begin) {
                result += self[begin_before..begin];
            }

            /// append the matching replacement to the string ///
            String match = self[begin..end];

            if(replacement[match] != null) {
                result += replacement[match];
            }
            else {
                result += match;
            }

            begin_before = end;
        }

        if(begin_before < self.length()) {
            result += self[begin_before..null];
        }

        return result.toString();
    }

    bool include(String@Nullable other_str) {
        if(other_str == "" || other_str == null) {
            return false;
        }

        Parser parser = self.toParser();

        while(!parser.end()) {
            if(parser.getString(other_str.length()) == other_str) {
                return true;
            }
            parser.forward(1);
        }

        return false;
    }

    int index(String substr, int@Nullable offset=0, int count=1) {
        if(offset == null) { offset = self.length(); }
        if(offset < 0) { offset += self.length(); }
        if(offset < 0) { offset = 0; }
        if(offset > self.length()) { offset = self.length(); }

        int count2 = 0;
        Parser parser = self.toParser();
        parser.setPoint(offset.toLong());
        while(!parser.end()) {
            if(parser.getString(substr.length()) == substr) {
                count2++;

                if(count2 == count) {
                    return parser.point().toInt();
                }
            }

            parser.forward(1);
        }

        return -1;
    }

    int index(Regex regex, int@Nullable offset=0, int count=1) {
        if(offset == null) { offset = self.length(); }
        if(offset < 0) { offset += self.length(); }
        if(offset < 0) { offset = 0; }
        if(offset > self.length()) { offset = self.length(); }

        int count2 = 0;
        int result = -1;

        self[offset..null].match(regex, 0, 1) {
            |int begin, int end, Array<Range> group_strings|

            count2++;

            if(count2 == count) {
                result = begin + offset;
                break;
            }
        }

        return result;
    }

    int rindex(String substr, int@Nullable offset=null, int count=1) {
        if(offset == null) { offset = self.length(); }
        if(offset < 0) { offset += self.length(); }
        if(offset < 0) { offset = 0; }
        if(offset > self.length()) { offset = self.length(); }

        int count2 = 0;
        for(int i=offset; i>=0; i--) {
            if(self[i..i+substr.length()] == substr) {
                count2++;

                if(count2 == count) {
                    return i;
                }
            }
        }

        return -1;
    }

    int rindex(Regex regex, int@Nullable offset=null, int count=1) {
        if(offset == null) { offset = self.length(); }
        if(offset < 0) { offset += self.length(); }
        if(offset < 0) { offset = 0; }
        if(offset > self.length()) { offset = self.length(); }

        int count2 = 0;
        int result = -1;

        self[0..offset].matchReverse(regex) {
            |int begin, int end, Array<Range> group_strings|

            count2++;

            if(count2 == count) {
                result = begin;
                break;
            }
        }

        return result;
    }

    String lstrip() {
        return self.sub(/^\s+(\S*)/) {
            |Array<String> group_strings, String prematch, String match, String postmatch| return group_strings[0]; }
    }

    String strip() {
        return self.sub(/^\s+|\s+$/g, "");
    }

    String rstrip() {
        int i = 0;

        for(i=self.length()-1; i>=0; i--) {
            if(self[i] != '\n' && self[i] != ' ' && self[i] != '\t') {
                break;
            }
        }

        if(i == -1) {
            self.setValue("");
        }
        else {
            self.setValue(self[0..i+1]);
        }

        return self;
    }

    String reverse() {
        return self[null..0];
    }

    /// result is Array<String> or Array<Array<String>>
    Array<anonymous> scan(Regex regex) {
        Array<anonymous> result = null;

        regex.setGlobal(true);          // force regex to be global

        self.match(regex) {
            |int begin, int end, Array<Range> group_strings|
            
            if(group_strings.length() == 0 || result != null && result.type() == Array<String>) {
                if(result == null) {
                    result = new Array<String>();
                }
                result.add(self[begin..end]);
            }
            else {
                if(result == null) {
                    result = new Array<Array<String>>();
                }

                Array<String> array = new Array<String>();
                group_strings.each() {|Range range|
                    array.add(self[range]);
                }
                result.add(array);
            }
        }

        return result;
    }

    Array<String> split(Regex regex=null, int limit=0) {
        Array<String> result = new Array<String>();
        int begin_before = 0;

        if(regex == null) {
            regex = /\s+/;
            self.setValue(self.strip());
        }

        regex.setGlobal(true); // force regex to be global

        self.match(regex, 0, 1) {
            |int begin, int end, Array<Range> group_strings|

            if(limit == 0) {
                if(begin_before < begin) {
                    result.add(self[begin_before..begin]);
                }

                if(group_strings.length() > 0) {
                    group_strings.each() {|Range range|
                        result.add(self[range]);
                    }
                }
            }
            else if(limit < 0) {
                if(begin_before < begin) {
                    result.add(self[begin_before..begin]);
                }
                else {
                    result.add("");
                }

                if(group_strings.length() > 0) {
                    group_strings.each() {|Range range|
                        result.add(self[range]);
                    }
                }
            }
            else {     // limit > 0
                if(result.length() < limit-1) {
                    if(begin_before < begin) {
                        result.add(self[begin_before..begin]);
                    }
                    else {
                        result.add("");
                    }
                }
                else {
                    break;
                }

                if(group_strings.length() > 0) {
                    group_strings.each() {|Range range|
                        if(result.length() < limit-1) {
                            result.add(self[range]);
                        }
                        else {
                            break;
                        }
                    }
                }
            }

            begin_before = end;
        }

        if(limit < 0) {
            if(begin_before < self.length()) {
                result.add(self[begin_before..null]);
            }
            else {
                result.add("");
            }
        }
        else if(limit == 0) {
            if(begin_before < self.length()) {
                result.add(self[begin_before..null]);
            }
        }                   // limit > 0
        else {
            if(result.length() < limit) {
                if(begin_before < self.length()) {
                    result.add(self[begin_before..null]);
                }
                else {
                    result.add("");
                }
            }
        }

        return result;
    }

    String squeeze() {
        StringBuffer result = new StringBuffer();
        char character_before = null;
        Parser parser = self.toParser();
        while(!parser.end()) {
            char c = parser.getChar();

            if(c != character_before) {
                result += c;
            }

            character_before = c;

            parser.forward(1);
        }

        return result.toString();
    }

    String swapcase() {
        StringBuffer result = new StringBuffer();
        Parser parser = self.toParser();
        while(!parser.end()) {
            char c = parser.getChar();

            if(c >= 'a' && c <= 'z') {
                result += c.upcase();
            }
            else if(c >= 'A' && c <= 'Z') {
                result += c.downcase();
            }
            else {
                result += c;
            }

            parser.forward(1);
        }

        return result.toString();
    }

    String tr(String from_str, String to_str) {
        StringBuffer result = new StringBuffer();
        String from_str_corrected = "";
        String to_str_corrected = "";
        bool negative = false;

        /// parse from_str ///
        if(from_str[0] == '^') { negative = true; }

        for(int i=(negative ? 1:0); i<from_str.length(); i++) {
            if(from_str[i+1] == '-') {
                if(i+2 < from_str.length()) {
                    for(int c=from_str[i].toInt(); c<=from_str[i+2].toInt(); c++) {
                        from_str_corrected += c.toChar().toString();
                    }
                    i+=2;
                }
                else {
                    i++;
                }
            }
            else {
                from_str_corrected += from_str[i].toString();
            }
        }

        /// parse to_str ///
        for(int i=0; i<to_str.length(); i++) {
            if(to_str[i+1] == '-') {
                if(i+2 < to_str.length()) {
                    for(int c=to_str[i].toInt(); c<=to_str[i+2].toInt(); c++) {
                        to_str_corrected += c.toChar().toString();
                    }
                    i+=2;
                }
                else {
                    i++;
                }
            }
            else {
                to_str_corrected += to_str[i].toString();
            }
        }

        /// go ///
        for(int i=0; i<self.length(); i++) {
            bool found = false;
            int j = 0;

            for(j=0; j<from_str_corrected.length(); j++) {
                if(self[i] == from_str_corrected[j])
                {
                    found = true;
                    break;
                }
            }

            if(!negative && found || negative && !found) {
                if(j < to_str_corrected.length()) {
                    result += to_str_corrected[j];
                }
                else {
                    result += to_str_corrected[-1];
                }
            }
            else {
                result += self[i];
            }
        }

        return result.toString();
    }

    int hex() {
        bool continues = false;
        bool minus = false;
        int result = 0;
        for(int i=0; i<self.length(); i++) {
            if(self[i] == '-') {
                continues = true;
                minus = true;
            }
            else if(!continues && self[i] == '0' && self[i+1] == 'x') {
                continues = true;
                i++;
            }
            else if(self[i] >= '0' && self[i] <= '9') {
                result *= 16;
                result += (self[i].toInt() - '0'.toInt());
                continues = true;
            }
            else if(self[i] >= 'a' && self[i] <= 'f') {
                result *= 16;
                result += (self[i].toInt() - 'a'.toInt()) + 10;
                continues = true;
            }
            else if(self[i] >= 'A' && self[i] <= 'F') {
                result *= 16;
                result += (self[i].toInt() - 'A'.toInt()) + 10;
                continues = true;
            }
            else {
                if(continues) {
                    break;
                }
            }
        }

        if(minus) {
            result *= -1;
        }

        return result;
    }

    int oct() {
        bool continues = false;
        bool minus = false;
        int result = 0;
        for(int i=0; i<self.length(); i++) {
            if(self[i] == '-') {
                continues = true;
                minus = true;
            }
            else if(!continues && self[i] == '0') {
                continues = true;
            }
            else if(self[i] >= '0' && self[i] <= '7') {
                result *= 8;
                result += (self[i].toInt() - '0'.toInt());
                continues = true;
            }
            else {
                if(continues) {
                    break;
                }
            }
        }

        if(minus) {
            result *= -1;
        }

        return result;
    }
}

native class Bytes implements IComparableMore, ICloneable, IInspectable 
{
    native virtual void setValue(Bytes value);

    virtual Bytes clone() throws Exception{
        Bytes new_string = new Bytes();
        new_string.setValue(self);
        return new_string;
    }

    virtual Bytes dup() {
        return self.clone();
    }

    Bytes toBytes() {
        return new Bytes(self);
    }

    native int length();

    native byte@CheckForNull char(int index);
    byte@CheckForNull operator[] (int index) {
        return self.char(index);
    }

    native byte replace(int index, byte c) throws RangeException;
    byte operator[]= (int index, byte c) throws RangeException {
        return self.replace(index, c);
    }

    virtual native String toString() throws ConvertingStringCodeException;

    native int cmp(Bytes right);

    native Bytes append(Bytes string);

    Bytes operator+= (Bytes string) {
        return self.append(string);
    }

    virtual bool operator==(Bytes@Nullable right) {
        return (self \== right);
    }
    virtual bool operator!=(Bytes@Nullable right) {
        return !(self \== right);
    }
    virtual bool operator>(Bytes right) {
        return self.cmp(right) > 0;
    }
    virtual bool operator<(Bytes right) {
        return self.cmp(right) < 0;
    }
    virtual bool operator>=(Bytes right) {
        return self.cmp(right) > 0 || self \== right;
    }
    virtual bool operator<=(Bytes right) {
        return self.cmp(right) < 0 || self \== right;
    }

    Bytes operator +(Bytes value) {
        return self \+ value;
    }

    /// pointer method ///
    native void forward(int size=1) throws Exception;
    native void backward(int size=1) throws Exception;
    native void setPoint(long point) throws Exception;
    native long point();

    native byte getByte();
    native short getShort();
    native uint getUInt();
    native long getLong();
}

native class Range implements ICloneable, IInspectable, IComparableMore
{
    native void setHead(int head);
    native void setTail(int tail);
    native virtual void setValue(Range range);
    native int head();
    native int tail();

    Range toRange() {
        return new Range(self);
    }

    virtual Range clone() throws Exception{
        Range new_range = new Range();
        new_range.setHead(self.head().clone());
        new_range.setTail(self.tail().clone());
        return new_range;
    }

    virtual Range dup() {
        return self.clone();
    }

    virtual bool operator==(Range@Nullable range) {
        if(self.type() == Null || range.type() == Null) {
            return self.type() == Null && range.type() == Null;
        }

        return self.head() == range.head() && self.tail() == range.tail();
    }
    virtual bool operator!=(Range@Nullable range) {
        return !(self == range);
    }
    virtual bool operator>(Range@Nullable range) {
        if(self.type() == Null || range.type() == Null) {
            return self.type() == Null && range.type() == Null;
        }

        return self.head() > range.head() && self.tail() > range.tail();
    }
    virtual bool operator<(Range@Nullable range) {
        if(self.type() == Null || range.type() == Null) {
            return self.type() == Null && range.type() == Null;
        }

        return self.head() < range.head() && self.tail() < range.tail();
    }
    virtual bool operator>=(Range range) {
        return self == range || self > range;
    }
    virtual bool operator<=(Range range) {
        return self == range || self < range;
    }
    void correct(Range range, int length) {
        int head = self.head();
        int tail = self.tail();

        if(head == null) { head = length; }
        if(tail == null) { tail = length; }
        if(head < 0) { head += length; }
        if(tail < 0) { tail += length; }

        if(head < 0) { head = 0; }
        if(tail < 0) { tail = 0; }
        if(head > length) { head = length; }
        if(tail > length) { tail = length; }

        range.setHead(head);
        range.setTail(tail);
    }

    bool include(int number) {
        return number >= self.head() && number <= self.tail();
    }

    virtual String toString() {
        return self.head().toString() + ".." + self.tail().toString();
    }
}

native class Array<T implements IComparable> implements ICloneable, IInspectable, IComparable
{
    native virtual void setValue(Array<T> value);

    native Array<T> add(T@Nullable item);
    native T@CheckForNull items(int index);
    native int length();
    native Array<T> setItem(int index, T@Nullable item);

    Array<T> toArray() {
        return new Array<T>(self);
    }

    /// deep copy ///
    virtual Array<T> clone() throws Exception {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            new_array.add(self.items(i).clone());
        }

        return new_array;
    }

    /// shallow copy ///
    virtual Array<T> dup() throws Exception {
        Array<T> new_array = new Array<T>();

        new_array.setValue(self);

        return new_array;
    }

/*
    T items(int index, T@Nullable default) {
        int index2 = index;

        if(index2 < 0) {
            index2 += self.length();
        }

        if(index2 < 0 || index2 >= self.length()) {
            return default;
        }

        return self.items(index);
    }

    T items(int index) with T block(int index) {
        int index2 = index;

        if(index2 < 0) {
            index2 += self.length();
        }

        if(index2 < 0 || index2 >= self.length()) {
            return block(index2).get2();
        }
    
        return self.items(index);
    }
*/
/*
    T find(int find_count=1) with bool block(T item) {
        int count = 0;
        for(int i=0; i<self.length(); i++) {
            if(block(self.items(i)).get2()) {
                count++;
                if(count == find_count) {
                    return self.items(i);
                }
            }
        }

        return null;
    }
*/

    Array<T> operator*(int num) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<num; i++) {
            for(int j=0; j<self.length(); j++) {
                new_array.add(self.items(j));
            }
        }

        return new_array;
    }

    Array<T> operator + (Array<T> right) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            new_array.add(self.items(i));
        }

        for(int i=0; i<right.length(); i++) {
            new_array.add(right.items(i));
        }

        return new_array;
    }

    virtual bool operator==(Array<anonymous>@Nullable array2) {
        if(self.type() == Null || array2.type() == Null) {
            return self.type() == Null && array2.type() == Null;
        }

        if(self.length() != array2.length()) {
            return false;
        }

        for(int i=0; i<self.length(); i++) {
            if(self[i] != array2[i]) {
                return false;
            }
        }

        return true;
    }
    virtual bool operator!=(Array<anonymous>@Nullable array2) {
        return !(self == array2);
    }

    T@CheckForNull operator[] (int index) {
        return self.items(index);
    }

    Array<T> operator[]= (int index, T item) {
        return self.setItem(index, item);
    }

/*
    bool empty() {
        return self.length() == 0;
    }
*/

/*
    Array<T> compact() {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(self.items(i) != null) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }
*/

    Array<T> deleteAt(int number) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(i != number) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }

/*
    T@CheckForNull first() {
        return self.items(0);
    }

    T@CheckForNull last() {
        return self.items(self.length()-1);
    }
*/

    T@CheckForNull pop() {
        if(self.length() == 0) {
            return null;
        }

        Array<T> new_array = new Array<T>();
        T result = self.items(self.length()-1);

        for(int i=0; i<self.length()-1; i++) {
            new_array.add(self.items(i));
        }

        self.setValue(new_array);

        return result;
    }

    bool include(T item) {
        for(int i=0; i<self.length(); i++) {
            if(self.items(i) == item) {
                return true;
            }
        }

        return false;
    }

    int count(T item) {
        int c = 0;

        for(int i=0; i<self.length(); i++) {
            if(self.items(i) == item) {
                c++;
            }
        }

        return c;
    }

    Array<T> delete(T@Nullable item) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(self.items(i) != item) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }

    int index(T@Nullable item, int count=1) {
        int c = 0;

        for(int i=0; i<self.length(); i++) {
            if(self.items(i) == item) {
                c++;

                if(c == count) {
                    return i;
                }
            }
        }

        return -1;
    }

    int index(int count=1) with bool block(T item) {
        int c = 0;

        for(int i=0; i<self.length(); i++) {
            if(block(self.items(i)).get2()) {
                c++;

                if(c == count) {
                    return i;
                }
            }
        }

        return -1;
    }

    virtual String toString() {
        StringBuffer result = new StringBuffer();
        
        result.append("{");

        for(int i=0; i<self.length(); i++) {
            if(i == self.length()-1) {
                result.append(self.items(i).toString());
            }
            else {
                result.append(self.items(i).toString());
                result.append(",");
            }
        }

        result.append("}");

        return result.toString();
    }

    String join(String separator="") {
        String result = "";

        for(int i=0; i<self.length(); i++) {
            if(i == self.length()-1) {
                result += self.items(i).toString();
            }
            else {
                result += self.items(i).toString();
                result += separator;
            }
        }

        return result;
    }

    int rindex(T@Nullable item, int count=1) {
        int c = 0;
        for(int i=self.length()-1; i>=0; i--) {
            if(self.items(i) == item) {
                c++;

                if(c == count) {
                    return i;
                }
            }
        }

        return -1;
    }

    int rindex(int count=1) with bool block(T item) {
        int c = 0;
        for(int i=self.length()-1; i>=0; i--) {
            if(block(self.items(i)).get2()) {
                c++;

                if(c == count) {
                    return i;
                }
            }
        }

        return -1;
    }

    Array<T> each() with void block(T item) {
        for(int i=0; i<self.length(); i++) {
            bool break_existance = block(self.items(i));
            if(break_existance) {
                break;
            }
        }

        return self;
    }
    Array<T> each() with void block(T item, int index) {
        for(int i=0; i<self.length(); i++) {
            bool break_existance = block(self.items(i), i);
            if(break_existance) {
                break;
            }
        }

        return self;
    }
    Array<T> clear() {
        self.setValue(new Array<T>());
        return self;
    }

    Array<anonymous> collect() with anonymous block(T item) {
        Array<anonymous> new_array = new Array<anonymous>();

        for(int i=0; i<self.length(); i++) {
            new_array.add(block(self.items(i)).get2());
        }

        return new_array;
    }

    Array<T> concat(Array<T> array) {
        for(int i=0; i<array.length(); i++) {
            self.add(array.items(i));
        }

        return self;
    }

/*
    Array<T> cycle(int number) with void block(T item) {
        for(int i=0; i<number; i++) {
            for(int j=0; j<self.length(); j++) {
                block(self.items(j));
            }
        }

        return self;
    }
*/

    Array<T> deleteIf() with bool block(T item) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(!block(self.items(i)).get2()) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }

    /*
    Array<T> drop(int number) {
        Array<T> new_array = new Array<T>();

        int number2 = number;

        if(number2 < 0) { number2 = 0; }
        if(number2 >= self.length()) { number2 = self.length(); }

        for(int i=number2; i<self.length(); i++) {
            new_array.add(self.items(i));
        }

        self.setValue(new_array);

        return self;
    }

    Array<T> dropWhile() with bool block(T item) {
        Array<T> new_array = new Array<T>();
        bool addition = false;

        for(int i=0; i<self.length(); i++) {
            if(!addition && !block(self.items(i)).get2()) {
                addition = true;
            }

            if(addition) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }
*/

/*
    Array<T> eachIndex() with void block(int index) {
        for(int i=0; i<self.length(); i++) {
            block(i);
        }

        return self;
    }
*/

    Array<T> fill(T@Nullable item) {
        for(int i=0; i<self.length(); i++) {
            self.setItem(i, item.clone());
        }

        return self;
    }

    Array<T> fill() with T block(int index) {
        for(int i=0; i<self.length(); i++) {
            self.setItem(i, block(i).get2());
        }

        return self;
    }

    Array<T> fill(T@Nullable item, Range range) {
        int head = range.head();
        int tail = range.tail();

        if(head == null) { head = self.length(); }
        if(tail == null) { tail = self.length(); }
        if(head < 0) { head += self.length(); }
        if(tail < 0) { tail += self.length(); }

        if(head < tail) {
            int length = self.length();

            for(int i=head; i<tail; i++) {
                if(i < length) {
                    self.setItem(i, item);
                }
                else {
                    self.add(item);
                }
            }
        }
        else {
            int length = self.length();

            for(int i=head-1; i>=tail; i--) {
                if(i < length) {
                    self.setItem(i, item);
                }
                else {
                    self.add(item);
                }
            }
        }

        return self;
    }

    Array<T> fill(Range range) with T block(int index) {
        int head = range.head();
        int tail = range.tail();

        if(head == null) { head = self.length(); }
        if(tail == null) { tail = self.length(); }
        if(head < 0) { head += self.length(); }
        if(tail < 0) { tail += self.length(); }

        if(head < tail) {
            int length = self.length();

            for(int i=head; i<tail; i++) {
                if(i < length) {
                    self.setItem(i, block(i).get2());
                }
                else {
                    self.add(block(i).get2());
                }
            }
        }
        else {
            int length = self.length();

            for(int i=tail; i<head; i++) {
                if(i < length) {
                    self.setItem(i, block(i).get2());
                }
                else {
                    self.add(block(i).get2());
                }
            }
        }

        return self;
    }

/*
    Array<T> first(int num) {
        Array<T> new_array = new Array<T>();

        int num2 = num;

        if(num2 < 0) {
            num2 += self.length();
        }
        if(num2 >= self.length()) {
            num2 = self.length();
        }

        if(num2 < 0) {
            num2 = 0;
        }

        for(int i=0; i<num2; i++) {
            new_array.add(self.items(i));
        }

        return new_array;
    }
*/

    Array<T> insert(int index, T@Nullable item) {
        Array<T> new_array = new Array<T>();

        if(index < 0) {
            index += self.length();
        }

        if(index < 0) {
            index = 0;
        }

        if(index < self.length()) {
            for(int i=0; i<index; i++) {
                new_array.add(self.items(i));
            }

            new_array.add(item);

            for(int i=index; i<self.length(); i++) {
                new_array.add(self.items(i));
            }
        }
        else {
            for(int i=0; i<self.length(); i++) {
                new_array.add(self.items(i));
            }

            for(int i=self.length(); i<index; i++) {
                new_array.add(null);
            }

            new_array.add(item);
        }

        self.setValue(new_array);

        return self;
    }

    Array<T> insert(int index, Array<T> array) {
        Array<T> new_array = new Array<T>();

        if(index < 0) {
            index += self.length();
        }

        if(index < 0) {
            index = 0;
        }

        if(index < self.length()) {
            for(int i=0; i<index; i++) {
                new_array.add(self.items(i));
            }

            for(int i=0; i<array.length(); i++) {
                new_array.add(array.items(i));
            }

            for(int i=index; i<self.length(); i++) {
                new_array.add(self.items(i));
            }
        }
        else {
            for(int i=0; i<self.length(); i++) {
                new_array.add(self.items(i));
            }

            for(int i=self.length(); i<index; i++) {
                new_array.add(null);
            }

            for(int i=0; i<array.length(); i++) {
                new_array.add(array.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }

/*
    Array<T> keepIf() with bool block(T item) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(block(self.items(i)).get2()) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }

    Array<T> last(int num) {
        Array<T> new_array = new Array<T>();
        int num2 = num;

        if(num2 < 0) {
            num2 = 0;
        }

        if(num2 >= self.length()) {
            num2 = self.length();
        }

        for(int i=self.length()-num2; i<self.length(); i++) {
            new_array.add(self.items(i));
        }

        return new_array;
    }
*/
/*
    Array<T> pop(int num) {
        if(self.length() == 0) {
            return null;
        }

        int num2 = num;

        if(num2 < 0) { 
            num2 = 0 
        }

        if(num2 >= self.length()) {
            num2 = self.length();
        }

        Array<T> new_array = new Array<T>();
        Array<T> new_array2 = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(i < self.length()-num2) {
                new_array.add(self.items(i));
            }
            else {
                new_array2.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return new_array2;
    }
*/

    Array<T> push(T@Nullable item) {
        self.add(item);
        return self;
    }

    Array<T> reverse() {
        Array<T> new_array = new Array<T>();

        for(int i=self.length()-1; i>=0; i--) {
            new_array.add(self.items(i));
        }

        self.setValue(new_array);

        return self;
    }

/*
    Array<T> rotate(int num) {
        Array<T> new_array = new Array<T>();

        if(num < 0) {
            for(int i=self.length()+num; i<self.length(); i++) {
                new_array.add(self.items(i));
            }
            for(int i=0; i<self.length()+num; i++) {
                new_array.add(self.items(i));
            }
        }
        else if(num == 0) {
            new_array.setValue(self);
        }
        else {
            for(int i=num; i<self.length(); i++) {
                new_array.add(self.items(i));
            }
            for(int i=0; i<num; i++) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }
*/

    T sample() {
        int index = System.rand() % self.length();

        return self.items(index);
    }

    Array<T> sample(int num) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<num; i++) {
            int index = System.rand() % self.length();

            new_array.add(self.items(index));
        }

        return new_array;
    }

    Array<T> select() with bool block(T item) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(block(self[i]).get2()) {
                new_array.add(self[i]);
            }
        }

        self.setValue(new_array);

        return self;
    }

/*
    T shift() {
        Array<T> new_array = new Array<T>();

        T result = self.items(0);

        for(int i=1; i<self.length(); i++) {
            new_array.add(self.items(i));
        }

        self.setValue(new_array);

        return result;
    }
*/
/*
    Array<T> shift(int num) {
        Array<T> new_array = new Array<T>();

        Array<T> result = new Array<T>();

        int num2 = num;

        if(num2 < 0) {
            num2 = 0;
        }
        if(num2 >= self.length()) {
            num2 = self.length();
        }

        for(int i=0; i<num2; i++) {
            result.add(self.items(i));
        }

        for(int i=num2; i<self.length(); i++) {
            new_array.add(self.items(i));
        }

        self.setValue(new_array);

        return result;
    }

    Array<T> unshift(T@Nullable item) {
        Array<T> new_array = new Array<T>();

        new_array.add(item);

        for(int i=0; i<self.length(); i++) {
            new_array.add(self.items(i));
        }

        self.setValue(new_array);

        return self;
    }

    Array<T> unshift(Array<T> array) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<array.length(); i++) {
            new_array.add(array.items(i));
        }

        for(int i=0; i<self.length(); i++) {
            new_array.add(self.items(i));
        }

        self.setValue(new_array);

        return self;
    }
*/

    Array<T> shuffle() {
        Array<T> new_array = new Array<T>();

        Array<int> squence = new Array<int>();

        for(int i=0; i<self.length(); i++) {
            squence.add(i);
        }

        for(int i=0; i<self.length() * 2; i++) {
            int num = System.rand() % self.length();
            int num2 = System.rand() % self.length();

            if(num != num2) {
                int temp = squence[num];
                squence[num] = squence[num2];
                squence[num2] = temp;
            }
        }

        for(int i=0; i<self.length(); i++) {
            new_array.add(self.items(squence[i]));
        }

        self.setValue(new_array);

        return self;
    }

    Array<T> slice(Range range) {
        Array<T> result = new Array<T>();

        Range corrected_range = new Range();
        range.correct(corrected_range, self.length());

        if(self.length() == 0) {
            result = new Array<T>();
        }
        else if(corrected_range.head() < corrected_range.tail()) {
            for(int i=corrected_range.head(); i<corrected_range.tail(); i++) {
                result.add(self.items(i));
            }
        }
        else {
            for(int i=corrected_range.head()-1; i>=corrected_range.tail(); i--) {
                result.add(self.items(i));
            }
        }

        return result;
    }

    Array<T> operator[](Range range) {
        return self.slice(range);
    }

/*
    Array<T> take(int num) {
        Array<T> result = new Array<T>();

        int num2 = num;

        if(num2 < 0) { num2 = 0 }
        if(num2 > self.length()) { num2 = self.length(); }

        for(int i=0; i<num2; i++) {
            result.add(self.items(i));
        }

        return result;
    }

    Array<T> takeWhile() with bool block(T item) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(!block(self.items(i)).get2()) {
                break;
            }

            new_array.add(self.items(i));
        }

        return new_array;
    }
*/

    Array<T> uniq() {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            if(!new_array.include(self.items(i))) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }

/*
    Array<T> uniq() with T block(T item) {
        Array<T> new_array = new Array<T>();

        for(int i=0; i<self.length(); i++) {
            T item2 = block(self.items(i)).get2();

            bool found = false;
            for(int j=0; j<new_array.length(); j++) {
                if(block(new_array.items(j)).get2() == item2) {
                    found = true;
                    break;
                }
            }

            if(!found) {
                new_array.add(self.items(i));
            }
        }

        self.setValue(new_array);

        return self;
    }
*/

    Array<T> valuesAt(Array<anonymous> params, ...) throws TypeError {
        Array<T> new_array = new Array<T>();

        params.each() {|anonymous param|
            if(param.type() == int) {
                int index = param;
                new_array.add(self.items(index));
            }
            else if(param.type() == Range) {
                Range range = param;
                new_array.concat(self[range]);
            }
            else {
                throw new TypeError("Array.valuesAt() requires Range or int parametor");
            }
        }

        return new_array;
    }
}

class SortableArray<T implements IComparableMore> extends Array<T> implements ICloneable, IInspectable, IComparableMore
{
    virtual bool operator==(SortableArray<anonymous>@Nullable array2) {
        if(self.type() == Null || array2.type() == Null) {
            return self.type() == Null && array2.type() == Null;
        }

        if(self.length() != array2.length()) {
            return false;
        }

        for(int i=0; i<self.length(); i++) {
            if(self[i] != array2[i]) {
                return false;
            }
        }

        return true;
    }
    virtual bool operator!=(SortableArray<anonymous>@Nullable array2) {
        return !(self == array2);
    }
    virtual bool operator>(SortableArray<anonymous>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            if(right.type() == Null) {
                return true;
            }
            else {
                return false;
            }
        }

        if(self.length() == 0 || right.length() == 0) {
            if(right.length() == 0) {
                return true;
            }
            else {
                return false;
            }
        }

        if(self.length() > right.length()) {
            return true;
        }
        else if(self.length() < right.length()) {
            return false;
        }

        if(self[0] > right[0]) {
            return true;
        }
        else {
            return false;
        }
    }
    virtual bool operator<(SortableArray<anonymous>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            if(right.type() == Null) {
                return false;
            }
            else {
                return true;
            }
        }

        if(self.length() == 0 || right.length() == 0) {
            if(right.length() == 0) {
                return false;
            }
            else {
                return true;
            }
        }

        if(self.length() > right.length()) {
            return false;
        }
        else if(self.length() < right.length()) {
            return true;
        }

        if(self[0] < right[0]) {
            return true;
        }
        else {
            return false;
        }
    }

    virtual bool operator>=(SortableArray<anonymous>@Nullable right) {
        return self > right || self == right;
    }

    virtual bool operator<=(SortableArray<anonymous>@Nullable right) {
        return self < right || self == right;
    }

    virtual String toString() {
        String result = "{";

        for(int i=0; i<self.length(); i++) {
            if(i == self.length()-1) {
                result += self.items(i).toString();
            }
            else {
                result += self.items(i).toString();
                result += ",";
            }
        }

        result += "}";

        return result;
    }

    /// deep copy ///
    virtual SortableArray<T> clone() throws Exception {
        SortableArray<T> new_array = new SortableArray<T>();

        for(int i=0; i<self.length(); i++) {
            new_array.add(self.items(i).clone());
        }

        return new_array;
    }

    /// shallow copy ///
    virtual SortableArray<T> dup() throws Exception {
        SortableArray<T> new_array = new SortableArray<T>();

        new_array.setValue(self);

        return new_array;
    }

    private void quickSort(SortableArray<T> array, int left, int right) {
        int l_hold = left;
        int r_hold = right;

        T pivot = array[left];
        int pivot_num = left;

        while(left < right) {
            while((array[right] >= pivot) && (left < right)) {
                right--;
            }

            if(left != right) {
                array[left] = array[right];
                left++;
            }

            while((array[left] <= pivot) && (left < right)) {
                left++;
            }

            if(left != right) {
                array[right] = array[left];
                right--;
            }
        }

        array[left] = pivot;

        pivot_num = left;

        left = l_hold;
        right = r_hold;
        if(left < pivot_num) {
            self.quickSort(array, left, pivot_num-1);
        }

        if(right > pivot_num) {
            self.quickSort(array, pivot_num+1, right);

        }
    }

    SortableArray<T> sort() {
        SortableArray<T> array = self.clone();
        
        array.quickSort(array, 0, self.length()-1);

        self.setValue(array);

        return self;
    }

    private void quickSortWithBlock(SortableArray<T> array, int left, int right) with int block(T item, T item2) 
    {
        int l_hold = left;
        int r_hold = right;

        T pivot = array[left];
        int pivot_num = left;

        while(left < right) {
            while(bool { int result = block(array[right], pivot).get2(); result == 1 || result == 0} && (left < right)) {
                right--;
            }

            if(left != right) {
                array[left] = array[right];
                left++;
            }

            while(bool { int result2 = block(pivot, array[left]).get2(); result2 == 1 || result2 == 0} && (left < right)) 
            {
                left++;
            }

            if(left != right) {
                array[right] = array[left];
                right--;
            }
        }

        array[left] = pivot;

        pivot_num = left;

        left = l_hold;
        right = r_hold;
        if(left < pivot_num) {
            self.quickSortWithBlock(array, left, pivot_num-1) with block;
        }

        if(right > pivot_num) {
            self.quickSortWithBlock(array, pivot_num+1, right) with block;
        }
    }

    SortableArray<T> sort() with int block(T item, T item2) {
        SortableArray<T> array = self.clone();
        
        array.quickSortWithBlock(array, 0, self.length()-1) with block;

        self.setValue(array);

        return self;
    }

    private void quickSortBy(SortableArray<T> array, int left, int right) with anonymous block(T item) {
        int l_hold = left;
        int r_hold = right;

        T pivot_item = array[left];
        anonymous pivot_value = block(array[left]).get2();
        int pivot_num = left;

        while(left < right) {
            anonymous block_result = block(array[right]).get2();
            while((block_result >= pivot_value) && (left < right)) {
                right--;
            }

            if(left != right) {
                array[left] = array[right];
                left++;
            }

            anonymous block_result2 = block(array[left]).get2();
            while((block_result2 <= pivot_value) && (left < right)) {
                left++;
            }

            if(left != right) {
                array[right] = array[left];
                right--;
            }
        }

        array[left] = pivot_item;

        pivot_num = left;

        left = l_hold;
        right = r_hold;
        if(left < pivot_num) {
            self.quickSortBy(array, left, pivot_num-1) with block;
        }

        if(right > pivot_num) {
            self.quickSortBy(array, pivot_num+1, right) with block;

        }
    }

    SortableArray<T> sortBy() with anonymous block(T item) {
        SortableArray<T> array = self.clone();

        array.quickSortBy(array, 0, self.length()-1) with block;

        self.setValue(array);

        return array;

    }
}

native class Hash<K implements IComparable, V implements IComparable> implements ICloneable, IComparable, IInspectable, IHashKey
{
    native virtual void setValue(Hash<K, V> value) throws MethodMissingException;

    native Hash<K,V> erase(K key) throws MethodMissingException, Exception;

    native Tuple<K,V>@CheckForNull assoc(K key) throws MethodMissingException;

    native Hash<K,V> put(K key, V item) throws MethodMissingException;
    native int length();
    native Hash<K, V> each() with void block(K key, V value);

    Hash<K,V> toHash() {
        return new Hash<K,V>(self);
    }

    V@CheckForNull get(K key) throws MethodMissingException {
        Tuple<K,V> pair = self.assoc(key);

        if(pair == null) { return null; }

        return pair.get2();
    }

    V fetch(K key) throws KeyNotFoundException {
        Tuple<K,V> pair = self.assoc(key);

        if(pair == null) {
            throw new KeyNotFoundException("key not found");
        }

        return pair.get2();
    }

    V@CheckForNull operator[](K key) throws MethodMissingException {
        return self.get(key);
    }

    Hash<K,V> operator[]=(K key, V item) throws MethodMissingException {
        return self.put(key, item);
    }

    Array<K> keys() {
        Array<K> array = new Array<K>();

        self.each() {|K key, V value| 
            array.add(key);
        }

        return array;
    }

    Array<V> values() {
        Array<V> array = new Array<V>();

        self.each() {|K key, V value| 
            array.add(value);
        }

        return array;
    }

    Array<Tuple<K,V>> toArray() {
        Array<Tuple<K,V>> array = new Array<Tuple<K,V>>();

        self.each() {|K key, V value|
            Tuple<K, V> tuple = new Tuple<K, V>();

            tuple.set1(key);
            tuple.set2(value);

            array.add(tuple);
        }

        return array;
    }

    virtual bool operator==(Hash<K,V>@Nullable hash) throws MethodMissingException {
        if(self.type() == Null || hash.type() == Null) {
            return self.type() == Null && hash.type() == Null;
        }

        Array<Tuple<K,V>> left_array = self.toArray();
        Array<Tuple<K,V>> right_array = hash.toArray();

        if(left_array.length() != right_array.length()) {
            return false;
        }

        for(int i=0; i<left_array.length(); i++) {
            bool found = false;

            for(int j=0; j<right_array.length(); j++) {
                if(left_array[i] == right_array[j]) {
                    found = true;
                }
            }

            if(!found) {
                return false;
            }
        }

        return true;
    }
    virtual bool operator!=(Hash<K,V>@Nullable hash) throws MethodMissingException {
        return !(self == hash);
    }

    Hash<K,V> clear() throws MethodMissingException {
        self.setValue(new Hash<K,V>());
        return self;
    }

    virtual Hash<K,V> clone() throws MethodMissingException {
        Hash<K,V> new_hash = new Hash<K,V>();
        Array<Tuple<K,V>> array = self.toArray();
        for(int i=0; i<array.length(); i++) {
            new_hash.put(array[i].get1().clone(), array[i].get2().clone());
        }
        return new_hash;
    }

    virtual Hash<K,V> dup() throws MethodMissingException {
        Hash<K,V> new_hash = new Hash<K,V>();
        new_hash.setValue(self);
        return new_hash;
    }

    virtual String toString() {
        StringBuffer result = new StringBuffer("{");

        Array<Tuple<K,V>> array = self.toArray();
        for(int i=0; i<array.length(); i++) {
            result += array[i].get1().toString() + "=>" + array[i].get2().toString();
            if(i < array.length()-1) {
                result += ",";
            }
        }

        result += "}";

        return result.toString();
    }

    virtual int hashValue() {
        return self.toArray().hashValue();
    }

/*
    anonymous delete(K key) with anonymous block(K key) throws MethodMissingException
    {
        V item = self.erase(key);

        if(item == null) {
            return block(key).get2();
        }
        else {
            return item;
        }
    }
*/

    Hash<K,V> deleteIf() with bool block2(K key, V value) {
        self.each() { |K key, V value|
            if(block2(key, value).get2()) {
                self.erase(key);
            }
        }

        return self;
    }

    //bool empty() { return self.length() == 0; }

    K@CheckForNull key(V value) {
        Array<Tuple<K,V>> array = self.toArray();

        for(int i=0; i<array.length(); i++) {
            if(array[i].get2() == value) {
                return array[i].get1();
            }
        }

        return null;
    }

    Hash<V,K> invert() throws KeyOverlappingException,MethodMissingException {
        Hash<V,K> new_hash = new Hash<V, K>();
        Array<V> keys = self.values();

        self.each() { |K key, V value|
            if(new_hash.get(value) != null) {
                throw new KeyOverlappingException("There is the same key");
            }
            else {
                new_hash.put(value, key);
            }
        }

        return new_hash;
    }

    Hash<K,V> select() with bool block(K key, V value) {
        Hash<K, V> new_hash = new Hash<K, V>();

        self.each() {|K key, V value|
            if(block(key, value).get2()) {
                new_hash.put(key, value);
            }
        }

        self.setValue(new_hash);

        return self;
    }

    Hash<K,V> merge(Hash<K,V> other) throws MethodMissingException {
        Hash<K, V> new_hash = new Hash<K, V>();

        new_hash.setValue(self);

        other.each() {|K key, V value|
            new_hash.put(key, value);
        }

        self.setValue(new_hash);

        return self;
    }

/*
    Hash<K,V> merge(Hash<K,V> other) with V block2(K key, V value1, V value2) throws MethodMissingException
    {
        Hash<K, V> new_hash = new Hash<K, V>();

        new_hash.setValue(self);

        other.each() {|K key, V value|
            V value2 = new_hash.get(key);

            if(value2 != null) {
                new_hash.put(key, block2(key, value2, value).get2());
            }
            else {
                new_hash.put(key, value);
            }
        }

        self.setValue(new_hash);

        return self;
    }
*/

    Tuple<K,V>@CheckForNull rassoc(V value) throws MethodMissingException {
        Tuple<K,V> result = null;

        self.each() {|K key, V value2|
            if(value2 == value) {
                result = new Tuple<K,V>(key, value2);
            }
        }

        return result;
    }

    Array<V> valuesAt(Array<anonymous> param, ...) {
        Array<V> new_array = new Array<V>();
        param.each() {|anonymous key|
            if(key.type() == K) {
                new_array.add(self.get(key));
            }
        }
        return new_array;
    }
}

class Tuple<T1 implements IComparable> implements IHashKey, IInspectable, ICloneable, IComparable
{
    T1 value1;

    Tuple<T1> toTuple() {
        return new Tuple<T1>(self);
    }

    Tuple(T1 value) {
        self.value1 = value;
    }

    void set1(T1 value) {
        self.value1 = value;
    }

    T1 get1() {
        return self.value1;
    }

    virtual bool operator==(Tuple<T1>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.value1 == right.value1;
    }
    virtual bool operator!=(Tuple<T1>@Nullable right) {
        return !(self == right);
    }

    virtual Tuple<T1> clone() throws Exception{
        Tuple<T1> new_tuple = new Tuple<T1>();

        new_tuple.set1(self.get1().clone());

        return new_tuple;
    }

    virtual Tuple<T1> dup() throws Exception {
        Tuple<T1> new_tuple = new Tuple<T1>();

        new_tuple.set1(self.get1());

        return new_tuple;
    }

    virtual String toString() {
        return "(" + self.value1.toString() + ")";
    }
    virtual int hashValue() {
        return self.value1.hashValue();
    }
}

class Tuple<T1 implements IComparable, T2 implements IComparable> implements IHashKey, IInspectable, ICloneable, IComparable
{
    T1 value1;
    T2 value2;

    Tuple(T1 value, T2 value2) {
        self.value1 = value;
        self.value2 = value2;
    }

    Tuple<T1, T2> toTuple() {
        return new Tuple<T1, T2>(self);
    }

    void set1(T1 value) {
        self.value1 = value;
    }

    void set2(T2 value) {
        self.value2 = value;
    }

    T1 get1() {
        return self.value1;
    }

    T2 get2() {
        return self.value2;
    }

    virtual bool operator==(Tuple<T1, T2>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.value1 == right.value1 && self.value2 == right.value2;
    }
    virtual bool operator!=(Tuple<T1, T2>@Nullable right) {
        return !(self == right);
    }

    virtual Tuple<T1, T2> clone() throws Exception{
        Tuple<T1, T2> new_tuple = new Tuple<T1, T2>();

        new_tuple.set1(self.get1().clone());
        new_tuple.set2(self.get2().clone());

        return new_tuple;
    }

    virtual Tuple<T1, T2> dup() throws Exception {
        Tuple<T1, T2> new_tuple = new Tuple<T1, T2>();

        new_tuple.set1(self.get1());
        new_tuple.set2(self.get2());

        return new_tuple;
    }

    virtual String toString() {
        return "(" + self.value1.toString() + "," + self.value2.toString() + ")";
    }
    virtual int hashValue() {
        return self.value1.hashValue() ^ self.value2.hashValue();
    }
}

class Tuple<T1 implements IComparable, T2 implements IComparable, T3 implements IComparable> implements IHashKey, IInspectable, ICloneable, IComparable
{
    T1 value1;
    T2 value2;
    T3 value3;

    Tuple(T1 value, T2 value2, T3 value3) {
        self.value1 = value;
        self.value2 = value2;
        self.value3 = value3;
    }

    Tuple<T1, T2, T3> toTuple() {
        return new Tuple<T1, T2, T3>(self);
    }

    void set1(T1 value) {
        self.value1 = value;
    }

    void set2(T2 value) {
        self.value2 = value;
    }

    void set3(T3 value) {
        self.value3 = value;
    }

    T1 get1() {
        return self.value1;
    }

    T2 get2() {
        return self.value2;
    }

    T3 get3() {
        return self.value3;
    }

    virtual bool operator==(Tuple<T1, T2, T3>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.value1 == right.value1 && self.value2 == right.value2 && self.value3 == right.value3;
    }
    virtual bool operator!=(Tuple<T1, T2, T3>@Nullable right) {
        return !(self == right);
    }

    virtual Tuple<T1, T2, T3> clone() throws Exception{
        Tuple<T1, T2, T3> new_tuple = new Tuple<T1, T2, T3>();

        new_tuple.set1(self.get1().clone());
        new_tuple.set2(self.get2().clone());
        new_tuple.set3(self.get3().clone());

        return new_tuple;
    }

    virtual Tuple<T1, T2, T3> dup() throws Exception {
        Tuple<T1, T2, T3> new_tuple = new Tuple<T1, T2, T3>();

        new_tuple.set1(self.get1());
        new_tuple.set2(self.get2());
        new_tuple.set3(self.get3());

        return new_tuple;
    }

    virtual String toString() {
        return "(" + self.value1.toString() + "," + self.value2.toString() + "," + self.value3.toString() + ")";
    }
    virtual int hashValue() {
        return self.value1.hashValue() ^ self.value2.hashValue() ^ self.value3.hashValue();
    }
}

class Tuple<T1 implements IComparable, T2 implements IComparable, T3 implements IComparable, T4 implements IComparable>  implements IHashKey, IInspectable, ICloneable, IComparable
{
    T1 value1;
    T2 value2;
    T3 value3;
    T4 value4;

    Tuple(T1 value, T2 value2, T3 value3, T4 value4) {
        self.value1 = value;
        self.value2 = value2;
        self.value3 = value3;
        self.value4 = value4;
    }

    Tuple<T1, T2, T3, T4> toTuple() {
        return new Tuple<T1, T2, T3, T4>(self);
    }

    void set1(T1 value) {
        self.value1 = value;
    }

    void set2(T2 value) {
        self.value2 = value;
    }

    void set3(T3 value) {
        self.value3 = value;
    }

    void set4(T4 value) {
        self.value4 = value;
    }

    T1 get1() {
        return self.value1;
    }

    T2 get2() {
        return self.value2;
    }

    T3 get3() {
        return self.value3;
    }

    T4 get4() {
        return self.value4;
    }

    virtual bool operator==(Tuple<T1, T2, T3, T4>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.value1 == right.value1 && self.value2 == right.value2 && self.value3 == right.value3 && self.value4 == right.value4;
    }
    virtual bool operator!=(Tuple<T1, T2, T3, T4>@Nullable right) {
        return !(self == right);
    }

    virtual Tuple<T1, T2, T3, T4> clone() throws Exception{
        Tuple<T1, T2, T3, T4> new_tuple = new Tuple<T1, T2, T3, T4>();

        new_tuple.set1(self.get1().clone());
        new_tuple.set2(self.get2().clone());
        new_tuple.set3(self.get3().clone());
        new_tuple.set4(self.get4().clone());

        return new_tuple;
    }

    virtual Tuple<T1, T2, T3, T4> dup() throws Exception {
        Tuple<T1, T2, T3, T4> new_tuple = new Tuple<T1, T2, T3, T4>();

        new_tuple.set1(self.get1());
        new_tuple.set2(self.get2());
        new_tuple.set3(self.get3());
        new_tuple.set4(self.get4());

        return new_tuple;
    }

    virtual String toString() {
        return "(" + self.value1.toString() + "," + self.value2.toString() + "," + self.value3.toString() + "," + self.value4.toString() + ")";
    }
    virtual int hashValue() {
        return self.value1.hashValue() ^ self.value2.hashValue() ^ self.value3.hashValue() ^ self.value4.hashValue();
    }
}

class Tuple<T1 implements IComparable, T2 implements IComparable, T3 implements IComparable, T4 implements IComparable, T5 implements IComparable> implements IHashKey, IInspectable, ICloneable, IComparable
{
    T1 value1;
    T2 value2;
    T3 value3;
    T4 value4;
    T5 value5;

    Tuple(T1 value, T2 value2, T3 value3, T4 value4, T5 value5) {
        self.value1 = value;
        self.value2 = value2;
        self.value3 = value3;
        self.value4 = value4;
        self.value5 = value5;
    }

    Tuple<T1, T2, T3, T4, T5> toTuple() {
        return new Tuple<T1, T2, T3, T4, T5>(self);
    }

    void set1(T1 value) {
        self.value1 = value;
    }

    void set2(T2 value) {
        self.value2 = value;
    }

    void set3(T3 value) {
        self.value3 = value;
    }

    void set4(T4 value) {
        self.value4 = value;
    }

    void set5(T5 value) {
        self.value5 = value;
    }

    T1 get1() {
        return self.value1;
    }

    T2 get2() {
        return self.value2;
    }

    T3 get3() {
        return self.value3;
    }

    T4 get4() {
        return self.value4;
    }

    T5 get5() {
        return self.value5;
    }

    virtual bool operator==(Tuple<T1, T2, T3, T4, T5>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.value1 == right.value1 && self.value2 == right.value2 && self.value3 == right.value3 && self.value4 == right.value4 && self.value5 == right.value5;
    }
    virtual bool operator!=(Tuple<T1, T2, T3, T4, T5>@Nullable right) {
        return !(self == right);
    }

    virtual Tuple<T1, T2, T3, T4, T5> clone() throws Exception{
        Tuple<T1, T2, T3, T4, T5> new_tuple = new Tuple<T1, T2, T3, T4, T5>();

        new_tuple.set1(self.get1().clone());
        new_tuple.set2(self.get2().clone());
        new_tuple.set3(self.get3().clone());
        new_tuple.set4(self.get4().clone());
        new_tuple.set5(self.get5().clone());

        return new_tuple;
    }

    virtual Tuple<T1, T2, T3, T4, T5> dup() throws Exception {
        Tuple<T1, T2, T3, T4, T5> new_tuple = new Tuple<T1, T2, T3, T4, T5>();

        new_tuple.set1(self.get1());
        new_tuple.set2(self.get2());
        new_tuple.set3(self.get3());
        new_tuple.set4(self.get4());
        new_tuple.set5(self.get5());

        return new_tuple;
    }

    virtual String toString() {
        return "(" + self.value1.toString() + "," + self.value2.toString() + "," + self.value3.toString() + "," + self.value4.toString() + "," + self.value5.toString() + ")";
    }
    virtual int hashValue() {
        return self.value1.hashValue() ^ self.value2.hashValue() ^ self.value3.hashValue() ^ self.value4.hashValue() ^ self.value5.hashValue();
    }
}

class Tuple<T1 implements IComparable, T2 implements IComparable, T3 implements IComparable, T4 implements IComparable, T5 implements IComparable, T6 implements IComparable>  implements IHashKey, IInspectable, ICloneable, IComparable
{
    T1 value1;
    T2 value2;
    T3 value3;
    T4 value4;
    T5 value5;
    T6 value6;

    Tuple(T1 value, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6) {
        self.value1 = value;
        self.value2 = value2;
        self.value3 = value3;
        self.value4 = value4;
        self.value5 = value5;
        self.value6 = value6;
    }

    Tuple<T1, T2, T3, T4, T5,T6> toTuple() {
        return new Tuple<T1, T2, T3, T4, T5, T6>(self);
    }

    void set1(T1 value) {
        self.value1 = value;
    }

    void set2(T2 value) {
        self.value2 = value;
    }

    void set3(T3 value) {
        self.value3 = value;
    }

    void set4(T4 value) {
        self.value4 = value;
    }

    void set5(T5 value) {
        self.value5 = value;
    }

    void set6(T6 value) {
        self.value6 = value;
    }

    T1 get1() {
        return self.value1;
    }

    T2 get2() {
        return self.value2;
    }

    T3 get3() {
        return self.value3;
    }

    T4 get4() {
        return self.value4;
    }

    T5 get5() {
        return self.value5;
    }

    T6 get6() {
        return self.value6;
    }

    virtual bool operator==(Tuple<T1, T2, T3, T4, T5, T6>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.value1 == right.value1 && self.value2 == right.value2 && self.value3 == right.value3 && self.value4 == right.value4 && self.value5 == right.value5 && self.value6 == right.value6;
    }
    virtual bool operator!=(Tuple<T1, T2, T3, T4, T5, T6>@Nullable right) {
        return !(self == right);
    }

    virtual Tuple<T1, T2, T3, T4, T5, T6> clone() throws Exception{
        Tuple<T1, T2, T3, T4, T5, T6> new_tuple = new Tuple<T1, T2, T3, T4, T5, T6>();

        new_tuple.set1(self.get1().clone());
        new_tuple.set2(self.get2().clone());
        new_tuple.set3(self.get3().clone());
        new_tuple.set4(self.get4().clone());
        new_tuple.set5(self.get5().clone());
        new_tuple.set6(self.get6().clone());

        return new_tuple;
    }

    virtual Tuple<T1, T2, T3, T4, T5, T6> dup() throws Exception {
        Tuple<T1, T2, T3, T4, T5, T6> new_tuple = new Tuple<T1, T2, T3, T4, T5, T6>();

        new_tuple.set1(self.get1());
        new_tuple.set2(self.get2());
        new_tuple.set3(self.get3());
        new_tuple.set4(self.get4());
        new_tuple.set5(self.get5());
        new_tuple.set6(self.get6());

        return new_tuple;
    }

    virtual String toString() {
        return "(" + self.value1.toString() + "," + self.value2.toString() + "," + self.value3.toString() + "," + self.value4.toString() + "," + self.value5.toString() + "," + self.value6.toString() + ")";
    }
    virtual int hashValue() {
        return self.value1.hashValue() ^ self.value2.hashValue() ^ self.value3.hashValue() ^ self.value4.hashValue() ^ self.value5.hashValue() ^ self.value6.hashValue();
    }
}

class Tuple<T1 implements IComparable, T2 implements IComparable, T3 implements IComparable, T4 implements IComparable, T5 implements IComparable, T6 implements IComparable, T7 implements IComparable>  implements IHashKey, IInspectable, ICloneable, IComparable
{
    T1 value1;
    T2 value2;
    T3 value3;
    T4 value4;
    T5 value5;
    T6 value6;
    T7 value7;

    Tuple(T1 value, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7) {
        self.value1 = value;
        self.value2 = value2;
        self.value3 = value3;
        self.value4 = value4;
        self.value5 = value5;
        self.value6 = value6;
        self.value7 = value7;
    }

    Tuple<T1, T2, T3, T4, T5, T6, T7> toTuple() {
        return new Tuple<T1, T2, T3, T4, T5, T6, T7>(self);
    }

    void set1(T1 value) {
        self.value1 = value;
    }

    void set2(T2 value) {
        self.value2 = value;
    }

    void set3(T3 value) {
        self.value3 = value;
    }

    void set4(T4 value) {
        self.value4 = value;
    }

    void set5(T5 value) {
        self.value5 = value;
    }

    void set6(T6 value) {
        self.value6 = value;
    }

    void set7(T7 value) {
        self.value7 = value;
    }

    T1 get1() {
        return self.value1;
    }

    T2 get2() {
        return self.value2;
    }

    T3 get3() {
        return self.value3;
    }

    T4 get4() {
        return self.value4;
    }

    T5 get5() {
        return self.value5;
    }

    T6 get6() {
        return self.value6;
    }

    T7 get7() {
        return self.value7;
    }

    virtual bool operator==(Tuple<T1, T2, T3, T4, T5, T6, T7>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.value1 == right.value1 && self.value2 == right.value2 && self.value3 == right.value3 && self.value4 == right.value4 && self.value5 == right.value5 && self.value6 == right.value6 && self.value7 == right.value7;
    }
    virtual bool operator!=(Tuple<T1, T2, T3, T4, T5, T6, T7>@Nullable right) {
        return !(self == right);
    }

    virtual Tuple<T1, T2, T3, T4, T5, T6, T7> clone() throws Exception{
        Tuple<T1, T2, T3, T4, T5, T6, T7> new_tuple = new Tuple<T1, T2, T3, T4, T5, T6, T7>();

        new_tuple.set1(self.get1().clone());
        new_tuple.set2(self.get2().clone());
        new_tuple.set3(self.get3().clone());
        new_tuple.set4(self.get4().clone());
        new_tuple.set5(self.get5().clone());
        new_tuple.set6(self.get6().clone());
        new_tuple.set7(self.get7().clone());

        return new_tuple;
    }

    virtual Tuple<T1, T2, T3, T4, T5, T6, T7> dup() throws Exception {
        Tuple<T1, T2, T3, T4, T5, T6, T7> new_tuple = new Tuple<T1, T2, T3, T4, T5, T6, T7>();

        new_tuple.set1(self.get1());
        new_tuple.set2(self.get2());
        new_tuple.set3(self.get3());
        new_tuple.set4(self.get4());
        new_tuple.set5(self.get5());
        new_tuple.set6(self.get6());
        new_tuple.set7(self.get7());

        return new_tuple;
    }

    virtual String toString() {
        return "(" + self.value1.toString() + "," + self.value2.toString() + "," + self.value3.toString() + "," + self.value4.toString() + "," + self.value5.toString() + "," + self.value6.toString() + "," + self.value7.toString() + ")";
    }
    virtual int hashValue() {
        return self.value1.hashValue() ^ self.value2.hashValue() ^ self.value3.hashValue() ^ self.value4.hashValue() ^ self.value5.hashValue() ^ self.value6.hashValue() ^ self.value7.hashValue();
    }
}

class Tuple<T1 implements IComparable, T2 implements IComparable, T3 implements IComparable, T4 implements IComparable, T5 implements IComparable, T6 implements IComparable, T7 implements IComparable, TRest implements IComparable>  implements IHashKey, IInspectable, ICloneable, IComparable
{
    T1 value1;
    T2 value2;
    T3 value3;
    T4 value4;
    T5 value5;
    T6 value6;
    T7 value7;
    TRest rest;

    Tuple(T1 value, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, TRest rest) 
    {
        self.value1 = value;
        self.value2 = value2;
        self.value3 = value3;
        self.value4 = value4;
        self.value5 = value5;
        self.value6 = value6;
        self.value7 = value7;
        self.rest = rest;
    }

    Tuple<T1, T2, T3, T4, T5,T6, T7, TRest> toTuple() {
        return new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>(self);
    }

    void set1(T1 value) {
        self.value1 = value;
    }

    void set2(T2 value) {
        self.value2 = value;
    }

    void set3(T3 value) {
        self.value3 = value;
    }

    void set4(T4 value) {
        self.value4 = value;
    }

    void set5(T5 value) {
        self.value5 = value;
    }

    void set6(T6 value) {
        self.value6 = value;
    }

    void set7(T7 value) {
        self.value7 = value;
    }

    void setRest(TRest value) {
        self.rest = value;
    }

    T1 get1() {
        return self.value1;
    }

    T2 get2() {
        return self.value2;
    }

    T3 get3() {
        return self.value3;
    }

    T4 get4() {
        return self.value4;
    }

    T5 get5() {
        return self.value5;
    }

    T6 get6() {
        return self.value6;
    }

    T7 get7() {
        return self.value7;
    }

    TRest getRest() {
        return self.rest;
    }

    virtual bool operator==(Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.value1 == right.value1 && self.value2 == right.value2 && self.value3 == right.value3 && self.value4 == right.value4 && self.value5 == right.value5 && self.value6 == right.value6 && self.value7 == right.value7 && self.rest == right.rest;
    }
    virtual bool operator!=(Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>@Nullable right) {
        return !(self == right);
    }

    virtual Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> clone() throws Exception{
        Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> new_tuple = new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>();

        new_tuple.set1(self.get1().clone());
        new_tuple.set2(self.get2().clone());
        new_tuple.set3(self.get3().clone());
        new_tuple.set4(self.get4().clone());
        new_tuple.set5(self.get5().clone());
        new_tuple.set6(self.get6().clone());
        new_tuple.set7(self.get7().clone());
        new_tuple.setRest(self.getRest().clone());

        return new_tuple;
    }

    virtual Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> dup() throws Exception {
        Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> new_tuple = new Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>();

        new_tuple.set1(self.get1());
        new_tuple.set2(self.get2());
        new_tuple.set3(self.get3());
        new_tuple.set4(self.get4());
        new_tuple.set5(self.get5());
        new_tuple.set6(self.get6());
        new_tuple.set7(self.get7());
        new_tuple.setRest(self.getRest());

        return new_tuple;
    }

    virtual String toString() {
        return "(" + self.value1.toString() + "," + self.value2.toString() + "," + self.value3.toString() + "," + self.value4.toString() + "," + self.value5.toString() + "," + self.value6.toString() + "," + self.value7.toString() + "," + self.rest.toString() + ")";
    }
    virtual int hashValue() {
        return self.value1.hashValue() ^ self.value2.hashValue() ^ self.value3.hashValue() ^ self.value4.hashValue() ^ self.value5.hashValue() ^ self.value6.hashValue() ^ self.value7.hashValue() ^ self.rest.hashValue();
    }
}


native final class Field implements ICloneable, IInspectable, IComparable
{
    native virtual void setValue(Field field) throws NullPointerException;
    native anonymous classFieldValue() throws NullPointerException, Exception;
    native void setClassFieldValue(anonymous value);
    native int index();

    virtual Field clone() throws Exception {
        Field new_field = new Field();
        new_field.setValue(self);
        return new_field;
    }

    virtual Field dup() {
        return self.clone();
    }

    native bool isStaticField() throws NullPointerException;
    native bool isPrivateField() throws NullPointerException;
    native bool isProtectedField() throws NullPointerException;

    bool isPublicField() throws NullPointerException {
        return !self.isPrivateField() && !self.isProtectedField();
    }

    native String name() throws NullPointerException, ConvertingStringCodeException;

    native Type fieldType();

    virtual String toString() {
        return self.fieldType().toString() + " " + self.name();
    }

    virtual bool operator==(Field value) {
        return self.toString() == value.toString() && self.class() == value.class();
    }

    virtual bool operator!=(Field value) {
        return !(self == value);
    }

    native Type class();
}

native final class Method implements ICloneable, IInspectable, IComparable
{
    native virtual void setValue(Method field);

    virtual Method clone() throws Exception {
        Method new_method = new Method();
        new_method.setValue(self);
        return new_method;
    }

    virtual Method dup() {
        return self.clone();
    }

    native anonymous invokeMethod(Object object, Array<anonymous> param, ...) throws NullPointerException, MethodMissingException;

    native bool isNativeMethod() throws NullPointerException;
    native bool isClassMethod() throws NullPointerException;
    native bool isPrivateMethod() throws NullPointerException;
    native bool isConstructor() throws NullPointerException;
    native bool isSynchronizedMethod() throws NullPointerException;
    native bool isVirtualMethod() throws NullPointerException;
    native bool isAbstractMethod() throws NullPointerException;
    native bool isProtectedMethod() throws NullPointerException;
    native bool isParamVariableArguments() throws NullPointerException;

    bool isPublicMethod() throws NullPointerException{
        return !self.isPrivateMethod() && !self.isProtectedMethod();
    }

    native String name() throws NullPointerException;
    native String path() throws NullPointerException;

    native Type resultType() throws NullPointerException;
    native Array<Type> parametors() throws NullPointerException;
    native bool blockExists() throws NullPointerException;
    native Type blockResultType() throws NullPointerException;
    native Array<Type> blockParametors() throws NullPointerException;
    native Array<Type> exceptions() throws NullPointerException;

    virtual String toString() {
        String result = "";

        result += self.resultType().toString() + " " + self.name() + "(" + self.parametors().toString()[1..-1] + ")";

        if(self.blockExists()) {
            result += " with " + self.blockResultType().toString() + "(" + self.blockParametors().toString()[1..-1] + ")";
        }

        if(self.exceptions().length() > 0) {
            result += " throws " + self.exceptions().toString()[1..-1];
        }

        return result;
    }

    virtual bool operator==(Method value) {
        return self.toString() == value.toString() && self.class() == value.class();
    }

    virtual bool operator!=(Method value) {
        return !(self == value);
    }

    native Type class();
}

native abstract final class Block implements IInspectable, IComparable
{
    native Array<Type> parametors();
    native Type resultType();

    virtual String toString() {
        return self.resultType().toString() 
            + " Block(" 
            + self.parametors().toString() 
            + ")";
    }

    virtual void setValue(Block value) {
    }
    virtual Block dup() throws Exception {
        return self;
    }
    virtual Block clone() throws Exception {
        return self;
    }

    virtual bool operator==(Block value) {
        return self.toString() == value.toString();
    }
    virtual bool operator!=(Block value) {
        return !(self.toString() == value.toString());
    }
}

final class GenericsParametor
{
    private Array<Type> implementedInterfaces;
    private Type extendsType;

    Array<Type> implementedInterfaces() { 
        return self.implementedInterfaces; 
    }

    Type extendsType() {
        return self.extendsType;
    }
}

native final class Class implements ICloneable, IInspectable, IComparable
{
    native virtual void setValue(Class class);

    virtual Class clone() throws Exception {
        Class new_class = new Class();
        new_class.setValue(self);
        return new_class;
    }

    virtual Class dup() {
        return self.clone();
    }

    native Type toType();

    virtual native String toString();

    String name() {
        return self.toString();
    }

    native anonymous newInstance();

    native Array<Field> fields();
    native Array<Method> methods();

    Array<Method> constructors() {
        Array<Method> constructors = new Array<Method>();

        Array<Type> super_classes = self.superClasses();
        
        for(int i=0; i<super_classes.length(); i++) {
            Class super_class = super_classes[i].toClass();

            Array<Method> methods = super_class.methods();
            for(int i=0; i<methods.length(); i++) {
                if(methods[i].isConstructor()) {
                    constructors.add(methods[i]);
                }
            }
        }

        Array<Method> methods = self.methods();
        for(int i=0; i<methods.length(); i++) {
            if(methods[i].isConstructor()) {
                constructors.add(methods[i]);
            }
        }

        return constructors;
    }

    Field@Nullable getFieldFromName(String name) {
        Array<Type> super_classes = self.superClasses();
        
        for(int i=0; i<super_classes.length(); i++) {
            Class super_class = super_classes[i].toClass();

            Array<Field> fields = super_class.fields();
            for(int i=0; i<fields.length(); i++) {
                if(fields[i].name() == name) {
                    return fields[i];
                }
            }
        }

        Array<Field> fields = self.fields();
        for(int i=0; i<fields.length(); i++) {
            if(fields[i].name() == name) {
                return fields[i];
            }
        }

        return null;
    }

    Method@Nullable getMethodFromNameAndParametorTypes(String name, Array<Type> params)
    {
        Array<Type> super_classes = self.superClasses();
        
        for(int i=0; i<super_classes.length(); i++) {
            Class super_class = super_classes[i].toClass();

            Array<Method> methods = self.methods();

            for(int i=0; i<methods.length(); i++) {
                if(methods[i].name() == name) {
                    if(methods[i].parametors() == params) {
                        return methods[i];
                    }
                }
            }
        }

        Array<Method> methods = self.methods();

        for(int i=0; i<methods.length(); i++) {
            if(methods[i].name() == name) {
                if(methods[i].parametors() == params) {
                    return methods[i];
                }
            }
        }

        return null;
    }

    native bool isNativeClass();
    native bool isInterface();
    native bool isAbstractClass();
    native bool isFinalClass();
    native bool isStruct();

    virtual bool operator==(Class@Nullable right) {
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        return self.toString() == right.toString();
    }

    virtual bool operator !=(Class@Nullable right) {
        return !(self == right);
    }

    native Array<Type> superClasses();
    native Array<Type> implementedInterfacesOnlyThisClass();

    Array<Type> implementedInterfaces() {
        Array<Type> result = new Array<Type>();

        Array<Type> super_classes = self.superClasses();

        for(int i=0; i<super_classes.length(); i++) {
            Class super_class = super_classes[i].toClass();

            super_class.implementedInterfacesOnlyThisClass().each() {
                |Type interface|

                if(!result.include(interface)) {
                    result.add(interface);
                }
            }
        }

        self.implementedInterfacesOnlyThisClass().each() {
            |Type interface|

            if(!result.include(interface)) {
                result.add(interface);
            }
        }

        return result;
    }
    native Array<Class> classDependences();

    native Array<GenericsParametor> genericsParametorTypes() throws NullPointerException;

}

native final class Type implements ICloneable, IInspectable, IComparable
{
    native virtual void setValue(Type type);

    virtual native String toString();
    native static Type createFromString(String name) throws Exception;
    native bool equals(Type@Nullable value);
    native Class toClass();

    native Type class();
    native Type genericsParam(int index) throws RangeException;
    native int genericsParamNumber();
    native Type@CheckForNull parentClass();
    native int parentClassNumber();

    native bool substitutionPosibility(Type object, bool dynamic_typing=true);

/*
    String namespace() {
        Array<String> group_str = new Array<String>();
        Type class = self.class();

        String class_name = class.toString();

        class_name.scan("\(.+\)::.+", group_str);

        return group_str[0];
    }
*/

    virtual bool operator==(Type@Nullable value) {
        return self.equals(value);
    }
    virtual bool operator !=(Type@Nullable value) {
        return !(self == value);
    }

    virtual Type clone() throws Exception {
        Type new_type = new Type();
        new_type.setValue(self);
        return new_type;
    }

    virtual Type dup() {
        return self.clone();
    }

    bool isInstance(Object object) {
        return object.type() == self
    }
}

class Enum extends int
{
    native static Hash<String, anonymous> toHash();
}

dynamic_typing final native class Null implements ICloneable, IComparable, IInspectable, IComparable extends void
{
    Null() {
    }

    virtual void setValue(Null null) {
    }

    virtual Null dup() {
        return self.clone();
    }

    virtual Null clone() {
        return new Null();
    }

    int toInt() {
        return 0;
    }
    virtual String toString() {
        return "null";
    }
    bool toBool() {
        return false;
    }

    virtual bool operator==(anonymous@Nullable value) {
        return self.type() == Null && value.type() == Null;
    }
    virtual bool operator!=(anonymous@Nullable value) {
        return !(self == value);
    }
}

dynamic_typing final abstract native class anonymous 
{
    virtual void setValue(anonymous value) {
    }
    virtual anonymous dup() {
        return self;
    }
    virtual anonymous clone() {
        return self;
    }
}

abstract native class void
{
}

native final class Thread implements ICloneable
{
    native virtual void setValue(Thread value);
    native nosynchronized Thread() with void block() throws Exception;
    native nosynchronized void join();

    virtual Thread clone() throws Exception {
        Thread new_thread = new Thread();
        new_thread.setValue(self);
        return new_thread;
    }

    virtual Thread dup() {
        return self.clone();
    }
}

native final class Mutex implements ICloneable
{
    native virtual void setValue(Mutex value);

    native void run() with void block();

    virtual Mutex clone() throws Exception {
        Mutex new_mutex = new Mutex();
        new_mutex.setValue(self);
        return new_mutex;
    }

    virtual Mutex dup() {
        return self.clone();
    }
}

final abstract class Clover 
{
    static Array<String> argv = Clover.getCloverArgv();
    alias print;
    alias println;
    alias echo;

    native static Array<String>@Nullable getCloverArgv();
    native static void print(String string) throws NullPointerException, ConvertingStringCodeException;
    static void println(String string) {
        Clover.print(string + "\n");
    }
    static void echo(String string) {
        Clover.print(string + "\n");
    }
    native static void showClasses();
    native static String outputToString() with void block() throws ConvertingStringCodeException;
    native static void gc();

    /// called at the first part of runtime ///
    static bool initialize() {
        String clover_home = System.getenv("HOME") + "/.clover/";

        System.system("if test -x /usr/bin/mkdir; then /usr/bin/mkdir -p " + clover_home + "; else /bin/mkdir -p " + clover_home + "; fi");
        System.system("if test -x /usr/bin/chmod; then /usr/bin/chmod 700 " + clover_home + "; else /bin/chmod 700 " + clover_home + "; fi");
        System.system("if test -x /usr/bin/mkdir; then /usr/bin/mkdir -p " + clover_home + "tmpfiles" + "; else /bin/mkdir -p " + clover_home + "tmpfiles" + "; fi");
        System.system("if test -x /usr/bin/chmod; then /usr/bin/chmod 700 " + clover_home + "tmpfiles" + "; else /bin/chmod 700 " + clover_home + "tmpfiles" + "; fi");

        return true;
    }

    static void runTest(String message, int err_num=2) with bool block() {
        print(message + "...");
        if(block().get2()) {
            println("TRUE");
        }
        else {
            println("FALSE");
            System.exit(err_num);
        }
    }

    static void assert(bool expression, int err_num=2) {
        if(!expression) {
            println("assert abort");
            System.exit(err_num);
        }
    }
}

final abstract class System 
{
    native static String getenv(String env) throws ConvertingStringCodeException;
    native static void setenv(String name, String value, int overwrite) throws SystemException, ConvertingStringCodeException;
    native static nosynchronized int sleep(int second) throws RangeException;
    native static int msleep(int msecond) throws RangeException;
    native static int nanosleep(int nanosecond) throws RangeException;
    native static void exit(int status_code) throws RangeException;
    native static int rand();
    native static void srand(int seed);
    native static int system(String command);
}

/// Exception classes //
class Exception 
{
    protected String message;

    Exception(String message) {
        self.message = message;
    }

    String getMessage() {
        return self.message;
    }
}

class SystemException extends Exception
{
    SystemException(String message) {
        self.message = message;
    }
}

class NullPointerException extends Exception 
{
    NullPointerException(String message) {
        self.message = message;
    }
}

class RangeException extends Exception 
{
    RangeException(String message) {
        self.message = message;
    }
}

class ConvertingStringCodeException extends Exception 
{
    ConvertingStringCodeException(String message) {
        self.message = message;
    }
}

class ClassNotFoundException extends Exception 
{
    ClassNotFoundException(String message) {
        self.message = message;
    }
}

class IOException extends Exception 
{
    IOException(String message) {
        self.message = message;
    }
}

class OverflowException extends Exception 
{
    OverflowException(String message) {
        self.message = message;
    }
}

class CantSolveGenericsType extends Exception 
{
    CantSolveGenericsType(String message) {
        self.message = message;
    }
}

class TypeError extends Exception 
{
    TypeError(String message) {
        self.message = message;
    }
}

class MethodMissingException extends Exception 
{
    MethodMissingException(String message) {
        self.message = message;
    }
}

class DivisionByZeroException extends Exception 
{
    DivisionByZeroException(String message) {
        self.message = message;
    }
}

class OverflowStackSizeException extends Exception 
{
    OverflowStackSizeException(String message) {
        self.message = message;
    }
}

class InvalidRegexException extends Exception 
{
    InvalidRegexException(String message) {
        self.message = message;
    }
}

class KeyNotFoundException extends Exception
{
    KeyNotFoundException(String message) {
        self.message = message;
    }
}

class KeyOverlappingException extends Exception
{
    KeyOverlappingException(String message) {
        self.message = message;
    }
}

class OutOfRangeOfStackException extends Exception
{
    OutOfRangeOfStackException(String message) {
        self.message = message;
    }
}

class OutOfRangeOfFieldException extends Exception
{
    OutOfRangeOfFieldException(String message) {
        self.message = message;
    }
}

/// abstract classes ///
abstract class Object implements IHashKey, IInspectable, ICloneable
{
    native Type type() throws ConvertingStringCodeException;
    native int ID();
    native anonymous fields(int num) throws Exception, RangeException;
    native anonymous setField(int num, anonymous obj) throws Exception, RangeException;
    native int numFields();

    bool instanceOf(Type@Nullable type_object) {
        return self.type() == type_object;
    }
    bool isChild(Type@Nullable type_object) {
        Type it = self.type().class();
        while(it != null) {
            if(it == type_object.class()) {
                return true;
            }
            it = it.parentClass();
        }

        return false;
    }

    Null toNull() throws TypeError {
        if(self.type() == Null) {
            return self;
        }
        else {
            throw new TypeError("type error");
        }
    }

    anonymous toAnonymous() {
        return self;
    }

    virtual int hashValue() {
        int sum = 0;
        for(int i=0; i<self.numFields(); i++) {
            sum += self.fields(i).ID();
        }
        return sum + self.ID();
    }

    virtual String toString() {
        return self.type().toString();
    }

    virtual void outputValueForInterpreter() {
        ("=> " + self.toString().chomp()).println();
    }

    /// deep copy ///
    virtual anonymous clone() throws Exception {
        /// native class object ///
        if(self.type().toClass().isNativeClass()) {
            throw new Exception("An object of special class can't clone at Object.clone(). A special class should be defined clone method.");
        }
        /// user object ///
        else {
            Object new_object = self.type().toClass().newInstance();
            for(int i=0; i<self.numFields(); i++) {
                new_object.setField(i, self.fields(i).clone());
            }
            return new_object;
        }
    }

    /// shallow copy ///
    virtual anonymous dup() throws Exception {
        /// native class object ///
        if(self.type().toClass().isNativeClass()) {
            throw new Exception("An object of special class can't dup at Object.dup(). A special class should be defined dup method.");
        }
        /// user object ///
        else {
            Object new_object = self.type().toClass().newInstance();
            for(int i=0; i<self.numFields(); i++) {
                new_object.setField(i, self.fields(i));
            }
            return new_object;
        }
    }
}

abstract class NativeClass extends Object implements ICloneable, IDupeable, ISetValue includes ConstructorModule
{
    abstract void setValue(anonymous value);
    abstract anonymous dup() throws Exception;
    abstract anonymous clone() throws Exception;
}

abstract class UserClass extends Object implements IComparable includes ComparableModule, ConstructorModule
{
    void setValue(UserClass value) throws Exception {
        if(self.type() != value.type()) {
            throw new Exception("Invalid type");
        }
        if(self.numFields() != value.numFields()) {
            throw new Exception("Invalid field number");
        }
        for(int i=0; i<self.numFields(); i++) {
            self.setField(i, value.fields(i));
        }
    }
}

/// interfaces ///
interface IComparable 
{
    bool operator==(anonymous right);
    bool operator!=(anonymous right);
}

interface IComparableMore extends IComparable 
{
    bool operator>(anonymous right);
    bool operator<(anonymous right);
    bool operator>=(anonymous right);
    bool operator<=(anonymous right);
}

interface IInspectable 
{
    String toString();
}

interface IHashKey 
{
    int hashValue();
}

interface ICloneable 
{
    anonymous clone() throws Exception;
}

interface IDupeable
{
    anonymous dup() throws Exception;
}

interface ISetValue
{
    void setValue(anonymous value);
}

/// modules ///
module OperatorModule
{
    Self operator +(Self value) {
        return self \+ value;
    }
    Self operator -(Self value) {
        return self \- value;
    }
    Self operator *(Self value) {
        return self \* value;
    }
    Self operator %(Self value) {
        return self \% value;
    }
    Self operator /(Self value) {
        return self \/ value;
    }
    Self operator <<(Self value) {
        return self \<< value;
    }
    Self operator >>(Self value) {
        return self \>> value;
    }
    virtual bool operator==(Self@Nullable value) {
        return self \== value;
    }
    virtual bool operator!=(Self@Nullable value) {
        return self \!= value;
    }
    virtual bool operator <(Self value) {
        return self \< value;
    }
    virtual bool operator <=(Self value) {
        return self \<= value;
    }
    virtual bool operator >(Self value) {
        return self \> value;
    }
    virtual bool operator >=(Self value) {
        return self \>= value;
    }
    Self operator &(Self value) {
        return self \& value;
    }
    Self operator ^(Self value) {
        return self \^ value;
    }
    Self operator |(Self value) {
        return self \| value;
    }
    Self operator ~() {
        return \~self;
    }

    Self operator ++() {
        Self value = new Self(1);
        self.setValue(self + value);
        return self;
    }
    Self operator ++2() {
        Self value = new Self(1);
        self.setValue(self + value);
        return self - value;
    }
    Self operator --() {
        Self value = new Self(1);
        self.setValue(self - value);
        return self;
    }
    Self operator --2() {
        Self value = new Self(1);
        self.setValue(self - value);
        return self + value;
    }
    Self operator +=(Self value) {
        return self \+= value;
    }
    Self operator -=(Self value) {
        return self \-= value;
    }
    Self operator *=(Self value) {
        return self \*= value;
    }
    Self operator /=(Self value) {
        return self \/= value;
    }
    Self operator %=(Self value) {
        return self \%= value;
    }
    Self operator <<=(Self value) {
        return self \<<= value;
    }
    Self operator >>=(Self value) {
        return self \>>= value;
    }
    Self operator &=(Self value) {
        return self \&= value;
    }
    Self operator ^=(Self value) {
        return self \^= value;
    }
    Self operator |=(Self value) {
        return self \|= value;
    }
}

module OperatorModuleForDouble
{
    Self operator ++() {
        Self value = new Self(1);
        self.setValue(self + value);
        return self;
    }
    Self operator ++2() {
        Self value = new Self(1);
        self.setValue(self + value);
        return self - value;
    }
    Self operator --() {
        Self value = new Self(1);
        self.setValue(self - value);
        return self;
    }
    Self operator --2() {
        Self value = new Self(1);
        self.setValue(self - value);
        return self + value;
    }
    Self operator +=(Self value) {
        return self \+= value;
    }
    Self operator -=(Self value) {
        return self \-= value;
    }
    Self operator *=(Self value) {
        return self \*= value;
    }
    Self operator /=(Self value) {
        return self \/= value;
    }
    Self operator +(Self value) {
        return self \+ value;
    }
    Self operator -(Self value) {
        return self \- value;
    }
    Self operator *(Self value) {
        return self \* value;
    }
    Self operator /(Self value) {
        return self \/ value;
    }
    virtual bool operator==(Self@Nullable value) {
        return self \== value;
    }
    virtual bool operator!=(Self@Nullable value) {
        return self \!= value;
    }
    virtual bool operator <(Self value) {
        return self \< value;
    }
    virtual bool operator <=(Self value) {
        return self \<= value;
    }
    virtual bool operator >(Self value) {
        return self \> value;
    }
    virtual bool operator >=(Self value) {
        return self \>= value;
    }
}

module ComparableModule 
{
    virtual bool operator==(Self@Nullable right) throws TypeError {
        /// null type ///
        if(self.type() == Null || right.type() == Null) {
            return self.type() == Null && right.type() == Null;
        }
        /// other type ///
        else {
            if(self.type() != right.type()) {
                throw new TypeError("The parametor of operator== method should be the same type of self.");
            }
            /// native class object ///
            if(self.type().toClass().isNativeClass() || right.type().toClass().isNativeClass()) 
            {
                return self.ID() == right.ID();
            }
            /// user object ///
            else {
                if(self.numFields() != right.numFields()) {
                    return false;
                }

                for(int i=0; i<self.numFields(); i++) {
                    if(self.fields(i) != right.fields(i)) {
                        return false;
                    }
                }
                return true;
            }
        }
    }

    virtual bool operator !=(Self@Nullable right) throws TypeError {
        return !(self == right);
    }
}

module ConstructorModule 
{
    Self(Self value) {
        self.setValue(value);
    }
}

/// Generics Parametor classes(hidden classes ///
final class GenericsParam0 extends Object {}   // for generics parametor
final class GenericsParam1 extends Object {}
final class GenericsParam2 extends Object {}
final class GenericsParam3 extends Object {}
final class GenericsParam4 extends Object {}
final class GenericsParam5 extends Object {}
final class GenericsParam6 extends Object {}
final class GenericsParam7 extends Object {}

