utils.pas

Переключить прокрутку окна
Загрузить этот исходный код

{
    Utils – содержит классы для работы с элементарными типами данных как с объектами,
    хэш-таблицами, векторами, датой и временем, календарями.

    Copyright © 2017 Малик Разработчик

    Это свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она может быть полезна,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
}

unit Utils;

{$MODE OBJFPC}

interface

uses
    Lang,
    {$IF DEFINED(GO32V2)} IntfGo32
    {$ELSEIF DEFINED(WINDOWS)} IntfWin
    {$ENDIF};

{$ASMMODE INTEL,CALLING REGISTER,INLINE ON,GOTO ON}
{$H+,I-,J-,M-,Q-,R-,T-}

type
    Enumeration = interface;
    BooleanAsObject = interface;
    CharAsObject = interface;
    UCharAsObject = interface;
    IntegerAsObject = interface;
    LongAsObject = interface;
    UltraAsObject = interface;
    FloatAsObject = interface;
    DoubleAsObject = interface;
    RealAsObject = interface;
    XVectorAsObject = interface;
    StringAsObject = interface;
    UnicodeStringAsObject = interface;
    Hashtable = class;
    Vector = class;
    Stack = class;
    DateTime = class;
    TimeZone = class;
    Calendar = class;
    ExtendedCalendar = class;
    JulianCalendar = class;
    GregorianCalendar = class;
    NoSuchElementException = class;
    EmptyStackException = class;

    Enumeration = interface(_Interface) ['{AB9B4D27-2302-4FD0-BD7B-E4AA2420558C}']
        function hasMoreElements(): boolean;
        function nextElement(): _Interface;
    end;

    BooleanAsObject = interface(_Interface) ['{BE57986A-5F30-459A-B8CD-E0888E02DA00}']
        function booleanValue(): boolean;
    end;

    CharAsObject = interface(_Interface) ['{BE57986A-5F30-459A-B8CD-E0888E02DA01}']
        function charValue(): char;
    end;

    UCharAsObject = interface(_Interface) ['{BE57986A-5F30-459A-B8CD-E0888E02DA02}']
        function ucharValue(): uchar;
    end;

    IntegerAsObject = interface(_Interface) ['{BE57986A-5F30-459A-B8CD-E0888E02DA14}']
        function byteValue(): int;
        function shortValue(): int;
        function intValue(): int;
    end;

    LongAsObject = interface(IntegerAsObject) ['{BE57986A-5F30-459A-B8CD-E0888E02DA18}']
        function nativeValue(): int64;
        function longValue(): long;
    end;

    UltraAsObject = interface(LongAsObject) ['{BE57986A-5F30-459A-B8CD-E0888E02DA1F}']
        function getShort(index: int): int;
        function getInt(index: int): int;
        function ultraValue(): ultra;
    end;

    FloatAsObject = interface(LongAsObject) ['{BE57986A-5F30-459A-B8CD-E0888E02DA24}']
        function floatValue(): float;
    end;

    DoubleAsObject = interface(FloatAsObject) ['{BE57986A-5F30-459A-B8CD-E0888E02DA28}']
        function doubleValue(): double;
    end;

    RealAsObject = interface(DoubleAsObject) ['{BE57986A-5F30-459A-B8CD-E0888E02DA2A}']
        function realValue(): real;
    end;

    XVectorAsObject = interface(RealAsObject) ['{BE57986A-5F30-459A-B8CD-E0888E02DA2F}']
        function getFloat(index: int): float;
        function xvectorValue(): xvector;
    end;

    StringAsObject = interface(_Interface) ['{BE57986A-5F30-459A-B8CD-E0888E02DA31}']
        function stringValue(): AnsiString;
    end;

    UnicodeStringAsObject = interface(StringAsObject) ['{BE57986A-5F30-459A-B8CD-E0888E02DA32}']
        function unicodeStringValue(): UnicodeString;
    end;

    Hashtable = class(RefCountInterfacedObject)
    strict private
        type Entry = class(_Object)
        public
            constructor create(hash: int; key, value: _Interface; next: Entry);
            destructor destroy; override;
        public
            nextf: boolean;
            hash: int;
            key: _Interface;
            value: _Interface;
            next: Entry;
        end;
        type Entry_Array1d = packed array of Entry;
    protected
        type Enumerator = class(RefCountInterfacedObject, Enumeration)
        public
            constructor create(keys: boolean; const table: Entry_Array1d);
            function hasMoreElements(): boolean; virtual;
            function nextElement(): _Interface; virtual;
        strict private
            keys: boolean;
            index: int;
            entryf: Entry;
            table: Entry_Array1d;
        end;

    public
        constructor create(); overload;
        constructor create(initialCapacity: int); overload;
        destructor destroy; override;
        function toString(): AnsiString; override;
        procedure clear(); virtual;
        function isEmpty(): boolean; virtual;
        function contains(value: _Interface): boolean; virtual;
        function containsKey(key: _Interface): boolean; virtual;
        function size(): int; virtual;
        function remove(key: _Interface): _Interface; virtual;
        function get(key: _Interface): _Interface; virtual;
        function put(key, value: _Interface): _Interface; virtual;
        function keys(): Enumeration; virtual;
        function elements(): Enumeration; virtual;
    protected
        procedure rehash(); virtual;
    strict private
        factor: int;
        length: int;
        table: Entry_Array1d;
    end;

    Vector = class(RefCountInterfacedObject)
    protected
        type _Interface_Array1d = packed array of _Interface;
        type Enumerator = class(RefCountInterfacedObject, Enumeration)
        public
            constructor create(thisVector: Vector);
            function hasMoreElements(): boolean; virtual;
            function nextElement(): _Interface; virtual;
        strict private
            thisVector: Vector;
            index: int;
        end;

    public
        constructor create(); overload;
        constructor create(initialCapacity: int); overload;
        function toString(): AnsiString; override;
        procedure clear(); virtual;
        procedure trimToSize(); virtual;
        procedure copyInto(const destination: Interface_Array1d); virtual;
        procedure ensureCapacity(minimumCapacity: int); virtual;
        procedure removeElementAt(index: int); virtual;
        procedure insertElementAt(index: int; element: _Interface); virtual;
        procedure setElementAt(index: int; element: _Interface); virtual;
        procedure addElement(element: _Interface); virtual;
        procedure setSize(newSize: int); virtual;
        function isEmpty(): boolean; virtual;
        function contains(element: _Interface): boolean; virtual;
        function removeElement(element: _Interface): boolean; virtual;
        function capacity(): int; virtual;
        function size(): int; virtual;
        function indexOf(element: _Interface): int; overload; virtual;
        function indexOf(element: _Interface; fromIndex: int): int; overload; virtual;
        function lastIndexOf(element: _Interface): int; overload; virtual;
        function lastIndexOf(element: _Interface; fromIndex: int): int; overload; virtual;
        function firstElement(): _Interface; virtual;
        function lastElement(): _Interface; virtual;
        function elementAt(index: int): _Interface; virtual;
        function elements(): Enumeration; virtual;
    protected
        elementCount: int;
        elementData: _Interface_Array1d;
    private
        function ensureCapacityHelper(minimumCapacity: int): _Interface_Array1d;
    end;

    Stack = class(Vector)
    public
        constructor create(); overload;
        constructor create(initialCapacity: int); overload;
        function pop(): _Interface; virtual;
        function peek(): _Interface; virtual;
        procedure push(element: _Interface); virtual;
    end;

    DateTime = class(RefCountInterfacedObject)
    public
        constructor create(internalRepresentation: long); overload;
        constructor create(year, month, day, hour, minute, second, millisecond: int); overload;
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
    strict private
        {
            внутреннее представление даты и времени:
            ┌───────┬───┬───┬───┬───┬───────┐
            │  год  │мес│чис│час│мин│миллис.│  – поля
            ├───┬───┼───┼───┼───┼───┼───┬───┤
            │ 7 │ 6 │ 5 │ 4 │ 3 │ 2 │ 1 │ 0 │  – байты
            ├───┴───┼───┴───┼───┴───┼───┴───┤
            │   3   │   2   │   1   │   0   │  – слова
            └───────┴───────┴───────┴───────┘
        }
        fieldInternalRepresentation: long;
        procedure setByte(index, value: int);
        procedure setWord(index, value: int);
        procedure setSecond(value: int);
        procedure setMillisecond(value: int);
        function getByte(index: int): int;
        function getWord(index: int): int;
        function getSecond(): int;
        function getMillisecond(): int;
    published
        property year: int index 3
                read getWord
                write setWord
                stored false;
        property month: int index 5
                read getByte
                write setByte
                stored false;
        property day: int index 4
                read getByte
                write setByte
                stored false;
        property hour: int index 3
                read getByte
                write setByte
                stored false;
        property minute: int index 2
                read getByte
                write setByte
                stored false;
        property second: int
                read getSecond
                write setSecond
                stored false;
        property millisecond: int
                read getMillisecond
                write setMillisecond
                stored false;
        property nativeRepresentation: int64
                read fieldInternalRepresentation.native
                write fieldInternalRepresentation.native
                default 0;
    end;

    TimeZone = class(_Object)
    public
        class function getCurrentOffsetInMillis(): int;
    end;

    Calendar = class(RefCountInterfacedObject)
    public
        { индексы полей }
        const FIELD_MILLIS = 0;
        const FIELD_SECOND = 1;
        const FIELD_MINUTE = 2;
        const FIELD_HOUR_OF_DAY = 3;
        const FIELD_HOUR = 4;
        const FIELD_AM_PM = 5;
        const FIELD_DAY_OF_WEEK = 6;
        const FIELD_DAY = 7;
        const FIELD_MONTH = 8;
        const FIELD_YEAR = 9;
        const FIELD_ARRAY_LENGTH = 10;
        { до/после полудня }
        const AM = 0;
        const PM = 1;
        { дни недели }
        const MONDAY = 1;
        const TUESDAY = 2;
        const WEDNESDAY = 3;
        const THURSDAY = 4;
        const FRIDAY = 5;
        const SATURDAY = 6;
        const SUNDAY = 0;
        { месяцы }
        const JANUARY = 1;
        const FEBRUARY = 2;
        const MARCH = 3;
        const APRIL = 4;
        const MAY = 5;
        const JUNE = 6;
        const JULY = 7;
        const AUGUST = 8;
        const SEPTEMBER = 9;
        const OCTOBER = 10;
        const NOVEMBER = 11;
        const DECEMBER = 12;

    public
        constructor create(); overload;
        constructor create(offsetInMillis: int; time: DateTime); overload;
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        procedure setOffsetInMillis(offsetInMillis: int); virtual;
        function before(when: Calendar): boolean; virtual;
        function after(when: Calendar): boolean; virtual;
        function getOffsetInMillis(): int; virtual;
        procedure getTime(dst: DateTime);
        procedure setTime(src: DateTime);
        procedure setField(field, value: int);
        procedure setTimeInMillis(timeInMillis: long);
        function getField(field: int): int;
        function getTimeInMillis(): long;
    protected
        timeInMillis: long;
        isSet: boolean_Array1d;
        fields: int_Array1d;
        procedure computeFields(); virtual; abstract;
        procedure computeTimeInMillis(); virtual; abstract;
        procedure computeHourOfDay(); virtual;
        procedure computeHour(); virtual;
    strict private
        timeSet: boolean;
        offsetInMillis: int;
    end;

    ExtendedCalendar = class(Calendar)
    public
        function isLeapYear(year: int): boolean; virtual; abstract;
        function getNumOfDays(year, month: int): int; virtual; abstract;
        function getDayOfWeek(year, month, day: int): int; virtual; abstract;
        function getInternalRepresentation(time: long;
                offsetInMillis: int): long; virtual; abstract;
        function getTime(internalRepresentation: long;
                offsetInMillis: int): long; overload; virtual; abstract;
        function getTime(year, month, day, hour, minute, second, millis,
                offsetInMillis: int): long; overload; virtual; abstract;
    end;

    JulianCalendar = class(ExtendedCalendar)
    private
        class var DAYS: byte_Array2d;
        class procedure clinit();
        class procedure cldone();

    public
        function isLeapYear(year: int): boolean; override; final;
        function getNumOfDays(year, month: int): int; override; final;
        function getDayOfWeek(year, month, day: int): int; override; final;
        function getInternalRepresentation(time: long;
                offsetInMillis: int): long; override; final;
        function getTime(internalRepresentation: long;
                offsetInMillis: int): long; overload; override; final;
        function getTime(year, month, day, hour, minute, second, millis,
                offsetInMillis: int): long; overload; override; final;
    protected
        procedure computeFields(); override; final;
        procedure computeTimeInMillis(); override; final;
    end;

    GregorianCalendar = class(ExtendedCalendar)
    public
        function isLeapYear(year: int): boolean; override; final;
        function getNumOfDays(year, month: int): int; override; final;
        function getDayOfWeek(year, month, day: int): int; override; final;
        function getInternalRepresentation(time: long;
                offsetInMillis: int): long; override; final;
        function getTime(internalRepresentation: long;
                offsetInMillis: int): long; overload; override; final;
        function getTime(year, month, day, hour, minute, second, millis,
                offsetInMillis: int): long; overload; override; final;
    protected
        procedure computeFields(); override; final;
        procedure computeTimeInMillis(); override; final;
    end;

    NoSuchElementException = class(RuntimeException);

    EmptyStackException = class(RuntimeException);

