codegen/QtWebSockets: updated

codegen/QtWebSockets: updated

Modified:
codegen/QtWebSockets/QWebSocket.prg

%%
%% Qt5xHb - Bindings libraries for Harbour/xHarbour and Qt Framework 5
%%
%% Copyright (C) 2018 Marcos Antonio Gambeta <marcosgambeta AT outlook DOT com>
%%

$header

#include "hbclass.ch"

$addRequests

$beginClassFrom=QObject

$addMethods

$addSignals

$endClass

$destructor

#pragma BEGINDUMP

$includes=5,3,0

#include <QMaskGenerator>

$prototype=explicit QWebSocket(const QString &origin = QString(),QWebSocketProtocol::Version version = QWebSocketProtocol::VersionLatest,QObject *parent = Q_NULLPTR)
$constructor=5,3,0|new|const QString &=QString(),QWebSocketProtocol::Version=QWebSocketProtocol::VersionLatest,QObject *=Q_NULLPTR

$deleteMethod=5,3,0

$prototype=void abort()
$method=5,3,0|void|abort|

$prototype=QAbstractSocket::SocketError error() const
$method=5,3,0|QAbstractSocket::SocketError|error|

$prototype=QString errorString() const
$method=5,3,0|QString|errorString|

$prototype=bool flush()
$method=5,3,0|bool|flush|

$prototype=bool isValid() const
$method=5,3,0|bool|isValid|

$prototype=QHostAddress localAddress() const
$method=5,3,0|QHostAddress|localAddress|

$prototype=quint16 localPort() const
$method=5,3,0|quint16|localPort|

$prototype=QAbstractSocket::PauseModes pauseMode() const
$method=5,3,0|QAbstractSocket::PauseModes|pauseMode|

$prototype=QHostAddress peerAddress() const
$method=5,3,0|QHostAddress|peerAddress|

$prototype=QString peerName() const
$method=5,3,0|QString|peerName|

$prototype=quint16 peerPort() const
$method=5,3,0|quint16|peerPort|

$prototype=QNetworkProxy proxy() const
$method=5,3,0|QNetworkProxy|proxy|

$prototype=void setProxy(const QNetworkProxy &networkProxy)
$method=5,3,0|void|setProxy|const QNetworkProxy &

$prototype=const QMaskGenerator *maskGenerator() const
$method=5,3,0|const QMaskGenerator *|maskGenerator|

$prototype=void setMaskGenerator(const QMaskGenerator *maskGenerator)
$method=5,3,0|void|setMaskGenerator|const QMaskGenerator *

$prototype=qint64 readBufferSize() const
$method=5,3,0|qint64|readBufferSize|

$prototype=void setReadBufferSize(qint64 size)
$method=5,3,0|void|setReadBufferSize|qint64

$prototype=void resume()
$method=5,3,0|void|resume|

$prototype=void setPauseMode(QAbstractSocket::PauseModes pauseMode)
$method=5,3,0|void|setPauseMode|QAbstractSocket::PauseModes

$prototype=QAbstractSocket::SocketState state() const
$method=5,3,0|QAbstractSocket::SocketState|state|

$prototype=QWebSocketProtocol::Version version() const
$method=5,3,0|QWebSocketProtocol::Version|version|

$prototype=QString resourceName() const
$method=5,3,0|QString|resourceName|

$prototype=QUrl requestUrl() const
$method=5,3,0|QUrl|requestUrl|

$prototype=QString origin() const
$method=5,3,0|QString|origin|

$prototype=QWebSocketProtocol::CloseCode closeCode() const
$method=5,3,0|QWebSocketProtocol::CloseCode|closeCode|

$prototype=QString closeReason() const
$method=5,3,0|QString|closeReason|

$prototype=qint64 sendTextMessage(const QString &message)
$method=5,3,0|qint64|sendTextMessage|const QString &

$prototype=qint64 sendBinaryMessage(const QByteArray &data)
$method=5,3,0|qint64|sendBinaryMessage|const QByteArray &

$prototype=void ignoreSslErrors(const QList<QSslError> &errors)
$internalMethod=5,3,0|void|ignoreSslErrors,ignoreSslErrors1|const QList<QSslError> &

$prototype=void ignoreSslErrors()
$internalMethod=5,3,0|void|ignoreSslErrors,ignoreSslErrors2|

//[1]void ignoreSslErrors(const QList<QSslError> &errors)
//[2]void ignoreSslErrors()

HB_FUNC_STATIC( QWEBSOCKET_IGNORESSLERRORS )
{
  if( ISNUMPAR(1) && ISARRAY(1) )
  {
    QWebSocket_ignoreSslErrors1();
  }
  else if( ISNUMPAR(0) )
  {
    QWebSocket_ignoreSslErrors2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}
$addMethod=ignoreSslErrors

$prototype=QSslConfiguration sslConfiguration() const
$method=5,3,0|QSslConfiguration|sslConfiguration|

$prototype=void setSslConfiguration(const QSslConfiguration &sslConfiguration)
$method=5,3,0|void|setSslConfiguration|const QSslConfiguration &

$prototype=void close(QWebSocketProtocol::CloseCode closeCode = QWebSocketProtocol::CloseCodeNormal,const QString &reason = QString())
$method=5,3,0|void|close|QWebSocketProtocol::CloseCode=QWebSocketProtocol::CloseCodeNormal,const QString &=QString()

$prototype=void open(const QUrl &url)
$method=5,3,0|void|open|const QUrl &

$prototype=void ping(const QByteArray &payload = QByteArray())
$method=5,3,0|void|ping|const QByteArray &=QByteArray()

$beginSignals
$signal=5,3,0|aboutToClose()
$signal=5,3,0|connected()
$signal=5,3,0|disconnected()
$signal=5,3,0|stateChanged(QAbstractSocket::SocketState)
$signal=5,3,0|proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)
$signal=5,3,0|readChannelFinished()
$signal=5,3,0|textFrameReceived(QString,bool)
$signal=5,3,0|binaryFrameReceived(QByteArray,bool)
$signal=5,3,0|textMessageReceived(QString)
$signal=5,3,0|binaryMessageReceived(QByteArray)
$signal=5,3,0|error(QAbstractSocket::SocketError)
$signal=5,3,0|pong(quint64,QByteArray)
$signal=5,3,0|bytesWritten(qint64)
$signal=5,3,0|sslErrors(QList<QSslError>)
$endSignals

#pragma ENDDUMP

%%
%% Qt5xHb - Bindings libraries for Harbour/xHarbour and Qt Framework 5
%%
%% Copyright (C) 2018 Marcos Antonio Gambeta <marcosgambeta AT outlook DOT com>
%%

$header

#include "hbclass.ch"

$addRequests

$beginClassFrom=QObject

$addMethods

$addSignals

$endClass

$destructor

#pragma BEGINDUMP

$includes=5,3,0

#include <QMaskGenerator>

$prototype=explicit QWebSocket(const QString &origin = QString(),QWebSocketProtocol::Version version = QWebSocketProtocol::VersionLatest,QObject *parent = Q_NULLPTR)
$constructor=5,3,0|new|const QString &=QString(),QWebSocketProtocol::Version=QWebSocketProtocol::VersionLatest,QObject *=Q_NULLPTR

$deleteMethod=5,3,0

$prototype=void abort()
$method=5,3,0|void|abort|

$prototype=QAbstractSocket::SocketError error() const
$method=5,3,0|QAbstractSocket::SocketError|error|

$prototype=QString errorString() const
$method=5,3,0|QString|errorString|

$prototype=bool flush()
$method=5,3,0|bool|flush|

$prototype=bool isValid() const
$method=5,3,0|bool|isValid|

$prototype=QHostAddress localAddress() const
$method=5,3,0|QHostAddress|localAddress|

$prototype=quint16 localPort() const
$method=5,3,0|quint16|localPort|

$prototype=QAbstractSocket::PauseModes pauseMode() const
$method=5,3,0|QAbstractSocket::PauseModes|pauseMode|

$prototype=QHostAddress peerAddress() const
$method=5,3,0|QHostAddress|peerAddress|

