[Runtime] Fixed Generic Scan functions for negative counts and scanning from the back to the front.

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

// Use UDC below to standardize the NULL checks for the array arguments
#command ARRAYNULL_RETURNZERO <aArray>    => IF <aArray> == NULL ; return 0 ; ENDIF
#command ARRAYNOTNULL <aArray> => IF <aArray> == NULL ; THROW Error.NullArgumentError(__FUNCTION__,nameof(<aArray>), 1) ; ENDIF
#command ARRAYNULL <aArray>    => IF <aArray> == NULL ; return <aArray> ; ENDIF

INTERNAL STATIC CLASS ArrayHelpers

    STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, element  AS T , nStart AS LONG, nCount AS LONG) AS DWORD
        ARRAYNOTNULL aTarget
        IF ! ArrayHelpers.ValidateArrayParams(aTarget, REF nStart, REF nCount, OUT VAR nSize)
            RETURN 0
        ENDIF
        LOCAL nItem AS LONG
        IF nStart < nSize
            FOR nItem := nStart TO nSize
                IF Object.Equals(aTarget[ nItem], element)
                    RETURN (DWORD) nItem
                ENDIF
                nCount -= 1
                IF nCount == 0
                    EXIT
                ENDIF
            NEXT
        ELSE
            FOR nItem := nStart DOWNTO nSize
                IF nCount > 0
                    IF Object.Equals(aTarget[ nItem], element)
                        RETURN (DWORD) nItem
                    ENDIF
                    nCount--
                ELSE
                    EXIT
                ENDIF
            NEXT
        ENDIF
        RETURN 0

    STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, bAction AS @@Func<T, LOGIC> , nStart AS LONG, nCount AS LONG) AS DWORD
        ARRAYNOTNULL aTarget
        IF ! ArrayHelpers.ValidateArrayParams(aTarget, REF nStart, REF nCount, OUT VAR nSize)
            RETURN 0
        ENDIF
        LOCAL nItem AS LONG
        IF nStart < nSize
            FOR nItem := nStart TO nSize
                LOCAL oElement := aTarget[ nItem] AS T
                IF bAction(oElement)
                    RETURN  (DWORD) nItem
                ENDIF
                nCount -= 1
                IF nCount == 0
                    EXIT
                ENDIF
            NEXT
        ELSE
            FOR nItem := nStart DOWNTO nSize
                LOCAL oElement := aTarget[ nItem] AS T
                IF nCount > 0
                    IF bAction(oElement)
                        RETURN (DWORD) nItem
                    ENDIF
                    nCount--
                ELSE
                    EXIT
                ENDIF
            NEXT
        ENDIF
        RETURN 0

    STATIC METHOD AScan( aTarget AS USUAL, x AS USUAL, uStart AS USUAL, uCount AS USUAL, lExact AS LOGIC ) AS DWORD
        IF ! ArrayHelpers.ValidateArrayParams(REF aTarget, REF uStart, REF uCount, OUT VAR nSize)
            RETURN 0
        ENDIF
        LOCAL a := aTarget AS ARRAY
        LOCAL nStart := uStart	AS DWORD
        LOCAL nCount := uCount	AS DWORD
        LOCAL nRet := 0			AS DWORD
        LOCAL i					AS DWORD
        LOCAL cb				AS CODEBLOCK
        IF IsCodeBlock( x )
            cb := x
        ELSE
            IF lExact
                cb   := {|element| element == x }
            ELSE
                cb   := {|element| element = x }
            ENDIF
        ENDIF
        IF nStart < nSize
            FOR i := nStart UPTO nSize
                IF nCount > 0
                    IF Eval( cb, a[i] )
                        nRet := i
                        EXIT
                    ENDIF
                    nCount--
                ELSE
                    EXIT
                ENDIF
            NEXT
        ELSE
            FOR i := nStart DOWNTO nSize
                IF nCount > 0
                    IF Eval( cb, a[i] )
                        nRet := i
                        EXIT
                    ENDIF
                    nCount--
                ELSE
                    EXIT
                ENDIF
            NEXT
        ENDIF

        RETURN nRet

    STATIC METHOD AScanBin(cFuncName AS STRING, a AS ARRAY, seekVal AS USUAL, lExact AS LOGIC ) AS DWORD
        LOCAL dwLow        AS DWORD
        LOCAL dwHigh       AS DWORD
        LOCAL x            AS DWORD
        LOCAL dwRet        AS DWORD
        LOCAL iSave        AS DWORD
        LOCAL lIsCodeBlock AS LOGIC
        LOCAL iCBRet       AS USUAL
        LOCAL iComp        AS INT
        LOCAL cb			  AS CODEBLOCK

        dwLow  := 1
        dwHigh := (DWORD) ALen(a)
        iSave := dwRet := 0
        iComp := 0
        lIsCodeBlock := IsCodeBlock( seekVal )
        IF lIsCodeBlock
            cb := seekVal
        ELSEIF lExact
            cb := {|element| IIF( element == seekVal , 0, IIF( seekVal < element, -1, 1 ) ) }
        ELSE
            cb := {|element| IIF( element = seekVal , 0, IIF( seekVal < element, -1, 1 ) ) }
        ENDIF

        DO WHILE dwLow <= dwHigh
            x := dwLow + ( ( dwHigh - dwLow ) / 2 )

            IF iSave == x
                IF dwHigh - dwLow == 1
                    x++
                    dwLow++
                ELSE
                    EXIT
                ENDIF
            ENDIF

            iSave := x
            IF lIsCodeBlock
                iCBRet := Eval( cb, a[x] )
                IF ! iCBRet:IsNumeric
                    THROW Error.DataTypeError(cFuncName, "Return value of Codeblock", 0)
                ELSE
                    iComp := iCBRet
                ENDIF
            ELSE
                iComp := Eval( cb, a[x] )
            ENDIF
            IF iComp < 0
                dwHigh := x
            ELSEIF iComp > 0
                dwLow := x
            ELSE
                dwRet := x
                x--

                DO WHILE dwLow <= x

                    IF lIsCodeBlock
                        iCBRet := Eval( cb, a[x] )
                        IF ! iCBRet:IsNumeric
                            THROW Error.DataTypeError(cFuncName, "Return value of Codeblock", 0)
                        ELSE
                            iComp := iCBRet
                        ENDIF
                    ELSE
                        iComp := Eval( cb, a[x] )
                    ENDIF

                    IF iComp != 0
                        EXIT
                    ENDIF

                    dwRet := x
                    x--
                ENDDO
                dwLow := dwHigh + 1
            ENDIF
        ENDDO

        RETURN dwRet

    STATIC METHOD AEval(aArray AS ARRAY, cbBlock AS ICodeblock, nStart AS DWORD, nCount AS DWORD, bUpdateArray AS CONST LOGIC )  AS ARRAY
        LOCAL elements := ALen(aArray) AS DWORD
        LOCAL last   AS DWORD
        LOCAL result AS USUAL
        LOCAL x      AS DWORD
        IF elements == 0
            RETURN aArray
        ENDIF
        ARRAYNOTNULL aArray
        IF nStart == 0
            THROW  Error.ArgumentError( __FUNCTION__, nameof(nStart), 3, __CavoStr( VOErrors.ARGCANNOTBEZERO ), { nStart } )
        ENDIF

        IF nCount != 0

            IF nStart < 0
                nStart := elements + 1 + nStart
            ENDIF

            IF nCount > 0

                last := Math.Min( nStart + ( nCount - 1 ), elements )

                FOR x := nStart UPTO last
                    result := Eval( cbBlock, aArray[x], x )

                    IF ( bUpdateArray )
                        aArray[x] := result
                    ENDIF
                NEXT
            ELSE

                last := (DWORD) Math.Max( 1, nStart + nCount + 1 )

                FOR x := nStart DOWNTO last
                    result := Eval( cbBlock, aArray[x], x )

                    IF ( bUpdateArray )
                        aArray[x] := result
                    ENDIF
                NEXT
            ENDIF
        ENDIF

        RETURN aArray

    STATIC METHOD AEvalCheckArgs(aArray AS ARRAY, cb AS ICodeblock, iStart REF USUAL, iCount REF USUAL,cFuncName AS STRING) AS VOID
        IF aArray == NULL_ARRAY
            RETURN
        ENDIF
        IF cb == NULL
            THROW Error.NullArgumentError( cFuncName, NAMEOF(cb),2)
        ENDIF
        @@Default( REF iStart, 1)
        @@Default( REF iCount, ALen(aArray))
        IF ! iStart:IsNumeric
            THROW Error.ArgumentError( cFuncName, NAMEOF(iStart), 3 , <OBJECT>{iStart})
        ENDIF
        IF ! iCount:IsNumeric
            THROW Error.ArgumentError( cFuncName, NAMEOF(iCount), 4 , <OBJECT>{iCount})
        ENDIF
        RETURN

    STATIC METHOD ValidateArrayParams(aTarget REF USUAL, nStart REF USUAL,nCount REF USUAL, nSize OUT DWORD) AS LOGIC
        nSize := 0
        IF aTarget:IsArray
            nSize := ALen( (ARRAY) aTarget )
            IF nSize == 0
                RETURN FALSE
            ENDIF
        ELSE
            RETURN FALSE
        ENDIF

        IF ! nCount:IsNumeric
            IF ! nStart:IsNumeric
                nStart := 1
            END IF
            nCount := ALen(aTarget) - nStart + 1
        ELSE
            IF nCount >= 0
                IF ! nStart:IsNumeric
                    nStart := 1
                ENDIF
                IF nStart > nSize
                    RETURN FALSE
                END IF
            ELSE
                IF ! nStart:IsNumeric
                    nStart := ALen(aTarget)
                ENDIF
                nSize := 1
                nCount := - nCount
                IF nStart < nSize
                    RETURN FALSE
                END IF
            END IF
        END IF
        RETURN TRUE
    STATIC METHOD ValidateArrayParams<T>(aTarget AS __ArrayBase<T>, nStart REF LONG,nCount REF LONG, nSize OUT DWORD) AS LOGIC
         nSize := aTarget:Length
         IF nSize == 0
             RETURN FALSE
         ENDIF
        IF nCount >= 0
            IF nStart > nSize
                RETURN FALSE
            END IF
        ELSE
            nSize := 1
            nCount := - nCount
            IF nStart < nSize
                RETURN FALSE
            END IF
        END IF
        RETURN TRUE

        END CLASS

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraycreate/*" />
FUNCTION ArrayCreate(dwElements AS DWORD) AS ARRAY
    RETURN __Array{dwElements, TRUE}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraycreate/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayCreate<T>(dwElements AS DWORD) AS __ArrayBase<T>
    RETURN __ArrayBase<T>{dwElements,TRUE}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayinit/*" />
FUNCTION ArrayInit(wElements AS DWORD, avalues REF USUAL[]) AS ARRAY
    LOCAL aTemp AS ARRAY
    LOCAL x AS DWORD

    IF wElements > (DWORD) avalues:Length
        THROW Error.ArgumentError( __FUNCTION__, NAMEOF(wElements), "Element too big")
    ENDIF

    aTemp := ArrayNew(avalues:Length)
    FOR x := 1 UPTO avalues:Length
        aTemp [x] := avalues[x]
    NEXT
    RETURN aTemp

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aadd/*" />

FUNCTION AAdd(aTarget AS ARRAY,uNewElement AS USUAL) AS USUAL
    ARRAYNOTNULL aTarget
    RETURN AAdd<USUAL>(aTarget, uNewElement)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aadd/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AAdd<T>(aTarget AS __ArrayBase<T>,uNewElement AS T) AS T
    ARRAYNOTNULL aTarget
    aTarget:Add(uNewElement)
    RETURN uNewElement

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aclone/*" />
FUNCTION AClone(aSource AS ARRAY) AS ARRAY
    IF aSource == NULL_ARRAY
        RETURN aSource
    END IF
    RETURN (ARRAY) aSource:Clone()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aclone/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AClone<T>(aSource AS __ArrayBase<T>) AS __ArrayBase<T>
    IF aSource == NULL
        RETURN aSource
    END IF
    RETURN  aSource:Clone()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acloneshallow/*" />
FUNCTION ACloneShallow(aSource AS ARRAY) AS ARRAY
    IF aSource == NULL_ARRAY
        RETURN aSource
    END IF
    RETURN (ARRAY) aSource:CloneShallow()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acloneshallow/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ACloneShallow<T>(aSource AS __ArrayBase<T>) AS __ArrayBase<T>
    IF aSource == NULL
        RETURN aSource
    END IF
    RETURN aSource:Clone()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ADel(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
    ARRAYNOTNULL aTarget
    IF aTarget:__IsFoxArray
        RETURN _CallClipFunc(#__FoxADel, aTarget, dwPosition, 2)
    ENDIF
    aTarget:Delete((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ADel<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T>
    ARRAYNOTNULL aTarget
    aTarget:Delete((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ATrueDel(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
    ARRAYNOTNULL aTarget
    aTarget:RemoveAt((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ATrueDel<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T>
    ARRAYNOTNULL aTarget
    aTarget:RemoveAt((INT) dwPosition)
    RETURN aTarget

    /// Calculate the # of dimensions in an array
        /// <param name="a"></param>
    /// <returns>Number of dimensions in an array</returns>
FUNCTION ADim(a AS ARRAY) AS DWORD
    LOCAL dwDims AS DWORD
    dwDims := 1
    DO WHILE a != NULL_ARRAY
        IF ALen(a) > 0
            IF IsArray(a[1])
                dwDims += 1
                a := a[1]
            ELSE
                EXIT
            ENDIF
        ELSE
            EXIT
        ENDIF
    ENDDO
    RETURN dwDims

    /// Calculate a string that represents the dimensions in an array
        /// <param name="a"></param>
    /// <returns>String that displays the dimensions in an array</returns>
FUNCTION ADimPic(a AS ARRAY) AS STRING
RETURN Repl("[]", ADim(a))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ains/*" />
FUNCTION AIns(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
    ARRAYNOTNULL aTarget
    IF aTarget:__IsFoxArray
        _CallClipFunc(#__FoxAIns, aTarget, dwPosition, 1)
    ENDIF
    aTarget:Insert((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ains/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AIns<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T>
    ARRAYNOTNULL aTarget
    aTarget:Insert((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alen/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ALen<T>(aTarget AS __ArrayBase<T>) AS DWORD
    IF aTarget != NULL
        RETURN aTarget:Length
    ELSE
        RETURN 0
    ENDIF

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alen/*" />
FUNCTION ALen(aTarget AS ARRAY) AS DWORD
    IF aTarget == NULL
        RETURN 0
    ELSEIF aTarget:__IsFoxArray
        RETURN _CallClipFunc(#__FoxALen, aTarget)
    ENDIF
    RETURN aTarget:Length

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraydeprotect/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayDeProtect<T>(aTarget AS __ArrayBase<T>) AS LOGIC
    ARRAYNOTNULL aTarget
    RETURN aTarget:Lock(FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraydeprotect/*" />
FUNCTION ArrayDeProtect(aTarget AS ARRAY) AS LOGIC
    ARRAYNOTNULL aTarget
    RETURN aTarget:Lock(FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayget/*" />
FUNCTION ArrayGet(aTarget AS ARRAY,dwElement AS DWORD) AS USUAL
    ARRAYNOTNULL aTarget
    RETURN aTarget:__GetElement( (INT) dwElement-1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayget/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayGet<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD) AS T
    ARRAYNOTNULL aTarget
    RETURN aTarget:__GetElement( (INT) dwElement-1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayprotect/*" />
FUNCTION ArrayProtect(aTarget AS ARRAY) AS LOGIC
    ARRAYNOTNULL aTarget
    RETURN aTarget:Lock(TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayprotect/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayProtect<T>(aTarget AS __ArrayBase<T>) AS LOGIC
    ARRAYNOTNULL aTarget
    RETURN aTarget:Lock(TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayput/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayPut<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD,uValue AS T) AS T
    ARRAYNOTNULL aTarget
    aTarget:__SetElement(uValue, (INT)dwElement -1)
    RETURN uValue

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayput/*" />
FUNCTION ArrayPut(aTarget AS ARRAY,dwElement AS DWORD,uValue AS USUAL) AS USUAL
    ARRAYNOTNULL aTarget
    aTarget:__SetElement(uValue, (INT)dwElement -1)
    RETURN uValue

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraystore/*" />
FUNCTION ArrayStore(aSource AS ARRAY,Buff AS USUAL PTR,dwLen AS DWORD) AS DWORD
    LOCAL i AS DWORD
    LOCAL nLen AS DWORD
    nLen := ALen(aSource)
    dwLen := Math.Min(dwLen, nLen)
    FOR i := 1 TO dwLen
        Buff[i] := aSource[i]
    NEXT
    RETURN dwLen

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraystore/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayStore<T>(aSource AS __ArrayBase<T>,Buff AS T PTR,dwLen AS DWORD) AS DWORD
    ARRAYNOTNULL aSource
    LOCAL i, nLen AS DWORD
    nLen := aSource:Length
    dwLen := Math.Min(dwLen, nLen)
    FOR i := 1 TO dwLen
        Buff[i] := aSource[(INT) i]
    NEXT
    RETURN dwLen

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayswap/*" />
FUNCTION ArraySwap(aTarget AS ARRAY,dwElement AS DWORD,uNewValue AS USUAL) AS USUAL
    ARRAYNOTNULL aTarget
    RETURN aTarget:Swap((INT) dwElement, uNewValue)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayswap/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArraySwap<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD,uNewValue AS T) AS T
    ARRAYNOTNULL aTarget
    RETURN aTarget:Swap((INT) dwElement, uNewValue)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart := NIL AS USUAL,nCount := NIL AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount, SetExact())

    /// <inheritdoc cref='AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, NIL, SetExact())

    /// <inheritdoc cref='AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, 1, NIL, SetExact())

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount, TRUE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, NIL, TRUE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, 1, NIL, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanbin/*" />
FUNCTION AScanBin(aTarget AS ARRAY,uSearch AS USUAL) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScanBin( "AscanBin" , aTarget, uSearch, FALSE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanbinexact/*" />
FUNCTION AScanBinExact(aTarget AS ARRAY,uSearch AS USUAL) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScanBin( "AscanBin" , aTarget, uSearch, TRUE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch,1, (INT) aTarget:Length)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
    /// <param name="act">A lambda expression that will be evaluated for every element in the array.</param>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, act,1, (INT) aTarget:Length)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T, nStart AS LONG) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, (INT) aTarget:Length- nStart +1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
    /// <param name="act">A lambda expression that will be evaluated for every element in the array.</param>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, act, nStart, (INT) aTarget:Length - nStart +1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T, nStart AS LONG, nCount AS LONG) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG, nCount  AS LONG) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, act, nStart, nCount)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asize/*" />
FUNCTION ASize(aTarget AS ARRAY,dwLength AS DWORD) AS ARRAY
    ARRAYNOTNULL aTarget
    aTarget:Resize((INT) dwLength)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asize/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASize<T>(aTarget AS __ArrayBase<T>,dwLength AS DWORD) AS __ArrayBase<T>
    ARRAYNOTNULL aTarget
    aTarget:Resize((INT) dwLength)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atail/*" />
FUNCTION ATail(aTarget AS ARRAY) AS USUAL
    ARRAYNOTNULL aTarget
    RETURN aTarget:Tail()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atail/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ATail<T>(aTarget AS __ArrayBase<T>) AS T
    ARRAYNOTNULL aTarget
    RETURN aTarget:Tail()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acopy/*" />
FUNCTION ACopy(aSource ,aTarget ,nStart ,nCount ,nTargetPos ) AS ARRAY CLIPPER
    LOCAL sourceLen  AS LONG
    LOCAL start AS LONG
    LOCAL count AS LONG
    IF !aSource:IsArray
        THROW Error.ArgumentError( __FUNCTION__, NAMEOF(aSource), 1, <OBJECT>{ aSource } )
    ENDIF

    IF !aTarget:IsArray
        THROW Error.ArgumentError( __FUNCTION__, NAMEOF(aTarget), 2, <OBJECT>{ aTarget } )
    ENDIF
    start := 1
    sourceLen  := (LONG) ALen(aSource)
    IF pCount() > 2
        IF nStart:IsNumeric
            start := nStart
        ELSEIF nStart:IsNil
            IF pCount() >= 4 .and. nCount:IsNumeric .and. nCount < 0
                start := (LONG) ALen(aSource) -1
            ELSE
                start := 1
            END IF
        ELSE
            THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nStart), 3, <OBJECT>{ nStart } )
        ENDIF
        IF start < 0
            start := sourceLen
        ELSE
            start := Math.Min(start, sourceLen)
        ENDIF
    ENDIF
    IF pCount() > 3 .and. .not. nCount:IsNil
        IF nCount:IsNumeric
            count := nCount
        ELSE
            THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nCount), 4, <OBJECT>{ nCount } )
        ENDIF
        IF count > 0
            sourceLen := Math.Min(sourceLen, start+count-1)
        ELSE
            sourceLen := Math.Max(1, start+count-1)
        ENDIF
    ENDIF
    LOCAL offSet		:= 1 AS LONG
    LOCAL targetLen	    := (LONG) ALen(aTarget) AS LONG
    IF pCount() > 4 .and. .not. nTargetPos:IsNil
        IF nTargetPos:IsNumeric
            offSet := nTargetPos
            offSet := Math.Min( offSet, targetLen )
            offSet := Math.Max( 1, offSet )
        ELSE
            THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nTargetPos), 5, <OBJECT>{ nTargetPos } )
        ENDIF
    ENDIF
    XSharp.__Array.Copy(aSource, aTarget, start, sourceLen, offSet, targetLen)

    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/afill/*" />
FUNCTION AFill(aTarget AS ARRAY,uValue := NIL AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS ARRAY
    // The behavior of AFill() in VO is different than what is descibed in the help file
    // - if start <= 0 throws an error
    // - if start == NIL, then start becomes 1
    // - if count < 0 then it does nothing, unless start == nil, in which case start becomes 1 and count becomes 1, too (yeah, crap!)
    // - if count == nil, then it fills from start to lenght of array

    // warning, with the current definition of the function, it is not possible for the user to omit the start param
    LOCAL nLen := ALen( aTarget ) AS DWORD
    IF nLen > 0

        LOCAL lStartWasNil := FALSE AS LOGIC
        IF nStart == NIL
            nStart := 1
            lStartWasNil := TRUE
        ENDIF

        IF nStart > nLen .OR. nStart <= 0
            THROW Error.BoundError( "AFill", nameof(nStart), 3, <OBJECT>{ nStart } )
        ENDIF
        IF nCount == NIL
            nCount := (INT)nLen - nStart + 1
        ELSEIF nCount > 0
            // VO does not throw an error if count is longer than the array
            IF nStart + nCount - 1 > nLen
                nCount := (INT)nLen - nStart + 1
            END IF
        ELSE
            IF lStartWasNil
                nCount := 1
            ELSE
                RETURN aTarget
            END IF
        END IF

        FOR LOCAL x := nStart AS INT UPTO nStart + nCount - 1
            aTarget[(DWORD) x] := uValue
        NEXT
    ENDIF
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraybuild/*" />
FUNCTION ArrayBuild() AS ARRAY
    RETURN ARRAY{}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION ArrayNew() AS ARRAY
    RETURN ArrayNew(0)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION @@Array() AS ARRAY
    RETURN ArrayNew(0)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION ArrayNew(wElementList PARAMS USUAL[]) AS ARRAY
    LOCAL aDimInt AS INT[]
    LOCAL i AS INT
    aDimInt := INT[]{wElementList:Length}
    FOR i := 1 TO wElementList:Length
        aDimInt[i] := (INT) wElementList[i]
    NEXT
    RETURN __Array.ArrayCreate(aDimInt)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION @@Array(wElementList PARAMS USUAL[]) AS ARRAY
    RETURN ArrayNew(wElementList)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayNew<T>(wElementList AS DWORD) AS __ArrayBase<T>
    RETURN __ArrayBase<T>{wElementList}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayNew<T>(wElementList AS INT) AS __ArrayBase<T>
    RETURN __ArrayBase<T>{(DWORD) wElementList}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/areplicate/*" />
FUNCTION AReplicate(xFill AS USUAL,nElements AS DWORD) AS ARRAY
    VAR a:= __Array{nElements, TRUE}
    LOCAL i AS DWORD
    FOR i := 1 UPTO nElements
        a[i] := xFill
    NEXT
    RETURN a

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
FUNCTION ASort(aTarget AS ARRAY, nStart := NIL AS USUAL,nCount := NIL AS USUAL,cbOrder := NIL AS USUAL) AS ARRAY
    LOCAL nLen AS DWORD
    LOCAL oBlock as OBJECT
    @@Default( REF nStart, 1 )

    nLen := ALen(aTarget)
    IF nLen == 0 // Let it execute if nLen == 1, maybe the codeblock is important to be executed in this case for some (user) reason
        RETURN aTarget
    END IF

    EnforceNumeric( nStart )
    @@Default( REF nCount, nLen - nStart + 1 )
    EnforceNumeric( nCount )

    // Note: ASort() in VO accepts arguments out of bounds and translates them this way:
    IF nStart <= 0
        nStart := 1
    ELSEIF nStart > nLen
        RETURN aTarget
    END IF

    IF nCount <= 0 .OR. nStart + nCount - 1 > nLen
        nCount := nLen - nStart + 1
    ENDIF

    /*	IF startIndex < 1 .or. nStart > nLen
    THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nStart), 2, <OBJECT>{ nStart } )
    ENDIF
    IF nCount + nStart > ALen((ARRAY)aArray)+1
    THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nCount), 3, <OBJECT>{ nCount } )
    ENDIF */

    IF cbOrder != NIL
        IF cbOrder:IsCodeblock
            VAR cb := (CODEBLOCK) cbOrder
            IF cb:PCount() < 2
                THROW Error.ArgumentError( __FUNCTION__, nameof(cbOrder), "ASort Codeblock must have at least 2 arguments" )
            ENDIF
        ELSEIF cbOrder:IsObject
            IF ! IsMethod(cbOrder, "Eval")
                THROW Error.ArgumentError( __FUNCTION__, nameof(cbOrder), "ASort Sort Object must have an Eval method" )
            ENDIF
            oBlock := cbOrder
            cbOrder := {|a,b|  Send(oBlock,"Eval",a,b) }
        ELSE
            THROW Error.ArgumentError( __FUNCTION__, nameof(cbOrder), 4, <OBJECT>{ cbOrder } )
        ENDIF

    ENDIF

    IF IsCodeBlock(cbOrder )
        aTarget:Sort( nStart, nCount, ArraySortComparer{ cbOrder } )
    ELSE
        aTarget:Sort( nStart, nCount, NULL ) // this uses __Usual.ICompareTo()
    ENDIF

    RETURN aTarget

    // This wraps a codeblock and provides an IComparer implementation so
    // we can use ArrayList:Sort() with a codeblock.