resourcestring
    msgNoSuchElement = 'Больше не осталось элементов для перечисления.';
    msgEmptyStack = 'Стек пуст.';

operator :=(const value: boolean): _Interface;
operator :=(const value: char): _Interface;
operator :=(const value: uchar): _Interface;
operator :=(const value: byte): _Interface;
operator :=(const value: short): _Interface;
operator :=(const value: int): _Interface;
operator :=(const value: int64): _Interface;
operator :=(const value: long): _Interface;
operator :=(const value: ultra): _Interface;
operator :=(const value: float): _Interface;
operator :=(const value: double): _Interface;
operator :=(const value: real): _Interface;
operator :=(const value: xvector): _Interface;
operator :=(const value: AnsiString): _Interface;
operator :=(const value: UnicodeString): _Interface;
operator :=(const value: boolean): BooleanAsObject;
operator :=(const value: char): CharAsObject;
operator :=(const value: uchar): UCharAsObject;
operator :=(const value: byte): IntegerAsObject;
operator :=(const value: short): IntegerAsObject;
operator :=(const value: int): IntegerAsObject;
operator :=(const value: int64): LongAsObject;
operator :=(const value: long): LongAsObject;
operator :=(const value: ultra): UltraAsObject;
operator :=(const value: float): FloatAsObject;
operator :=(const value: double): DoubleAsObject;
operator :=(const value: real): RealAsObject;
operator :=(const value: xvector): XVectorAsObject;
operator :=(const value: AnsiString): StringAsObject;
operator :=(const value: UnicodeString): UnicodeStringAsObject;

implementation

type
    BooleanVal = class;
    NumericVal = class;
    IntegerVal = class;
    LongVal = class;
    UltraVal = class;
    RealVal = class;
    XVectorVal = class;
    CharVal = class;
    UCharVal = class;
    StringVal = class;
    UStringVal = class;

    BooleanVal = class(RefCountInterfacedObject, BooleanAsObject)
    private
        class var FALSE: BooleanAsObject;
        class var TRUE: BooleanAsObject;
        class procedure clinit();
        class procedure cldone();

    public
        constructor create(value: boolean);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function booleanValue(): boolean; virtual;
    private
        value: boolean;
    end;

    NumericVal = class(RefCountInterfacedObject, IntegerAsObject, LongAsObject,
            FloatAsObject, DoubleAsObject, RealAsObject)
    public
        constructor create();
        function byteValue(): int; virtual;
        function shortValue(): int; virtual;
        function intValue(): int; virtual; abstract;
        function nativeValue(): int64; virtual; abstract;
        function longValue(): long; virtual; abstract;
        function floatValue(): float; virtual; abstract;
        function doubleValue(): double; virtual; abstract;
        function realValue(): real; virtual; abstract;
    end;

    IntegerVal = class(NumericVal)
    public
        constructor create(value: int);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function intValue(): int; override;
        function nativeValue(): int64; override;
        function longValue(): long; override;
        function floatValue(): float; override;
        function doubleValue(): double; override;
        function realValue(): real; override;
    private
        int0: int;
    end;

    LongVal = class(IntegerVal)
    public
        constructor create(const value: long); overload;
        constructor create(const value: int64); overload;
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function nativeValue(): int64; override;
        function longValue(): long; override;
        function floatValue(): float; override;
        function doubleValue(): double; override;
        function realValue(): real; override;
    private
        int1: int;
        function long0(): long;
    end;

    UltraVal = class(IntegerVal, UltraAsObject)
    public
        constructor create(const value: ultra);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function nativeValue(): int64; override;
        function longValue(): long; override;
        function getShort(index: int): int; virtual;
        function getInt(index: int): int; virtual;
        function ultraValue(): ultra; virtual;
    private
        int1: int;
        long1: long;
        function long0(): long;
        function ultra0(): ultra;
    end;

    RealVal = class(NumericVal)
    public
        constructor create(const value: real);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function intValue(): int; override;
        function nativeValue(): int64; override;
        function longValue(): long; override;
        function floatValue(): float; override;
        function doubleValue(): double; override;
        function realValue(): real; override;
    private
        value: real;
    end;

    XVectorVal = class(NumericVal, XVectorAsObject)
    public
        constructor create(const value: xvector);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function intValue(): int; override;
        function nativeValue(): int64; override;
        function longValue(): long; override;
        function floatValue(): float; override;
        function doubleValue(): double; override;
        function realValue(): real; override;
        function getFloat(index: int): float; virtual;
        function xvectorValue(): xvector; virtual;
    private
        value: xvector;
    end;

    CharVal = class(RefCountInterfacedObject, CharAsObject)
    public
        constructor create(value: char);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function charValue(): char; virtual;
    private
        value: char;
    end;

    UCharVal = class(RefCountInterfacedObject, UCharAsObject)
    public
        constructor create(value: uchar);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function ucharValue(): uchar; virtual;
    private
        value: uchar;
    end;

    StringVal = class(RefCountInterfacedObject, StringAsObject, UnicodeStringAsObject)
    public
        constructor create(const value: AnsiString);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function stringValue(): AnsiString; virtual;
        function unicodeStringValue(): UnicodeString; virtual;
    private
        value: AnsiString;
    end;

    UStringVal = class(RefCountInterfacedObject, StringAsObject, UnicodeStringAsObject)
    public
        constructor create(const value: UnicodeString);
        function equals(obj: TObject): boolean; override;
        function getHashCode(): int; override;
        function toString(): AnsiString; override;
        function stringValue(): AnsiString; virtual;
        function unicodeStringValue(): UnicodeString; virtual;
    private
        value: UnicodeString;
    end;