$prototype=QString peerName() const
$method=5,3,0|QString|peerName|

$prototype=quint16 peerPort() const
$method=5,3,0|quint16|peerPort|

$prototype=QNetworkProxy proxy() const
$method=5,3,0|QNetworkProxy|proxy|

$prototype=void setProxy(const QNetworkProxy &networkProxy)
$method=5,3,0|void|setProxy|const QNetworkProxy &

$prototype=const QMaskGenerator *maskGenerator() const
$method=5,3,0|const QMaskGenerator *|maskGenerator|

$prototype=void setMaskGenerator(const QMaskGenerator *maskGenerator)
$method=5,3,0|void|setMaskGenerator|const QMaskGenerator *

$prototype=qint64 readBufferSize() const
$method=5,3,0|qint64|readBufferSize|

$prototype=void setReadBufferSize(qint64 size)
$method=5,3,0|void|setReadBufferSize|qint64

$prototype=void resume()
$method=5,3,0|void|resume|

$prototype=void setPauseMode(QAbstractSocket::PauseModes pauseMode)
$method=5,3,0|void|setPauseMode|QAbstractSocket::PauseModes

$prototype=QAbstractSocket::SocketState state() const
$method=5,3,0|QAbstractSocket::SocketState|state|

$prototype=QWebSocketProtocol::Version version() const
$method=5,3,0|QWebSocketProtocol::Version|version|

$prototype=QString resourceName() const
$method=5,3,0|QString|resourceName|

$prototype=QUrl requestUrl() const
$method=5,3,0|QUrl|requestUrl|

$prototype=QString origin() const
$method=5,3,0|QString|origin|

$prototype=QWebSocketProtocol::CloseCode closeCode() const
$method=5,3,0|QWebSocketProtocol::CloseCode|closeCode|

$prototype=QString closeReason() const
$method=5,3,0|QString|closeReason|

$prototype=qint64 sendTextMessage(const QString &message)
$method=5,3,0|qint64|sendTextMessage|const QString &

$prototype=qint64 sendBinaryMessage(const QByteArray &data)
$method=5,3,0|qint64|sendBinaryMessage|const QByteArray &

$prototype=void ignoreSslErrors(const QList<QSslError> &errors)
$internalMethod=5,3,0|void|ignoreSslErrors,ignoreSslErrors1|const QList<QSslError> &

$prototype=void ignoreSslErrors()
$internalMethod=5,3,0|void|ignoreSslErrors,ignoreSslErrors2|

//[1]void ignoreSslErrors(const QList<QSslError> &errors)
//[2]void ignoreSslErrors()