INTERNAL STRUCTURE ArraySortComparer  IMPLEMENTS System.Collections.Generic.IComparer<USUAL>

    PRIVATE _cb AS ICodeblock

    CONSTRUCTOR( cb AS CODEBLOCK)
        _cb := cb
        RETURN

    METHOD Compare( x AS USUAL, y AS USUAL ) AS INT
        IF x == y
            RETURN 0
        ENDIF
        LOCAL u AS USUAL
        u := _cb:EvalBlock( x, y )
        RETURN IIF (  (LOGIC) u , -1, 1 )

        END STRUCTURE

INTERNAL STRUCTURE ArraySortComparer<T, U>  IMPLEMENTS System.Collections.Generic.IComparer<T>

    PRIVATE _cb AS @@Func<T,T,LOGIC>

    CONSTRUCTOR( cb AS @@Func<T,T,LOGIC> )
        _cb := cb
        RETURN

    METHOD Compare( x AS T, y AS T ) AS INT
        IF Object.Equals(x, y)
            RETURN 0
        ENDIF
        LOCAL u AS LOGIC
        u := SELF:_cb( x, y )
        RETURN IIF (  u , -1, 1 )

        END STRUCTURE

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASort<T>(aTarget AS __ArrayBase<T> ,nStart AS INT,nCount AS INT,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T>
    ARRAYNULL aTarget
    aTarget:Sort( nStart, nCount, ArraySortComparer<T, LOGIC> { cbOrder } )
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASort<T>(aTarget AS __ArrayBase<T> ,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T>
    ARRAYNULL aTarget
    aTarget:Sort( ArraySortComparer<T, LOGIC> { cbOrder } )
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>) AS __ArrayBase<T>
    ARRAYNULL aArray
    RETURN AEval(aArray, cbBlock, 1, ALen(aArray) )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>,nStart AS DWORD) AS __ArrayBase<T>
    ARRAYNULL aArray
    RETURN AEval(aArray, cbBlock, nStart, ALen(aArray) - nStart +1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>,nStart AS DWORD,nCount  AS DWORD) AS __ArrayBase<T>
    ARRAYNULL aArray
    LOCAL nEnd AS DWORD
    nEnd := nStart + nCount -1
    FOR VAR nX := nStart TO nEnd
        cbBlock(aArray[ (INT) nX])
    NEXT
    RETURN aArray

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount    := NIL AS USUAL
    LOCAL uStart	:= NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEval")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart, uCount, FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ,nStart AS USUAL ) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount    := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEval")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart, uCount, FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ,nStart AS USUAL ,nCount AS USUAL) AS ARRAY
    ARRAYNULL aArray
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEval")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart, nCount , FALSE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount    := NIL AS USUAL
    LOCAL uStart	:= NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEvalA")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart,uCount , TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock, nStart AS USUAL ) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount    := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEvalA")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,uCount , TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock, nStart  AS USUAL ,nCount AS USUAL) AS ARRAY
    ARRAYNULL aArray
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEvalA")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,nCount , TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>) AS __ArrayBase<T>
    ARRAYNULL aArray
    RETURN AEvalA(aArray, cbBlock, 1, ALen(aArray))

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>,nStart AS DWORD) AS __ArrayBase<T>
    ARRAYNULL aArray
    RETURN AEvalA(aArray, cbBlock, nStart, ALen(aArray) - nStart +1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>,nStart AS DWORD, nCount AS DWORD) AS __ArrayBase<T>
    ARRAYNULL aArray
    LOCAL nEnd  AS DWORD
    nEnd := nStart + nCount -1
    FOR VAR nX := nStart TO nEnd
        aArray[ (INT) nX] := cbBlock( aArray[(INT)  nX])
    NEXT
    RETURN aArray

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock,nStart  AS USUAL ,nCount AS USUAL) AS ARRAY
    ARRAYNULL aArray
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEvalOld")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,nCount , FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock,nStart  AS USUAL ) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount	 := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEvalOld")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,uCount , FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock) AS ARRAY
    ARRAYNULL aArray
    LOCAL uStart	 := NIL AS USUAL
    LOCAL uCount	 := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEvalOld")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart,uCount , FALSE)

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