{ Hashtable.Entry }

constructor Hashtable.Entry.create(hash: int; key, value: _Interface; next: Entry);
begin
    inherited create();
    self.nextf := true;
    self.hash := hash;
    self.key := key;
    self.value := value;
    self.next := next;
end;

destructor Hashtable.Entry.destroy;
begin
    if nextf then begin
        next.free();
    end;
    inherited destroy;
end;

{ Hashtable.Enumerator }

constructor Hashtable.Enumerator.create(keys: boolean; const table: Entry_Array1d);
begin
    inherited create();
    self.keys := keys;
    self.index := System.length(table);
    self.entryf := nil;
    self.table := table;
end;

function Hashtable.Enumerator.hasMoreElements(): boolean;
var
    i: int;
    e: Entry;
    t: Entry_Array1d;
begin
    if entryf <> nil then begin
        result := true;
        exit;
    end;
    t := table;
    for i := index - 1 downto 0 do begin
        e := t[i];
        entryf := e;
        if e <> nil then begin
            index := i;
            result := true;
            exit;
        end;
    end;
    index := -1;
    result := false;
end;

function Hashtable.Enumerator.nextElement(): _Interface;
label
    label0;
var
    i: int;
    e: Entry;
    t: Entry_Array1d;
begin
    if entryf = nil then begin
        t := table;
        for i := index - 1 downto 0 do begin
            e := t[i];
            entryf := e;
            if e <> nil then begin
                index := i;
                goto label0;
            end;
        end;
        index := -1;
    end;
    label0:
    e := entryf;
    if e = nil then begin
        raise NoSuchElementException.create(msgNoSuchElement);
    end;
    entryf := e.next;
    if keys then begin
        result := e.key;
    end else begin
        result := e.value;
    end;
end;

{ Hashtable }

constructor Hashtable.create();
begin
    create($0f);
end;

constructor Hashtable.create(initialCapacity: int);
begin
    inherited create();
    if initialCapacity <= 0 then begin
        initialCapacity := 1;
    end;
    self.factor := (initialCapacity * 3) shr 2;
    self.length := 0;
    self.table := Entry_Array1d(Object_Array1d_create(initialCapacity));
end;

destructor Hashtable.destroy;
var
    i: int;
    t: Entry_Array1d;
begin
    t := table;
    for i := System.length(t) - 1 downto 0 do begin
        t[i].free();
    end;
    inherited destroy;
end;

function Hashtable.toString(): AnsiString;
var
    i: int;
    k: Enumeration;
    e: Enumeration;
    t: Entry_Array1d;
begin
    t := table;
    k := Enumerator.create(true, t);
    e := Enumerator.create(false, t);
    result := '{';
    for i := length - 1 downto 0 do begin
        result := result + (k.nextElement().toString() + '=' + e.nextElement().toString());
        if i > 0 then begin
            result := result + ', ';
        end;
    end;
    result := result + '}';
end;

procedure Hashtable.clear();
var
    i: int;
    t: Entry_Array1d;
begin
    t := table;
    for i := System.length(t) - 1 downto 0 do begin
        t[i].free();
        t[i] := nil;
    end;
    length := 0;
end;

function Hashtable.isEmpty(): boolean;
begin
    result := length = 0;
end;

function Hashtable.contains(value: _Interface): boolean;
var
    i: int;
    e: Entry;
    t: Entry_Array1d;
begin
    if value = nil then begin
        result := false;
        exit;
    end;
    t := table;
    for i := System.length(t) - 1 downto 0 do begin
        e := t[i];
        while e <> nil do begin
            if value.equals(e.value as TObject) then begin
                result := true;
                exit;
            end;
            e := e.next;
        end;
    end;
    result := false;
end;

function Hashtable.containsKey(key: _Interface): boolean;
var
    hash: int;
    e: Entry;
    t: Entry_Array1d;
begin
    if key = nil then begin
        result := false;
        exit;
    end;
    hash := key.getHashCode();
    t := table;
    e := t[(hash and MAX_INT) mod System.length(t)];
    while e <> nil do begin
        if (hash = e.hash) and (key.equals(e.key as TObject)) then begin
            result := true;
            exit;
        end;
        e := e.next;
    end;
    result := false;
end;

function Hashtable.size(): int;
begin
    result := length;
end;

function Hashtable.remove(key: _Interface): _Interface;
var
    hash: int;
    i: int;
    e: Entry;
    f: Entry;
    t: Entry_Array1d;
begin
    if key = nil then begin
        result := nil;
        exit;
    end;
    hash := key.getHashCode();
    t := table;
    i := (hash and MAX_INT) mod System.length(t);
    f := nil;
    e := t[i];
    while e <> nil do begin
        if (hash = e.hash) and (key.equals(e.key as TObject)) then begin
            result := e.value;
            if f <> nil then begin
                f.next := e.next;
            end else begin
                t[i] := e.next;
            end;
            e.nextf := false;
            e.free();
            dec(length);
            exit;
        end;
        f := e;
        e := e.next;
    end;
    result := nil;
end;

function Hashtable.get(key: _Interface): _Interface;
var
    hash: PtrInt;
    e: Entry;
    t: Entry_Array1d;
begin
    if key = nil then begin
        result := nil;
        exit;
    end;
    hash := key.getHashCode();
    t := table;
    e := t[(hash and MAX_INT) mod System.length(t)];
    while e <> nil do begin
        if (hash = e.hash) and (key.equals(e.key as TObject)) then begin
            result := e.value;
            exit;
        end;
        e := e.next;
    end;
    result := nil;
end;

function Hashtable.put(key, value: _Interface): _Interface;
var
    hash: PtrInt;
    i: int;
    l: int;
    e: Entry;
    t: Entry_Array1d;
begin
    if (key = nil) or (value = nil) then begin
        result := nil;
        exit;
    end;
    hash := key.getHashCode();
    t := table;
    i := (hash and MAX_INT) mod System.length(t);
    e := t[i];
    while e <> nil do begin
        if (hash = e.hash) and (key.equals(e.key as TObject)) then begin
            result := e.value;
            e.value := value;
            exit;
        end;
        e := e.next;
    end;
    l := length;
    if l >= factor then begin
        rehash();
        t := table;
        i := (hash and MAX_INT) mod System.length(t);
    end;
    t[i] := Entry.create(hash, key, value, t[i]);
    length := l + 1;
    result := nil;
end;

function Hashtable.keys(): Enumeration;
begin
    result := Enumerator.create(true, table);
end;

function Hashtable.elements(): Enumeration;
begin
    result := Enumerator.create(false, table);
end;

procedure Hashtable.rehash();
var
    i: int;
    j: int;
    nc: int;
    oc: int;
    e: Entry;
    f: Entry;
    nt: Entry_Array1d;
    ot: Entry_Array1d;
begin
    ot := table;
    oc := System.length(ot);
    nc := (oc shl 1) + 1;
    nt := Entry_Array1d(Object_Array1d_create(nc));
    table := nt;
    factor := (nc * 3) shr 2;
    for i := oc - 1 downto 0 do begin
        f := ot[i];
        while f <> nil do begin
            e := f;
            j := (e.hash and MAX_INT) mod nc;
            f := f.next;
            e.next := nt[j];
            nt[j] := e;
        end;
    end;
end;

{ Vector.Enumerator }

constructor Vector.Enumerator.create(thisVector: Vector);
begin
    inherited create();
    self.thisVector := thisVector;
    self.index := 0;
end;

function Vector.Enumerator.hasMoreElements(): boolean;
begin
    result := index < thisVector.elementCount;
end;

function Vector.Enumerator.nextElement(): _Interface;
var
    i: int;
    vect: Vector;
begin
    i := index;
    vect := thisVector;
    if i >= vect.elementCount then begin
        raise NoSuchElementException.create(msgNoSuchElement);
    end;
    index := i + 1;
    result := vect.elementData[i];
end;

{ Vector }

constructor Vector.create();
begin
    create($0f);
end;

constructor Vector.create(initialCapacity: int);
begin
    inherited create();
    if initialCapacity <= 0 then begin
        initialCapacity := 1;
    end;
    self.elementCount := 0;
    self.elementData := _Interface_Array1d(Interface_Array1d_create(initialCapacity));
end;

function Vector.toString(): AnsiString;
var
    i: int;
    c: int;
    e: _Interface;
    d: _Interface_Array1d;