HB_FUNC_STATIC( QWEBSOCKET_IGNORESSLERRORS )
{
  if( ISNUMPAR(1) && ISARRAY(1) )
  {
    QWebSocket_ignoreSslErrors1();
  }
  else if( ISNUMPAR(0) )
  {
    QWebSocket_ignoreSslErrors2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QSslConfiguration sslConfiguration() const
$method=5,3,0|QSslConfiguration|sslConfiguration|

$prototype=void setSslConfiguration(const QSslConfiguration &sslConfiguration)
$method=5,3,0|void|setSslConfiguration|const QSslConfiguration &

$prototype=void close(QWebSocketProtocol::CloseCode closeCode = QWebSocketProtocol::CloseCodeNormal,const QString &reason = QString())
$method=5,3,0|void|close|QWebSocketProtocol::CloseCode=QWebSocketProtocol::CloseCodeNormal,const QString &=QString()

$prototype=void open(const QUrl &url)
$method=5,3,0|void|open|const QUrl &

$prototype=void ping(const QByteArray &payload = QByteArray())
$method=5,3,0|void|ping|const QByteArray &=QByteArray()

$beginSignals
$signal=5,3,0|aboutToClose()
$signal=5,3,0|connected()
$signal=5,3,0|disconnected()
$signal=5,3,0|stateChanged(QAbstractSocket::SocketState)
$signal=5,3,0|proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)
$signal=5,3,0|readChannelFinished()
$signal=5,3,0|textFrameReceived(QString,bool)
$signal=5,3,0|binaryFrameReceived(QByteArray,bool)
$signal=5,3,0|textMessageReceived(QString)
$signal=5,3,0|binaryMessageReceived(QByteArray)
$signal=5,3,0|error(QAbstractSocket::SocketError)
$signal=5,3,0|pong(quint64,QByteArray)
$signal=5,3,0|bytesWritten(qint64)
$signal=5,3,0|sslErrors(QList<QSslError>)
$endSignals

#pragma ENDDUMP


[Runtime] Fix for AReplicate(). (had missed including this file in previous commit)

//
// 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.
//

INTERNAL STATIC CLASS ArrayHelpers

	STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, element  AS T , nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
		LOCAL nItem AS LONG
		LOCAL nLen  AS LONG
		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 WHERE T IS NEW()
		LOCAL nItem AS LONG
		LOCAL nLen  AS LONG
		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
		LOCAL nSize		AS DWORD
		IF ! ArrayHelpers.ValidateArrayParams(REF aTarget, REF uStart, REF uCount, OUT 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, bPassIndex 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
		IF nStart == 0
			THROW  Error.ArgumentError( __ENTITY__, "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
					IF ( bPassIndex )
						result := Eval( cbBlock, aArray[x], x )
					ELSE
						result := Eval( cbBlock, aArray[x] )
					ENDIF

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

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

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

					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

///
/// Create an uninitialized, one-dimensional Array.
///
/// <param name="dwDim">The number of elements in the new Array.</param>
/// <returns>
/// An uninitialized of the given length.
/// </returns>
FUNCTION ArrayCreate(dwDim AS DWORD) AS ARRAY
	RETURN __Array{dwDim, TRUE}

///
/// Create an uninitialized, one-dimensional Array.
///
/// <param name="dwDim">The number of elements in the new Array.</param>
/// <returns>
/// An uninitialized of the given length.
/// </returns>
FUNCTION ArrayCreate<T>(dwDim AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{dwDim}

///
/// Create an initialized Array.
///
/// <param name="dwDim"></param>
/// <param name="ptrBuff"></param>
/// <returns>
/// </returns>
FUNCTION ArrayInit(dwDim AS DWORD, avalues REF USUAL[]) AS ARRAY
	LOCAL aTemp AS ARRAY
	LOCAL x AS DWORD

	IF dwDim > (DWORD) aValues:Length
		THROW Error.ArgumentError( __ENTITY__, NAMEOF(dwDim), "Element too big")
	ENDIF

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

///
/// Add a new element to the end of an Array.
///
/// <param name="a"></param>
/// <param name="x"></param>
/// <returns>
/// </returns>
FUNCTION AAdd(a AS ARRAY,x AS USUAL) AS USUAL
	RETURN AAdd<USUAL>(a, x)

///
/// Add a new element to the end of an Array.
///
/// <param name="a"></param>
/// <param name="x"></param>
/// <returns>
/// </returns>
FUNCTION AAdd<T>(a AS __ArrayBase<T>,x AS T) AS T WHERE T IS NEW()
	a:Add(x)
	RETURN x

///
/// Duplicate an array .
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION AClone(a AS ARRAY) AS ARRAY
	IF a == NULL_ARRAY
		RETURN a
	END IF
	RETURN (ARRAY) a:Clone()

///
/// Duplicate a multidimensional Array.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION AClone<T>(a AS __ArrayBase<T>) AS __ArrayBase<T> WHERE T IS NEW()
	IF a == NULL
		RETURN a
	END IF
	RETURN  a:Clone()

///
/// Duplicate an Array without its subArrays.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION ACloneShallow(a AS ARRAY) AS ARRAY
	IF a == NULL_ARRAY
		RETURN a
	END IF
	RETURN (ARRAY) a:CloneShallow()

///
/// Duplicate a multidimensional Array.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION ACloneShallow<T>(a AS __ArrayBase<T>) AS __ArrayBase<T> WHERE T IS NEW()
	IF a == NULL
		RETURN a
	END IF
	RETURN a:Clone()

///
/// Delete an Array element.
///
/// <param name="a"></param>
/// <param name="dwEl"></param>
/// <returns>
/// </returns>
FUNCTION ADel(a AS ARRAY,dwEl AS DWORD) AS ARRAY
	a:Delete((INT) dwEl)
	RETURN a

///
/// Delete an Array element.
///
/// <param name="a"></param>
/// <param name="dwEl"></param>
/// <returns>
/// </returns>
FUNCTION ADel<T>(a AS __ArrayBase<T>,dwEl AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	a:Delete((INT) dwEl)
	RETURN a

///
/// Delete an Array element.
///
/// <param name="a"></param>
/// <param name="dwEl"></param>
/// <returns>
/// </returns>
FUNCTION ATrueDel(a AS ARRAY,dwEl AS DWORD) AS ARRAY
	a:RemoveAt((INT) dwEl)
	RETURN a

///
/// Delete an Array element.
///
/// <param name="a"></param>
/// <param name="dwEl"></param>
/// <returns>
/// </returns>
FUNCTION ATrueDel<T>(a AS __ArrayBase<T>,dwEl AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	a:RemoveAt((INT) dwEl)
	RETURN a

/// 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))

///
/// Insert an element into an Array and assign it a NIL value.
///
/// <param name="a">The array into which the element will be inserted.</param>
/// <param name="dwEl">The position at which the element will be inserted.</param>
/// <returns>A reference to the original array</returns>
FUNCTION AIns(a AS ARRAY,dwEl AS DWORD) AS ARRAY
	a:Insert((INT) dwEl)
	RETURN a

///
/// Insert an element into an Array and assign it a NIL value.
///
/// <param name="a">The array into which the element will be inserted.</param>
/// <param name="dwEl">The position at which the element will be inserted.</param>
/// <returns>A reference to the original array</returns>
FUNCTION AIns<T>(a AS __ArrayBase<T>,dwEl AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	a:Insert((INT) dwEl)
	RETURN a

///
/// Return the number of elements in an Array.
///
/// <param name="a">The array to count.</param>
/// <returns>The number of elements in the array.  If the array is empty, ALen() returns 0.
/// </returns>
FUNCTION ALen<T>(a AS __ArrayBase<T>) AS DWORD WHERE T IS NEW()
	IF a != NULL
		RETURN a:Length
	ELSE
		RETURN 0
	ENDIF

///
/// Return the number of elements in an Array.
///
/// <param name="a">The array to count.</param>
/// <returns>The number of elements in the array.  If the array is empty, ALen() returns 0.
/// </returns>
FUNCTION ALen(a AS ARRAY) AS DWORD
	IF a != NULL
		RETURN a:Length
	ELSE
		RETURN 0
	ENDIF

///
/// Removes write protection from an entire Array.
///
/// <param name="a">The array to deprotect.</param>
/// <returns>TRUE if the array was successfully deprotected; otherwise, FALSE.
/// </returns>
FUNCTION ArrayDeProtect<T>(a AS __ArrayBase<T>) AS LOGIC WHERE T IS NEW()
	RETURN a:Lock(FALSE)

///
/// Removes write protection from an entire Array.
///
/// <param name="a">The array to deprotect.</param>
/// <returns>TRUE if the array was successfully deprotected; otherwise, FALSE.
/// </returns>
FUNCTION ArrayDeProtect(a AS ARRAY) AS LOGIC
	RETURN a:Lock(FALSE)

///
/// Read an Array element.
///
/// <param name="a">The array to read.</param>
/// <param name="dwEl">The number of the element to read.</param>
/// <returns>The value held by the element.
/// </returns>

FUNCTION ArrayGet(a AS ARRAY,dwEl AS DWORD) AS USUAL
	RETURN a:__GetElement( (INT) dwEl-1)

///
/// Read an Array element.
///
/// <param name="a">The array to read.</param>
/// <param name="dwEl">The number of the element to read.</param>
/// <returns>The value held by the element.
/// </returns>

FUNCTION ArrayGet<T>(a AS __ArrayBase<T>,dwEl AS DWORD) AS T WHERE T IS NEW()
	RETURN a:__GetElement( (INT) dwEl-1)

///
/// Protect an Array from change in all functions except the one in which it was declared.
///
/// <param name="a">The array to protect.</param>
/// <returns>TRUE if the array was successfully protected; otherwise, FALSE.
/// </returns>
FUNCTION ArrayProtect(a AS ARRAY) AS LOGIC
	RETURN a:Lock(TRUE)

///
/// Protect an Array from change in all functions except the one in which it was declared.
///
/// <param name="a">The array to protect.</param>
/// <returns>TRUE if the array was successfully protected; otherwise, FALSE.
/// </returns>
FUNCTION ArrayProtect<T>(a AS __ArrayBase<T>) AS LOGIC WHERE T IS NEW()
	RETURN a:Lock(TRUE)

///
/// Write a value to an Array element.
///
/// <param name="a">The array to write to.</param>
/// <param name="dwEl">The number of the array element to receive the value.</param>
/// <param name="u">The value to write to the array element.</param>
/// <returns>The value assigned.
/// </returns>
FUNCTION ArrayPut<T>(a AS __ArrayBase<T>,dwEl AS DWORD,u AS T) AS T WHERE T IS NEW()
	a:__SetElement(u, (INT)dwEl -1)
	RETURN u

///
/// Write a value to an Array element.
///
/// <param name="a">The array to write to.</param>
/// <param name="dwEl">The number of the array element to receive the value.</param>
/// <param name="u">The value to write to the array element.</param>
/// <returns>The value assigned.
/// </returns>
FUNCTION ArrayPut(a AS ARRAY,dwEl AS DWORD,u AS USUAL) AS USUAL
	a:__SetElement(u, (INT)dwEl -1)
	RETURN u

///
/// Store an Array to a buffer.
///
/// <param name="a">The array to be stored to a buffer.</param>
/// <param name="Buff">A pointer to the buffer.</param>
/// <param name="dwLen">The length of the buffer</param>
/// <returns>The number of values stored to the buffer.</returns>
FUNCTION ArrayStore(a AS ARRAY,Buff AS USUAL PTR,dwLen AS DWORD) AS DWORD
	LOCAL i AS DWORD
	LOCAL nLen AS DWORD
	nLen := ALen(a)
	dwLen := Math.Min(dwLen, nLen)
	FOR i := 1 TO dwLen
		buff[i] := a[i]
	NEXT
	RETURN dwLen

///
/// Store an Array to a buffer.
///
/// <param name="a">The array to be stored to a buffer.</param>
/// <param name="Buff">A pointer to the buffer.</param>
/// <param name="dwLen">The length of the buffer</param>
/// <returns>The number of values stored to the buffer.</returns>
FUNCTION ArrayStore<T>(a AS __ArrayBase<T>,Buff AS T PTR,dwLen AS DWORD) AS DWORD WHERE T IS NEW()
	LOCAL i AS DWORD
	LOCAL nLen AS DWORD
	nLen := a:Length
	dwLen := Math.Min(dwLen, nLen)
	FOR i := 1 TO (LONG) dwLen
		buff[i] := a[(INT) i]
	NEXT
	RETURN dwLen

///
/// Replace an Array element with a new value and return the old value.
///
/// <param name="a">The array whose element will be replaced with a new value.</param>
/// <param name="dwEl">The number of the element to be replaced.</param>
/// <param name="u">The new value.</param>
/// <returns>The original value that was replaced by u.</returns>
FUNCTION ArraySwap(a AS ARRAY,dwEl AS DWORD,u AS USUAL) AS USUAL
	RETURN a:Swap((INT) dwEl, u)

///
/// Replace an Array element with a new value and return the old value.
///
/// <param name="a">The array whose element will be replaced with a new value.</param>
/// <param name="dwEl">The number of the element to be replaced.</param>
/// <param name="u">The new value.</param>
/// <returns>The original value that was replaced by u.</returns>
FUNCTION ArraySwap<T>(a AS __ArrayBase<T>,dwEl AS DWORD,u AS T) AS T  WHERE T IS NEW()
	RETURN a:Swap((INT) dwEl, u)

///
/// Scan an array until a value is found or a code block returns TRUE.
///
/// <param name="aTarget">The array whose element will be scanned.</param>
/// <param name="uSearch">The value to search for.</param>
/// <param name="nStart">The number of the element to start with.</param>
/// <param name="nCount">The number fo elements the scan.</param>
/// <returns>If uSearch is a code block then the functions returns the position of the first element for which the code block returns TRUE.  Otherwise it returns the position of the first matching element.  The function returns 0 if no match is found.</returns>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart := NIL AS USUAL,nCount := NIL AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount, SetExact())

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

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

///
/// Scan an array until an exact match with a value is found or a code block returns TRUE.
///
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, nCount, TRUE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AScanExact(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, NIL, TRUE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AScanExact(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, 1, NIL, TRUE )

///
/// Scan a sorted Array until a value is found or a code block returns 0.
///
/// <param name="a"></param>
/// <param name="x"></param>
/// <returns>
/// </returns>
FUNCTION AScanBin(a AS ARRAY,x AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScanBin( "AscanBin" , a, x, FALSE )

///
/// Scan a sorted Array until there is an exact match or a code block returns 0.
///
/// <inheritdoc cref='M:XSharp.RT.Functions.AScanBin(XSharp.__Array,XSharp.__Usual)'/>
FUNCTION AScanBinExact(a AS ARRAY,x AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScanBin( "AscanBin" , a, x, TRUE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, element AS T) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, element,1, (INT) aTarget:Length)

///
/// Scan an array until an expression returns TRUE.
///
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act,1, (INT) aTarget:Length)

///
/// Scan an array until value is found.
///
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, element AS T, nStart AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, element, nStart, (INT) aTarget:Length- nStart +1)

///
/// Scan an array until an expression returns TRUE.
///
/// <param name="act">The lambda expression to use for looking up the correct element.</param>
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act, nStart, (INT) aTarget:Length - nStart +1)

///
/// Scan an array until value is found.
///
/// <param name="act">The lambda expression to use for looking up the correct element.</param>
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, element AS T, nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, element, nStart, nCount)

///
/// Scan an array until an expression returns TRUE.
///
/// <param name="act">The lambda expression to use for looking up the correct element.</param>
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG, nCount  AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act, nStart, nCount)

///
/// Grow or shrink an Array.
///
/// <param name="a"></param>
/// <param name="dwDim"></param>
/// <returns>
/// </returns>
FUNCTION ASize(a AS ARRAY,dwDim AS DWORD) AS ARRAY
	a:Resize((INT) dwDim)
	RETURN a

///
/// Grow or shrink an Array.
///
/// <param name="a"></param>
/// <param name="dwDim"></param>
/// <returns>
/// </returns>
FUNCTION ASize<T>(a AS __ArrayBase<T>,dwDim AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	a:Resize((INT) dwDim)
	RETURN a

///
/// Return the highest numbered element of an Array.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION ATail(a AS ARRAY) AS USUAL
	RETURN a:Tail()

///
/// Return the highest numbered element of an Array.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION ATail<T>(a AS __ArrayBase<T>) AS T WHERE T IS NEW()
	RETURN a:Tail()

///
/// Copy elements from one Array to another.
///
/// <param name="uSource"></param>
/// <param name="uTarget"></param>
/// <param name="nStart"></param>
/// <param name="nCount"></param>
/// <param name="nStartDest"></param>
/// <returns>
/// </returns>
FUNCTION ACopy(uSource ,uTarget ,nStart ,nCount ,nStartDest ) AS ARRAY CLIPPER
	LOCAL aSource  AS ARRAY
	LOCAL aTarget  AS ARRAY
	LOCAL sourceLen  AS DWORD
	LOCAL start AS DWORD
	LOCAL count AS DWORD
	IF uSource:IsArray
       aSource := uSource
    ELSE
      THROW Error.ArgumentError( __ENTITY__, NAMEOF(uSource), 1, <OBJECT>{ uSource } )
    ENDIF

     IF uTarget:IsArray
        aTarget := uTarget
     ELSE
        THROW Error.ArgumentError( __ENTITY__, NAMEOF(uTarget), 2, <OBJECT>{ uTarget } )
     ENDIF
	 start := 1
	 sourceLen  := ALen(aSource)
	 IF pCount() > 2
		IF nStart:IsNumeric
			start := nStart
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nStart), 3, <OBJECT>{ nStart } )
		ENDIF
		IF start < 0
			start := sourceLen
		ELSE
			start := Math.Min(start, sourceLen)
		ENDIF
	 ENDIF
	 IF pCount() > 3
		IF nCount:IsNumeric
			count := nCount
		ELSE
			THROW Error.ArgumentError( __ENTITY__, 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 DWORD
	 LOCAL targetLen	:= ALen(aTarget) AS DWORD
	 IF pCount() > 4
		IF nStartDest:IsNumeric
			offSet := nStartDest
			offSet := Math.Min( offSet, targetLen )
            offSet := Math.Max( 1, offSet )
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nStartDest), 5, <OBJECT>{ nStartDest } )
		ENDIF
	 ENDIF
	 XSharp.__Array.Copy(aSource, aTarget, start, sourceLen, offSet, targetLen)

	 RETURN aTarget

///
/// Fill Array elements with a specified value.
///
/// <param name="a"></param>
/// <param name="x"></param>
/// <param name="Start"></param>
/// <param name="Stop"></param>
/// <returns>
/// </returns>
FUNCTION AFill(a AS ARRAY,fill := NIL AS USUAL, start := NIL AS USUAL, count := 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( a ) AS DWORD
	IF nLen > 0

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

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

		FOR LOCAL x := start AS INT UPTO start + count - 1
			a[(DWORD) x] := fill
		NEXT
	ENDIF
	RETURN a

///
/// Create an empty Array.
///
/// <returns>
/// </returns>
FUNCTION ArrayBuild() AS ARRAY
	RETURN ARRAY{}

///
/// Create an uninitialized Array with a single dimension and no elements.
///
/// <returns>
/// </returns>
FUNCTION ArrayNew() AS ARRAY
	RETURN ArrayNew(0)

///
/// Create an uninitialized Array with the specified number of elements and dimensions.
///
/// <param name="aDims"></param>
/// <returns>
/// </returns>
FUNCTION ArrayNew(aDims PARAMS USUAL[]) AS ARRAY
	LOCAL aDimInt AS INT[]
	LOCAL i AS INT
	aDimInt := INT[]{aDims:Length}
	FOR i := 1 TO aDims:Length
		aDimInt[i] := (INT) aDims[i]
	NEXT
	RETURN __Array.ArrayCreate(aDimInt)

///
/// Create an uninitialized Array with the specified number of elements and dimensions.
///
/// <param name="nDim"></param>
/// <returns>
/// </returns>
FUNCTION ArrayNew<T>(nSize AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{nSize}

///
/// Create an uninitialized Array with the specified number of elements and dimensions.
///
/// <param name="nDim"></param>
/// <returns>
/// </returns>
FUNCTION ArrayNew<T>(nSize AS INT) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{(DWORD) nSize}

///
/// To create an Array and fill its elements with a default value.
///
/// <param name="x"></param>
/// <param name="nCount"></param>
/// <returns>
/// </returns>
FUNCTION AReplicate(x AS USUAL,nCount AS DWORD) AS ARRAY
	VAR a:= __Array{nCount, TRUE}
	LOCAL i AS DWORD
	FOR i := 1 UPTO nCount
		a[i] := x
	NEXT
	RETURN a

///
/// Sort an Array.
///
/// <param name="uArray"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION ASort(aArray AS ARRAY, startIndex := NIL AS USUAL,nCount := NIL AS USUAL,cbOrder := NIL AS USUAL) AS ARRAY
	LOCAL nLen AS DWORD
	Default( REF startIndex, 1 )

	nLen := ALen(aArray)
	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 aArray
	END IF

	EnforceNumeric( startIndex )
	Default( REF nCount, nLen - startIndex + 1 )
	EnforceNumeric( nCount )

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

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

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

	IF cbOrder != NIL .AND. ( ( ! cbOrder:IsCodeBlock ) || ((CODEBLOCK)cbOrder):PCount() != 2 )
		THROW Error.ArgumentError( __ENTITY__, "cbOrder", 4, <OBJECT>{ cbOrder } )
	ENDIF

	IF cbOrder == NIL
		aArray:Sort( startIndex, nCount, NULL ) // this uses __Usual.ICompareTo()
	ELSE
		aArray:Sort( startIndex, nCount, ArraySortComparer{ cbOrder } )
	ENDIF

	RETURN aArray

	// 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 ICodeblock)
		_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> WHERE T IS NEW()

	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.ReferenceEquals(x, y )
			RETURN 0
		ENDIF
		LOCAL u AS LOGIC
		u := _cb( x, y )
		RETURN IIF (  u , -1, 1 )

END STRUCTURE

///
/// Sort an Array.
///
/// <param name="a"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION ASort<T>(aArray AS __ArrayBase<T> ,startIndex AS INT,nCount AS INT,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T> WHERE T IS NEW()
	aArray:Sort( startIndex, nCount, ArraySortComparer<T, LOGIC> { cbOrder } )
	RETURN aArray

///
/// Sort an Array.
///
/// <param name="a"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION ASort<T>(aArray AS __ArrayBase<T> ,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T> WHERE T IS NEW()

	aArray:Sort( ArraySortComparer<T, LOGIC> { cbOrder } )

	RETURN aArray

///
/// Execute a code block for each element in an Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cb AS Action<T>) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEval(aArray, cb, 1, ALen(aArray) )

///
/// Execute a code block for each element in an Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <returns>
/// </returns>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cb AS Action<T>,iStart AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEval(aArray, cb, iStart, ALen(aArray) - iStart +1)

///
/// Execute a code block for each element in an Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <returns>
/// </returns>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cb AS Action<T>,iStart AS DWORD,iCount  AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	LOCAL nX AS DWORD
	LOCAL nEnd AS DWORD
	nEnd := iStart + iCount -1
	FOR nX := iStart TO nEnd
		cb(aArray[ (INT) nX])
	NEXT
	RETURN aArray

/// <inheritdoc cref='M:XSharp.RT.Functions.AEval(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEval(aArray AS ARRAY,cb AS ICodeblock ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	LOCAL uStart	:= NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart, uCount, FALSE, FALSE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AEval(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEval(aArray AS ARRAY,cb AS ICodeblock ,uStart AS USUAL ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart, uCount, FALSE, FALSE )

///
/// Execute a code block for each element in an Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <param name="uStart"></param>
/// <param name="uCount"></param>
/// <returns>
/// </returns>
FUNCTION AEval(aArray AS ARRAY,cb AS ICodeblock ,uStart AS USUAL ,uCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart, uCount , FALSE, FALSE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AEvalA(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEvalA(aArray AS ARRAY ,cb AS ICodeblock) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	LOCAL uStart	:= NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , TRUE, FALSE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AEvalA(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEvalA(aArray AS ARRAY ,cb AS ICodeblock, uStart AS USUAL ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , TRUE, FALSE )

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="a"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <returns>
/// </returns>
FUNCTION AEvalA(aArray AS ARRAY ,cb AS ICodeblock, uStart  AS USUAL ,uCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , TRUE, FALSE )

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="a"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cb AS @@Func<T,T>) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEvalA(aArray, cb, 1, ALen(aArray))

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="a"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <returns>
/// </returns>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cb AS @@Func<T,T>,iStart AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEvalA(aArray, cb, iStart, ALen(aArray) - iStart +1)

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="a"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <returns>
/// </returns>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cb AS @@Func<T,T>,iStart AS DWORD,iCount AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	LOCAL nX AS DWORD
	LOCAL nEnd AS DWORD
	nEnd := iStart + iCount -1
	FOR nX := iStart TO nEnd
		aArray[ (INT) nX] := cb( aArray[(INT)  nX])
	NEXT
	RETURN aArray

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <param name="uStart"></param>
/// <param name="uCount"></param>
/// <returns>
/// </returns>
FUNCTION AEvalOld(aArray AS ARRAY ,cb AS ICodeblock,uStart  AS USUAL ,uCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , FALSE, TRUE)

/// <inheritdoc cref='M:XSharp.RT.Functions.AEvalOld(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEvalOld(aArray AS ARRAY ,cb AS ICodeblock,uStart  AS USUAL ) AS ARRAY
	LOCAL uCount	 := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , FALSE, TRUE)

/// <inheritdoc cref='M:XSharp.RT.Functions.AEvalOld(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEvalOld(aArray AS ARRAY ,cb AS ICodeblock) AS ARRAY
	LOCAL uStart	 := NIL AS USUAL
	LOCAL uCount	 := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , FALSE, TRUE)

//
// 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.
//

INTERNAL STATIC CLASS ArrayHelpers

	STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, element  AS T , nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
		LOCAL nItem AS LONG
		LOCAL nLen  AS LONG
		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 WHERE T IS NEW()
		LOCAL nItem AS LONG
		LOCAL nLen  AS LONG
		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
		LOCAL nSize		AS DWORD
		IF ! ArrayHelpers.ValidateArrayParams(REF aTarget, REF uStart, REF uCount, OUT 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, bPassIndex 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
		IF nStart == 0
			THROW  Error.ArgumentError( __ENTITY__, "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
					IF ( bPassIndex )
						result := Eval( cbBlock, aArray[x], x )
					ELSE
						result := Eval( cbBlock, aArray[x] )
					ENDIF

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

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

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

					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

///
/// Create an uninitialized, one-dimensional Array.
///
/// <param name="dwDim">The number of elements in the new Array.</param>
/// <returns>
/// An uninitialized of the given length.
/// </returns>
FUNCTION ArrayCreate(dwDim AS DWORD) AS ARRAY
	RETURN __Array{dwDim, TRUE}

///
/// Create an uninitialized, one-dimensional Array.
///
/// <param name="dwDim">The number of elements in the new Array.</param>
/// <returns>
/// An uninitialized of the given length.
/// </returns>
FUNCTION ArrayCreate<T>(dwDim AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{dwDim}

///
/// Create an initialized Array.
///
/// <param name="dwDim"></param>
/// <param name="ptrBuff"></param>
/// <returns>
/// </returns>
FUNCTION ArrayInit(dwDim AS DWORD, avalues REF USUAL[]) AS ARRAY
	LOCAL aTemp AS ARRAY
	LOCAL x AS DWORD

	IF dwDim > (DWORD) aValues:Length
		THROW Error.ArgumentError( __ENTITY__, NAMEOF(dwDim), "Element too big")
	ENDIF

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

///
/// Add a new element to the end of an Array.
///
/// <param name="a"></param>
/// <param name="x"></param>
/// <returns>
/// </returns>
FUNCTION AAdd(a AS ARRAY,x AS USUAL) AS USUAL
	RETURN AAdd<USUAL>(a, x)

///
/// Add a new element to the end of an Array.
///
/// <param name="a"></param>
/// <param name="x"></param>
/// <returns>
/// </returns>
FUNCTION AAdd<T>(a AS __ArrayBase<T>,x AS T) AS T WHERE T IS NEW()
	a:Add(x)
	RETURN x

///
/// Duplicate an array .
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION AClone(a AS ARRAY) AS ARRAY
	IF a == NULL_ARRAY
		RETURN a
	END IF
	RETURN (ARRAY) a:Clone()

///
/// Duplicate a multidimensional Array.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION AClone<T>(a AS __ArrayBase<T>) AS __ArrayBase<T> WHERE T IS NEW()
	IF a == NULL
		RETURN a
	END IF
	RETURN  a:Clone()

///
/// Duplicate an Array without its subArrays.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION ACloneShallow(a AS ARRAY) AS ARRAY
	IF a == NULL_ARRAY
		RETURN a
	END IF
	RETURN (ARRAY) a:CloneShallow()

///
/// Duplicate a multidimensional Array.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION ACloneShallow<T>(a AS __ArrayBase<T>) AS __ArrayBase<T> WHERE T IS NEW()
	IF a == NULL
		RETURN a
	END IF
	RETURN a:Clone()

///
/// Delete an Array element.
///
/// <param name="a"></param>
/// <param name="dwEl"></param>
/// <returns>
/// </returns>
FUNCTION ADel(a AS ARRAY,dwEl AS DWORD) AS ARRAY
	a:Delete((INT) dwEl)
	RETURN a

///
/// Delete an Array element.
///
/// <param name="a"></param>
/// <param name="dwEl"></param>
/// <returns>
/// </returns>
FUNCTION ADel<T>(a AS __ArrayBase<T>,dwEl AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	a:Delete((INT) dwEl)
	RETURN a

///
/// Delete an Array element.
///
/// <param name="a"></param>
/// <param name="dwEl"></param>
/// <returns>
/// </returns>
FUNCTION ATrueDel(a AS ARRAY,dwEl AS DWORD) AS ARRAY
	a:RemoveAt((INT) dwEl)
	RETURN a

///
/// Delete an Array element.
///
/// <param name="a"></param>
/// <param name="dwEl"></param>
/// <returns>
/// </returns>
FUNCTION ATrueDel<T>(a AS __ArrayBase<T>,dwEl AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	a:RemoveAt((INT) dwEl)
	RETURN a

/// 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))

///
/// Insert an element into an Array and assign it a NIL value.
///
/// <param name="a">The array into which the element will be inserted.</param>
/// <param name="dwEl">The position at which the element will be inserted.</param>
/// <returns>A reference to the original array</returns>
FUNCTION AIns(a AS ARRAY,dwEl AS DWORD) AS ARRAY
	a:Insert((INT) dwEl)
	RETURN a

///
/// Insert an element into an Array and assign it a NIL value.
///
/// <param name="a">The array into which the element will be inserted.</param>
/// <param name="dwEl">The position at which the element will be inserted.</param>
/// <returns>A reference to the original array</returns>
FUNCTION AIns<T>(a AS __ArrayBase<T>,dwEl AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	a:Insert((INT) dwEl)
	RETURN a

///
/// Return the number of elements in an Array.
///
/// <param name="a">The array to count.</param>
/// <returns>The number of elements in the array.  If the array is empty, ALen() returns 0.
/// </returns>
FUNCTION ALen<T>(a AS __ArrayBase<T>) AS DWORD WHERE T IS NEW()
	IF a != NULL
		RETURN a:Length
	ELSE
		RETURN 0
	ENDIF

///
/// Return the number of elements in an Array.
///
/// <param name="a">The array to count.</param>
/// <returns>The number of elements in the array.  If the array is empty, ALen() returns 0.
/// </returns>
FUNCTION ALen(a AS ARRAY) AS DWORD
	IF a != NULL
		RETURN a:Length
	ELSE
		RETURN 0
	ENDIF

///
/// Removes write protection from an entire Array.
///
/// <param name="a">The array to deprotect.</param>
/// <returns>TRUE if the array was successfully deprotected; otherwise, FALSE.
/// </returns>
FUNCTION ArrayDeProtect<T>(a AS __ArrayBase<T>) AS LOGIC WHERE T IS NEW()
	RETURN a:Lock(FALSE)

///
/// Removes write protection from an entire Array.
///
/// <param name="a">The array to deprotect.</param>
/// <returns>TRUE if the array was successfully deprotected; otherwise, FALSE.
/// </returns>
FUNCTION ArrayDeProtect(a AS ARRAY) AS LOGIC
	RETURN a:Lock(FALSE)

///
/// Read an Array element.
///
/// <param name="a">The array to read.</param>
/// <param name="dwEl">The number of the element to read.</param>
/// <returns>The value held by the element.
/// </returns>

FUNCTION ArrayGet(a AS ARRAY,dwEl AS DWORD) AS USUAL
	RETURN a:__GetElement( (INT) dwEl-1)

///
/// Read an Array element.
///
/// <param name="a">The array to read.</param>
/// <param name="dwEl">The number of the element to read.</param>
/// <returns>The value held by the element.
/// </returns>

FUNCTION ArrayGet<T>(a AS __ArrayBase<T>,dwEl AS DWORD) AS T WHERE T IS NEW()
	RETURN a:__GetElement( (INT) dwEl-1)

///
/// Protect an Array from change in all functions except the one in which it was declared.
///
/// <param name="a">The array to protect.</param>
/// <returns>TRUE if the array was successfully protected; otherwise, FALSE.
/// </returns>
FUNCTION ArrayProtect(a AS ARRAY) AS LOGIC
	RETURN a:Lock(TRUE)

///
/// Protect an Array from change in all functions except the one in which it was declared.
///
/// <param name="a">The array to protect.</param>
/// <returns>TRUE if the array was successfully protected; otherwise, FALSE.
/// </returns>
FUNCTION ArrayProtect<T>(a AS __ArrayBase<T>) AS LOGIC WHERE T IS NEW()
	RETURN a:Lock(TRUE)

///
/// Write a value to an Array element.
///
/// <param name="a">The array to write to.</param>
/// <param name="dwEl">The number of the array element to receive the value.</param>
/// <param name="u">The value to write to the array element.</param>
/// <returns>The value assigned.
/// </returns>
FUNCTION ArrayPut<T>(a AS __ArrayBase<T>,dwEl AS DWORD,u AS T) AS T WHERE T IS NEW()
	a:__SetElement(u, (INT)dwEl -1)
	RETURN u

///
/// Write a value to an Array element.
///
/// <param name="a">The array to write to.</param>
/// <param name="dwEl">The number of the array element to receive the value.</param>
/// <param name="u">The value to write to the array element.</param>
/// <returns>The value assigned.
/// </returns>
FUNCTION ArrayPut(a AS ARRAY,dwEl AS DWORD,u AS USUAL) AS USUAL
	a:__SetElement(u, (INT)dwEl -1)
	RETURN u

///
/// Store an Array to a buffer.
///
/// <param name="a">The array to be stored to a buffer.</param>
/// <param name="Buff">A pointer to the buffer.</param>
/// <param name="dwLen">The length of the buffer</param>
/// <returns>The number of values stored to the buffer.</returns>
FUNCTION ArrayStore(a AS ARRAY,Buff AS USUAL PTR,dwLen AS DWORD) AS DWORD
	LOCAL i AS DWORD
	LOCAL nLen AS DWORD
	nLen := ALen(a)
	dwLen := Math.Min(dwLen, nLen)
	FOR i := 1 TO dwLen
		buff[i] := a[i]
	NEXT
	RETURN dwLen

///
/// Store an Array to a buffer.
///
/// <param name="a">The array to be stored to a buffer.</param>
/// <param name="Buff">A pointer to the buffer.</param>
/// <param name="dwLen">The length of the buffer</param>
/// <returns>The number of values stored to the buffer.</returns>
FUNCTION ArrayStore<T>(a AS __ArrayBase<T>,Buff AS T PTR,dwLen AS DWORD) AS DWORD WHERE T IS NEW()
	LOCAL i AS DWORD
	LOCAL nLen AS DWORD
	nLen := a:Length
	dwLen := Math.Min(dwLen, nLen)
	FOR i := 1 TO (LONG) dwLen
		buff[i] := a[(INT) i]
	NEXT
	RETURN dwLen

///
/// Replace an Array element with a new value and return the old value.
///
/// <param name="a">The array whose element will be replaced with a new value.</param>
/// <param name="dwEl">The number of the element to be replaced.</param>
/// <param name="u">The new value.</param>
/// <returns>The original value that was replaced by u.</returns>
FUNCTION ArraySwap(a AS ARRAY,dwEl AS DWORD,u AS USUAL) AS USUAL
	RETURN a:Swap((INT) dwEl, u)

///
/// Replace an Array element with a new value and return the old value.
///
/// <param name="a">The array whose element will be replaced with a new value.</param>
/// <param name="dwEl">The number of the element to be replaced.</param>
/// <param name="u">The new value.</param>
/// <returns>The original value that was replaced by u.</returns>
FUNCTION ArraySwap<T>(a AS __ArrayBase<T>,dwEl AS DWORD,u AS T) AS T  WHERE T IS NEW()
	RETURN a:Swap((INT) dwEl, u)

///
/// Scan an array until a value is found or a code block returns TRUE.
///
/// <param name="aTarget">The array whose element will be scanned.</param>
/// <param name="uSearch">The value to search for.</param>
/// <param name="nStart">The number of the element to start with.</param>
/// <param name="nCount">The number fo elements the scan.</param>
/// <returns>If uSearch is a code block then the functions returns the position of the first element for which the code block returns TRUE.  Otherwise it returns the position of the first matching element.  The function returns 0 if no match is found.</returns>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart := NIL AS USUAL,nCount := NIL AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount, SetExact())

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

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

///
/// Scan an array until an exact match with a value is found or a code block returns TRUE.
///
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, nCount, TRUE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AScanExact(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, NIL, TRUE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AScanExact(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, 1, NIL, TRUE )

///
/// Scan a sorted Array until a value is found or a code block returns 0.
///
/// <param name="a"></param>
/// <param name="x"></param>
/// <returns>
/// </returns>
FUNCTION AScanBin(a AS ARRAY,x AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScanBin( "AscanBin" , a, x, FALSE )

///
/// Scan a sorted Array until there is an exact match or a code block returns 0.
///
/// <inheritdoc cref='M:XSharp.RT.Functions.AScanBin(XSharp.__Array,XSharp.__Usual)'/>
FUNCTION AScanBinExact(a AS ARRAY,x AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScanBin( "AscanBin" , a, x, TRUE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, element AS T) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, element,1, (INT) aTarget:Length)

///
/// Scan an array until an expression returns TRUE.
///
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act,1, (INT) aTarget:Length)

///
/// Scan an array until value is found.
///
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, element AS T, nStart AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, element, nStart, (INT) aTarget:Length- nStart +1)

///
/// Scan an array until an expression returns TRUE.
///
/// <param name="act">The lambda expression to use for looking up the correct element.</param>
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act, nStart, (INT) aTarget:Length - nStart +1)

///
/// Scan an array until value is found.
///
/// <param name="act">The lambda expression to use for looking up the correct element.</param>
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, element AS T, nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, element, nStart, nCount)

///
/// Scan an array until an expression returns TRUE.
///
/// <param name="act">The lambda expression to use for looking up the correct element.</param>
/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG, nCount  AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act, nStart, nCount)

///
/// Grow or shrink an Array.
///
/// <param name="a"></param>
/// <param name="dwDim"></param>
/// <returns>
/// </returns>
FUNCTION ASize(a AS ARRAY,dwDim AS DWORD) AS ARRAY
	a:Resize((INT) dwDim)
	RETURN a

///
/// Grow or shrink an Array.
///
/// <param name="a"></param>
/// <param name="dwDim"></param>
/// <returns>
/// </returns>
FUNCTION ASize<T>(a AS __ArrayBase<T>,dwDim AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	a:Resize((INT) dwDim)
	RETURN a

///
/// Return the highest numbered element of an Array.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION ATail(a AS ARRAY) AS USUAL
	RETURN a:Tail()

///
/// Return the highest numbered element of an Array.
///
/// <param name="a"></param>
/// <returns>
/// </returns>
FUNCTION ATail<T>(a AS __ArrayBase<T>) AS T WHERE T IS NEW()
	RETURN a:Tail()

///
/// Copy elements from one Array to another.
///
/// <param name="uSource"></param>
/// <param name="uTarget"></param>
/// <param name="nStart"></param>
/// <param name="nCount"></param>
/// <param name="nStartDest"></param>
/// <returns>
/// </returns>
FUNCTION ACopy(uSource ,uTarget ,nStart ,nCount ,nStartDest ) AS ARRAY CLIPPER
	LOCAL aSource  AS ARRAY
	LOCAL aTarget  AS ARRAY
	LOCAL sourceLen  AS DWORD
	LOCAL start AS DWORD
	LOCAL count AS DWORD
	IF uSource:IsArray
       aSource := uSource
    ELSE
      THROW Error.ArgumentError( __ENTITY__, NAMEOF(uSource), 1, <OBJECT>{ uSource } )
    ENDIF

     IF uTarget:IsArray
        aTarget := uTarget
     ELSE
        THROW Error.ArgumentError( __ENTITY__, NAMEOF(uTarget), 2, <OBJECT>{ uTarget } )
     ENDIF
	 start := 1
	 sourceLen  := ALen(aSource)
	 IF pCount() > 2
		IF nStart:IsNumeric
			start := nStart
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nStart), 3, <OBJECT>{ nStart } )
		ENDIF
		IF start < 0
			start := sourceLen
		ELSE
			start := Math.Min(start, sourceLen)
		ENDIF
	 ENDIF
	 IF pCount() > 3
		IF nCount:IsNumeric
			count := nCount
		ELSE
			THROW Error.ArgumentError( __ENTITY__, 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 DWORD
	 LOCAL targetLen	:= ALen(aTarget) AS DWORD
	 IF pCount() > 4
		IF nStartDest:IsNumeric
			offSet := nStartDest
			offSet := Math.Min( offSet, targetLen )
            offSet := Math.Max( 1, offSet )
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nStartDest), 5, <OBJECT>{ nStartDest } )
		ENDIF
	 ENDIF
	 XSharp.__Array.Copy(aSource, aTarget, start, sourceLen, offSet, targetLen)

	 RETURN aTarget

///
/// Fill Array elements with a specified value.
///
/// <param name="a"></param>
/// <param name="x"></param>
/// <param name="Start"></param>
/// <param name="Stop"></param>
/// <returns>
/// </returns>
FUNCTION AFill(a AS ARRAY,fill := NIL AS USUAL, start := NIL AS USUAL, count := 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( a ) AS DWORD
	IF nLen > 0

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

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

		FOR LOCAL x := start AS INT UPTO start + count - 1
			a[(DWORD) x] := fill
		NEXT
	ENDIF
	RETURN a

///
/// Create an empty Array.
///
/// <returns>
/// </returns>
FUNCTION ArrayBuild() AS ARRAY
	RETURN ARRAY{}

///
/// Create an uninitialized Array with a single dimension and no elements.
///
/// <returns>
/// </returns>
FUNCTION ArrayNew() AS ARRAY
	RETURN ArrayNew(0)

///
/// Create an uninitialized Array with the specified number of elements and dimensions.
///
/// <param name="aDims"></param>
/// <returns>
/// </returns>
FUNCTION ArrayNew(aDims PARAMS USUAL[]) AS ARRAY
	LOCAL aDimInt AS INT[]
	LOCAL i AS INT
	aDimInt := INT[]{aDims:Length}
	FOR i := 1 TO aDims:Length
		aDimInt[i] := (INT) aDims[i]
	NEXT
	RETURN __Array.ArrayCreate(aDimInt)

///
/// Create an uninitialized Array with the specified number of elements and dimensions.
///
/// <param name="nDim"></param>
/// <returns>
/// </returns>
FUNCTION ArrayNew<T>(nSize AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{nSize}

///
/// Create an uninitialized Array with the specified number of elements and dimensions.
///
/// <param name="nDim"></param>
/// <returns>
/// </returns>
FUNCTION ArrayNew<T>(nSize AS INT) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{(DWORD) nSize}

///
/// To create an Array and fill its elements with a default value.
///
/// <param name="x"></param>
/// <param name="nCount"></param>
/// <returns>
/// </returns>
FUNCTION AReplicate(x AS USUAL,nCount AS DWORD) AS ARRAY
	VAR a:= __Array{nCount}
	LOCAL i AS DWORD
	FOR i := 1 TO nCount
		a[i] := x
	NEXT
	RETURN a

///
/// Sort an Array.
///
/// <param name="uArray"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION ASort(aArray AS ARRAY, startIndex := NIL AS USUAL,nCount := NIL AS USUAL,cbOrder := NIL AS USUAL) AS ARRAY
	LOCAL nLen AS DWORD
	Default( REF startIndex, 1 )

	nLen := ALen(aArray)
	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 aArray
	END IF

	EnforceNumeric( startIndex )
	Default( REF nCount, nLen - startIndex + 1 )
	EnforceNumeric( nCount )

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

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

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

	IF cbOrder != NIL .AND. ( ( ! cbOrder:IsCodeBlock ) || ((CODEBLOCK)cbOrder):PCount() != 2 )
		THROW Error.ArgumentError( __ENTITY__, "cbOrder", 4, <OBJECT>{ cbOrder } )
	ENDIF

	IF cbOrder == NIL
		aArray:Sort( startIndex, nCount, NULL ) // this uses __Usual.ICompareTo()
	ELSE
		aArray:Sort( startIndex, nCount, ArraySortComparer{ cbOrder } )
	ENDIF

	RETURN aArray

	// 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 ICodeblock)
		_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> WHERE T IS NEW()

	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.ReferenceEquals(x, y )
			RETURN 0
		ENDIF
		LOCAL u AS LOGIC
		u := _cb( x, y )
		RETURN IIF (  u , -1, 1 )

END STRUCTURE

///
/// Sort an Array.
///
/// <param name="a"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION ASort<T>(aArray AS __ArrayBase<T> ,startIndex AS INT,nCount AS INT,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T> WHERE T IS NEW()
	aArray:Sort( startIndex, nCount, ArraySortComparer<T, LOGIC> { cbOrder } )
	RETURN aArray

///
/// Sort an Array.
///
/// <param name="a"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION ASort<T>(aArray AS __ArrayBase<T> ,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T> WHERE T IS NEW()

	aArray:Sort( ArraySortComparer<T, LOGIC> { cbOrder } )

	RETURN aArray

///
/// Execute a code block for each element in an Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cb AS Action<T>) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEval(aArray, cb, 1, ALen(aArray) )

///
/// Execute a code block for each element in an Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <returns>
/// </returns>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cb AS Action<T>,iStart AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEval(aArray, cb, iStart, ALen(aArray) - iStart +1)

///
/// Execute a code block for each element in an Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <returns>
/// </returns>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cb AS Action<T>,iStart AS DWORD,iCount  AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	LOCAL nX AS DWORD
	LOCAL nEnd AS DWORD
	nEnd := iStart + iCount -1
	FOR nX := iStart TO nEnd
		cb(aArray[ (INT) nX])
	NEXT
	RETURN aArray

/// <inheritdoc cref='M:XSharp.RT.Functions.AEval(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEval(aArray AS ARRAY,cb AS ICodeblock ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	LOCAL uStart	:= NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart, uCount, FALSE, FALSE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AEval(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEval(aArray AS ARRAY,cb AS ICodeblock ,uStart AS USUAL ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart, uCount, FALSE, FALSE )

///
/// Execute a code block for each element in an Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <param name="uStart"></param>
/// <param name="uCount"></param>
/// <returns>
/// </returns>
FUNCTION AEval(aArray AS ARRAY,cb AS ICodeblock ,uStart AS USUAL ,uCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart, uCount , FALSE, FALSE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AEvalA(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEvalA(aArray AS ARRAY ,cb AS ICodeblock) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	LOCAL uStart	:= NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , TRUE, FALSE )

/// <inheritdoc cref='M:XSharp.RT.Functions.AEvalA(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEvalA(aArray AS ARRAY ,cb AS ICodeblock, uStart AS USUAL ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , TRUE, FALSE )

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="a"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <returns>
/// </returns>
FUNCTION AEvalA(aArray AS ARRAY ,cb AS ICodeblock, uStart  AS USUAL ,uCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , TRUE, FALSE )

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="a"></param>
/// <param name="cb"></param>
/// <returns>
/// </returns>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cb AS @@Func<T,T>) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEvalA(aArray, cb, 1, ALen(aArray))

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="a"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <returns>
/// </returns>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cb AS @@Func<T,T>,iStart AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEvalA(aArray, cb, iStart, ALen(aArray) - iStart +1)

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="a"></param>
/// <param name="cb"></param>
/// <param name="iStart"></param>
/// <param name="iCount"></param>
/// <returns>
/// </returns>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cb AS @@Func<T,T>,iStart AS DWORD,iCount AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	LOCAL nX AS DWORD
	LOCAL nEnd AS DWORD
	nEnd := iStart + iCount -1
	FOR nX := iStart TO nEnd
		aArray[ (INT) nX] := cb( aArray[(INT)  nX])
	NEXT
	RETURN aArray

///
/// Execute a code block for each element in an Array and assign the return value to each element in the Array.
///
/// <param name="aArray"></param>
/// <param name="cb"></param>
/// <param name="uStart"></param>
/// <param name="uCount"></param>
/// <returns>
/// </returns>
FUNCTION AEvalOld(aArray AS ARRAY ,cb AS ICodeblock,uStart  AS USUAL ,uCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , FALSE, TRUE)

/// <inheritdoc cref='M:XSharp.RT.Functions.AEvalOld(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEvalOld(aArray AS ARRAY ,cb AS ICodeblock,uStart  AS USUAL ) AS ARRAY
	LOCAL uCount	 := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , FALSE, TRUE)

/// <inheritdoc cref='M:XSharp.RT.Functions.AEvalOld(XSharp.__Array,XSharp.ICodeblock,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AEvalOld(aArray AS ARRAY ,cb AS ICodeblock) AS ARRAY
	LOCAL uStart	 := NIL AS USUAL
	LOCAL uCount	 := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cb, REF uStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cb, uStart,uCount , FALSE, TRUE)


baby step

baby step

data Dir :: *2 where
  Hor :: name ~> Dir -- these are nodes
  Ver :: name ~> Dir -- should be tree of names!

data Tree :: Dir ~> *1 where
  Pri :: Tag ~> Tree (Hor Tag)
  Unit :: Tree (Ver name)
  Ni :: Tree (Hor name)
  Fork :: Tree (d Tag) ~> Tree (Hor name) ~> Tree (Hor name)
 deriving syntax (tr) List(Ni, Fork) Unit(Unit) Item(Pri)

data Tree' :: Tree d ~> * where
  Labeled :: Label tag -> Tree' (tag)tr
  In :: Tree' ()tr
  Fork :: Tree' head -> Tree' tail -> Tree' [head; tail]tr
  Done :: Tree' []tr
 deriving syntax (ar) List(Done, Fork) Unit(In) Item(Labeled)

kind Wrap a = W a

data Stack :: Tree (d Tag) ~> Tree (e Tag) ~> * where
  Cell :: Stack ()tr ()tr
  NicheDone :: Stack ()tr []tr
  Niche :: Stack tr out -> Stack tr [out]tr
  Also :: Tree' at -> Stack tr out' -> Stack tr out -> Stack tr [out'; out]tr
 deriving syntax(z) Record(NicheDone, Also)

t1 = {(`hey)ar=Cell}z

data Dir :: *2 where
  Hor :: name ~> Dir
  Ver :: name ~> Dir -- tree of names!

data Tree :: Dir ~> *1 where
  Unit :: Tree (Ver name)
  Ni :: Tree (Hor name)
  Fork :: Tree (d Tag) ~> Tree (Hor name) ~> Tree (Hor name)
 deriving syntax (tr) List(Ni, Fork) Unit(Unit)

data Tree' :: Tree d ~> * where
  In :: Tree' ()tr
  Fork :: Tree' head -> Tree' tail -> Tree' [head; tail]tr
  Done :: Tree' []tr
 deriving syntax (ar) List(Done, Fork) Unit(In)

data Stack :: Tree (d Tag) ~> Tree (e Nat) ~> * where
  Cell :: Stack ()tr ()tr
  NicheDone :: Stack ()tr []tr
  Niche :: Stack tr out -> Stack tr [out]tr
  Also :: Tree' at -> Stack tr out' -> Stack tr out -> Stack tr [out'; out]tr

 deriving syntax(z) Record(NicheDone, Also)