// Use UDC below to standardize the NULL checks for the array arguments
#command ARRAYNULL_RETURNZERO <aArray>    => IF <aArray> == NULL ; return 0 ; ENDIF
#command ARRAYNOTNULL <aArray> => IF <aArray> == NULL ; THROW Error.NullArgumentError(__FUNCTION__,nameof(<aArray>), 1) ; ENDIF
#command ARRAYNULL <aArray>    => IF <aArray> == NULL ; return <aArray> ; ENDIF

INTERNAL STATIC CLASS ArrayHelpers

    STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, element  AS T , nStart AS LONG, nCount AS LONG) AS DWORD
        LOCAL nItem AS LONG
        LOCAL nLen  AS LONG
        ARRAYNOTNULL aTarget
        nLen := (INT) aTarget:Length
        FOR nItem := nStart TO nLen
            IF Object.Equals(aTarget[ nItem], element)
                RETURN (DWORD) nItem
            ENDIF
            nCount -= 1
            IF nCount == 0
                EXIT
            ENDIF
        NEXT
        RETURN 0

    STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, bAction AS @@Func<T, LOGIC> , nStart AS LONG, nCount AS LONG) AS DWORD
        LOCAL nItem AS LONG
        LOCAL nLen  AS LONG
        ARRAYNOTNULL aTarget
        nLen := (INT) aTarget:Length
        FOR nItem := nStart TO nLen
            LOCAL oElement := aTarget[ nItem] AS T
            IF bAction(oElement)
                RETURN  (DWORD) nItem
            ENDIF
            nCount -= 1
            IF nCount == 0
                EXIT
            ENDIF
        NEXT
        RETURN 0

    STATIC METHOD AScan( aTarget AS USUAL, x AS USUAL, uStart AS USUAL, uCount AS USUAL, lExact AS LOGIC ) AS DWORD
        IF ! ArrayHelpers.ValidateArrayParams(REF aTarget, REF uStart, REF uCount, OUT VAR nSize)
            RETURN 0
        ENDIF
        LOCAL a := aTarget AS ARRAY
        LOCAL nStart := uStart	AS DWORD
        LOCAL nCount := uCount	AS DWORD
        LOCAL nRet := 0			AS DWORD
        LOCAL i					AS DWORD
        LOCAL cb				AS CODEBLOCK
        IF IsCodeBlock( x )
            cb := x
        ELSE
            IF lExact
                cb   := {|element| element == x }
            ELSE
                cb   := {|element| element = x }
            ENDIF
        ENDIF
        IF nStart < nSize
            FOR i := nStart UPTO nSize
                IF nCount > 0
                    IF Eval( cb, a[i] )
                        nRet := i
                        EXIT
                    ENDIF
                    nCount--
                ELSE
                    EXIT
                ENDIF
            NEXT
        ELSE
            FOR i := nStart DOWNTO nSize
                IF nCount > 0
                    IF Eval( cb, a[i] )
                        nRet := i
                        EXIT
                    ENDIF
                    nCount--
                ELSE
                    EXIT
                ENDIF
            NEXT
        ENDIF

        RETURN nRet

    STATIC METHOD AScanBin(cFuncName AS STRING, a AS ARRAY, seekVal AS USUAL, lExact AS LOGIC ) AS DWORD
        LOCAL dwLow        AS DWORD
        LOCAL dwHigh       AS DWORD
        LOCAL x            AS DWORD
        LOCAL dwRet        AS DWORD
        LOCAL iSave        AS DWORD
        LOCAL lIsCodeBlock AS LOGIC
        LOCAL iCBRet       AS USUAL
        LOCAL iComp        AS INT
        LOCAL cb			  AS CODEBLOCK

        dwLow  := 1
        dwHigh := (DWORD) ALen(a)
        iSave := dwRet := 0
        iComp := 0
        lIsCodeBlock := IsCodeBlock( seekVal )
        IF lIsCodeBlock
            cb := seekVal
        ELSEIF lExact
            cb := {|element| IIF( element == seekVal , 0, IIF( seekVal < element, -1, 1 ) ) }
        ELSE
            cb := {|element| IIF( element = seekVal , 0, IIF( seekVal < element, -1, 1 ) ) }
        ENDIF

        DO WHILE dwLow <= dwHigh
            x := dwLow + ( ( dwHigh - dwLow ) / 2 )

            IF iSave == x
                IF dwHigh - dwLow == 1
                    x++
                    dwLow++
                ELSE
                    EXIT
                ENDIF
            ENDIF

            iSave := x
            IF lIsCodeBlock
                iCBRet := Eval( cb, a[x] )
                IF ! iCBRet:IsNumeric
                    THROW Error.DataTypeError(cFuncName, "Return value of Codeblock", 0)
                ELSE
                    iComp := iCBRet
                ENDIF
            ELSE
                iComp := Eval( cb, a[x] )
            ENDIF
            IF iComp < 0
                dwHigh := x
            ELSEIF iComp > 0
                dwLow := x
            ELSE
                dwRet := x
                x--

                DO WHILE dwLow <= x

                    IF lIsCodeBlock
                        iCBRet := Eval( cb, a[x] )
                        IF ! iCBRet:IsNumeric
                            THROW Error.DataTypeError(cFuncName, "Return value of Codeblock", 0)
                        ELSE
                            iComp := iCBRet
                        ENDIF
                    ELSE
                        iComp := Eval( cb, a[x] )
                    ENDIF

                    IF iComp != 0
                        EXIT
                    ENDIF

                    dwRet := x
                    x--
                ENDDO
                dwLow := dwHigh + 1
            ENDIF
        ENDDO

        RETURN dwRet

    STATIC METHOD AEval(aArray AS ARRAY, cbBlock AS ICodeblock, nStart AS DWORD, nCount AS DWORD, bUpdateArray AS CONST LOGIC )  AS ARRAY
        LOCAL elements := ALen(aArray) AS DWORD
        LOCAL last   AS DWORD
        LOCAL result AS USUAL
        LOCAL x      AS DWORD
        IF elements == 0
            RETURN aArray
        ENDIF
        ARRAYNOTNULL aArray
        IF nStart == 0
            THROW  Error.ArgumentError( __FUNCTION__, nameof(nStart), 3, __CavoStr( VOErrors.ARGCANNOTBEZERO ), { nStart } )
        ENDIF

        IF nCount != 0

            IF nStart < 0
                nStart := elements + 1 + nStart
            ENDIF

            IF nCount > 0

                last := Math.Min( nStart + ( nCount - 1 ), elements )

                FOR x := nStart UPTO last
                    result := Eval( cbBlock, aArray[x], x )

                    IF ( bUpdateArray )
                        aArray[x] := result
                    ENDIF
                NEXT
            ELSE

                last := (DWORD) Math.Max( 1, nStart + nCount + 1 )

                FOR x := nStart DOWNTO last
                    result := Eval( cbBlock, aArray[x], x )

                    IF ( bUpdateArray )
                        aArray[x] := result
                    ENDIF
                NEXT
            ENDIF
        ENDIF

        RETURN aArray

    STATIC METHOD AEvalCheckArgs(aArray AS ARRAY, cb AS ICodeblock, iStart REF USUAL, iCount REF USUAL,cFuncName AS STRING) AS VOID
        IF aArray == NULL_ARRAY
            RETURN
        ENDIF
        IF cb == NULL
            THROW Error.NullArgumentError( cFuncName, NAMEOF(cb),2)
        ENDIF
        @@Default( REF iStart, 1)
        @@Default( REF iCount, ALen(aArray))
        IF ! iStart:IsNumeric
            THROW Error.ArgumentError( cFuncName, NAMEOF(iStart), 3 , <OBJECT>{iStart})
        ENDIF
        IF ! iCount:IsNumeric
            THROW Error.ArgumentError( cFuncName, NAMEOF(iCount), 4 , <OBJECT>{iCount})
        ENDIF
        RETURN

    STATIC METHOD ValidateArrayParams(aTarget REF USUAL, nStart REF USUAL,nCount REF USUAL, nSize OUT DWORD) AS LOGIC
        nSize := 0
        IF aTarget:IsArray
            nSize := ALen( (ARRAY) aTarget )
            IF nSize == 0
                RETURN FALSE
            ENDIF
        ELSE
            RETURN FALSE
        ENDIF

        IF ! nCount:IsNumeric
            IF ! nStart:IsNumeric
                nStart := 1
            END IF
            nCount := ALen(aTarget) - nStart + 1
        ELSE
            IF nCount >= 0
                IF ! nStart:IsNumeric
                    nStart := 1
                ENDIF
                IF nStart > nSize
                    RETURN FALSE
                END IF
            ELSE
                IF ! nStart:IsNumeric
                    nStart := ALen(aTarget)
                ENDIF
                nSize := 1
                nCount := - nCount
                IF nStart < nSize
                    RETURN FALSE
                END IF
            END IF
        END IF
        RETURN TRUE

        END CLASS

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraycreate/*" />
FUNCTION ArrayCreate(dwElements AS DWORD) AS ARRAY
    RETURN __Array{dwElements, TRUE}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraycreate/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayCreate<T>(dwElements AS DWORD) AS __ArrayBase<T>
    RETURN __ArrayBase<T>{dwElements,TRUE}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayinit/*" />
FUNCTION ArrayInit(wElements AS DWORD, avalues REF USUAL[]) AS ARRAY
    LOCAL aTemp AS ARRAY
    LOCAL x AS DWORD

    IF wElements > (DWORD) avalues:Length
        THROW Error.ArgumentError( __FUNCTION__, NAMEOF(wElements), "Element too big")
    ENDIF

    aTemp := ArrayNew(avalues:Length)
    FOR x := 1 UPTO avalues:Length
        aTemp [x] := avalues[x]
    NEXT
    RETURN aTemp

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aadd/*" />

FUNCTION AAdd(aTarget AS ARRAY,uNewElement AS USUAL) AS USUAL
    ARRAYNOTNULL aTarget
    RETURN AAdd<USUAL>(aTarget, uNewElement)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aadd/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AAdd<T>(aTarget AS __ArrayBase<T>,uNewElement AS T) AS T
    ARRAYNOTNULL aTarget
    aTarget:Add(uNewElement)
    RETURN uNewElement

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aclone/*" />
FUNCTION AClone(aSource AS ARRAY) AS ARRAY
    IF aSource == NULL_ARRAY
        RETURN aSource
    END IF
    RETURN (ARRAY) aSource:Clone()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aclone/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AClone<T>(aSource AS __ArrayBase<T>) AS __ArrayBase<T>
    IF aSource == NULL
        RETURN aSource
    END IF
    RETURN  aSource:Clone()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acloneshallow/*" />
FUNCTION ACloneShallow(aSource AS ARRAY) AS ARRAY
    IF aSource == NULL_ARRAY
        RETURN aSource
    END IF
    RETURN (ARRAY) aSource:CloneShallow()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acloneshallow/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ACloneShallow<T>(aSource AS __ArrayBase<T>) AS __ArrayBase<T>
    IF aSource == NULL
        RETURN aSource
    END IF
    RETURN aSource:Clone()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ADel(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
    ARRAYNOTNULL aTarget
    IF aTarget:__IsFoxArray
        RETURN _CallClipFunc(#__FoxADel, aTarget, dwPosition, 2)
    ENDIF
    aTarget:Delete((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ADel<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T>
    ARRAYNOTNULL aTarget
    aTarget:Delete((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ATrueDel(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
    ARRAYNOTNULL aTarget
    aTarget:RemoveAt((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ATrueDel<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T>
    ARRAYNOTNULL aTarget
    aTarget:RemoveAt((INT) dwPosition)
    RETURN aTarget

    /// Calculate the # of dimensions in an array
        /// <param name="a"></param>
    /// <returns>Number of dimensions in an array</returns>
FUNCTION ADim(a AS ARRAY) AS DWORD
    LOCAL dwDims AS DWORD
    dwDims := 1
    DO WHILE a != NULL_ARRAY
        IF ALen(a) > 0
            IF IsArray(a[1])
                dwDims += 1
                a := a[1]
            ELSE
                EXIT
            ENDIF
        ELSE
            EXIT
        ENDIF
    ENDDO
    RETURN dwDims

    /// Calculate a string that represents the dimensions in an array
        /// <param name="a"></param>
    /// <returns>String that displays the dimensions in an array</returns>
FUNCTION ADimPic(a AS ARRAY) AS STRING
RETURN Repl("[]", ADim(a))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ains/*" />
FUNCTION AIns(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
    ARRAYNOTNULL aTarget
    IF aTarget:__IsFoxArray
        _CallClipFunc(#__FoxAIns, aTarget, dwPosition, 1)
    ENDIF
    aTarget:Insert((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ains/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AIns<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T>
    ARRAYNOTNULL aTarget
    aTarget:Insert((INT) dwPosition)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alen/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ALen<T>(aTarget AS __ArrayBase<T>) AS DWORD
    IF aTarget != NULL
        RETURN aTarget:Length
    ELSE
        RETURN 0
    ENDIF

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alen/*" />
FUNCTION ALen(aTarget AS ARRAY) AS DWORD
    IF aTarget == NULL
        RETURN 0
    ELSEIF aTarget:__IsFoxArray
        RETURN _CallClipFunc(#__FoxALen, aTarget)
    ENDIF
    RETURN aTarget:Length

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraydeprotect/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayDeProtect<T>(aTarget AS __ArrayBase<T>) AS LOGIC
    ARRAYNOTNULL aTarget
    RETURN aTarget:Lock(FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraydeprotect/*" />
FUNCTION ArrayDeProtect(aTarget AS ARRAY) AS LOGIC
    ARRAYNOTNULL aTarget
    RETURN aTarget:Lock(FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayget/*" />
FUNCTION ArrayGet(aTarget AS ARRAY,dwElement AS DWORD) AS USUAL
    ARRAYNOTNULL aTarget
    RETURN aTarget:__GetElement( (INT) dwElement-1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayget/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayGet<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD) AS T
    ARRAYNOTNULL aTarget
    RETURN aTarget:__GetElement( (INT) dwElement-1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayprotect/*" />
FUNCTION ArrayProtect(aTarget AS ARRAY) AS LOGIC
    ARRAYNOTNULL aTarget
    RETURN aTarget:Lock(TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayprotect/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayProtect<T>(aTarget AS __ArrayBase<T>) AS LOGIC
    ARRAYNOTNULL aTarget
    RETURN aTarget:Lock(TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayput/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayPut<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD,uValue AS T) AS T
    ARRAYNOTNULL aTarget
    aTarget:__SetElement(uValue, (INT)dwElement -1)
    RETURN uValue

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayput/*" />
FUNCTION ArrayPut(aTarget AS ARRAY,dwElement AS DWORD,uValue AS USUAL) AS USUAL
    ARRAYNOTNULL aTarget
    aTarget:__SetElement(uValue, (INT)dwElement -1)
    RETURN uValue

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraystore/*" />
FUNCTION ArrayStore(aSource AS ARRAY,Buff AS USUAL PTR,dwLen AS DWORD) AS DWORD
    LOCAL i AS DWORD
    LOCAL nLen AS DWORD
    nLen := ALen(aSource)
    dwLen := Math.Min(dwLen, nLen)
    FOR i := 1 TO dwLen
        Buff[i] := aSource[i]
    NEXT
    RETURN dwLen

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraystore/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayStore<T>(aSource AS __ArrayBase<T>,Buff AS T PTR,dwLen AS DWORD) AS DWORD
    ARRAYNOTNULL aSource
    LOCAL i, nLen AS DWORD
    nLen := aSource:Length
    dwLen := Math.Min(dwLen, nLen)
    FOR i := 1 TO dwLen
        Buff[i] := aSource[(INT) i]
    NEXT
    RETURN dwLen

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayswap/*" />
FUNCTION ArraySwap(aTarget AS ARRAY,dwElement AS DWORD,uNewValue AS USUAL) AS USUAL
    ARRAYNOTNULL aTarget
    RETURN aTarget:Swap((INT) dwElement, uNewValue)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayswap/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArraySwap<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD,uNewValue AS T) AS T
    ARRAYNOTNULL aTarget
    RETURN aTarget:Swap((INT) dwElement, uNewValue)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart := NIL AS USUAL,nCount := NIL AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount, SetExact())

    /// <inheritdoc cref='AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, NIL, SetExact())

    /// <inheritdoc cref='AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, 1, NIL, SetExact())

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount, TRUE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, NIL, TRUE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
    ARRAYNULL_RETURNZERO aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, 1, NIL, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanbin/*" />
FUNCTION AScanBin(aTarget AS ARRAY,uSearch AS USUAL) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScanBin( "AscanBin" , aTarget, uSearch, FALSE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanbinexact/*" />
FUNCTION AScanBinExact(aTarget AS ARRAY,uSearch AS USUAL) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScanBin( "AscanBin" , aTarget, uSearch, TRUE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch,1, (INT) aTarget:Length)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
    /// <param name="act">A lambda expression that will be evaluated for every element in the array.</param>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScan( aTarget, act,1, (INT) aTarget:Length)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T, nStart AS LONG) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, (INT) aTarget:Length- nStart +1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
    /// <param name="act">A lambda expression that will be evaluated for every element in the array.</param>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScan( aTarget, act, nStart, (INT) aTarget:Length - nStart +1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T, nStart AS LONG, nCount AS LONG) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG, nCount  AS LONG) AS DWORD
    ARRAYNOTNULL aTarget
    RETURN ArrayHelpers.AScan( aTarget, act, nStart, nCount)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asize/*" />
FUNCTION ASize(aTarget AS ARRAY,dwLength AS DWORD) AS ARRAY
    ARRAYNOTNULL aTarget
    aTarget:Resize((INT) dwLength)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asize/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASize<T>(aTarget AS __ArrayBase<T>,dwLength AS DWORD) AS __ArrayBase<T>
    ARRAYNOTNULL aTarget
    aTarget:Resize((INT) dwLength)
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atail/*" />
FUNCTION ATail(aTarget AS ARRAY) AS USUAL
    ARRAYNOTNULL aTarget
    RETURN aTarget:Tail()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atail/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ATail<T>(aTarget AS __ArrayBase<T>) AS T
    ARRAYNOTNULL aTarget
    RETURN aTarget:Tail()

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acopy/*" />
FUNCTION ACopy(aSource ,aTarget ,nStart ,nCount ,nTargetPos ) AS ARRAY CLIPPER
    LOCAL sourceLen  AS LONG
    LOCAL start AS LONG
    LOCAL count AS LONG
    IF !aSource:IsArray
        THROW Error.ArgumentError( __FUNCTION__, NAMEOF(aSource), 1, <OBJECT>{ aSource } )
    ENDIF

    IF !aTarget:IsArray
        THROW Error.ArgumentError( __FUNCTION__, NAMEOF(aTarget), 2, <OBJECT>{ aTarget } )
    ENDIF
    start := 1
    sourceLen  := (LONG) ALen(aSource)
    IF pCount() > 2
        IF nStart:IsNumeric
            start := nStart
        ELSEIF nStart:IsNil
            IF pCount() >= 4 .and. nCount:IsNumeric .and. nCount < 0
                start := (LONG) ALen(aSource) -1
            ELSE
                start := 1
            END IF
        ELSE
            THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nStart), 3, <OBJECT>{ nStart } )
        ENDIF
        IF start < 0
            start := sourceLen
        ELSE
            start := Math.Min(start, sourceLen)
        ENDIF
    ENDIF
    IF pCount() > 3 .and. .not. nCount:IsNil
        IF nCount:IsNumeric
            count := nCount
        ELSE
            THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nCount), 4, <OBJECT>{ nCount } )
        ENDIF
        IF count > 0
            sourceLen := Math.Min(sourceLen, start+count-1)
        ELSE
            sourceLen := Math.Max(1, start+count-1)
        ENDIF
    ENDIF
    LOCAL offSet		:= 1 AS LONG
    LOCAL targetLen	    := (LONG) ALen(aTarget) AS LONG
    IF pCount() > 4 .and. .not. nTargetPos:IsNil
        IF nTargetPos:IsNumeric
            offSet := nTargetPos
            offSet := Math.Min( offSet, targetLen )
            offSet := Math.Max( 1, offSet )
        ELSE
            THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nTargetPos), 5, <OBJECT>{ nTargetPos } )
        ENDIF
    ENDIF
    XSharp.__Array.Copy(aSource, aTarget, start, sourceLen, offSet, targetLen)

    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/afill/*" />
FUNCTION AFill(aTarget AS ARRAY,uValue := NIL AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS ARRAY
    // The behavior of AFill() in VO is different than what is descibed in the help file
    // - if start <= 0 throws an error
    // - if start == NIL, then start becomes 1
    // - if count < 0 then it does nothing, unless start == nil, in which case start becomes 1 and count becomes 1, too (yeah, crap!)
    // - if count == nil, then it fills from start to lenght of array

    // warning, with the current definition of the function, it is not possible for the user to omit the start param
    LOCAL nLen := ALen( aTarget ) AS DWORD
    IF nLen > 0

        LOCAL lStartWasNil := FALSE AS LOGIC
        IF nStart == NIL
            nStart := 1
            lStartWasNil := TRUE
        ENDIF

        IF nStart > nLen .OR. nStart <= 0
            THROW Error.BoundError( "AFill", nameof(nStart), 3, <OBJECT>{ nStart } )
        ENDIF
        IF nCount == NIL
            nCount := (INT)nLen - nStart + 1
        ELSEIF nCount > 0
            // VO does not throw an error if count is longer than the array
            IF nStart + nCount - 1 > nLen
                nCount := (INT)nLen - nStart + 1
            END IF
        ELSE
            IF lStartWasNil
                nCount := 1
            ELSE
                RETURN aTarget
            END IF
        END IF

        FOR LOCAL x := nStart AS INT UPTO nStart + nCount - 1
            aTarget[(DWORD) x] := uValue
        NEXT
    ENDIF
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraybuild/*" />
FUNCTION ArrayBuild() AS ARRAY
    RETURN ARRAY{}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION ArrayNew() AS ARRAY
    RETURN ArrayNew(0)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION @@Array() AS ARRAY
    RETURN ArrayNew(0)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION ArrayNew(wElementList PARAMS USUAL[]) AS ARRAY
    LOCAL aDimInt AS INT[]
    LOCAL i AS INT
    aDimInt := INT[]{wElementList:Length}
    FOR i := 1 TO wElementList:Length
        aDimInt[i] := (INT) wElementList[i]
    NEXT
    RETURN __Array.ArrayCreate(aDimInt)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION @@Array(wElementList PARAMS USUAL[]) AS ARRAY
    RETURN ArrayNew(wElementList)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayNew<T>(wElementList AS DWORD) AS __ArrayBase<T>
    RETURN __ArrayBase<T>{wElementList}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayNew<T>(wElementList AS INT) AS __ArrayBase<T>
    RETURN __ArrayBase<T>{(DWORD) wElementList}

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/areplicate/*" />
FUNCTION AReplicate(xFill AS USUAL,nElements AS DWORD) AS ARRAY
    VAR a:= __Array{nElements, TRUE}
    LOCAL i AS DWORD
    FOR i := 1 UPTO nElements
        a[i] := xFill
    NEXT
    RETURN a

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
FUNCTION ASort(aTarget AS ARRAY, nStart := NIL AS USUAL,nCount := NIL AS USUAL,cbOrder := NIL AS USUAL) AS ARRAY
    LOCAL nLen AS DWORD
    LOCAL oBlock as OBJECT
    @@Default( REF nStart, 1 )

    nLen := ALen(aTarget)
    IF nLen == 0 // Let it execute if nLen == 1, maybe the codeblock is important to be executed in this case for some (user) reason
        RETURN aTarget
    END IF

    EnforceNumeric( nStart )
    @@Default( REF nCount, nLen - nStart + 1 )
    EnforceNumeric( nCount )

    // Note: ASort() in VO accepts arguments out of bounds and translates them this way:
    IF nStart <= 0
        nStart := 1
    ELSEIF nStart > nLen
        RETURN aTarget
    END IF

    IF nCount <= 0 .OR. nStart + nCount - 1 > nLen
        nCount := nLen - nStart + 1
    ENDIF

    /*	IF startIndex < 1 .or. nStart > nLen
    THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nStart), 2, <OBJECT>{ nStart } )
    ENDIF
    IF nCount + nStart > ALen((ARRAY)aArray)+1
    THROW Error.ArgumentError( __FUNCTION__, NAMEOF(nCount), 3, <OBJECT>{ nCount } )
    ENDIF */

    IF cbOrder != NIL
        IF cbOrder:IsCodeblock
            VAR cb := (CODEBLOCK) cbOrder
            IF cb:PCount() < 2
                THROW Error.ArgumentError( __FUNCTION__, nameof(cbOrder), "ASort Codeblock must have at least 2 arguments" )
            ENDIF
        ELSEIF cbOrder:IsObject
            IF ! IsMethod(cbOrder, "Eval")
                THROW Error.ArgumentError( __FUNCTION__, nameof(cbOrder), "ASort Sort Object must have an Eval method" )
            ENDIF
            oBlock := cbOrder
            cbOrder := {|a,b|  Send(oBlock,"Eval",a,b) }
        ELSE
            THROW Error.ArgumentError( __FUNCTION__, nameof(cbOrder), 4, <OBJECT>{ cbOrder } )
        ENDIF

    ENDIF

    IF IsCodeBlock(cbOrder )
        aTarget:Sort( nStart, nCount, ArraySortComparer{ cbOrder } )
    ELSE
        aTarget:Sort( nStart, nCount, NULL ) // this uses __Usual.ICompareTo()
    ENDIF

    RETURN aTarget

    // This wraps a codeblock and provides an IComparer implementation so
    // we can use ArrayList:Sort() with a codeblock.