begin
    result := '[';
    c := elementCount - 1;
    d := elementData;
    for i := 0 to c do begin
        e := d[i];
        if e <> nil then begin
            result := result + e.toString();
        end else begin
            result := result + 'null';
        end;
        if i < c then begin
            result := result + ', ';
        end;
    end;
    result := result + ']';
end;

procedure Vector.clear();
var
    i: int;
    d: _Interface_Array1d;
begin
    d := elementData;
    for i := elementCount - 1 downto 0 do begin
        d[i] := nil;
    end;
    elementCount := 0;
end;

procedure Vector.trimToSize();
var
    c: int;
    od: _Interface_Array1d;
    nd: _Interface_Array1d;
begin
    c := elementCount;
    od := elementData;
    if c < length(od) then begin
        nd := _Interface_Array1d(Interface_Array1d_create(c));
        arraycopyInterfaces(od, 0, nd, 0, c);
        elementData := nd;
    end;
end;

procedure Vector.copyInto(const destination: Interface_Array1d);
var
    i: int;
    d: _Interface_Array1d;
begin
    d := elementData;
    for i := Math.min(elementCount, length(destination)) - 1 downto 0 do begin
        destination[i] := d[i];
    end;
end;

procedure Vector.ensureCapacity(minimumCapacity: int);
begin
    if minimumCapacity > length(elementData) then begin
        ensureCapacityHelper(minimumCapacity);
    end;
end;

procedure Vector.removeElementAt(index: int);
var
    i: int;
    c: int;
    d: _Interface_Array1d;
begin
    c := elementCount - 1;
    if (index < 0) or (index > c) then begin
        raise ArrayIndexOutOfBoundsException.create(msgArrayIndexOutOfBounds);
    end;
    d := elementData;
    i := c - index;
    if i > 0 then begin
        arraycopyInterfaces(d, index + 1, d, index, i);
    end;
    d[c] := nil;
    elementCount := c;
end;

procedure Vector.insertElementAt(index: int; element: _Interface);
var
    i: int;
    c: int;
    d: _Interface_Array1d;
begin
    c := elementCount;
    if (index < 0) or (index > c) then begin
        raise ArrayIndexOutOfBoundsException.create(msgArrayIndexOutOfBounds);
    end;
    d := elementData;
    if c = length(d) then begin
        d := ensureCapacityHelper(c + 1);
    end;
    i := c - index;
    if i > 0 then begin
        arraycopyInterfaces(d, index, d, index + 1, i);
    end;
    d[index] := element;
    elementCount := c + 1;
end;

procedure Vector.setElementAt(index: int; element: _Interface);
begin
    if (index < 0) or (index >= elementCount) then begin
        raise ArrayIndexOutOfBoundsException.create(msgArrayIndexOutOfBounds);
    end;
    elementData[index] := element;
end;

procedure Vector.addElement(element: _Interface);
var
    c: int;
    d: _Interface_Array1d;
begin
    c := elementCount;
    d := elementData;
    if c = length(d) then begin
        d := ensureCapacityHelper(c + 1);
    end;
    d[c] := element;
    elementCount := c + 1;
end;

procedure Vector.setSize(newSize: int);
var
    i: int;
    c: int;
    d: _Interface_Array1d;
begin
    d := elementData;
    if newSize < 0 then begin
        newSize := 0;
    end;
    if newSize > length(d) then begin
        d := ensureCapacityHelper(newSize);
    end;
    c := elementCount;
    if newSize >= c then begin
        for i := newSize - 1 downto c do begin
            d[i] := nil;
        end;
    end else begin
        for i := c - 1 downto newSize do begin
            d[i] := nil;
        end;
    end;
    elementCount := newSize;
end;

function Vector.isEmpty(): boolean;
begin
    result := elementCount <= 0;
end;

function Vector.contains(element: _Interface): boolean;
var
    i: int;
    d: _Interface_Array1d;
begin
    d := elementData;
    if element = nil then begin
        for i := elementCount - 1 downto 0 do begin
            if d[i] = nil then begin
                result := true;
                exit;
            end;
        end;
    end else begin
        for i := elementCount - 1 downto 0 do begin
            if element.equals(d[i] as TObject) then begin
                result := true;
                exit;
            end;
        end;
    end;
    result := false;
end;

function Vector.removeElement(element: _Interface): boolean;
label
    label0;
var
    index: int;
    i: int;
    c: int;
    d: _Interface_Array1d;
begin
    c := elementCount - 1;
    d := elementData;
    begin
        if element = nil then begin
            for i := 0 to c do begin
                if d[i] = nil then begin
                    index := i;
                    goto label0;
                end;
            end;
        end else begin
            for i := 0 to c do begin
                if element.equals(d[i] as TObject) then begin
                    index := i;
                    goto label0;
                end;
            end;
        end;
        result := false;
        exit;
    end;
    label0:
    i := c - index;
    if i > 0 then begin
        arraycopyInterfaces(d, index + 1, d, index, i);
    end;
    d[c] := nil;
    elementCount := c;
    result := true;
end;

function Vector.capacity(): int;
begin
    result := length(elementData);
end;

function Vector.size(): int;
begin
    result := elementCount;
end;

function Vector.indexOf(element: _Interface): int;
var
    i: int;
    c: int;
    d: _Interface_Array1d;
begin
    c := elementCount - 1;
    d := elementData;
    if element = nil then begin
        for i := 0 to c do begin
            if d[i] = nil then begin
                result := i;
                exit;
            end;
        end;
    end else begin
        for i := 0 to c do begin
            if element.equals(d[i] as TObject) then begin
                result := i;
                exit;
            end;
        end;
    end;
    result := -1;
end;

function Vector.indexOf(element: _Interface; fromIndex: int): int;
var
    i: int;
    c: int;
    d: _Interface_Array1d;
begin
    c := elementCount - 1;
    d := elementData;
    if fromIndex < 0 then begin
        fromIndex := 0;
    end;
    if element = nil then begin
        for i := fromIndex to c do begin
            if d[i] = nil then begin
                result := i;
                exit;
            end;
        end;
    end else begin
        for i := fromIndex to c do begin
            if element.equals(d[i] as TObject) then begin
                result := i;
                exit;
            end;
        end;
    end;
    result := -1;
end;

function Vector.lastIndexOf(element: _Interface): int;
var
    i: int;
    c: int;
    d: _Interface_Array1d;
begin
    c := elementCount - 1;
    d := elementData;
    if element = nil then begin
        for i := c downto 0 do begin
            if d[i] = nil then begin
                result := i;
                exit;
            end;
        end;
    end else begin
        for i := c downto 0 do begin
            if element.equals(d[i] as TObject) then begin
                result := i;
                exit;
            end;
        end;
    end;
    result := -1;
end;

function Vector.lastIndexOf(element: _Interface; fromIndex: int): int;
var
    i: int;
    c: int;
    d: _Interface_Array1d;
begin
    c := elementCount - 1;
    d := elementData;
    if fromIndex > c then begin
        fromIndex := c;
    end;
    if element = nil then begin
        for i := fromIndex downto 0 do begin
            if d[i] = nil then begin
                result := i;
                exit;
            end;
        end;
    end else begin
        for i := fromIndex downto 0 do begin
            if element.equals(d[i] as TObject) then begin
                result := i;
                exit;
            end;
        end;
    end;
    result := -1;
end;

function Vector.firstElement(): _Interface;
begin
    if elementCount <= 0 then begin
        raise NoSuchElementException.create(msgNoSuchElement);
    end;
    result := elementData[0];
end;

function Vector.lastElement(): _Interface;
var
    c: int;
begin
    c := elementCount;
    if c <= 0 then begin
        raise NoSuchElementException.create(msgNoSuchElement);
    end;
    result := elementData[c - 1];
end;

function Vector.elementAt(index: int): _Interface;
begin
    if (index < 0) or (index >= elementCount) then begin
        raise ArrayIndexOutOfBoundsException.create(msgArrayIndexOutOfBounds);
    end;
    result := elementData[index];
end;

function Vector.elements(): Enumeration;
begin
    result := Enumerator.create(self);
end;

function Vector.ensureCapacityHelper(minimumCapacity: int): _Interface_Array1d;
var
    oc: int;
    nc: int;
    d: _Interface_Array1d;
begin
    d := elementData;
    oc := length(d);
    nc := (oc shl 1) + 1;
    if nc < minimumCapacity then begin
        nc := minimumCapacity;
    end;
    result := _Interface_Array1d(Interface_Array1d_create(nc));
    arraycopyInterfaces(d, 0, result, 0, elementCount);
    elementData := result;
end;

{ Stack }

constructor Stack.create();
begin
    inherited create();
end;

constructor Stack.create(initialCapacity: int);
begin
    inherited create(initialCapacity);
end;

function Stack.pop(): _Interface;
var
    index: int;
begin
    index := size() - 1;
    if index < 0 then begin
        raise EmptyStackException.create(msgEmptyStack);
    end;
    result := elementAt(index);
    removeElementAt(index);
end;

function Stack.peek(): _Interface;
var
    index: int;
begin
    index := size() - 1;
    if index < 0 then begin
        raise EmptyStackException.create(msgEmptyStack);
    end;
    result := elementAt(index);