INTERNAL STRUCTURE ArraySortComparer  IMPLEMENTS System.Collections.Generic.IComparer<USUAL>

    PRIVATE _cb AS ICodeblock

    CONSTRUCTOR( cb AS CODEBLOCK)
        _cb := cb
        RETURN

    METHOD Compare( x AS USUAL, y AS USUAL ) AS INT
        IF x == y
            RETURN 0
        ENDIF
        LOCAL u AS USUAL
        u := _cb:EvalBlock( x, y )
        RETURN IIF (  (LOGIC) u , -1, 1 )

        END STRUCTURE

INTERNAL STRUCTURE ArraySortComparer<T, U>  IMPLEMENTS System.Collections.Generic.IComparer<T>

    PRIVATE _cb AS @@Func<T,T,LOGIC>

    CONSTRUCTOR( cb AS @@Func<T,T,LOGIC> )
        _cb := cb
        RETURN

    METHOD Compare( x AS T, y AS T ) AS INT
        IF Object.Equals(x, y)
            RETURN 0
        ENDIF
        LOCAL u AS LOGIC
        u := SELF:_cb( x, y )
        RETURN IIF (  u , -1, 1 )

        END STRUCTURE

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASort<T>(aTarget AS __ArrayBase<T> ,nStart AS INT,nCount AS INT,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T>
    ARRAYNULL aTarget
    aTarget:Sort( nStart, nCount, ArraySortComparer<T, LOGIC> { cbOrder } )
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASort<T>(aTarget AS __ArrayBase<T> ,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T>
    ARRAYNULL aTarget
    aTarget:Sort( ArraySortComparer<T, LOGIC> { cbOrder } )
    RETURN aTarget

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>) AS __ArrayBase<T>
    ARRAYNULL aArray
    RETURN AEval(aArray, cbBlock, 1, ALen(aArray) )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>,nStart AS DWORD) AS __ArrayBase<T>
    ARRAYNULL aArray
    RETURN AEval(aArray, cbBlock, nStart, ALen(aArray) - nStart +1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>,nStart AS DWORD,nCount  AS DWORD) AS __ArrayBase<T>
    ARRAYNULL aArray
    LOCAL nEnd AS DWORD
    nEnd := nStart + nCount -1
    FOR VAR nX := nStart TO nEnd
        cbBlock(aArray[ (INT) nX])
    NEXT
    RETURN aArray

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount    := NIL AS USUAL
    LOCAL uStart	:= NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEval")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart, uCount, FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ,nStart AS USUAL ) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount    := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEval")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart, uCount, FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ,nStart AS USUAL ,nCount AS USUAL) AS ARRAY
    ARRAYNULL aArray
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEval")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart, nCount , FALSE )

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount    := NIL AS USUAL
    LOCAL uStart	:= NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEvalA")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart,uCount , TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock, nStart AS USUAL ) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount    := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEvalA")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,uCount , TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock, nStart  AS USUAL ,nCount AS USUAL) AS ARRAY
    ARRAYNULL aArray
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEvalA")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,nCount , TRUE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>) AS __ArrayBase<T>
    ARRAYNULL aArray
    RETURN AEvalA(aArray, cbBlock, 1, ALen(aArray))

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>,nStart AS DWORD) AS __ArrayBase<T>
    ARRAYNULL aArray
    RETURN AEvalA(aArray, cbBlock, nStart, ALen(aArray) - nStart +1)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
    /// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>,nStart AS DWORD, nCount AS DWORD) AS __ArrayBase<T>
    ARRAYNULL aArray
    LOCAL nEnd  AS DWORD
    nEnd := nStart + nCount -1
    FOR VAR nX := nStart TO nEnd
        aArray[ (INT) nX] := cbBlock( aArray[(INT)  nX])
    NEXT
    RETURN aArray

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock,nStart  AS USUAL ,nCount AS USUAL) AS ARRAY
    ARRAYNULL aArray
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEvalOld")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,nCount , FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock,nStart  AS USUAL ) AS ARRAY
    ARRAYNULL aArray
    LOCAL uCount	 := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEvalOld")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,uCount , FALSE)

    /// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock) AS ARRAY
    ARRAYNULL aArray
    LOCAL uStart	 := NIL AS USUAL
    LOCAL uCount	 := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEvalOld")
    RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart,uCount , FALSE)


cleanup

cleanup

import "LangPrelude.prg"

data Free :: Tag ~> Row Tag * ~> * where
  Klar :: Free t {}r
  Mehr :: DiffLabel t t' -> Free t r -> Free t {t'=a;r}r
 deriving List(f)

notMentionedIn :: Label a -> Record sh -> Maybe (Free a sh)
notMentionedIn l {} = Just $ Klar
notMentionedIn l {m=v; r} = do
                            diff <- case sameLabel l m of
                                    R x -> Just x
      	      	      	      	    _ -> Nothing
                            r' <- notMentionedIn l r
                            return $ Mehr diff r'
                       where monad maybeM

Just test1 = `a `notMentionedIn` {`g=7, `h='a'}

##test "`a occurs in head position"
  Just test2 = `a `notMentionedIn` {`g=7, `a='a'}

##test "`a occurs in second position"
  Just test3 = `a `notMentionedIn` {`a=7, `b='b'}

data Environment :: Row Tag * ~> * where
  Empty :: Environment {}r
  Extend :: (Free t s, Label t) -> a -> Environment s -> Environment {t=a;s}r
 deriving Record(e)

verifyEnv :: Record sh -> Maybe (Environment sh)
verifyEnv {} = Just {}e
verifyEnv {l=v; r} = do
                     l' <- l `notMentionedIn` r
                     r' <- verifyEnv r
                     return {(l', l)=v; r'}e
                 where monad maybeM

Just test4 = verifyEnv {`g=7, `a='a', `h="hey"}