end;

procedure Stack.push(element: _Interface);
begin
    addElement(element);
end;

{ DateTime }

constructor DateTime.create(year, month, day, hour, minute, second, millisecond: int);
begin
    create(longBuild((year shl 16) or ((month and $ff) shl 8) or (day and $ff),
            (hour shl 24) or ((minute and $ff) shl 16) or
            ((second * 1000 + millisecond) and $ffff)));
end;

constructor DateTime.create(internalRepresentation: long);
begin
    inherited create();
    self.fieldInternalRepresentation := internalRepresentation;
end;

function DateTime.equals(obj: TObject): boolean;
begin
    result := (obj = self) or (obj is DateTime) and
            (fieldInternalRepresentation = DateTime(obj).fieldInternalRepresentation);
end;

function DateTime.getHashCode(): int;
var
    value: long;
begin
    value := fieldInternalRepresentation;
    result := value.ints[0] xor value.ints[1];
end;

function DateTime.toString(): AnsiString;
var
    y: int;
    m: int;
    d: int;
    hrs: int;
    min: int;
    sec: int;
    msc: int;
    word0: int;
    reprs: long;
    cares: char_Array1d;
begin
    reprs := fieldInternalRepresentation;
    word0 := reprs.shorts[0] and $ffff;
    y := reprs.shorts[3] and $ffff;
    m := reprs.bytes[5] and $ff;
    d := reprs.bytes[4] and $ff;
    hrs := reprs.bytes[3] and $ff;
    min := reprs.bytes[2] and $ff;
    sec := word0 div 1000;
    msc := word0 mod 1000;
    cares := char_Array1d_create([
            '-', DIGITS[(m div 10) + 1], DIGITS[(m mod 10) + 1],
            '-', DIGITS[(d div 10) + 1], DIGITS[(d mod 10) + 1],
            ' ', DIGITS[(hrs div 10) + 1], DIGITS[(hrs mod 10) + 1],
            ':', DIGITS[(min div 10) + 1], DIGITS[(min mod 10) + 1],
            ':', DIGITS[(sec div 10) + 1], DIGITS[(sec mod 10) + 1],
            '.', DIGITS[(msc div 100) + 1], DIGITS[((msc div 10) mod 10) + 1],
            DIGITS[(msc mod 10) + 1] ]);
    result := intToString(y) + String_create(cares, 0, length(cares));
end;

procedure DateTime.setByte(index, value: int);
begin
    fieldInternalRepresentation.bytes[index] := byte(value);
end;

procedure DateTime.setWord(index, value: int);
begin
    fieldInternalRepresentation.shorts[index] := short(value);
end;

procedure DateTime.setSecond(value: int);
var
    pword0: ^short;
begin
    pword0 := @(fieldInternalRepresentation.shorts[0]);
    pword0^ := value * 1000 + ((pword0^ and $ffff) mod 1000);
end;

procedure DateTime.setMillisecond(value: int);
var
    pword0: ^short;
begin
    pword0 := @(fieldInternalRepresentation.shorts[0]);
    pword0^ := ((pword0^ and $ffff) div 1000) * 1000 + value;
end;

function DateTime.getByte(index: int): int;
begin
    result := fieldInternalRepresentation.bytes[index] and $ff;
end;

function DateTime.getWord(index: int): int;
begin
    result := fieldInternalRepresentation.shorts[index] and $ffff;
end;

function DateTime.getSecond(): int;
begin
    result := (fieldInternalRepresentation.shorts[0] and $ffff) div 1000;
end;

function DateTime.getMillisecond(): int;
begin
    result := (fieldInternalRepresentation.shorts[0] and $ffff) mod 1000;
end;

class function TimeZone.getCurrentOffsetInMillis(): int;
begin
    result := osintfGetCurrentUTCOffsetInMillis();
end;

{ Calendar }

constructor Calendar.create();
begin
    create(0, nil);
end;

constructor Calendar.create(offsetInMillis: int; time: DateTime);
var
    s: boolean_Array1d;
    f: int_Array1d;
begin
    inherited create();
    s := boolean_Array1d_create(FIELD_ARRAY_LENGTH);
    f := int_Array1d_create(FIELD_ARRAY_LENGTH);
    self.timeInMillis := 0;
    self.isSet := s;
    self.fields := f;
    self.timeSet := false;
    self.offsetInMillis := offsetInMillis;
    if time <> nil then begin
        s[FIELD_MILLIS] := true;
        s[FIELD_SECOND] := true;
        s[FIELD_MINUTE] := true;
        s[FIELD_HOUR_OF_DAY] := true;
        s[FIELD_DAY] := true;
        s[FIELD_MONTH] := true;
        s[FIELD_YEAR] := true;
        f[FIELD_MILLIS] := time.millisecond;
        f[FIELD_SECOND] := time.second;
        f[FIELD_MINUTE] := time.minute;
        f[FIELD_HOUR_OF_DAY] := time.hour;
        f[FIELD_DAY] := time.day;
        f[FIELD_MONTH] := time.month;
        f[FIELD_YEAR] := time.year;
    end;
end;

function Calendar.equals(obj: TObject): boolean;
begin
    result := (obj = self) or (obj is Calendar) and
            (getTimeInMillis() = Calendar(obj).getTimeInMillis());
end;

function Calendar.getHashCode(): int;
var
    millis: long;
begin
    millis := getTimeInMillis();
    result := millis.ints[0] xor millis.ints[1];
end;

procedure Calendar.setOffsetInMillis(offsetInMillis: int);
begin
    getTimeInMillis();
    self.offsetInMillis := offsetInMillis;
    computeFields();
end;

function Calendar.before(when: Calendar): boolean;
begin
    result := self.getTimeInMillis() < when.getTimeInMillis();
end;

function Calendar.after(when: Calendar): boolean;
begin
    result := self.getTimeInMillis() > when.getTimeInMillis();
end;

function Calendar.getOffsetInMillis(): int;
begin
    result := offsetInMillis;
end;

procedure Calendar.getTime(dst: DateTime);
var
    f: int_Array1d;
begin
    if dst = nil then begin
        raise NullPointerException.create(msgNullPointer);
    end;
    getTimeInMillis();
    computeFields();
    f := fields;
    dst.nativeRepresentation := longBuild(
            (f[FIELD_YEAR] shl 16) or ((f[FIELD_MONTH] and $ff) shl 8) or (f[FIELD_DAY] and $ff),
            (f[FIELD_HOUR_OF_DAY] shl 24) or ((f[FIELD_MINUTE] and $ff) shl 16) or
            ((f[FIELD_SECOND] * 1000 + f[FIELD_MILLIS]) and $ffff)).native;
end;

procedure Calendar.setTime(src: DateTime);
var
    s: boolean_Array1d;
    f: int_Array1d;
begin
    if src = nil then begin
        raise NullPointerException.create(msgNullPointer);
    end;
    s := isSet;
    f := fields;
    timeSet := false;
    s[FIELD_MILLIS] := true;
    s[FIELD_SECOND] := true;
    s[FIELD_MINUTE] := true;
    s[FIELD_HOUR_OF_DAY] := true;
    s[FIELD_DAY] := true;
    s[FIELD_MONTH] := true;
    s[FIELD_YEAR] := true;
    f[FIELD_MILLIS] := src.millisecond;
    f[FIELD_SECOND] := src.second;
    f[FIELD_MINUTE] := src.minute;
    f[FIELD_HOUR_OF_DAY] := src.hour;
    f[FIELD_DAY] := src.day;
    f[FIELD_MONTH] := src.month;
    f[FIELD_YEAR] := src.year;
end;

procedure Calendar.setField(field, value: int);
begin
    timeSet := false;
    isSet[field] := true;
    fields[field] := value;
end;

procedure Calendar.setTimeInMillis(timeInMillis: long);
begin
    self.timeSet := true;
    self.timeInMillis := timeInMillis;
    fields[FIELD_DAY_OF_WEEK] := -1;
    computeFields();
end;

function Calendar.getField(field: int): int;
begin
    case field of
    FIELD_HOUR_OF_DAY, FIELD_HOUR, FIELD_AM_PM, FIELD_DAY_OF_WEEK: begin
        getTimeInMillis();
        computeFields();
    end;
    end;
    result := fields[field];
end;

function Calendar.getTimeInMillis(): long;
begin
    if timeSet = false then begin
        computeTimeInMillis();
        timeSet := true;
    end;
    result := timeInMillis;
end;

procedure Calendar.computeHourOfDay();
var
    hour: int;
    ampm: int;
    f: int_Array1d;
begin
    f := fields;
    ampm := Math.max(0, Math.min(1, f[FIELD_AM_PM]));
    hour := Math.max(1, Math.min(12, f[FIELD_HOUR])) mod 12;
    f[FIELD_HOUR_OF_DAY] := ampm * 12 + hour;
end;

procedure Calendar.computeHour();
var
    hour: int;
    hourOfDay: int;
    f: int_Array1d;
begin
    f := fields;
    hourOfDay := Math.max(0, Math.min(23, f[FIELD_HOUR_OF_DAY]));
    hour := hourOfDay mod 12;
    if hour = 0 then begin
        hour := 12;
    end;
    f[FIELD_HOUR] := hour;
    f[FIELD_AM_PM] := hourOfDay div 12;