##test "`g occurs twice"
  Just test5 = verifyEnv {`g=7, `a='a', `g="2"}

import "LangPrelude.prg"

data Free :: Tag ~> Row Tag * ~> * where
  Klar :: Free t {}r
  Mehr :: DiffLabel t t' -> Free t r -> Free t {t'=a;r}r
 deriving List(f)

notMentionedIn :: Label a -> Record sh -> Maybe (Free a sh)
notMentionedIn l {} = Just $ Klar
notMentionedIn l {m=v; r} = do
                            diff <- case sameLabel l m of
                                    R x -> Just x
      	      	      	      	    _ -> Nothing
                            r' <- notMentionedIn l r
                            return $ Mehr diff r'
                       where monad maybeM

Just test1 = `a `notMentionedIn` {`g=7, `h='a'}

##test "`a occurs in head position"
  Just test2 = `a `notMentionedIn` {`g=7, `a='a'}

##test "`a occurs in second position"
  Just test3 = `a `notMentionedIn` {`a=7, `b='b'}

--setLike :: Row Tag * ~> ???
--{setLike {}r} =

data Environment :: Row Tag * ~> * where
  Empty :: Environment {}r
  Extend :: (Free t s, Label t) -> a -> Environment s -> Environment {t=a;s}r
 deriving Record(e)

verifyEnv :: Record sh -> Maybe (Environment sh)
verifyEnv {} = Just {}e
verifyEnv {l=v; r} = do
                     l' <- l `notMentionedIn` r
                     r' <- verifyEnv r
                     return {(l', l)=v; r'}e
                 where monad maybeM

Just test4 = verifyEnv {`g=7, `a='a', `h="hey"}