end;

{ JulianCalendar }

class procedure JulianCalendar.clinit();
begin
    DAYS := byte_Array2d_create([
            byte_Array1d_create([ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]),
            byte_Array1d_create([ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ])]);
end;

class procedure JulianCalendar.cldone();
begin
    DAYS := nil;
end;

function JulianCalendar.isLeapYear(year: int): boolean;
begin
    result := year mod 4 = 0;
end;

function JulianCalendar.getNumOfDays(year, month: int): int;
var
    leap: int;
begin
    if (month < 1) or (month > 12) then begin
        raise IllegalArgumentException.create(msgIllegalArgument);
    end;
    if isLeapYear(year) then begin
        leap := 1;
    end else begin
        leap := 0;
    end;
    result := JulianCalendar.DAYS[leap][month - 1];
end;

function JulianCalendar.getDayOfWeek(year, month, day: int): int;
begin
    result := int((((getTime(year, month, day, 0, 0, 0, 0, 0) + long(2 * 86400000)) div
            86400000) + 6) mod 7);
end;

function JulianCalendar.getInternalRepresentation(time: long; offsetInMillis: int): long;
var
    leap: int;
    year: int;
    month: int;
    day: int;
    hour: int;
    minute: int;
    millis: int;
    dur: int;
    j: int;
    i: long;
    months: byte_Array1d;
begin
    inc(time, long(offsetInMillis) + long(2 * 86400000));
    i := time mod 86400000;
    hour := int(i div 3600000);
    i := i mod 3600000;
    minute := int(i div 60000);
    i := i mod 60000;
    millis := int(i);
    i := time div 86400000;
    j := int((i div 1461) * 4);
    i := i mod 1461;
    if i = 1460 then begin
        inc(j, 3);
        i := 365;
    end else begin
        inc(j, int(i div 365));
        i := i mod 365;
    end;
    inc(j);
    year := j;
    if isLeapYear(j) then begin
        leap := 1;
    end else begin
        leap := 0;
    end;
    months := JulianCalendar.DAYS[leap];
    j := 0;
    dur := months[j];
    while i >= long(dur) do begin
        dec(i, long(dur));
        inc(j);
        dur := months[j];
    end;
    month := j + 1;
    day := int(i) + 1;
    result := longBuild((year shl 16) or (month shl 8) or day,
            (hour shl 24) or (minute shl 16) or millis);
end;

function JulianCalendar.getTime(internalRepresentation: long; offsetInMillis: int): long;
var
    hi: int;
    lo: int;
    word0: int;
begin
    hi := internalRepresentation.ints[1];
    lo := internalRepresentation.ints[0];
    word0 := lo and $ffff;
    result := getTime(hi shr 16, (hi shr 8) and $ff, hi and $ff,
            lo shr 24, (lo shr 16) and $ff, word0 div 1000, word0 mod 1000, offsetInMillis);
end;

function JulianCalendar.getTime(year, month, day, hour, minute, second, millis,
        offsetInMillis: int): long;
var
    i: int;
    leap: int;
    months: byte_Array1d;
begin
    if isLeapYear(year) then begin
        leap := 1;
    end else begin
        leap := 0;
    end;
    dec(year);
    result := -2 * 86400000;
    inc(result, 126230400000 * long(year div 4));
    year := year mod 4;
    inc(result, 31536000000 * long(year));
    months := JulianCalendar.DAYS[leap];
    for i := month - 2 downto 0 do begin
        inc(result, 86400000 * long(months[i]));
    end;
    dec(day);
    inc(result, 86400000 * long(day) + 3600000 * long(hour) + 60000 * long(minute) +
            1000 * long(second) + long(millis) - long(offsetInMillis));
end;

procedure JulianCalendar.computeFields();
var
    h: int;
    j: int;
    dur: int;
    leap: int;
    i: long;
    time: long;
    months: byte_Array1d;
    f: int_Array1d;
begin
    time := timeInMillis + (long(getOffsetInMillis()) + long(2 * 86400000));
    i := time mod 86400000;
    h := i div 3600000;
    f := fields;
    f[FIELD_HOUR_OF_DAY] := h;
    f[FIELD_AM_PM] := h div 12;
    h := h mod 12;
    if h = 0 then begin
        f[FIELD_HOUR] := 12;
    end else begin
        f[FIELD_HOUR] := h;
    end;
    i := i mod 3600000;
    f[FIELD_MINUTE] := int(i div 60000);
    i := i mod 60000;
    f[FIELD_SECOND] := int(i div 1000);
    i := i mod 1000;
    f[FIELD_MILLIS] := int(i);
    time := time div 86400000;
    i := time;
    j := int((i div 1461) * 4);
    i := i mod 1461;
    if i = 1460 then begin
        inc(j, 3);
        i := 365;
    end else begin
        inc(j, int(i div 365));
        i := i mod 365;
    end;
    inc(j);
    f[FIELD_YEAR] := j;
    if isLeapYear(j) then begin
        leap := 1;
    end else begin
        leap := 0;
    end;
    months := JulianCalendar.DAYS[leap];
    j := 0;
    dur := months[j];
    while i >= long(dur) do begin
        dec(i, long(dur));
        inc(j);
        dur := months[j];
    end;
    f[FIELD_MONTH] := j + 1;
    f[FIELD_DAY] := int(i) + 1;
    f[FIELD_DAY_OF_WEEK] := int((time + 6) mod 7);
end;

procedure JulianCalendar.computeTimeInMillis();
var
    s: boolean_Array1d;
    f: int_Array1d;
    hour: int;
begin
    s := isSet;
    f := fields;
    if s[FIELD_AM_PM] or s[FIELD_HOUR] then begin
        hour := Math.max(1, Math.min(12, f[FIELD_HOUR]));
        if hour = 12 then begin
            hour := 0;
        end;
        if f[FIELD_AM_PM] <> 0 then begin
            inc(hour, 12);
        end;
    end else begin
        hour := f[FIELD_HOUR_OF_DAY];
    end;
    s[FIELD_AM_PM] := false;
    s[FIELD_HOUR] := false;
    timeInMillis := getTime(f[FIELD_YEAR], f[FIELD_MONTH], f[FIELD_DAY],
            hour, f[FIELD_MINUTE], f[FIELD_SECOND], f[FIELD_MILLIS], getOffsetInMillis());
end;

{ GregorianCalendar }

function GregorianCalendar.isLeapYear(year: int): boolean;
begin
    if year mod 100 = 0 then begin
        result := year mod 400 = 0;
    end else begin
        result := year mod 4 = 0;
    end;
end;

function GregorianCalendar.getNumOfDays(year, month: int): int;
var
    leap: int;
begin
    if (month < 1) or (month > 12) then begin
        raise IllegalArgumentException.create(msgIllegalArgument);
    end;
    if isLeapYear(year) then begin
        leap := 1;
    end else begin
        leap := 0;
    end;
    result := JulianCalendar.DAYS[leap][month - 1];
end;

function GregorianCalendar.getDayOfWeek(year, month, day: int): int;
begin
    result := int(((getTime(year, month, day, 0, 0, 0, 0, 0) div 86400000) + 1) mod 7);
end;

function GregorianCalendar.getInternalRepresentation(time: long; offsetInMillis: int): long;
var
    leap: int;
    year: int;
    month: int;
    day: int;
    hour: int;
    minute: int;
    millis: int;
    dur: int;
    j: int;
    i: long;
    months: byte_Array1d;
begin
    inc(time, long(offsetInMillis));
    i := time mod 86400000;
    hour := int(i div 3600000);
    i := i mod 3600000;
    minute := int(i div 60000);
    i := i mod 60000;
    millis := int(i);
    i := time div 86400000;
    j := int((i div 146097) * 400);
    i := i mod 146097;
    if i = 146096 then begin
        inc(j, 399);
        i := 365;
    end else begin
        inc(j, int((i div 36524) * 100));
        i := i mod 36524;
        inc(j, int((i div 1461) * 4));
        i := i mod 1461;
        if i = 1460 then begin
            inc(j, 3);
            i := 365;
        end else begin
            inc(j, int(i div 365));
            i := i mod 365;
        end;
    end;
    inc(j);
    year := j;
    if isLeapYear(j) then begin
        leap := 1;
    end else begin
        leap := 0;
    end;
    months := JulianCalendar.DAYS[leap];
    j := 0;
    dur := months[j];
    while i >= long(dur) do begin
        dec(i, long(dur));
        inc(j);
        dur := months[j];
    end;
    month := j + 1;
    day := int(i) + 1;
    result := longBuild((year shl 16) or (month shl 8) or day,
            (hour shl 24) or (minute shl 16) or millis);
end;

function GregorianCalendar.getTime(internalRepresentation: long; offsetInMillis: int): long;
var
    hi: int;
    lo: int;
    word0: int;
begin
    hi := internalRepresentation.ints[1];
    lo := internalRepresentation.ints[0];
    word0 := lo and $ffff;
    result := getTime(hi shr 16, (hi shr 8) and $ff, hi and $ff,
            lo shr 24, (lo shr 16) and $ff, word0 div 1000, word0 mod 1000, offsetInMillis);