##test "`g occurs twice"
  Just test5 = verifyEnv {`g=7, `a='a', `g="2"}


[VODesigners] Added images to Toolbox items

USING System.Windows.Forms
USING System.Drawing
USING System.Collections.Generic
USING System.Reflection
USING System.IO

INTERNAL CLASS ToolBoxButton INHERIT Button
	PROTECT oTemplate AS VOControlTemplate
	PROTECT oDragPoint AS Point
	CONSTRUCTOR()
		SUPER()
		SELF:Text := "Pointer"
		SELF:Dock := DockStyle.Top
		SELF:TextAlign := ContentAlignment.MiddleLeft
		SELF:FlatStyle := FlatStyle.Flat
	RETURN
	CONSTRUCTOR(_oTemplate AS VOControlTemplate)
		SUPER()
		SELF:oTemplate := _oTemplate
		SELF:Text := SELF:oTemplate:cName
		SELF:Dock := DockStyle.Top
		SELF:TextAlign := ContentAlignment.MiddleLeft
		SELF:FlatStyle := FlatStyle.Flat
		SELF:ImageAlign := ContentAlignment.MiddleLeft
		SELF:TextImageRelation := TextImageRelation.ImageBeforeText
	RETURN
	ACCESS Template AS VOControlTemplate
	RETURN SELF:oTemplate
	PROTECTED METHOD OnMouseDown(e AS MouseEventArgs) AS VOID
		SUPER:OnMouseDown(e)
		SELF:oDragPoint := e:Location
	RETURN
	PROTECTED METHOD OnMouseUp(e AS MouseEventArgs) AS VOID
		SUPER:OnMouseUp(e)
		SELF:oDragPoint := Point.Empty
	RETURN
	PROTECTED METHOD OnMouseMove(e AS MouseEventArgs) AS VOID
		SUPER:OnMouseMove(e)
		IF SELF:oTemplate == NULL .or. SELF:oDragPoint == Point.Empty
			RETURN
		ENDIF
		IF Math.Abs(e:X - SELF:oDragPoint:X) > 2 .or. Math.Abs(e:Y - SELF:oDragPoint:Y) > 2
			SELF:DoDragDrop(SELF:oTemplate , DragDropEffects.Move)
			SELF:oDragPoint := Point.Empty
		ENDIF
	RETURN

END CLASS

CLASS ToolBox INHERIT Panel
	INTERNAL oCurrent AS ToolBoxButton
	PROTECT eCurrentMode AS ViewMode
	CONSTRUCTOR()

		SUPER()

		LOCAL oTemplate AS VOControlTemplate
		LOCAL oButton AS ToolBoxButton
		LOCAL oImageList AS ImageList
		LOCAL n AS INT

		SELF:AutoScroll := TRUE
		SELF:Dock := DockStyle.Fill

		IF !VOWindowEditorTemplate.Loaded
			RETURN
		ENDIF

		LOCAL oAssembly AS Assembly
		oAssembly := TypeOf(System.Windows.Forms.Form):Assembly
		oImageList := ImageList{}
		oImageList:TransparentColor := Color.Fuchsia

		FOR n := VOWindowEditorTemplate.Count - 1 DOWNTO 0
			oTemplate := VOWindowEditorTemplate.Get(n)
			IF (!oTemplate:lUse .or. oTemplate:lForm) //.and. n != 0
				LOOP
			ENDIF
			oButton := ToolBoxButton{oTemplate}
			oImageList:Images:Add((Bitmap)Image.FromStream(oAssembly:GetManifestResourceStream(SELF:ImageNameFromTemplate(oTemplate))))
			oButton:ImageList := oImageList
			oButton:ImageIndex := oImageList:Images:Count - 1
			oButton:Text := "   " + oButton:Text

			oButton:Click += EventHandler{ SELF , @ButtonClicked() }
			SELF:Controls:Add(oButton)
		NEXT

		LOCAL aStandard AS STRING[]
		aStandard := <STRING>{"FIXEDTEXT","PUSHBUTTON","CHECKBOX","RADIOBUTTON","SINGLELINEEDIT","MULTILINEEDIT","COMBOBOX","LISTBOX","LISTVIEW","TREEVIEW","GROUPBOX","RADIOBUTTONGROUP"}
		n := 0
		DO WHILE n < SELF:Controls:Count
//		FOR n := 0 UPTO SELF:Controls:Count - 1
			LOCAL m AS INT
			oButton := (ToolBoxButton)SELF:Controls[n]
			IF oButton:Template != NULL
				oTemplate := oButton:Template
				FOR m := 1 UPTO aStandard:Length
					IF aStandard[m] == oTemplate:cControl:ToUpper()
						IF SELF:Controls:GetChildIndex(oButton) != SELF:Controls:Count - m
							SELF:Controls:SetChildIndex(oButton , SELF:Controls:Count - m)
							n --
							EXIT
						END IF
					ENDIF
				NEXT
			ENDIF
			n ++
//		NEXT
		ENDDO

		TRY
			oButton := ToolBoxButton{VOWindowEditorTemplate.Get("SINGLELINEEDIT")}
		CATCH
			oButton := ToolBoxButton{}
		END TRY
		oButton:Text := "DataColumn"
		oButton:Click += EventHandler{ SELF , @ButtonClicked() }
		SELF:Controls:Add(oButton)

		oButton := ToolBoxButton{}
		oButton:Click += EventHandler{ SELF , @ButtonClicked() }
		SELF:Controls:Add(oButton)

		SELF:SetViewMode(ViewMode.Form)
		SELF:SelectPointer()
	RETURN
	PROTECTED METHOD ImageNameFromTemplate(oTemplate AS VOControlTemplate) AS STRING
		LOCAL cRet AS STRING
		LOCAL cClass AS STRING
		cClass := oTemplate:cFullClass:ToUpperInvariant()
		DO CASE
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:BASELISTBOX:COMBOBOX")
			cRet := "System.Windows.Forms.ComboBox.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:BASELISTBOX:LISTBOX")
			cRet := "System.Windows.Forms.ListBox.bmp"
		CASE cClass:StartsWith("CONTROL:COMMONCONTROL:LISTVIEW")
			cRet := "System.Windows.Forms.ListView.bmp"
		CASE cClass:StartsWith("CONTROL:COMMONCONTROL:TREEVIEW")
			cRet := "System.Windows.Forms.TreeView.bmp"
		CASE cClass:StartsWith("CONTROL:COMMONCONTROL:TABCONTROL")
			cRet := "System.Windows.Forms.TabControl.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:MONTHCALENDAR")
			cRet := "System.Windows.Forms.MonthCalendar.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:DATETIMEPICKER")
			cRet := "System.Windows.Forms.DateTimePicker.bmp"
		CASE cClass:StartsWith("CONTROL:COMMONCONTROL:PROGRESSBAR")
			cRet := "System.Windows.Forms.ProgressBar.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:GROUPBOX") .or. ;
			cClass:StartsWith("CONTROL:TEXTCONTROL:RADIOBUTTONGROUP")
			cRet := "System.Windows.Forms.GroupBox.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:FIXEDTEXT")
			cRet := "System.Windows.Forms.Label.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:BUTTON:RADIOBUTTON")
			cRet := "System.Windows.Forms.RadioButton.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:BUTTON:PUSHBUTTON")
			cRet := "System.Windows.Forms.Button.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:BUTTON:CHECKBOX")
			cRet := "System.Windows.Forms.Button.bmp"
		CASE cClass:StartsWith("CONTROL:SCROLLBAR:VERTICALSCROLLBAR")
			cRet := "System.Windows.Forms.VScrollBar.bmp"
		CASE cClass:StartsWith("CONTROL:SCROLLBAR:HORIZONTALSCROLLBAR")
			cRet := "System.Windows.Forms.HScrollBar.bmp"
		CASE cClass:StartsWith("CONTROL:FIXEDBITMAP") .or. ;
			cClass:StartsWith("CONTROL:FIXEDICON")
			cRet := "System.Windows.Forms.PictureBox.bmp"
/*		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:EDIT:MULTILINEEDIT:RICHEDIT")
			cRet := "System.Windows.Forms.RichEdit.bmp"*/
		CASE cClass:StartsWith("CONTROL:SCROLLBAR:SPINNER:HORIZONTALSPINNER") .or. ;
			cClass:StartsWith("CONTROL:SCROLLBAR:SPINNER:VERTICALSPINNER")
			cRet := "System.Windows.Forms.NumericUpDown.bmp"
		CASE cClass:StartsWith("CONTROL:SCROLLBAR:SLIDER:VERTICALSLIDER") .or. ;
			cClass:StartsWith("CONTROL:SCROLLBAR:SLIDER:HORIZONTALSLIDER")
			cRet := "System.Windows.Forms.TrackBar.bmp"
		CASE cClass:StartsWith("CONTROL:TEXTCONTROL:IPADDRESS") .or. ;
			cClass:StartsWith("CONTROL:TEXTCONTROL:HOTKEYEDIT") .or. ;
			cClass:StartsWith("CONTROL:TEXTCONTROL:EDIT:MULTILINEEDIT") .or. ;
			cClass:StartsWith("CONTROL:TEXTCONTROL:EDIT:SINGLELINEEDIT") .or. ;
			cClass:StartsWith("CONTROL:TEXTCONTROL:HOTKEYEDIT") .or. ;
			cClass:StartsWith("CONTROL:TEXTCONTROL:HOTKEYEDIT") .or. ;
			cClass:StartsWith("CONTROL:TEXTCONTROL:IPADDRESS")
			cRet := "System.Windows.Forms.TextBox.bmp"
		OTHERWISE
			MessageBox.Show(oTemplate:cFullClass)
			cRet := "System.Windows.Forms.Panel.bmp"
		END CASE
	RETURN cRet

	METHOD SetViewMode(eViewMode AS ViewMode) AS VOID
		LOCAL n AS INT
		IF eViewMode == ViewMode.Auto
			eViewMode := ViewMode.Form
		END IF
		IF SELF:eCurrentMode != eViewMode
			SELF:eCurrentMode := eViewMode
			FOR n := 0 UPTO SELF:Controls:Count - 2
				SELF:Controls[n]:Visible := SELF:eCurrentMode == ViewMode.Form
			NEXT
			SELF:Controls[SELF:Controls:Count - 2]:Visible := SELF:eCurrentMode == ViewMode.Browse
		END IF
	RETURN

	ACCESS Selected() AS VOControlTemplate
		IF SELF:oCurrent == NULL
			RETURN NULL
		ENDIF
	RETURN SELF:oCurrent:Template
	ACCESS PointerSelected() AS LOGIC
	RETURN SELF:oCurrent == NULL .or. SELF:oCurrent:Template == NULL
	METHOD SelectPointer() AS VOID
		LOCAL oPointer AS ToolBoxButton
		IF SELF:Controls:Count == 0
			RETURN
		ENDIF
		oPointer := (ToolBoxButton)SELF:Controls[SELF:Controls:Count - 1]
		SELF:SelectButton(oPointer)
		SELF:ScrollControlIntoView(oPointer)
		oPointer:Select()
	RETURN
	METHOD ButtonClicked(o AS OBJECT , e AS EventArgs) AS VOID
		SELF:SelectButton((ToolBoxButton)o)
	RETURN
	INTERNAL METHOD SelectButton(oButton AS ToolBoxButton) AS VOID
		IF SELF:oCurrent != NULL
			SELF:oCurrent:BackColor := Color.FromKnownColor(KnownColor.Control)
			SELF:oCurrent:ForeColor := Color.Black
		ENDIF
		oButton:BackColor := Color.White
		oButton:ForeColor := Color.Red
		SELF:oCurrent := oButton
	RETURN

END CLASS

#using System.Windows.Forms
#using System.Drawing
#using System.Collections.Generic

INTERNAL CLASS ToolBoxButton INHERIT Button
	PROTECT oTemplate AS VOControlTemplate
	PROTECT oDragPoint AS Point
	CONSTRUCTOR()
		SUPER()
		SELF:Text := "Pointer"
		SELF:Dock := DockStyle.Top
		SELF:TextAlign := ContentAlignment.MiddleLeft
		SELF:FlatStyle := FlatStyle.Flat
	RETURN
	CONSTRUCTOR(_oTemplate AS VOControlTemplate)
		SUPER()
		SELF:oTemplate := _oTemplate
		SELF:Text := SELF:oTemplate:cName
		SELF:Dock := DockStyle.Top
		SELF:TextAlign := ContentAlignment.MiddleLeft
		SELF:FlatStyle := FlatStyle.Flat
	RETURN
	ACCESS Template AS VOControlTemplate
	RETURN SELF:oTemplate
	PROTECTED METHOD OnMouseDown(e AS MouseEventArgs) AS VOID
		SUPER:OnMouseDown(e)
		SELF:oDragPoint := e:Location
	RETURN
	PROTECTED METHOD OnMouseUp(e AS MouseEventArgs) AS VOID
		SUPER:OnMouseUp(e)
		SELF:oDragPoint := Point.Empty
	RETURN
	PROTECTED METHOD OnMouseMove(e AS MouseEventArgs) AS VOID
		SUPER:OnMouseMove(e)
		IF SELF:oTemplate == NULL .or. SELF:oDragPoint == Point.Empty
			RETURN
		ENDIF
		IF Math.Abs(e:X - SELF:oDragPoint:X) > 2 .or. Math.Abs(e:Y - SELF:oDragPoint:Y) > 2
			SELF:DoDragDrop(SELF:oTemplate , DragDropEffects.Move)
			SELF:oDragPoint := Point.Empty
		ENDIF
	RETURN

END CLASS

CLASS ToolBox INHERIT Panel
	INTERNAL oCurrent AS ToolBoxButton
	PROTECT eCurrentMode AS ViewMode
	CONSTRUCTOR()

		SUPER()

		LOCAL oTemplate AS VOControlTemplate
		LOCAL oButton AS ToolBoxButton
		LOCAL n AS INT

		SELF:AutoScroll := TRUE
		SELF:Dock := DockStyle.Fill

		IF !VOWindowEditorTemplate.Loaded
			RETURN
		ENDIF

		FOR n := VOWindowEditorTemplate.Count - 1 DOWNTO 0
			oTemplate := VOWindowEditorTemplate.Get(n)
			IF (!oTemplate:lUse .or. oTemplate:lForm) //.and. n != 0
				LOOP
			ENDIF
			oButton := ToolBoxButton{oTemplate}
			oButton:Click += EventHandler{ SELF , @ButtonClicked() }
			SELF:Controls:Add(oButton)
		NEXT

		LOCAL aStandard AS STRING[]
		aStandard := <STRING>{"FIXEDTEXT","PUSHBUTTON","CHECKBOX","RADIOBUTTON","SINGLELINEEDIT","MULTILINEEDIT","COMBOBOX","LISTBOX","LISTVIEW","TREEVIEW","GROUPBOX","RADIOBUTTONGROUP"}
		n := 0
		DO WHILE n < SELF:Controls:Count
//		FOR n := 0 UPTO SELF:Controls:Count - 1
			LOCAL m AS INT
			oButton := (ToolBoxButton)SELF:Controls[n]
			IF oButton:Template != NULL
				oTemplate := oButton:Template
				FOR m := 1 UPTO aStandard:Length
					IF aStandard[m] == oTemplate:cControl:ToUpper()
						IF SELF:Controls:GetChildIndex(oButton) != SELF:Controls:Count - m
							SELF:Controls:SetChildIndex(oButton , SELF:Controls:Count - m)
							n --
							EXIT
						END IF
					ENDIF
				NEXT
			ENDIF
			n ++
//		NEXT
		ENDDO

		TRY
			oButton := ToolBoxButton{VOWindowEditorTemplate.Get("SINGLELINEEDIT")}
		CATCH
			oButton := ToolBoxButton{}
		END TRY
		oButton:Text := "DataColumn"
		oButton:Click += EventHandler{ SELF , @ButtonClicked() }
		SELF:Controls:Add(oButton)

		oButton := ToolBoxButton{}
		oButton:Click += EventHandler{ SELF , @ButtonClicked() }
		SELF:Controls:Add(oButton)

		SELF:SetViewMode(ViewMode.Form)
		SELF:SelectPointer()
	RETURN
	METHOD SetViewMode(eViewMode AS ViewMode) AS VOID
		LOCAL n AS INT
		IF eViewMode == ViewMode.Auto
			eViewMode := ViewMode.Form
		END IF
		IF SELF:eCurrentMode != eViewMode
			SELF:eCurrentMode := eViewMode
			FOR n := 0 UPTO SELF:Controls:Count - 2
				SELF:Controls[n]:Visible := SELF:eCurrentMode == ViewMode.Form
			NEXT
			SELF:Controls[SELF:Controls:Count - 2]:Visible := SELF:eCurrentMode == ViewMode.Browse
		END IF
	RETURN

	ACCESS Selected() AS VOControlTemplate
		IF SELF:oCurrent == NULL
			RETURN NULL
		ENDIF
	RETURN SELF:oCurrent:Template
	ACCESS PointerSelected() AS LOGIC
	RETURN SELF:oCurrent == NULL .or. SELF:oCurrent:Template == NULL
	METHOD SelectPointer() AS VOID
		LOCAL oPointer AS ToolBoxButton
		IF SELF:Controls:Count == 0
			RETURN
		ENDIF
		oPointer := (ToolBoxButton)SELF:Controls[SELF:Controls:Count - 1]
		SELF:SelectButton(oPointer)
		SELF:ScrollControlIntoView(oPointer)
		oPointer:Select()
	RETURN
	METHOD ButtonClicked(o AS OBJECT , e AS EventArgs) AS VOID
		SELF:SelectButton((ToolBoxButton)o)
	RETURN
	INTERNAL METHOD SelectButton(oButton AS ToolBoxButton) AS VOID
		IF SELF:oCurrent != NULL
			SELF:oCurrent:BackColor := Color.FromKnownColor(KnownColor.Control)
			SELF:oCurrent:ForeColor := Color.Black
		ENDIF
		oButton:BackColor := Color.White
		oButton:ForeColor := Color.Red
		SELF:oCurrent := oButton
	RETURN

END CLASS