end;

function GregorianCalendar.getTime(year, month, day, hour, minute, second, millis,
        offsetInMillis: int): long;
var
    i: int;
    leap: int;
    months: byte_Array1d;
begin
    if isLeapYear(year) then begin
        leap := 1;
    end else begin
        leap := 0;
    end;
    dec(year);
    result := 0;
    inc(result, 12622780800000 * long(year div 400));
    year := year mod 400;
    inc(result, 3155673600000 * long(year div 100));
    year := year mod 100;
    inc(result, 126230400000 * long(year div 4));
    year := year mod 4;
    inc(result, 31536000000 * long(year));
    months := JulianCalendar.DAYS[leap];
    for i := month - 2 downto 0 do begin
        inc(result, 86400000 * long(months[i]));
    end;
    dec(day);
    inc(result, 86400000 * long(day) + 3600000 * long(hour) + 60000 * long(minute) +
            1000 * long(second) + long(millis) - long(offsetInMillis));
end;

procedure GregorianCalendar.computeFields();
var
    h: int;
    j: int;
    dur: int;
    leap: int;
    i: long;
    time: long;
    months: byte_Array1d;
    f: int_Array1d;
begin
    time := timeInMillis + getOffsetInMillis();
    i := time mod 86400000;
    h := i div 3600000;
    f := fields;
    f[FIELD_HOUR_OF_DAY] := h;
    f[FIELD_AM_PM] := h div 12;
    h := h mod 12;
    if h = 0 then begin
        f[FIELD_HOUR] := 12;
    end else begin
        f[FIELD_HOUR] := h;
    end;
    i := i mod 3600000;
    f[FIELD_MINUTE] := int(i div 60000);
    i := i mod 60000;
    f[FIELD_SECOND] := int(i div 1000);
    i := i mod 1000;
    f[FIELD_MILLIS] := int(i);
    time := time div 86400000;
    i := time;
    j := int((i div 146097) * 400);
    i := i mod 146097;
    if i = 146096 then begin
        inc(j, 399);
        i := 365;
    end else begin
        inc(j, int((i div 36524) * 100));
        i := i mod 36524;
        inc(j, int((i div 1461) * 4));
        i := i mod 1461;
        if i = 1460 then begin
            inc(j, 3);
            i := 365;
        end else begin
            inc(j, int(i div 365));
            i := i mod 365;
        end;
    end;
    inc(j);
    f[FIELD_YEAR] := j;
    if isLeapYear(j) then begin
        leap := 1;
    end else begin
        leap := 0;
    end;
    months := JulianCalendar.DAYS[leap];
    j := 0;
    dur := months[j];
    while i >= long(dur) do begin
        dec(i, long(dur));
        inc(j);
        dur := months[j];
    end;
    f[FIELD_MONTH] := j + 1;
    f[FIELD_DAY] := int(i) + 1;
    f[FIELD_DAY_OF_WEEK] := int((time + 1) mod 7);
end;

procedure GregorianCalendar.computeTimeInMillis();
var
    s: boolean_Array1d;
    f: int_Array1d;
    hour: int;
begin
    s := isSet;
    f := fields;
    if s[FIELD_AM_PM] or s[FIELD_HOUR] then begin
        hour := Math.max(1, Math.min(12, f[FIELD_HOUR]));
        if hour = 12 then begin
            hour := 0;
        end;
        if f[FIELD_AM_PM] <> 0 then begin
            inc(hour, 12);
        end;
    end else begin
        hour := f[FIELD_HOUR_OF_DAY];
    end;
    s[FIELD_AM_PM] := false;
    s[FIELD_HOUR] := false;
    timeInMillis := getTime(f[FIELD_YEAR], f[FIELD_MONTH], f[FIELD_DAY],
            hour, f[FIELD_MINUTE], f[FIELD_SECOND], f[FIELD_MILLIS], getOffsetInMillis());
end;

{ BooleanVal }

class procedure BooleanVal.clinit();
begin
    FALSE := BooleanVal.create(System.false);
    TRUE := BooleanVal.create(System.true);
end;

class procedure BooleanVal.cldone();
begin
    FALSE := nil;
    TRUE := nil;
end;

constructor BooleanVal.create(value: boolean);
begin
    inherited create();
    self.value := value;
end;

function BooleanVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is BooleanAsObject) and
            (value = (_Object(obj) as BooleanAsObject).booleanValue());
end;

function BooleanVal.getHashCode(): int;
begin
    if value then begin
        result := 1231;
    end else begin
        result := 1237;
    end;
end;

function BooleanVal.toString(): AnsiString;
begin
    if value then begin
        result := 'true';
    end else begin
        result := 'false';
    end;
end;

function BooleanVal.booleanValue(): boolean;
begin
    result := value;
end;

{ NumericVal }

constructor NumericVal.create();
begin
    inherited create();
end;

function NumericVal.byteValue(): int;
begin
    result := byte(intValue());
end;

function NumericVal.shortValue(): int;
begin
    result := short(intValue());
end;

{ IntegerVal }

constructor IntegerVal.create(value: int);
begin
    inherited create();
    self.int0 := value;
end;

function IntegerVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is IntegerAsObject) and
            (int0 = (_Object(obj) as IntegerAsObject).intValue());
end;

function IntegerVal.getHashCode(): int;
begin
    result := int0;
end;

function IntegerVal.toString(): AnsiString;
begin
    result := intToString(int0);
end;

function IntegerVal.intValue(): int;
begin
    result := int0;
end;

function IntegerVal.nativeValue(): int64;
begin
    result := int0;
end;

function IntegerVal.longValue(): long;
begin
    result := int0;
end;

function IntegerVal.floatValue(): float;
begin
    result := int0;
end;

function IntegerVal.doubleValue(): double;
begin
    result := int0;
end;

function IntegerVal.realValue(): real;
begin
    result := int0;
end;

{ LongVal }

constructor LongVal.create(const value: long);
begin
    inherited create(value.ints[0]);
    self.int1 := value.ints[1];
end;

constructor LongVal.create(const value: int64);
begin
    create(long(value));
end;

function LongVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is LongAsObject) and
            (long0() = (_Object(obj) as LongAsObject).longValue());
end;

function LongVal.getHashCode(): int;
begin
    result := int0 xor int1;
end;

function LongVal.toString(): AnsiString;
begin
    result := longToString(long0());
end;

function LongVal.nativeValue(): int64;
begin
    result := long0().native;
end;

function LongVal.longValue(): long;
begin
    result := long0();
end;

function LongVal.floatValue(): float;
begin
    result := real(long0());
end;

function LongVal.doubleValue(): double;
begin
    result := real(long0());
end;

function LongVal.realValue(): real;
begin
    result := real(long0());
end;

function LongVal.long0(): long;
begin
    result := longBuild(int1, int0);
end;

{ UltraVal }

constructor UltraVal.create(const value: ultra);
begin
    inherited create(value.ints[0]);
    self.int1 := value.ints[1];
    self.long1 := value.longs[1];
end;

function UltraVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is UltraAsObject) and
            (ultra0() = (_Object(obj) as UltraAsObject).ultraValue());
end;

function UltraVal.getHashCode(): int;
begin
    result := int0 xor int1 xor long1.ints[0] xor long1.ints[1];
end;

function UltraVal.toString(): AnsiString;
begin
    result := 'ultra{' + intToString(long1.ints[1]) + ', ' + intToString(long1.ints[0]) + ', ' +
            intToString(int1) + ', ' + intToString(int0) + '}';
end;

function UltraVal.nativeValue(): int64;
begin
    result := long0().native;
end;

function UltraVal.longValue(): long;
begin
    result := long0();
end;

function UltraVal.getShort(index: int): int;
begin
    case index of
    0: begin
        result := short(int0);
    end;
    1: begin
        result := short(int0 shr 16);
    end;
    2: begin
        result := short(int1);
    end;
    3: begin
        result := short(int1 shr 16);
    end;
    4..7: begin
        result := long1.shorts[index - 4];
    end;
    else
        raise IndexOutOfBoundsException.create(msgIndexOutOfBounds);
    end;
end;

function UltraVal.getInt(index: int): int;
begin
    case index of
    0: begin
        result := int0;
    end;
    1: begin
        result := int1;
    end;
    2..3: begin
        result := long1.ints[index - 2];
    end;
    else
        raise IndexOutOfBoundsException.create(msgIndexOutOfBounds);
    end;
end;

function UltraVal.ultraValue(): ultra;
begin
    result := ultra0();
end;

function UltraVal.long0(): long;
begin
    result := longBuild(int1, int0);
end;

function UltraVal.ultra0(): ultra;
begin
    result := ultraBuild(long1.ints[1], long1.ints[0], int1, int0);
end;

{ RealVal }

constructor RealVal.create(const value: real);
begin
    inherited create();
    self.value := value;
end;

function RealVal.equals(obj: TObject): boolean;
var
    tvalue: real;
    avalue: real;
begin
    if not (obj is _Object) then begin
        result := false;
        exit;
    end;
    if _Object(obj) is RealAsObject then begin
        tvalue := value;
        avalue := (_Object(obj) as RealAsObject).realValue();
        result := (realExtractExponent(tvalue) = realExtractExponent(avalue)) and
                (realExtractSignificand(tvalue) = realExtractSignificand(avalue));
    end else begin
        result := (_Object(obj) is DoubleAsObject) and (doubleToLongBits(value) =
                doubleToLongBits((_Object(obj) as DoubleAsObject).doubleValue())) or
                (_Object(obj) is FloatAsObject) and (floatToIntBits(value) =
                floatToIntBits((_Object(obj) as FloatAsObject).floatValue()));
    end;
end;

function RealVal.getHashCode(): int;
var
    e: int;
    s: long;
    v: real;
begin
    v := value;
    s := realExtractSignificand(v);
    e := realExtractExponent(v);
    result := e xor s.ints[0] xor s.ints[1];
end;

function RealVal.toString(): AnsiString;
begin
    result := realToString(value);
end;

function RealVal.intValue(): int;
begin
    result := realToInt(value);
end;

function RealVal.nativeValue(): int64;
begin
    result := realToLong(value).native;
end;

function RealVal.longValue(): long;
begin
    result := realToLong(value);
end;

function RealVal.floatValue(): float;
begin
    result := realToFloat(value);
end;

function RealVal.doubleValue(): double;
begin
    result := realToDouble(value);
end;

function RealVal.realValue(): real;
begin
    result := value;
end;

{ XVectorVal }

constructor XVectorVal.create(const value: xvector);
begin
    inherited create();
    self.value := value;
end;

function XVectorVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is XVectorAsObject) and
            (value = (_Object(obj) as XVectorAsObject).xvectorValue());
end;

function XVectorVal.getHashCode(): int;
begin
    result := floatToIntBits(value.floats[0]) xor floatToIntBits(value.floats[1]) xor
            floatToIntBits(value.floats[2]) xor floatToIntBits(value.floats[3]);
end;

function XVectorVal.toString(): AnsiString;
var
    repr: RealValueRepresenter;
begin
    repr := RealValueRepresenter.create(RealValueRepresenter.FLOAT_SIGNIFICAND_DIGITS,
            RealValueRepresenter.FLOAT_ORDER_DIGITS);
    try
        result := 'xvector{' +
                repr.toString(value.floats[3]) + ', ' + repr.toString(value.floats[2]) + ', ' +
                repr.toString(value.floats[1]) + ', ' + repr.toString(value.floats[0]) + '}';
    finally
        repr.free();
    end;
end;

function XVectorVal.intValue(): int;
begin
    result := realToInt(value.floats[0]);
end;

function XVectorVal.nativeValue(): int64;
begin
    result := realToLong(value.floats[0]).native;
end;

function XVectorVal.longValue(): long;
begin
    result := realToLong(value.floats[0]);
end;

function XVectorVal.floatValue(): float;
begin
    result := value.floats[0];
end;

function XVectorVal.doubleValue(): double;
begin
    result := value.floats[0];
end;

function XVectorVal.realValue(): real;
begin
    result := value.floats[0];
end;

function XVectorVal.getFloat(index: int): float;
begin
    if (index < 0) or (index > 3) then begin
        raise IndexOutOfBoundsException.create(msgIndexOutOfBounds);
    end;
    result := value.floats[index];
end;

function XVectorVal.xvectorValue(): xvector;
begin
    result := value;
end;

{ CharVal }

constructor CharVal.create(value: char);
begin
    inherited create();
    self.value := value;
end;

function CharVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is CharAsObject) and
            (int(value) = int((_Object(obj) as CharAsObject).charValue()));
end;

function CharVal.getHashCode(): int;
begin
    result := int(value);
end;

function CharVal.toString(): AnsiString;
begin
    result := value;
end;

function CharVal.charValue(): char;
begin
    result := value;
end;

{ UCharVal }

constructor UCharVal.create(value: uchar);
begin
    inherited create();
    self.value := value;
end;

function UCharVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is UCharAsObject) and
            (int(value) = int((_Object(obj) as UCharAsObject).ucharValue()));
end;

function UCharVal.getHashCode(): int;
begin
    result := int(value);
end;

function UCharVal.toString(): AnsiString;
begin
    result := stringToUTF8(value);
end;

function UCharVal.ucharValue(): uchar;
begin
    result := value;
end;

{ StringVal }

constructor StringVal.create(const value: AnsiString);
begin
    inherited create();
    self.value := value;
end;

function StringVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is StringAsObject) and
            (value = (_Object(obj) as StringAsObject).stringValue());
end;

function StringVal.getHashCode(): int;
var
    i: int;
    s: AnsiString;
begin
    s := value;
    result := 0;
    for i := length(s) downto 1 do begin
        result := (31 * result) + int(s[i]);
    end;
end;

function StringVal.toString(): AnsiString;
begin
    result := value;
end;

function StringVal.stringValue(): AnsiString;
begin
    result := value;
end;

function StringVal.unicodeStringValue(): UnicodeString;
begin
    result := stringToUTF16(value);
end;

{ UStringVal }

constructor UStringVal.create(const value: UnicodeString);
begin
    inherited create();
    self.value := value;
end;

function UStringVal.equals(obj: TObject): boolean;
begin
    result := (obj is _Object) and (_Object(obj) is UnicodeStringAsObject) and
            (value = (_Object(obj) as UnicodeStringAsObject).unicodeStringValue());
end;

function UStringVal.getHashCode(): int;
var
    i: int;
    s: UnicodeString;
begin
    s := value;
    result := 0;
    for i := length(s) downto 1 do begin
        result := (31 * result) + int(s[i]);
    end;
end;

function UStringVal.toString(): AnsiString;
begin
    result := stringToUTF8(value);
end;

function UStringVal.stringValue(): AnsiString;
begin
    result := stringToUTF8(value);
end;

function UStringVal.unicodeStringValue(): UnicodeString;
begin
    result := value;
end;

{ := operators }

operator :=(const value: boolean): _Interface;
begin
    if value then begin
        result := BooleanVal.TRUE;
    end else begin
        result := BooleanVal.FALSE;
    end;
end;

operator :=(const value: char): _Interface;
begin
    result := CharVal.create(value);
end;

operator :=(const value: uchar): _Interface;
begin
    result := UCharVal.create(value);
end;

operator :=(const value: byte): _Interface;
begin
    result := IntegerVal.create(value);
end;

operator :=(const value: short): _Interface;
begin
    result := IntegerVal.create(value);
end;

operator :=(const value: int): _Interface;
begin
    result := IntegerVal.create(value);
end;

operator :=(const value: int64): _Interface;
begin
    result := LongVal.create(value);
end;

operator :=(const value: long): _Interface;
begin
    result := LongVal.create(value);
end;

operator :=(const value: ultra): _Interface;
begin
    result := UltraVal.create(value);
end;

operator :=(const value: float): _Interface;
begin
    result := RealVal.create(value);
end;

operator :=(const value: double): _Interface;
begin
    result := RealVal.create(value);
end;

operator :=(const value: real): _Interface;
begin
    result := RealVal.create(value);
end;

operator :=(const value: xvector): _Interface;
begin
    result := XVectorVal.create(value);
end;

operator :=(const value: AnsiString): _Interface;
begin
    result := StringVal.create(value);
end;

operator :=(const value: UnicodeString): _Interface;
begin
    result := UStringVal.create(value);
end;

operator :=(const value: boolean): BooleanAsObject;
begin
    if value then begin
        result := BooleanVal.TRUE;
    end else begin
        result := BooleanVal.FALSE;
    end;
end;

operator :=(const value: char): CharAsObject;
begin
    result := CharVal.create(value);
end;

operator :=(const value: uchar): UCharAsObject;
begin
    result := UCharVal.create(value);
end;

operator :=(const value: byte): IntegerAsObject;
begin
    result := IntegerVal.create(value);
end;

operator :=(const value: short): IntegerAsObject;
begin
    result := IntegerVal.create(value);
end;

operator :=(const value: int): IntegerAsObject;
begin
    result := IntegerVal.create(value);
end;

operator :=(const value: int64): LongAsObject;
begin
    result := LongVal.create(value);
end;

operator :=(const value: long): LongAsObject;
begin
    result := LongVal.create(value);
end;

operator :=(const value: ultra): UltraAsObject;
begin
    result := UltraVal.create(value);
end;

operator :=(const value: float): FloatAsObject;
begin
    result := RealVal.create(value);
end;

operator :=(const value: double): DoubleAsObject;
begin
    result := RealVal.create(value);
end;

operator :=(const value: real): RealAsObject;
begin
    result := RealVal.create(value);
end;

operator :=(const value: xvector): XVectorAsObject;
begin
    result := XVectorVal.create(value);
end;

operator :=(const value: AnsiString): StringAsObject;
begin
    result := StringVal.create(value);
end;

operator :=(const value: UnicodeString): UnicodeStringAsObject;
begin
    result := UStringVal.create(value);
end;

initialization
    JulianCalendar.clinit();
    BooleanVal.clinit();

finalization
    BooleanVal.cldone();
    JulianCalendar.cldone();

end.