Changed default behavior of 'SIZEOF_NATIVE' on C++ targets.

Strict

Public

' Preprocessor related:
#SIZEOF_IMPLEMENTED = True

' By enabling this, you allow 'SizeOf' to be used with the standard 'DataBuffer' class.
#SIZEOF_DATABUFFER = True

#If LANG = "cpp"
	'#SIZEOF_NATIVE = True
#End

#If LANG = "cpp" And TARGET <> "win8" And TARGET <> "winrt"
	#SIZEOF_NORMAL_CPP_TARGET = True
#End

' Imports (Public):
'Import regal.vector

#If SIZEOF_NATIVE
	Import "native/sizes.${LANG}"
#End

' Imports (Private):
Private

#If SIZEOF_DATABUFFER
	Import brl.databuffer
#End

Public

' Global & Constant variable(s):

#Rem
	Please refrain from using these "constants" with your personal aliases.
	For example, you shouldn't do something like: "Const SizeOf_F:= SizeOf_FloatingPoint".
	If you must do this, please use a global variable as the "alias" (Could be slower).
	It's best not to bother with this, though, just use these variables directly.
	You could technically check against 'SIZEOF_NATIVE' with the preprocessor,
	but this may not be portable in the future.
#End

' Standard type sizes:
Const SizeOf_Octet:Int = 1
Const SizeOf_Octet_InBits:Int = 8

Const SizeOf_Byte:= SizeOf_Octet
Const SizeOf_Byte_InBits:= SizeOf_Octet_InBits

#If Not SIZEOF_NATIVE
	Const SizeOf_Integer:= 4 * SizeOf_Byte ' 8

	#If CPP_DOUBLE_PRECISION_FLOATS And SIZEOF_NORMAL_CPP_TARGET
		Const SizeOf_FloatingPoint:= 8 * SizeOf_Byte
	#Else
		Const SizeOf_FloatingPoint:= 4 * SizeOf_Byte
	#End

	Const SizeOf_Boolean:= SizeOf_Byte ' 1 ' 4

	Const SizeOf_Short:= 2 * SizeOf_Byte
	Const SizeOf_Long:= 8 * SizeOf_Byte
#Else
	' Global variable(s) (External):

	' Modifying these values is considered non-standard, and should not be attempted:
	Extern

	Global SizeOf_Integer:Int = "sizeof_int"
	Global SizeOf_FloatingPoint:Int = "sizeof_Float"
	Global SizeOf_Boolean:Int = "sizeof_boolean"

	Global SizeOf_Short:Int = "sizeof_short"
	Global SizeOf_Long:Int = "sizeof_long"

	Public
#End

#If SIZEOF_NATIVE And LANG = "cpp" And SIZEOF_NORMAL_CPP_TARGET
	' Global variable(s) (External):

	Extern

	' Modifying the value of this variable is considered non-standard, and should not be attempted.
	Global SizeOf_Char:Int = "sizeof_Char"

	Public
#Else
	Const SizeOf_Char:= SizeOf_Byte ' 1
#End

' Type sizes (In bits):
Global SizeOf_Char_InBits:= SizeOf_Char * SizeOf_Byte_InBits
Global SizeOf_Integer_InBits:= SizeOf_Integer * SizeOf_Byte_InBits
Global SizeOf_FloatingPoint_InBits:= SizeOf_FloatingPoint * SizeOf_Byte_InBits
Global SizeOf_Boolean_InBits:= SizeOf_Boolean * SizeOf_Byte_InBits ' SizeOf_Byte_InBits

Global SizeOf_Short_InBits:= SizeOf_Short * SizeOf_Byte_InBits
Global SizeOf_Long_InBits:= SizeOf_Long * SizeOf_Byte_InBits

' External bindings:
#If SIZEOF_NATIVE
	Extern

	#If LANG = "cpp"
		' Functions (Native):
		Function SizeOf:Int(I:Int)="(int)sizeof"
		Function SizeOf:Int(F:Float)="(int)sizeof"
		Function SizeOf:Int(B:Bool)="(int)sizeof"
	#Else
		' Nothing so far.
	#End

	Public
#End

' Functions (Monkey):

' This is mainly used for internal stream functionality in 'util'.
Function IntSize:Int(Size:Int)
	If (Size > 1) Then
		If (Size > 4) Then
			Return SizeOf_Long
		Elseif (Size < 4) Then
			Return SizeOf_Short
		Else
			Return SizeOf_Integer
		Endif
	Endif

	' Return the default response.
	Return SizeOf_Byte
End

#If Not SIZEOF_NATIVE
	Function SizeOf:Int(I:Int)
		Return SizeOf_Integer
	End

	Function SizeOf:Int(F:Float)
		Return SizeOf_FloatingPoint
	End

	Function SizeOf:Int(B:Bool)
		Return SizeOf_Boolean
	End
#End

#If Not MONKEYLANG_EXPLICIT_BOXES
	Function SizeOf:Int(IO:IntObject)
		Return SizeOf(IO.ToInt())
	End

	Function SizeOf:Int(FO:FloatObject)
		Return SizeOf(FO.ToFloat())
	End

	Function SizeOf:Int(BO:BoolObject)
		Return SizeOf(BO.ToBool())
	End

	Function SizeOf:Int(S:StringObject, IsString:Bool=True)
		Return SizeOf(S.ToString(), IsString)
	End
#End

Function SizeOf:Int(S:String, IsString:Bool=True)
	If (Not IsString) Then
		' Make the input-string upper-case.
		S = S.ToUpper()

		If (S.Find("INT") <> -1) Then
			Return SizeOf(0)
		Elseif (S.Find("FLOAT") <> -1) Then
			Return SizeOf(0.0)
		Elseif (S.Find("BOOL") <> -1) Then
			Return SizeOf(False)
		#Rem
			Elseif (S.Find("VEC") <> -1) Then
				Return Max(Int(S), 1)
		#End

		#Rem
			Elseif (S.Find("BYTE")) Then
				Return SizeOf_Byte
		#End
		Endif
	Endif

	' Return the default response.
	Return SizeOf_Char * S.Length()
End

#If SIZEOF_DATABUFFER
	Function SizeOf:Int(Data:DataBuffer)
		Return Data.Length()
	End
#End

Function InBits:Int(I:Int)
	Return SizeOf_Integer_InBits
End

Function InBits:Int(F:Float)
	Return SizeOf_FloatingPoint_InBits
End

Function InBits:Int(B:Bool)
	Return SizeOf_Boolean_InBits
End

Function InBits:Int(S:String, IsString:Bool=False)
	Local Output:= SizeOf(S, IsString)

	If (Not IsString) Then
		Return Output * SizeOf_Byte_InBits
	Endif

	Return Output * SizeOf_Char_InBits
End

Strict

Public

' Preprocessor related:
#SIZEOF_IMPLEMENTED = True

' By enabling this, you allow 'SizeOf' to be used with the standard 'DataBuffer' class.
#SIZEOF_DATABUFFER = True

#If LANG = "cpp"
	#SIZEOF_NATIVE = True
#End

#If LANG = "cpp" And TARGET <> "win8" And TARGET <> "winrt"
	#SIZEOF_NORMAL_CPP_TARGET = True
#End

' Imports (Public):
'Import regal.vector

#If SIZEOF_NATIVE
	Import "native/sizes.${LANG}"
#End

' Imports (Private):
Private

#If SIZEOF_DATABUFFER
	Import brl.databuffer
#End

Public

' Global & Constant variable(s):

#Rem
	Please refrain from using these "constants" with your personal aliases.
	For example, you shouldn't do something like: "Const SizeOf_F:= SizeOf_FloatingPoint".
	If you must do this, please use a global variable as the "alias" (Could be slower).
	It's best not to bother with this, though, just use these variables directly.
	You could technically check against 'SIZEOF_NATIVE' with the preprocessor,
	but this may not be portable in the future.
#End

' Standard type sizes:
Const SizeOf_Octet:Int = 1
Const SizeOf_Octet_InBits:Int = 8

Const SizeOf_Byte:= SizeOf_Octet
Const SizeOf_Byte_InBits:= SizeOf_Octet_InBits

#If Not SIZEOF_NATIVE
	Const SizeOf_Integer:= 4 * SizeOf_Byte ' 8

	#If CPP_DOUBLE_PRECISION_FLOATS And SIZEOF_NORMAL_CPP_TARGET
		Const SizeOf_FloatingPoint:= 8 * SizeOf_Byte
	#Else
		Const SizeOf_FloatingPoint:= 4 * SizeOf_Byte
	#End

	Const SizeOf_Boolean:= SizeOf_Byte ' 1

	Const SizeOf_Short:= 2 * SizeOf_Byte
	Const SizeOf_Long:= 8 * SizeOf_Byte
#Else
	' Global variable(s) (External):

	' Modifying these values is considered non-standard, and should not be attempted:
	Extern

	Global SizeOf_Integer:Int = "sizeof_int"
	Global SizeOf_FloatingPoint:Int = "sizeof_Float"
	Global SizeOf_Boolean:Int = "sizeof_boolean"

	Global SizeOf_Short:Int = "sizeof_short"
	Global SizeOf_Long:Int = "sizeof_long"

	Public
#End

#If SIZEOF_NATIVE And LANG = "cpp" And SIZEOF_NORMAL_CPP_TARGET
	' Global variable(s) (External):

	Extern

	' Modifying the value of this variable is considered non-standard, and should not be attempted.
	Global SizeOf_Char:Int = "sizeof_Char"

	Public
#Else
	Const SizeOf_Char:= SizeOf_Byte ' 1
#End

' Type sizes (In bits):
Global SizeOf_Char_InBits:= SizeOf_Char * SizeOf_Byte_InBits
Global SizeOf_Integer_InBits:= SizeOf_Integer * SizeOf_Byte_InBits
Global SizeOf_FloatingPoint_InBits:= SizeOf_FloatingPoint * SizeOf_Byte_InBits
Global SizeOf_Boolean_InBits:= SizeOf_Boolean * SizeOf_Byte_InBits ' SizeOf_Byte_InBits

Global SizeOf_Short_InBits:= SizeOf_Short * SizeOf_Byte_InBits
Global SizeOf_Long_InBits:= SizeOf_Long * SizeOf_Byte_InBits

' External bindings:
#If SIZEOF_NATIVE
	Extern

	#If LANG = "cpp"
		' Functions (Native):
		Function SizeOf:Int(I:Int)="(int)sizeof"
		Function SizeOf:Int(F:Float)="(int)sizeof"
		Function SizeOf:Int(B:Bool)="(int)sizeof"
	#Else
		' Nothing so far.
	#End

	Public
#End

' Functions (Monkey):

' This is mainly used for internal stream functionality in 'util'.
Function IntSize:Int(Size:Int)
	If (Size > 1) Then
		If (Size > 4) Then
			Return SizeOf_Long
		Elseif (Size < 4) Then
			Return SizeOf_Short
		Else
			Return SizeOf_Integer
		Endif
	Endif

	' Return the default response.
	Return SizeOf_Byte
End

#If Not SIZEOF_NATIVE
	Function SizeOf:Int(I:Int)
		Return SizeOf_Integer
	End

	Function SizeOf:Int(F:Float)
		Return SizeOf_FloatingPoint
	End

	Function SizeOf:Int(B:Bool)
		Return SizeOf_Boolean
	End
#End

#If Not MONKEYLANG_EXPLICIT_BOXES
	Function SizeOf:Int(IO:IntObject)
		Return SizeOf(IO.ToInt())
	End

	Function SizeOf:Int(FO:FloatObject)
		Return SizeOf(FO.ToFloat())
	End

	Function SizeOf:Int(BO:BoolObject)
		Return SizeOf(BO.ToBool())
	End

	Function SizeOf:Int(S:StringObject, IsString:Bool=True)
		Return SizeOf(S.ToString(), IsString)
	End
#End

Function SizeOf:Int(S:String, IsString:Bool=True)
	If (Not IsString) Then
		' Make the input-string upper-case.
		S = S.ToUpper()

		If (S.Find("INT") <> -1) Then
			Return SizeOf(0)
		Elseif (S.Find("FLOAT") <> -1) Then
			Return SizeOf(0.0)
		Elseif (S.Find("BOOL") <> -1) Then
			Return SizeOf(False)
		#Rem
			Elseif (S.Find("VEC") <> -1) Then
				Return Max(Int(S), 1)
		#End

		#Rem
			Elseif (S.Find("BYTE")) Then
				Return SizeOf_Byte
		#End
		Endif
	Endif

	' Return the default response.
	Return SizeOf_Char * S.Length()
End

#If SIZEOF_DATABUFFER
	Function SizeOf:Int(Data:DataBuffer)
		Return Data.Length()
	End
#End

Function InBits:Int(I:Int)
	Return SizeOf_Integer_InBits
End

Function InBits:Int(F:Float)
	Return SizeOf_FloatingPoint_InBits
End

Function InBits:Int(B:Bool)
	Return SizeOf_Boolean_InBits
End

Function InBits:Int(S:String, IsString:Bool=False)
	Local Output:= SizeOf(S, IsString)

	If (Not IsString) Then
		Return Output * SizeOf_Byte_InBits
	Endif

	Return Output * SizeOf_Char_InBits
End


Added IntToRoman and RomanToInt functions.

#Rem
Copyright (c) 2011 Steve Revill and Shane Woolcock
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#End

Function LinearTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	Return diff * t / d + b
End

Function QuadTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d / 2
	If t < 1 Return diff / 2 * t * t + b
	t -= 1
	Return -diff / 2 * (t * (t - 2) - 1) + b
End

Function QuinticTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d / 2
	If (t < 1) Return diff / 2 * t * t * t * t * t + b
	t -= 2
	Return diff / 2 * (t * t * t * t * t + 2) + b
End

Function TweenCalc:Float(p1:Float, p2:Float, t:Float)
	Return p1 + t * (p2 - p1)
End

Function TweenSmooth:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	Return p1 + v * (p2 - p1)
End

Function SmoothStep:Float(x:Float, interpSmooth:Int = 1)
	For Local i:Int = 0 Until interpSmooth
		x *= x * (3 - 2 * x)
	Next

	Return x
End

Function TweenUp:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	v = Pow(v, 2) 'power of 2.
	Return p1 + v * (p2 - p1)
End

Function TweenDown:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	v = 1 - Pow(1 - v, 2) 'InvSquared
	Return p1 + v * (p2 - p1)
End

Function Bezier:Float(p1:Float, p2:Float, cp1:Float, cp2:Float, t:Float)
	Local v:Float = p1 * Pow( (1 - t), 3) + 3 * cp1 * Pow( (1 - t), 2) * t + 3 * cp2 * (1 - t) * Pow(t, 2) + p2 * Pow(t, 3)
	Return v
End

Function EaseInBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	Return diff - EaseOutBounceTween(d - t, 0, diff, d) + b
End

Function EaseOutBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d
	If (t < (1 / 2.75))
		Return diff * (7.5625 * t * t) + b
	ElseIf(t < (2 / 2.75))
		t -= (1.5 / 2.75)
		Return diff * (7.5625 * t * t + 0.75) + b
	ElseIf(t < (2.5 / 2.75))
		t -= (2.25 / 2.75)
		Return diff * (7.5625 * t * t + 0.9375) + b
	Else
		t -= (2.625 / 2.75)
		Return diff * (7.5625 * t * t + 0.984375) + b
	End
End

Function EaseInOutBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	If (t < d / 2)
		Return EaseInBounceTween(t * 2, 0, diff, d) * 0.5 + b
	End
	Return EaseOutBounceTween(t * 2 - d, 0, diff, d) * 0.5 + diff * 0.5 + b
End

Function BackEaseInTween:Float(b:Float, c:Float, t:Float, d:Float = 1, s:Float = 2)
	Local diff:Float = c - b
	t /= d
	Return diff * t * t * ( (s + 1) * t - s) + b
End

Function BackEaseOutTween:Float(b:Float, c:Float, t:Float, d:Float = 1, s:Float = 2)
	Local diff:Float = c - b
	t = t / d - 1
	Return diff * (t * t * ( (s + 1) * t + s) + 1) + b
End

Function BackEaseInOutTween:Float(b:Float, c:Float, t:Float, d:Float = 1, s:Float = 2)
	Local diff:Float = c - b
	Local s2:Float = s
	t /= d / 2
	s2 *= 1.525
	If t < 1
		Return diff / 2 * (t * t * ( (s2 + 1) * t - s2)) + b
	End
	t -= 2
	Return diff / 2 * (t * t * ( (s2 + 1) * t + s2) + 2) + b
End

Function IntToRoman:String(input:Int)
	Local s:String = ""
    While input >= 1000
        s += "M"
        input -= 1000
	End
    While input >= 900
        s += "CM"
        input -= 900
	End
    While input >= 500
        s += "D"
        input -= 500
    End
    While input >= 400
        s += "CD"
        input -= 400
    End
    While input >= 100
        s += "C"
        input -= 100
    End
    While input >= 90
        s += "XC"
        input -= 90
    End
    While input >= 50
        s += "L"
        input -= 50
    End
    While input >= 40
        s += "XL"
        input -= 40
    End
    While input >= 10
        s += "X"
        input -= 10
    End
    While input >= 9
        s += "IX"
        input -= 9
    End
    While input >= 5
        s += "V"
        input -= 5
    End
    While input >= 4
        s += "IV"
        input -= 4
    End
    While input >= 1
        s += "I"
        input -= 1
    End
    Return s
End

Function RomanToInt:Int(input:String)
	Local last:Int = 1
	Local this:Int = 1
	Local rv:Int = 0
	For Local i:Int = input.Length-1 To 0 Step -1
		last = this
		Select input[i]
			Case "I"[0]
				this = 1
			Case "V"[0]
				this = 5
			Case "X"[0]
				this = 10
			Case "L"[0]
				this = 50
			Case "C"[0]
				this = 100
			Case "D"[0]
				this = 500
			Case "M"[0]
				this = 1000
		End
		If last > this Then rv -= this Else rv += this
	Next
	Return rv
End

Class RandomSource
Private
	Field currentSeed:Int
	Field snapshotSeed:Int

	Method NextRnd:Float()
		' cache global seed
		Local lastSeed:Int = Seed
		' update it to be ours if it's not the system one
		If Self <> SystemSource Then Seed = Self.currentSeed
		' call global Rnd function
		Local thisRnd:Float = Rnd()
		' update our seed
		Self.currentSeed = Seed
		' reset global seed if it's not the system one
		If Self <> SystemSource Then Seed = lastSeed
		' return the random float
		Return thisRnd
	End

Public
	Global SystemSource:RandomSource = New RandomSource

	Method CurrentSeed:Int() Property Return currentSeed End
	Method CurrentSeed:Void(currentSeed:Int) Property Self.currentSeed = currentSeed End

	Method New()
		currentSeed = Seed
		snapshotSeed = currentSeed
	End

	Method New(seed:Int)
		currentSeed = seed
		snapshotSeed = currentSeed
	End

	Method New(other:RandomSource)
		currentSeed = other.CurrentSeed
		snapshotSeed = currentSeed
	End

	Method NextInt:Int()
		Return (NextInt($10000) Shl 16) | NextInt($10000)
	End

	Method NextInt:Int(n:Int)
		Return Int(NextRnd() * n)
	End

	Method NextInt:Int(low:Int, high:Int)
		Return low + Int(NextRnd() * (high-low+1))
	End

	Method NextFloat:Float()
		Return NextRnd()
	End

	Method NextBool:Bool()
		Return NextRnd() >= 0.5
	End

	Method Snapshot:Void()
		snapshotSeed = currentSeed
	End

	Method Rollback:Void()
		currentSeed = snapshotSeed
	End
End

#Rem
Copyright (c) 2011 Steve Revill and Shane Woolcock
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#End

Function LinearTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	Return diff * t / d + b
End

Function QuadTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d / 2
	If t < 1 Return diff / 2 * t * t + b
	t -= 1
	Return -diff / 2 * (t * (t - 2) - 1) + b
End

Function QuinticTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d / 2
	If (t < 1) Return diff / 2 * t * t * t * t * t + b
	t -= 2
	Return diff / 2 * (t * t * t * t * t + 2) + b
End

Function TweenCalc:Float(p1:Float, p2:Float, t:Float)
	Return p1 + t * (p2 - p1)
End

Function TweenSmooth:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	Return p1 + v * (p2 - p1)
End

Function SmoothStep:Float(x:Float, interpSmooth:Int = 1)
	For Local i:Int = 0 Until interpSmooth
		x *= x * (3 - 2 * x)
	Next

	Return x
End

Function TweenUp:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	v = Pow(v, 2) 'power of 2.
	Return p1 + v * (p2 - p1)
End

Function TweenDown:Float(p1:Float, p2:Float, t:Float)
	Local v:Float = SmoothStep(t)
	v = 1 - Pow(1 - v, 2) 'InvSquared
	Return p1 + v * (p2 - p1)
End

Function Bezier:Float(p1:Float, p2:Float, cp1:Float, cp2:Float, t:Float)
	Local v:Float = p1 * Pow( (1 - t), 3) + 3 * cp1 * Pow( (1 - t), 2) * t + 3 * cp2 * (1 - t) * Pow(t, 2) + p2 * Pow(t, 3)
	Return v
End

Function EaseInBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	Return diff - EaseOutBounceTween(d - t, 0, diff, d) + b
End

Function EaseOutBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	t /= d
	If (t < (1 / 2.75))
		Return diff * (7.5625 * t * t) + b
	ElseIf(t < (2 / 2.75))
		t -= (1.5 / 2.75)
		Return diff * (7.5625 * t * t + 0.75) + b
	ElseIf(t < (2.5 / 2.75))
		t -= (2.25 / 2.75)
		Return diff * (7.5625 * t * t + 0.9375) + b
	Else
		t -= (2.625 / 2.75)
		Return diff * (7.5625 * t * t + 0.984375) + b
	End
End

Function EaseInOutBounceTween:Float(b:Float, c:Float, t:Float, d:Float = 1)
	Local diff:Float = c - b
	If (t < d / 2)
		Return EaseInBounceTween(t * 2, 0, diff, d) * 0.5 + b
	End
	Return EaseOutBounceTween(t * 2 - d, 0, diff, d) * 0.5 + diff * 0.5 + b
End

Function BackEaseInTween:Float(b:Float, c:Float, t:Float, d:Float = 1, s:Float = 2)
	Local diff:Float = c - b
	t /= d
	Return diff * t * t * ( (s + 1) * t - s) + b
End

Function BackEaseOutTween:Float(b:Float, c:Float, t:Float, d:Float = 1, s:Float = 2)
	Local diff:Float = c - b
	t = t / d - 1
	Return diff * (t * t * ( (s + 1) * t + s) + 1) + b
End

Function BackEaseInOutTween:Float(b:Float, c:Float, t:Float, d:Float = 1, s:Float = 2)
	Local diff:Float = c - b
	Local s2:Float = s
	t /= d / 2
	s2 *= 1.525
	If t < 1
		Return diff / 2 * (t * t * ( (s2 + 1) * t - s2)) + b
	End
	t -= 2
	Return diff / 2 * (t * t * ( (s2 + 1) * t + s2) + 2) + b
End

Class RandomSource
Private
	Field currentSeed:Int
	Field snapshotSeed:Int

	Method NextRnd:Float()
		' cache global seed
		Local lastSeed:Int = Seed
		' update it to be ours if it's not the system one
		If Self <> SystemSource Then Seed = Self.currentSeed
		' call global Rnd function
		Local thisRnd:Float = Rnd()
		' update our seed
		Self.currentSeed = Seed
		' reset global seed if it's not the system one
		If Self <> SystemSource Then Seed = lastSeed
		' return the random float
		Return thisRnd
	End

Public
	Global SystemSource:RandomSource = New RandomSource

	Method CurrentSeed:Int() Property Return currentSeed End
	Method CurrentSeed:Void(currentSeed:Int) Property Self.currentSeed = currentSeed End

	Method New()
		currentSeed = Seed
		snapshotSeed = currentSeed
	End

	Method New(seed:Int)
		currentSeed = seed
		snapshotSeed = currentSeed
	End

	Method New(other:RandomSource)
		currentSeed = other.CurrentSeed
		snapshotSeed = currentSeed
	End

	Method NextInt:Int()
		Return (NextInt($10000) Shl 16) | NextInt($10000)
	End

	Method NextInt:Int(n:Int)
		Return Int(NextRnd() * n)
	End

	Method NextInt:Int(low:Int, high:Int)
		Return low + Int(NextRnd() * (high-low+1))
	End

	Method NextFloat:Float()
		Return NextRnd()
	End

	Method NextBool:Bool()
		Return NextRnd() >= 0.5
	End

	Method Snapshot:Void()
		snapshotSeed = currentSeed
	End

	Method Rollback:Void()
		currentSeed = snapshotSeed
	End
End


New method SceneManager.Get() added

New method SceneManager.Get() added

Strict

Private

Import scene

Public

Class SceneManager
    Private

    Field scenes:StringMap<Scene> = New StringMap<Scene>
    Field nextScene_:Scene
    Field current_:Scene

    Public

    Method nextScene:Scene() Property
        Return nextScene_
    End

    Method current:Scene() Property
        Return current_
    End

    Method Add:Void(scene:Scene)
        If scenes.IsEmpty()
            current_ = scene
        ElseIf scenes.Contains(scene.name)
            Error("Scenemanager already contains a scene name " + scene.name)
        End

        scenes.Set(scene.name, scene)
    End

    Method Get:Scene(name:String)
        Return scenes.Get(name)
    End

    Method Goto:Void(name:String)
        If nextScene_ And nextScene_.name = name Then Return
        nextScene_ = scenes.Get(name)

        If Not nextScene_.created
            nextScene_.OnCreate()
            nextScene_.created = True
        End

        If current_ Then current_.OnLeave()
        nextScene_.OnEnter()

        current_ = nextScene_
    End
End

Strict

Private

Import scene

Public

Class SceneManager
    Private

    Field scenes:StringMap<Scene> = New StringMap<Scene>
    Field nextScene_:Scene
    Field current_:Scene

    Public

    Method nextScene:Scene() Property
        Return nextScene_
    End

    Method current:Scene() Property
        Return current_
    End

    Method Add:Void(scene:Scene)
        If scenes.IsEmpty()
            current_ = scene
        ElseIf scenes.Contains(scene.name)
            Error("Scenemanager already contains a scene name " + scene.name)
        End

        scenes.Set(scene.name, scene)
    End

    Method Goto:Void(name:String)
        If nextScene_ And nextScene_.name = name Then Return
        nextScene_ = scenes.Get(name)

        If Not nextScene_.created
            nextScene_.OnCreate()
            nextScene_.created = True
        End

        If current_ Then current_.OnLeave()
        nextScene_.OnEnter()

        current_ = nextScene_
    End
End


Added i18n to main diddy import.

Added i18n to main diddy import.

'
' Module diddy.diddy
'
Import mojo
Import functions
Import framework
Import inputcache
Import tween
Import collections
Import assert
Import gui
Import simplegui
Import serialization
Import xml
Import io
Import tile
Import font
Import filesystem
Import i18n


update maniac Main Filde

update maniac Main Filde

added some Global Graphic-Image Stuff

#Rem monkeydoc Module maniac
	Copyright (C) 2015  Stephan Duckerschein~n
	This Framework provides many additional Graphical Effects and primite Drawings, like unfilled rectangular , ellipsis etc. Diverse GUI Elements.~n
	It has it's own TileMap Engine included and even a Debug Tracking-System. ~n
	~n
	Installation:~n
	to use this Module, you have to Copy the "lib/" Folder data to Your App's Data.~n
	~n
	In the following is an Example, how to Include the maniac Framework to your Monkey Project.~n
Example:
<pre>
'This Example Shows how to integrate the Maniac-Framework to your App

'1. First You have to Import the Libs
import mojo
import maniac

'2. Main Function and App extending Class
Function Main:Int()
	New Example
	Return 0
End

Class Example extends App
	Method OnCreate:Int()
		SetUpdateRate( 60 )
		initManiac()			' THIS INITS THE MANIAC FRAMEWORK! THIS NEED TO BE DONE BEFORE USING IT!!!!!
	end Method

	Method OnUpdate:int()

	end method

	Method OnRender:int()
		Cls
	end Method
End class
</pre>

~n
Featurelist:
	GUI: - Textfield, Button, Dialog, GalleryViewer, Slider, DropDown, ListView, Checkbox ~n
	Graphics: - Outlined: Rect, Ellipsis ; LighningFX, Grid ~n
	TileMap: TileMapEngine featuring an Editor~n
	Font: Including a Font~n

#End

#rem
 <The Duke Game Framework. It provides useful little helperfunctions and class to develope 2D Games with Monkey X>
    Copyright (C) 2014-2015  Stephan Duckerschein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #end

#rem
	The main Aim is to provide a wideranged kit for developing games with Monkey X.
	It tries to be as lightweight as possible.
	And it should be usable without changeging the mojo framework.

	Features:
		DebugSystem: It tracks all used Elements from Maniac within the DebugClass.
		So you can easily monitor your Objects.
#end

#rem
	TO DO FEATURES:
		- Include Async Loader for the Images
		- make the including Paths to Files configurable by including an config.ini file to define them ...
#end

#rem
	Importing the Module-Parts of the maniac Framework.
#end

Import maniacLowLevel			'325		364
Import maniacFont				'249
'Import maniacDebug				'334
Import maniacGraphics			'686		763
Import maniacMisc				'248
Import maniacSimpleGUI			'1214		1515
Import maniacTween				'667
Import maniacMap				'168
Import maniacWIP
Import maniacSort
Import maniacSpline

#rem
	These are all global accessable Objects to your project.They will be initialised automatically within the initManiac() Method.
#end
Global MANIAC_FONT:ManiacFont
Global MANIAC_IMG_LOGO:Image
Global MANIAC_IMG_STAR:Image
Global MANIAC_IMG_STARBLUR:Image
Global MANIAC_IMG_BACKGROUND:Image
Global MANIAC_IMG_FRAME_RAW:Image 		' ## DEPRECATED, this global will be removed in next Version
Global MANIAC_IMG_FRAME_RECT2:Image		'
Global MANIAC_IMG_FRAME_ROUND1:Image
Global MANIAC_IMG_FRAME_ROUND2:Image
Global MANIAC_IMG_FRAME_ROUND3:Image
Global MANIAC_IMG_FRAME_BLUR:Image
Global MANIAC_IMG_FRAME_SMOOTHRECT:Image
Global MANIAC_IMG_FRAME_SMOOTHRECTBLUR:Image
Global MANIAC_IMG_BG_ROUND1:Image
Global MANIAC_IMG_BG_ROUND2:Image
Global MANIAC_IMG_BG_ROUND3:Image
Global MANIAC_IMG_BG_SMOOTHRECT:Image
Global MANIAC_IMG_SLIDERLINE:Image
Global MANIAC_IMG_SLIDERPICKER:Image
Global MANIAC_IMG_EDITICON:Image
Global MANIAC_IMG_CHECK:Image
Global MANIAC_IMG_DROPDOWN:Image
Global MANIAC_IMG_ARROWDOWN:Image
Global MANIAC_CHARACTERSCOUNT:Int = 30

#rem
	Here are the Paths to the Included Images for this Framework
	At the moment theyre not used.
	Future Feature: Set them up via a config.ini file or something.
#end
Global MANIAC_PATH_LOGO:String						= "lib/logo.png"
Global MANIAC_PATH_STAR:String						= "lib/star.png"
Global MANIAC_PATH_STARBLUR:String
Global MANIAC_PATH_BACKGROUND:String  				= "lib/Hintergrund.png"
Global MANIAC_PATH_FRAME_RECT:String
Global MANIAC_PATH_FRSME_RECTBLUR:String
Global MANIAC_PATH_FRAME_RECTROUND:String
Global MANIAC_PATH_FRAME_RECTROUNDBLUR:String
Global MANIAC_PATH_FRAME_CIRCLE:String
Global MANIAC_PATH_FRAME_CIRCLEBLUR:String
Global MANIAC_PATH_ICO_EDIT:String
Global MANIAC_PATH_ICO_CHECK:String
Global MANIAC_PATH_ICO_DROPDOWN_ARROW:String
Global MANIAC_PATH_ICO_ARROWDOWN:String
Global MANIAC_PATH_ICO_SLIDERLINE:String
Global MANIAC_PATH_ICO_SLIDERPICKER:String

Const FPSGRAPH_OFF:Int = 0
Const FPSGRAPH_FPS_ONLY:Int = 1
Const FPSGRAPH_GRAPH:Int = 2

Global MANIAC_FPSGRAPH:Maniac_Debug' = New fpsCounter
Global MODULE_INITED_CORRECT:Bool 		'if false, the whole Maniac-Module uses a fallback Drawings-Stuff

Global DW:Float,DH:Float,MX:Float,MY:Float
'Mouse Button States
Global gl_clicked:Bool
Global gl_mousereleased:Bool

Global MANIAC_DEBUG:Bool = False
Global MANIAC_LOADASYNC:Bool = False 		'## RECOMMEND: SET ON FALSE, as there is no Async Loader included @ the moment !!!

Global maniac_lastTime:Int
Global maniac_timeScale:Float

#Rem monkeydoc
	This Function Inits this Module.
	It Loads all necessary Images and Sounds and stuff from the lib/ folder.
	if No Images were found, it falls back to a "at least running without any Image" mode. so it just shows up, that there are Graphics missing
#End
Function initManiac(_Debug:Bool = False)
	MANIAC_DEBUG = _Debug
	DW = DeviceWidth()
	DH = DeviceHeight()
	MODULE_INITED_CORRECT = True

	If MANIAC_LOADASYNC = False
		MANIAC_FONT = New ManiacFont(22,27,["lib/font2.png"],[[32,5,27,0,0,0,0,0,0,19],[33,5,27,0,393,46,7,18,-1,4],[34,9,27,0,122,99,10,10,-1,3],[35,15,27,0,51,66,17,17,-1,5],[36,16,27,0,478,0,18,22,-1,2],[37,20,27,0,332,25,21,21,-1,2],[38,16,27,0,34,66,17,17,-1,5],[39,5,27,0,116,99,6,10,-1,3],[40,9,27,0,89,0,11,24,-1,2],[41,9,27,0,78,0,11,24,-1,2],[42,14,27,0,378,46,15,18,-1,4],[43,12,27,0,386,83,14,14,-1,6],[44,6,27,0,109,99,7,10,-1,14],[45,10,27,0,174,99,12,7,-1,10],[46,5,27,0,219,99,6,6,-1,15],[47,12,27,0,366,25,13,21,-1,2],[48,18,27,0,24,83,19,16,-1,5],[49,12,27,0,60,83,14,16,-1,5],[50,14,27,0,171,83,15,15,-1,6],[51,16,27,0,154,83,17,15,-1,6],[52,15,27,0,154,66,17,17,-1,5],[53,15,27,0,138,66,16,17,-1,5],[54,16,27,0,121,66,17,17,-1,5],[55,13,27,0,106,66,15,17,-1,5],[56,15,27,0,89,66,17,17,-1,5],[57,15,27,0,43,83,17,16,-1,6],[58,5,27,0,424,83,6,14,-1,7],[59,6,27,0,68,66,7,17,-1,7],[60,10,27,0,412,83,12,14,-1,7],[61,14,27,0,79,99,16,11,-1,7],[62,10,27,0,400,83,12,14,-1,7],[63,13,27,0,75,66,14,17,-1,5],[64,21,27,0,14,46,22,20,-1,6],[65,17,27,0,461,66,18,17,-1,5],[66,14,27,0,446,66,15,17,-1,5],[67,15,27,0,430,66,16,17,-1,5],[68,15,27,0,414,66,16,17,-1,5],[69,14,27,0,399,66,15,17,-1,5],[70,13,27,0,385,66,14,17,-1,5],[71,15,27,0,369,66,16,17,-1,5],[72,14,27,0,353,66,16,17,-1,5],[73,11,27,0,142,83,12,16,-1,6],[74,15,27,0,126,83,16,16,-1,5],[75,14,27,0,337,66,16,17,-1,5],[76,14,27,0,322,66,15,17,-1,5],[77,17,27,0,304,66,18,17,-1,5],[78,15,27,0,287,66,17,17,-1,5],[79,18,27,0,107,83,19,16,-1,5],[80,15,27,0,416,46,16,18,-1,4],[81,18,27,0,268,66,19,17,-1,5],[82,15,27,0,400,46,16,18,-1,4],[83,16,27,0,250,66,18,17,-1,5],[84,15,27,0,319,83,16,15,-1,6],[85,15,27,0,90,83,17,16,-1,5],[86,16,27,0,233,66,17,17,-1,5],[87,16,27,0,215,66,18,17,-1,5],[88,15,27,0,199,66,16,17,-1,5],[89,14,27,0,184,66,15,17,-1,5],[90,15,27,0,74,83,16,16,-1,5],[91,9,27,0,67,0,11,24,-1,2],[92,12,27,0,353,25,13,21,-1,2],[93,9,27,0,56,0,11,24,-1,2],[94,12,27,0,26,99,13,12,-1,2],[95,15,27,0,203,99,16,6,-1,20],[96,7,27,0,141,99,8,9,-1,3],[97,14,27,0,304,83,15,15,-1,7],[98,12,27,0,287,46,13,19,-1,3],[99,12,27,0,472,83,13,14,-1,7],[100,12,27,0,70,46,14,20,-1,2],[101,13,27,0,290,83,14,15,-1,7],[102,12,27,0,274,46,13,19,-1,3],[103,13,27,0,260,46,14,19,-1,7],[104,13,27,0,246,46,14,19,-1,3],[105,5,27,0,239,46,7,19,-1,3],[106,5,27,0,315,0,7,23,-1,3],[107,12,27,0,56,46,14,20,-1,2],[108,5,27,0,50,46,6,20,-1,2],[109,16,27,0,272,83,18,15,-1,7],[110,13,27,0,258,83,14,15,-1,7],[111,12,27,0,458,83,14,14,-1,7],[112,12,27,0,36,46,14,20,-1,7],[113,13,27,0,225,46,14,19,-1,7],[114,10,27,0,246,83,12,15,-1,7],[115,13,27,0,232,83,14,15,-1,7],[116,12,27,0,171,66,13,17,-1,4],[117,12,27,0,218,83,14,15,-1,7],[118,13,27,0,443,83,15,14,-1,7],[119,16,27,0,200,83,18,15,-1,7],[120,13,27,0,186,83,14,15,-1,7],[121,13,27,0,211,46,14,19,-1,7],[122,12,27,0,430,83,13,14,-1,8],[123,12,27,0,28,0,14,25,-1,2],[124,5,27,0,309,0,6,23,-1,3],[125,12,27,0,14,0,14,25,-1,2],[126,15,27,0,157,99,17,8,-1,10],[127,13,27,0,0,46,14,20,-1,3],[161,5,27,0,371,46,7,18,-1,9],[162,12,27,0,465,0,13,22,-1,3],[163,14,27,0,18,66,16,17,-1,5],[164,16,27,0,0,66,18,17,-1,4],[165,14,27,0,481,46,15,17,-1,5],[166,5,27,0,303,0,6,23,-1,3],[167,13,27,0,317,25,15,21,-1,5],[168,9,27,0,192,99,11,6,-1,5],[169,21,27,0,189,46,22,19,-1,5],[170,13,27,0,65,99,14,11,-1,5],[171,17,27,0,368,83,18,14,-1,7],[172,12,27,0,95,99,14,10,-1,10],[174,21,27,0,167,46,22,19,-1,5],[176,12,27,0,52,99,13,11,-1,4],[177,13,27,0,357,46,14,18,-1,4],[178,12,27,0,0,99,13,13,-1,4],[179,12,27,0,13,99,13,12,-1,5],[180,8,27,0,132,99,9,9,-1,3],[181,14,27,0,152,46,15,19,-1,7],[182,18,27,0,297,25,20,21,-1,4],[183,5,27,0,186,99,6,6,-1,10],[184,7,27,0,149,99,8,8,-1,17],[185,7,27,0,498,83,8,13,-1,5],[186,11,27,0,39,99,13,11,-1,5],[187,17,27,0,350,83,18,14,-1,7],[188,17,27,0,278,25,19,21,-1,2],[189,18,27,0,259,25,19,21,-1,2],[190,18,27,0,239,25,20,21,-1,2],[191,13,27,0,467,46,14,17,-1,10],[192,17,27,0,285,0,18,23,-1,-1],[193,17,27,0,267,0,18,23,-1,-1],[194,17,27,0,249,0,18,23,-1,-1],[195,17,27,0,447,0,18,22,-1,0],[196,17,27,0,221,25,18,21,-1,1],[197,17,27,0,231,0,18,23,-1,-1],[198,22,27,0,0,83,24,16,-1,6],[199,15,27,0,486,25,16,20,-1,5],[200,14,27,0,216,0,15,23,-1,-1],[201,14,27,0,201,0,15,23,-1,-1],[202,14,27,0,186,0,15,23,-1,-1],[203,14,27,0,206,25,15,21,-1,1],[204,11,27,0,174,0,12,23,-1,-1],[205,11,27,0,162,0,12,23,-1,-1],[206,12,27,0,148,0,14,23,-1,-1],[207,11,27,0,194,25,12,21,-1,1],[208,17,27,0,448,46,19,17,-1,5],[209,15,27,0,430,0,17,22,-1,0],[210,18,27,0,411,0,19,22,-1,-1],[211,18,27,0,392,0,19,22,-1,-1],[212,18,27,0,373,0,19,22,-1,-1],[213,18,27,0,175,25,19,21,-1,0],[214,18,27,0,467,25,19,20,-1,1],[215,12,27,0,485,83,13,13,-1,7],[216,18,27,0,129,0,19,23,-1,2],[217,15,27,0,356,0,17,22,-1,-1],[218,15,27,0,339,0,17,22,-1,-1],[219,15,27,0,322,0,17,22,-1,-1],[220,15,27,0,450,25,17,20,-1,1],[221,14,27,0,114,0,15,23,-1,-1],[222,14,27,0,432,46,16,17,-1,5],[223,14,27,0,342,46,15,18,-1,4],[224,14,27,0,160,25,15,21,-1,1],[225,14,27,0,145,25,15,21,-1,1],[226,14,27,0,130,25,15,21,-1,1],[227,14,27,0,435,25,15,20,-1,2],[228,14,27,0,137,46,15,19,-1,3],[229,14,27,0,115,25,15,21,-1,1],[230,21,27,0,479,66,23,16,-1,6],[231,12,27,0,329,46,13,18,-1,7],[232,13,27,0,101,25,14,21,-1,1],[233,13,27,0,87,25,14,21,-1,1],[234,13,27,0,72,25,15,21,-1,1],[235,13,27,0,123,46,14,19,-1,3],[236,7,27,0,64,25,8,21,-1,1],[237,8,27,0,55,25,9,21,-1,1],[238,11,27,0,42,25,13,21,-1,1],[239,9,27,0,112,46,11,19,-1,3],[240,14,27,0,314,46,15,18,-1,3],[241,13,27,0,421,25,14,20,-1,2],[242,12,27,0,407,25,14,20,-1,1],[243,12,27,0,393,25,14,20,-1,1],[244,12,27,0,379,25,14,20,-1,1],[245,12,27,0,98,46,14,19,-1,2],[246,12,27,0,300,46,14,18,-1,3],[247,14,27,0,335,83,15,14,-1,5],[248,12,27,0,28,25,14,21,-1,4],[249,12,27,0,14,25,14,21,-1,1],[250,12,27,0,0,25,14,21,-1,1],[251,12,27,0,496,0,14,21,-1,1],[252,12,27,0,84,46,14,19,-1,3],[253,13,27,0,0,0,14,25,-1,1],[254,12,27,0,42,0,14,24,-1,3],[255,13,27,0,100,0,14,23,-1,3]])
		MANIAC_IMG_BACKGROUND = LoadImage("lib/Hintergrund.png")
		MANIAC_IMG_STAR = LoadImage("lib/star.png")
		MANIAC_IMG_LOGO = LoadImage("lib/logo.png")
		MANIAC_IMG_FRAME_RAW = LoadImage("lib/Button/Frame_Round3.png",1,Image.MidHandle)
		MANIAC_IMG_FRAME_RECT2	= LoadImage("lib/Button/Frame_Rect2.png",1,Image.MidHandle)
		MANIAC_IMG_FRAME_ROUND1	= LoadImage("lib/Button/Frame_Round1.png",1,Image.MidHandle)
		MANIAC_IMG_FRAME_ROUND2	= LoadImage("lib/Button/Frame_Round2.png",1,Image.MidHandle)
		MANIAC_IMG_FRAME_ROUND3 = LoadImage("lib/Button/Frame_Round3.png",1,Image.MidHandle)
		MANIAC_IMG_BG_SMOOTHRECT = LoadImage("lib/Button/BG_Round3.png",1,Image.MidHandle)		'## DEPRECATED !!! Will be removed within next patch
		MANIAC_IMG_BG_ROUND1 = LoadImage("lib/Button/BG_Round1.png",1,Image.MidHandle)
		MANIAC_IMG_BG_ROUND2 = LoadImage("lib/Button/BG_Round2.png",1,Image.MidHandle)
		MANIAC_IMG_BG_ROUND3 = LoadImage("lib/Button/BG_Round3.png",1,Image.MidHandle)

		MANIAC_IMG_FRAME_BLUR = LoadImage("lib/Frame_blur.png",1,Image.MidHandle)
		MANIAC_IMG_EDITICON = LoadImage("lib/ico_edit.png")
		MANIAC_IMG_SLIDERLINE = LoadImage("lib/Slider_Line.png")
		MANIAC_IMG_SLIDERPICKER = LoadImage("lib/Slider_Picker.png",1,Image.MidHandle)
		MANIAC_IMG_CHECK = LoadImage("lib/ico_check.png")
		MANIAC_IMG_DROPDOWN = LoadImage("lib/ico_dropdown.png")
		MANIAC_IMG_ARROWDOWN = LoadImage("lib/ico_arrowdown.png")
	Else
		#rem
			TO DO:
			Try to find a way to include some Async Loading stuff with the lowest impact of how to use this Framework.
			## RECOMMEND : SET TO FALSE ##
		#end
	Endif

	If MANIAC_DEBUG = True
		MANIAC_FPSGRAPH = New Maniac_Debug(DW*0.2,DH*0.8,DW*0.65,DH*0.19)
	Endif
	If MANIAC_FONT = Null
		Print "Found no Font Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_FRAME_RAW = Null
		Print "Found no Raw Frame Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_FRAME_BLUR = Null
		Print "Found no blurred Frame Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_EDITICON = Null
		Print "Found no Edit_Icon"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_FPSGRAPH = Null
		Print "Couldnt create an FPS Graph"
		MODULE_INITED_CORRECT = False
	Endif

End Function

#Rem monkeydoc
	This Function should called on every Update() MEthod within your App.
	It keeps some important states of the ManiacModule active
#End
Function maniacUpdate()
	UpdateAsyncEvents()
	If MANIAC_DEBUG = True
		Maniac_Debug.addCall()
	Endif

	MX = MouseX()
	MY = MouseY()

	Maniac_CheckMouseState()

	ll_UpdateSpeeds()
End Function

Function maniacSetDebug(b:Bool = True)
	MANIAC_DEBUG = b
End Function

Function maniacSetAsyncLoad(b:Bool = True)
	MANIAC_LOADASYNC = b
End Function

#Rem monkeydoc Module maniac
	Copyright (C) 2015  Stephan Duckerschein~n
	This Framework provides many additional Graphical Effects and primite Drawings, like unfilled rectangular , ellipsis etc. Diverse GUI Elements.~n
	It has it's own TileMap Engine included and even a Debug Tracking-System. ~n
	~n
	Installation:~n
	to use this Module, you have to Copy the "lib/" Folder data to Your App's Data.~n
	~n
	In the following is an Example, how to Include the maniac Framework to your Monkey Project.~n
Example:
<pre>
'This Example Shows how to integrate the Maniac-Framework to your App

'1. First You have to Import the Libs
import mojo
import maniac

'2. Main Function and App extending Class
Function Main:Int()
	New Example
	Return 0
End

Class Example extends App
	Method OnCreate:Int()
		SetUpdateRate( 60 )
		initManiac()			' THIS INITS THE MANIAC FRAMEWORK! THIS NEED TO BE DONE BEFORE USING IT!!!!!
	end Method

	Method OnUpdate:int()

	end method

	Method OnRender:int()
		Cls
	end Method
End class
</pre>

~n
Featurelist:
	GUI: - Textfield, Button, Dialog, GalleryViewer, Slider, DropDown, ListView, Checkbox ~n
	Graphics: - Outlined: Rect, Ellipsis ; LighningFX, Grid ~n
	TileMap: TileMapEngine featuring an Editor~n
	Font: Including a Font~n

#End

#rem
 <The Duke Game Framework. It provides useful little helperfunctions and class to develope 2D Games with Monkey X>
    Copyright (C) 2014-2015  Stephan Duckerschein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #end

#rem
	The main Aim is to provide a wideranged kit for developing games with Monkey X.
	It tries to be as lightweight as possible.
	And it should be usable without changeging the mojo framework.

	Features:
		DebugSystem: It tracks all used Elements from Maniac within the DebugClass.
		So you can easily monitor your Objects.
#end

#rem
	TO DO FEATURES:
		- Include Async Loader for the Images
		- make the including Paths to Files configurable by including an config.ini file to define them ...
#end

#rem
	Importing the Module-Parts of the maniac Framework.
#end

Import maniacLowLevel			'325		364
Import maniacFont				'249
'Import maniacDebug				'334
Import maniacGraphics			'686		763
Import maniacMisc				'248
Import maniacSimpleGUI			'1214		1515
Import maniacTween				'667
Import maniacMap				'168
Import maniacWIP
Import maniacSort

#rem
	These are all global accessable Objects to your project.They will be initialised automatically within the initManiac() Method.
#end
Global MANIAC_FONT:ManiacFont
Global MANIAC_IMG_LOGO:Image
Global MANIAC_IMG_STAR:Image
Global MANIAC_IMG_STARBLUR:Image
Global MANIAC_IMG_BACKGROUND:Image
Global MANIAC_IMG_FRAME_RAW:Image 		'
Global MANIAC_IMG_FRAME_BLUR:Image
Global MANIAC_IMG_FRAME_SMOOTHRECT:Image
Global MANIAC_IMG_FRAME_SMOOTHRECTBLUR:Image
Global MANIAC_IMG_SLIDERLINE:Image
Global MANIAC_IMG_SLIDERPICKER:Image
Global MANIAC_IMG_EDITICON:Image
Global MANIAC_IMG_CHECK:Image
Global MANIAC_IMG_DROPDOWN:Image
Global MANIAC_IMG_ARROWDOWN:Image
Global MANIAC_CHARACTERSCOUNT:Int = 30

#rem
	Here are the Paths to the Included Images for this Framework
	At the moment theyre not used.
	Future Feature: Set them up via a config.ini file or something.
#end
Global MANIAC_PATH_LOGO:String						= "lib/logo.png"
Global MANIAC_PATH_STAR:String						= "lib/star.png"
Global MANIAC_PATH_STARBLUR:String
Global MANIAC_PATH_BACKGROUND:String  				= "lib/Hintergrund.png"
Global MANIAC_PATH_FRAME_RECT:String
Global MANIAC_PATH_FRSME_RECTBLUR:String
Global MANIAC_PATH_FRAME_RECTROUND:String
Global MANIAC_PATH_FRAME_RECTROUNDBLUR:String
Global MANIAC_PATH_FRAME_CIRCLE:String
Global MANIAC_PATH_FRAME_CIRCLEBLUR:String
Global MANIAC_PATH_ICO_EDIT:String
Global MANIAC_PATH_ICO_CHECK:String
Global MANIAC_PATH_ICO_DROPDOWN_ARROW:String
Global MANIAC_PATH_ICO_ARROWDOWN:String
Global MANIAC_PATH_ICO_SLIDERLINE:String
Global MANIAC_PATH_ICO_SLIDERPICKER:String

Const FPSGRAPH_OFF:Int = 0
Const FPSGRAPH_FPS_ONLY:Int = 1
Const FPSGRAPH_GRAPH:Int = 2

Global MANIAC_FPSGRAPH:Maniac_Debug' = New fpsCounter
Global MODULE_INITED_CORRECT:Bool 		'if false, the whole Maniac-Module uses a fallback Drawings-Stuff

Global DW:Float,DH:Float,MX:Float,MY:Float
'Mouse Button States
Global gl_clicked:Bool
Global gl_mousereleased:Bool

Global MANIAC_DEBUG:Bool = False
Global MANIAC_LOADASYNC:Bool = False 		'## RECOMMEND: SET ON FALSE, as there is no Async Loader included @ the moment !!!

Global maniac_lastTime:Int
Global maniac_timeScale:Float

#Rem monkeydoc
	This Function Inits this Module.
	It Loads all necessary Images and Sounds and stuff from the lib/ folder.
	if No Images were found, it falls back to a "at least running without any Image" mode. so it just shows up, that there are Graphics missing
#End
Function initManiac(_Debug:Bool = False)
	MANIAC_DEBUG = _Debug
	DW = DeviceWidth()
	DH = DeviceHeight()
	MODULE_INITED_CORRECT = True

	If MANIAC_LOADASYNC = False
		MANIAC_FONT = New ManiacFont(22,27,["lib/font2.png"],[[32,5,27,0,0,0,0,0,0,19],[33,5,27,0,393,46,7,18,-1,4],[34,9,27,0,122,99,10,10,-1,3],[35,15,27,0,51,66,17,17,-1,5],[36,16,27,0,478,0,18,22,-1,2],[37,20,27,0,332,25,21,21,-1,2],[38,16,27,0,34,66,17,17,-1,5],[39,5,27,0,116,99,6,10,-1,3],[40,9,27,0,89,0,11,24,-1,2],[41,9,27,0,78,0,11,24,-1,2],[42,14,27,0,378,46,15,18,-1,4],[43,12,27,0,386,83,14,14,-1,6],[44,6,27,0,109,99,7,10,-1,14],[45,10,27,0,174,99,12,7,-1,10],[46,5,27,0,219,99,6,6,-1,15],[47,12,27,0,366,25,13,21,-1,2],[48,18,27,0,24,83,19,16,-1,5],[49,12,27,0,60,83,14,16,-1,5],[50,14,27,0,171,83,15,15,-1,6],[51,16,27,0,154,83,17,15,-1,6],[52,15,27,0,154,66,17,17,-1,5],[53,15,27,0,138,66,16,17,-1,5],[54,16,27,0,121,66,17,17,-1,5],[55,13,27,0,106,66,15,17,-1,5],[56,15,27,0,89,66,17,17,-1,5],[57,15,27,0,43,83,17,16,-1,6],[58,5,27,0,424,83,6,14,-1,7],[59,6,27,0,68,66,7,17,-1,7],[60,10,27,0,412,83,12,14,-1,7],[61,14,27,0,79,99,16,11,-1,7],[62,10,27,0,400,83,12,14,-1,7],[63,13,27,0,75,66,14,17,-1,5],[64,21,27,0,14,46,22,20,-1,6],[65,17,27,0,461,66,18,17,-1,5],[66,14,27,0,446,66,15,17,-1,5],[67,15,27,0,430,66,16,17,-1,5],[68,15,27,0,414,66,16,17,-1,5],[69,14,27,0,399,66,15,17,-1,5],[70,13,27,0,385,66,14,17,-1,5],[71,15,27,0,369,66,16,17,-1,5],[72,14,27,0,353,66,16,17,-1,5],[73,11,27,0,142,83,12,16,-1,6],[74,15,27,0,126,83,16,16,-1,5],[75,14,27,0,337,66,16,17,-1,5],[76,14,27,0,322,66,15,17,-1,5],[77,17,27,0,304,66,18,17,-1,5],[78,15,27,0,287,66,17,17,-1,5],[79,18,27,0,107,83,19,16,-1,5],[80,15,27,0,416,46,16,18,-1,4],[81,18,27,0,268,66,19,17,-1,5],[82,15,27,0,400,46,16,18,-1,4],[83,16,27,0,250,66,18,17,-1,5],[84,15,27,0,319,83,16,15,-1,6],[85,15,27,0,90,83,17,16,-1,5],[86,16,27,0,233,66,17,17,-1,5],[87,16,27,0,215,66,18,17,-1,5],[88,15,27,0,199,66,16,17,-1,5],[89,14,27,0,184,66,15,17,-1,5],[90,15,27,0,74,83,16,16,-1,5],[91,9,27,0,67,0,11,24,-1,2],[92,12,27,0,353,25,13,21,-1,2],[93,9,27,0,56,0,11,24,-1,2],[94,12,27,0,26,99,13,12,-1,2],[95,15,27,0,203,99,16,6,-1,20],[96,7,27,0,141,99,8,9,-1,3],[97,14,27,0,304,83,15,15,-1,7],[98,12,27,0,287,46,13,19,-1,3],[99,12,27,0,472,83,13,14,-1,7],[100,12,27,0,70,46,14,20,-1,2],[101,13,27,0,290,83,14,15,-1,7],[102,12,27,0,274,46,13,19,-1,3],[103,13,27,0,260,46,14,19,-1,7],[104,13,27,0,246,46,14,19,-1,3],[105,5,27,0,239,46,7,19,-1,3],[106,5,27,0,315,0,7,23,-1,3],[107,12,27,0,56,46,14,20,-1,2],[108,5,27,0,50,46,6,20,-1,2],[109,16,27,0,272,83,18,15,-1,7],[110,13,27,0,258,83,14,15,-1,7],[111,12,27,0,458,83,14,14,-1,7],[112,12,27,0,36,46,14,20,-1,7],[113,13,27,0,225,46,14,19,-1,7],[114,10,27,0,246,83,12,15,-1,7],[115,13,27,0,232,83,14,15,-1,7],[116,12,27,0,171,66,13,17,-1,4],[117,12,27,0,218,83,14,15,-1,7],[118,13,27,0,443,83,15,14,-1,7],[119,16,27,0,200,83,18,15,-1,7],[120,13,27,0,186,83,14,15,-1,7],[121,13,27,0,211,46,14,19,-1,7],[122,12,27,0,430,83,13,14,-1,8],[123,12,27,0,28,0,14,25,-1,2],[124,5,27,0,309,0,6,23,-1,3],[125,12,27,0,14,0,14,25,-1,2],[126,15,27,0,157,99,17,8,-1,10],[127,13,27,0,0,46,14,20,-1,3],[161,5,27,0,371,46,7,18,-1,9],[162,12,27,0,465,0,13,22,-1,3],[163,14,27,0,18,66,16,17,-1,5],[164,16,27,0,0,66,18,17,-1,4],[165,14,27,0,481,46,15,17,-1,5],[166,5,27,0,303,0,6,23,-1,3],[167,13,27,0,317,25,15,21,-1,5],[168,9,27,0,192,99,11,6,-1,5],[169,21,27,0,189,46,22,19,-1,5],[170,13,27,0,65,99,14,11,-1,5],[171,17,27,0,368,83,18,14,-1,7],[172,12,27,0,95,99,14,10,-1,10],[174,21,27,0,167,46,22,19,-1,5],[176,12,27,0,52,99,13,11,-1,4],[177,13,27,0,357,46,14,18,-1,4],[178,12,27,0,0,99,13,13,-1,4],[179,12,27,0,13,99,13,12,-1,5],[180,8,27,0,132,99,9,9,-1,3],[181,14,27,0,152,46,15,19,-1,7],[182,18,27,0,297,25,20,21,-1,4],[183,5,27,0,186,99,6,6,-1,10],[184,7,27,0,149,99,8,8,-1,17],[185,7,27,0,498,83,8,13,-1,5],[186,11,27,0,39,99,13,11,-1,5],[187,17,27,0,350,83,18,14,-1,7],[188,17,27,0,278,25,19,21,-1,2],[189,18,27,0,259,25,19,21,-1,2],[190,18,27,0,239,25,20,21,-1,2],[191,13,27,0,467,46,14,17,-1,10],[192,17,27,0,285,0,18,23,-1,-1],[193,17,27,0,267,0,18,23,-1,-1],[194,17,27,0,249,0,18,23,-1,-1],[195,17,27,0,447,0,18,22,-1,0],[196,17,27,0,221,25,18,21,-1,1],[197,17,27,0,231,0,18,23,-1,-1],[198,22,27,0,0,83,24,16,-1,6],[199,15,27,0,486,25,16,20,-1,5],[200,14,27,0,216,0,15,23,-1,-1],[201,14,27,0,201,0,15,23,-1,-1],[202,14,27,0,186,0,15,23,-1,-1],[203,14,27,0,206,25,15,21,-1,1],[204,11,27,0,174,0,12,23,-1,-1],[205,11,27,0,162,0,12,23,-1,-1],[206,12,27,0,148,0,14,23,-1,-1],[207,11,27,0,194,25,12,21,-1,1],[208,17,27,0,448,46,19,17,-1,5],[209,15,27,0,430,0,17,22,-1,0],[210,18,27,0,411,0,19,22,-1,-1],[211,18,27,0,392,0,19,22,-1,-1],[212,18,27,0,373,0,19,22,-1,-1],[213,18,27,0,175,25,19,21,-1,0],[214,18,27,0,467,25,19,20,-1,1],[215,12,27,0,485,83,13,13,-1,7],[216,18,27,0,129,0,19,23,-1,2],[217,15,27,0,356,0,17,22,-1,-1],[218,15,27,0,339,0,17,22,-1,-1],[219,15,27,0,322,0,17,22,-1,-1],[220,15,27,0,450,25,17,20,-1,1],[221,14,27,0,114,0,15,23,-1,-1],[222,14,27,0,432,46,16,17,-1,5],[223,14,27,0,342,46,15,18,-1,4],[224,14,27,0,160,25,15,21,-1,1],[225,14,27,0,145,25,15,21,-1,1],[226,14,27,0,130,25,15,21,-1,1],[227,14,27,0,435,25,15,20,-1,2],[228,14,27,0,137,46,15,19,-1,3],[229,14,27,0,115,25,15,21,-1,1],[230,21,27,0,479,66,23,16,-1,6],[231,12,27,0,329,46,13,18,-1,7],[232,13,27,0,101,25,14,21,-1,1],[233,13,27,0,87,25,14,21,-1,1],[234,13,27,0,72,25,15,21,-1,1],[235,13,27,0,123,46,14,19,-1,3],[236,7,27,0,64,25,8,21,-1,1],[237,8,27,0,55,25,9,21,-1,1],[238,11,27,0,42,25,13,21,-1,1],[239,9,27,0,112,46,11,19,-1,3],[240,14,27,0,314,46,15,18,-1,3],[241,13,27,0,421,25,14,20,-1,2],[242,12,27,0,407,25,14,20,-1,1],[243,12,27,0,393,25,14,20,-1,1],[244,12,27,0,379,25,14,20,-1,1],[245,12,27,0,98,46,14,19,-1,2],[246,12,27,0,300,46,14,18,-1,3],[247,14,27,0,335,83,15,14,-1,5],[248,12,27,0,28,25,14,21,-1,4],[249,12,27,0,14,25,14,21,-1,1],[250,12,27,0,0,25,14,21,-1,1],[251,12,27,0,496,0,14,21,-1,1],[252,12,27,0,84,46,14,19,-1,3],[253,13,27,0,0,0,14,25,-1,1],[254,12,27,0,42,0,14,24,-1,3],[255,13,27,0,100,0,14,23,-1,3]])
		MANIAC_IMG_BACKGROUND = LoadImage("lib/Hintergrund.png")
		MANIAC_IMG_STAR = LoadImage("lib/star.png")
		MANIAC_IMG_LOGO = LoadImage("lib/logo.png")
		MANIAC_IMG_FRAME_RAW = LoadImage("lib/Frame_raw2.png",1,Image.MidHandle)
		MANIAC_IMG_FRAME_BLUR = LoadImage("lib/Frame_blur.png",1,Image.MidHandle)
		MANIAC_IMG_EDITICON = LoadImage("lib/ico_edit.png")
		MANIAC_IMG_SLIDERLINE = LoadImage("lib/Slider_Line.png")
		MANIAC_IMG_SLIDERPICKER = LoadImage("lib/Slider_Picker.png",1,Image.MidHandle)
		MANIAC_IMG_CHECK = LoadImage("lib/ico_check.png")
		MANIAC_IMG_DROPDOWN = LoadImage("lib/ico_dropdown.png")
		MANIAC_IMG_ARROWDOWN = LoadImage("lib/ico_arrowdown.png")
	Else
		#rem
			TO DO:
			Try to find a way to include some Async Loading stuff with the lowest impact of how to use this Framework.
			## RECOMMEND : SET TO FALSE ##
		#end
	Endif

	If MANIAC_DEBUG = True
		MANIAC_FPSGRAPH = New Maniac_Debug(DW*0.2,DH*0.8,DW*0.65,DH*0.19)
	Endif
	If MANIAC_FONT = Null
		Print "Found no Font Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_FRAME_RAW = Null
		Print "Found no Raw Frame Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_FRAME_BLUR = Null
		Print "Found no blurred Frame Data"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_IMG_EDITICON = Null
		Print "Found no Edit_Icon"
		MODULE_INITED_CORRECT = False
	Endif
	If MANIAC_FPSGRAPH = Null
		Print "Couldnt create an FPS Graph"
		MODULE_INITED_CORRECT = False
	Endif

End Function

#Rem monkeydoc
	This Function should called on every Update() MEthod within your App.
	It keeps some important states of the ManiacModule active
#End
Function maniacUpdate()
	UpdateAsyncEvents()
	If MANIAC_DEBUG = True
		Maniac_Debug.addCall()
	Endif

	MX = MouseX()
	MY = MouseY()

	Maniac_CheckMouseState()

	ll_UpdateSpeeds()
End Function

Function maniacSetDebug(b:Bool = True)
	MANIAC_DEBUG = b
End Function

Function maniacSetAsyncLoad(b:Bool = True)
	MANIAC_LOADASYNC = b
End Function


Cleaned up code.

Cleaned up code.

--HG--
extra : convert_revision : svn%3Ae934d3cd-0d57-f34a-94d0-9e8d31ae1c29/trunk%40113

Strict

Import assert

#Rem
Monkey Collections Framework
Based loosely on the Java Collections Framework
#End

'''' Top level Collection stuff ''''

#Rem
	AbstractCollection
	Due to limitations with generics in Monkey, ToArray cannot work with an array of type E.  We must return Object[] instead.
#End
Class AbstractCollection<E> Abstract
Private
	' A custom comparator to use for sorting and comparing items.
	Field comparator:AbstractComparator = Null

Public
' Abstract
	Method Add:Bool(o:E) Abstract
	Method AddAll:Bool(c:AbstractCollection<E>) Abstract
	Method Clear:Void() Abstract
	Method Contains:Bool(o:E) Abstract
	Method ContainsAll:Bool(c:AbstractCollection<E>) Abstract
	Method Enumerator:AbstractEnumerator<E>() Abstract
	Method FillArray:Int(arr:Object[]) Abstract ' populates the passed array and returns the number of items filled. best used for android
	Method IsEmpty:Bool() Abstract
	Method Remove:Bool(o:E) Abstract
	Method RemoveAll:Bool(c:AbstractCollection<E>) Abstract
	Method RetainAll:Bool(c:AbstractCollection<E>) Abstract
	Method Size:Int() Property Abstract
	Method Sort:Void(reverse:Bool = False, comp:AbstractComparator = Null) Abstract
	Method ToArray:Object[]() Abstract ' creates a new array of the correct size and returns it

' Methods
	Method ObjectEnumerator:AbstractEnumerator<E>()
		Return Enumerator()
	End

' Properties
	' Property to read comparator
	Method Comparator:AbstractComparator() Property
		Return comparator
	End

	' Property to write comparator
	Method Comparator:Void(comparator:AbstractComparator) Property
		Self.comparator = comparator
	End
End

#Rem
	AbstractEnumerator
	Used in the ObjectEnumerator method for calls to EachIn.
	If retrieved and used manually, the HasPrevious/PreviousObject/Remove/First/Last methods can be called.
#End
Class AbstractEnumerator<E>
' Abstract
	Method HasNext:Bool() Abstract
	Method HasPrevious:Bool() Abstract
	Method NextObject:E() Abstract
	Method PreviousObject:E() Abstract
	Method Remove:Void() Abstract
	Method First:Void() Abstract
	Method Last:Void() Abstract
	Method Reset:Void() Abstract
End

#Rem
	Comparable
	Allows developers to sort a collection without using a Comparator.  Each class is responsible
	for providing its own logic to determine how it should be sorted.
#End
Interface Comparable
	Method Compare:Int(o:Object)
	Method CompareBool:Bool(o:Object)
End

#Rem
	AbstractComparator
	This is a way for developers to provide a custom comparison method for sorting lists.
	It's sort of like a function pointer.
#End
Class AbstractComparator Abstract
' Abstract
	Method Compare:Int(o1:Object, o2:Object) Abstract

' Methods
	Method CompareBool:Bool(o1:Object, o2:Object)
		Return o1 = o2 Or Compare(o1, o2) = 0
	End

	Method HashCode:Int(o:Object)
		Return 0
	End
End

#Rem
	DefaultComparator
	Implements an AbstractComparator to handle primitive wrappers and strings.
#End
Global DEFAULT_COMPARATOR:DefaultComparator = New DefaultComparator
Class DefaultComparator Extends AbstractComparator
' Methods
	' Overrides AbstractComparator
	Method Compare:Int(o1:Object, o2:Object)
		If IntObject(o1) <> Null And IntObject(o2) <> Null Then
			If IntObject(o1).value < IntObject(o2).value Then Return -1
			If IntObject(o1).value > IntObject(o2).value Then Return 1
			Return 0
		ElseIf FloatObject(o1) <> Null And FloatObject(o2) <> Null Then
			If FloatObject(o1).value < FloatObject(o2).value Then Return -1
			If FloatObject(o1).value > FloatObject(o2).value Then Return 1
			Return 0
		ElseIf StringObject(o1) <> Null And StringObject(o2) <> Null Then
			If StringObject(o1).value < StringObject(o2).value Then Return -1
			If StringObject(o1).value > StringObject(o2).value Then Return 1
			Return 0
		End
		If o1 = o2 Then Return 0
		If o1 = Null Then Return -1
		If o2 = Null Then Return 1
		Return 0 ' don't know what to do!
	End

	' Overrides AbstractComparator
	Method CompareBool:Bool(o1:Object, o2:Object)
		If IntObject(o1) <> Null And IntObject(o2) <> Null Then
			Return IntObject(o1).value = IntObject(o2).value
		ElseIf FloatObject(o1) <> Null And FloatObject(o2) <> Null Then
			Return FloatObject(o1).value = FloatObject(o2).value
		ElseIf StringObject(o1) <> Null And StringObject(o2) <> Null Then
			Return StringObject(o1).value = StringObject(o2).value
		End
		Return o1 = o2
	End
End

'''' List stuff ''''

#Rem
	AbstractList
	Extends AbstractCollection to implement some of the abstract methods that apply to any kind of list.
#End
Class AbstractList<E> Extends AbstractCollection<E> Abstract
Private
	' If true, bounds checking should be performed.
#if CONFIG="debug"
	Field rangeChecking:Bool = True
#else
	Field rangeChecking:Bool = False
#end

	' A counter for modifications to the list.  Used for concurrency checks.
	Field modCount:Int = 0

	' Performs a range check.
	Method RangeCheck:Void(index:Int)
		Local size:Int = Self.Size()
		' range check doesn't use assert, for speed
		If index < 0 Or index >= size Then Error("AbstractList.RangeCheck: Index out of bounds: " + index + " is not 0<=index<" + size)
	End

Public
' Abstract
	Method Get:E(index:Int) Abstract
	Method Insert:Void(index:Int, o:E) Abstract
	Method InsertAll:Bool(index:Int, c:AbstractCollection<E>) Abstract
	Method IndexOf:Int(o:E) Abstract
	Method LastIndexOf:Int(o:E) Abstract
	Method RemoveAt:E(index:Int) Abstract ' Can't overload Remove since it's an inherited method, and Monkey doesn't support that.
	Method RemoveRange:Void(fromIndex:Int, toIndex:Int) Abstract
	Method Set:E(index:Int, o:E) Abstract

' Methods
	' Overrides AbstractCollection
	Method Enumerator:AbstractEnumerator<E>()
		Return New ListEnumerator<E>(Self)
	End

' Properties
	' Property to read rangeChecking
	Method RangeChecking:Bool() Property
		Return rangeChecking
	End

	' Property to write rangeChecking
	Method RangeChecking:Void(rangeChecking:Bool) Property
		Self.rangeChecking = rangeChecking
	End
End

#Rem
	ListEnumerator
	Extends AbstractEnumerator to provide support for EachIn.  Blocks concurrent modification, but allows elements to be removed on the fly.
#End
Class ListEnumerator<E> Extends AbstractEnumerator<E>
Private
	Field lst:AbstractList<E>
	Field lastIndex:Int = 0
	Field index:Int = 0
	Field expectedModCount:Int = 0

	Method CheckConcurrency:Void()
		' for speed we don't use assert
		If lst.modCount <> expectedModCount Then Error("ListEnumerator.CheckConcurrency: Concurrent list modification")
	End

Public
' Constructors
	Method New(lst:AbstractList<E>)
		Self.lst = lst
		expectedModCount = lst.modCount
	End

' Methods
	' Overrides AbstractEnumerator
	Method HasNext:Bool()
		CheckConcurrency()
		Return index < lst.Size
	End

	' Overrides AbstractEnumerator
	Method HasPrevious:Bool()
		CheckConcurrency()
		Return index > 0
	End

	' Overrides AbstractEnumerator
	Method NextObject:E()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex)
	End

	' Overrides AbstractEnumerator
	Method PreviousObject:E()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex)
	End

	' Overrides AbstractEnumerator
	Method Remove:Void()
		CheckConcurrency()
		lst.RemoveAt(lastIndex)
		If lastIndex < index Then index -= 1
		lastIndex = -1
		expectedModCount = lst.modCount
	End

	' Overrides AbstractEnumerator
	Method First:Void()
		CheckConcurrency()
		index = 0
	End

	' Overrides AbstractEnumerator
	Method Last:Void()
		CheckConcurrency()
		index = lst.Size
	End

	' Overrides AbstractEnumerator
	Method Reset:Void()
		index = 0
		expectedModCount = lst.modCount
	End
End

#Rem
	ArrayListEnumerator
	Extends ListEnumerator to avoid some method calls.
#End
Class ArrayListEnumerator<E> Extends ListEnumerator<E>
Private
	Field alst:ArrayList<E>

Public
' Constructors
	Method New(lst:ArrayList<E>)
		Super.New(lst)
		Self.alst = lst
		expectedModCount = alst.modCount
	End

' Methods
	' Overrides ListEnumerator
	Method HasNext:Bool()
		CheckConcurrency()
		Return index < alst.size
	End

	' Overrides ListEnumerator
	Method NextObject:E()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return alst.elements[lastIndex]
	End

	' Overrides ListEnumerator
	Method PreviousObject:E()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return alst.elements[lastIndex]
	End
End

Class IntListEnumerator Extends ListEnumerator<IntObject>
' Constructors
	Method New(lst:AbstractList<IntObject>)
		Super.New(lst)
	End

' Methods
	Method NextInt:Int()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousInt:Int()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

Class FloatListEnumerator Extends ListEnumerator<FloatObject>
' Constructors
	Method New(lst:AbstractList<FloatObject>)
		Super.New(lst)
	End

' Methods
	Method NextFloat:Float()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousFloat:Float()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

Class StringListEnumerator Extends ListEnumerator<StringObject>
' Constructors
	Method New(lst:AbstractList<IntObject>)
		Super.New(lst)
	End

' Methods
	Method NextString:String()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousString:String()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

#Rem
	ArrayList
	Concrete implementation of AbstractList that uses a dynamically sized array to store elements.
	Has best performance when it is initialised with a capacity large enough to hold the expected number of elements.
#End
Class ArrayList<E> Extends AbstractList<E>
Private
	' fields
	Field elements:Object[]
	Field size:Int = 0

	' resizes the elements array if necessary to ensure it can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			modCount += 1
		End
	End

	Method RangeCheck:Void(index:Int)
		' range check doesn't use assert, for speed
		If index < 0 Or index >= size Then Error("ArrayList.RangeCheck: Index out of bounds: " + index + " is not 0<=index<" + size)
	End

	Field tempArr:Object[] = New Object[128] ' temp array used for internal call to ToArray (so we don't create an object)

Public
' Constructors
	Method New()
		Self.elements = New Object[10]
	End

	Method New(initialCapacity:Int)
		AssertGreaterThanOrEqual(initialCapacity, 0, "ArrayList.New: Illegal Capacity:")
		Self.elements = New Object[initialCapacity]
	End

	Method New(c:AbstractCollection<E>)
		elements = c.ToArray()
		size = elements.Length
	End

' Methods
	' Overrides AbstractCollection
	Method Add:Bool(o:E)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = o
		size+=1
		modCount += 1
		Return True
	End

	' Overrides AbstractCollection
	Method AddAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return False
		Local newItemCount:Int = c.Size
		If size + newItemCount > elements.Length Then EnsureCapacity(size+newItemCount)
		If tempArr.Length < newItemCount Then tempArr = tempArr.Resize(newItemCount)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			elements[size] = tempArr[i]
			size+=1
		End
		modCount += 1
		Return newItemCount <> 0
	End

	' Overrides AbstractCollection
	Method Clear:Void()
		For Local i:Int = 0 Until size
			elements[i] = Null
		Next
		modCount += 1
		size = 0
	End

	' Overrides AbstractCollection
	Method Contains:Bool(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then Return True
		Next
		Return False
	End

	' Overrides AbstractCollection
	Method ContainsAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return True
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Not Self.Contains(E(tempArr[i])) Then Return False
		Next
		Return True
	End

	' Overrides AbstractCollection
	Method Enumerator:AbstractEnumerator<E>()
		Return New ArrayListEnumerator<E>(Self)
	End

	' Overrides AbstractCollection
	Method FillArray:Int(arr:Object[])
		AssertGreaterThanOrEqual(arr.Length, size, "ArrayList.FillArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = elements[i]
		Next
		Return size
	End

	' Overrides AbstractCollection
	Method IsEmpty:Bool()
		Return size = 0
	End

	' Overrides AbstractCollection
	Method Remove:Bool(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	' Overrides AbstractCollection
	Method RemoveAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return False
		Local modified:Bool = False
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Self.Contains(E(tempArr[i])) Then
				Self.Remove(E(tempArr[i]))
			End
		Next
		If modified Then modCount += 1
		Return modified
	End

	' Overrides AbstractCollection
	Method RetainAll:Bool(c:AbstractCollection<E>)
		Local modified:Bool = False
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Not Self.Contains(E(tempArr[i])) Then
				Self.Remove(E(tempArr[i]))
				modified = True
			End
		Next
		If modified Then modCount += 1
		Return modified
	End

	' Overrides AbstractCollection
	Method Size:Int() Property
		Return size
	End

	' Overrides AbstractCollection
	Method Sort:Void(reverse:Bool = False, comp:AbstractComparator = Null)
		If size <= 1 Then Return ' can't sort 0 or 1 elements
		If comp = Null Then comp = Self.Comparator
		If comp = Null Then comp = DEFAULT_COMPARATOR
		QuickSort(elements, 0, size-1, comp, reverse)
		modCount += 1
	End

	' Overrides AbstractCollection
	Method ToArray:Object[]()
		Local arr:Object[] = New Object[size]
		For Local i:Int = 0 Until size
			arr[i] = elements[i]
		Next
		Return arr
	End

	' Overrides AbstractList
	Method Get:E(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return E(elements[index])
	End

	' Overrides AbstractList
	Method Insert:Void(index:Int, o:E)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = o
		size+=1
		modCount += 1
	End

	' Overrides AbstractList
	Method InsertAll:Bool(index:Int, c:AbstractCollection<E>)
		Local newItemCount:Int = c.Size
		If newItemCount = 0 Then Return False
		If size + newItemCount > elements.Length Then EnsureCapacity(size+newItemCount)
		If tempArr.Length < newItemCount Then tempArr = tempArr.Resize(newItemCount)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = size - 1 To index Step -1
			elements[i+newItemCount] = elements[i]
		Next
		For Local i:Int = 0 Until newItemCount
			elements[index+i] = tempArr[i]
		End
		size += newItemCount
		modCount += 1
		Return newItemCount <> 0
	End

	' Overrides AbstractList
	Method IndexOf:Int(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then Return i
		Next
		Return -1
	End

	' Overrides AbstractList
	Method LastIndexOf:Int(o:E)
		For Local i:Int = size-1 To 0 Step -1
			If elements[i] = o Then Return i
		Next
		Return -1
	End

	' Overrides AbstractList
	Method RemoveAt:E(index:Int)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:E = E(elements[index])
		For Local i:Int = index Until size-1
			elements[i] = elements[i+1]
		Next
		elements[size-1] = Null
		size-=1
		modCount += 1
		Return oldValue
	End

	' Overrides AbstractList
	Method RemoveRange:Void(fromIndex:Int, toIndex:Int)
		AssertLessThanOrEqual(fromIndex, toIndex, "ArrayList.RemoveRange: fromIndex > toIndex:")
		If rangeChecking Then
			RangeCheck(fromIndex)
			RangeCheck(toIndex)
		End
		For Local i:Int = 0 Until toIndex - fromIndex
			RemoveAt(fromIndex)
		Next
	End

	' Overrides AbstractList
	Method Set:E(index:Int, o:E)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:E = E(elements[index])
		elements[index] = o
		modCount += 1
		Return oldValue
	End
End

' ArrayList wrapper classes

Class IntArrayList Extends ArrayList<IntObject>
' Methods
	Method AddInt:Bool(o:Int)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = New IntObject(o)
		size+=1
		modCount += 1
		Return True
	End

	Method ContainsInt:Bool(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<IntObject>()
		Return New IntArrayListEnumerator(Self)
	End

	Method RemoveInt:Bool(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToIntArray:Int[]()
		Local arr:Int[] = New Int[size]
		For Local i:Int = 0 Until size
			arr[i] = IntObject(elements[i]).value
		Next
		Return arr
	End

	Method GetInt:Int(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return IntObject(elements[index]).value
	End

	Method InsertInt:Void(index:Int, o:Int)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New IntObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfInt:Int(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfInt:Int(o:E)
		For Local i:Int = size-1 To 0 Step -1
			If IntObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetInt:Int(index:Int, o:Int)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:Int = IntObject(elements[index]).value
		If elements[index] <> Null Then
			IntObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillIntArray:Int(arr:Int[])
		AssertLessThan(arr.Length, size, "IntArrayList.FillIntArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = IntObject(elements[i]).value
		Next
		Return size
	End
End

Class FloatArrayList Extends ArrayList<FloatObject>
' Methods
	Method AddFloat:Bool(o:Float)
		If size + 1 > elements.Length Then EnsureCapacity(size + 1)
		elements[size] = New FloatObject(o)
		size += 1
		modCount += 1
		Return True
	End

	Method ContainsFloat:Bool(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<FloatObject>()
		Return New FloatArrayListEnumerator(Self)
	End

	Method RemoveFloat:Bool(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToFloatArray:Float[]()
		Local arr:Float[] = New Float[size]
		For Local i:Int = 0 Until size
			arr[i] = FloatObject(elements[i]).value
		Next
		Return arr
	End

	Method GetFloat:Float(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return FloatObject(elements[index]).value
	End

	Method InsertFloat:Void(index:Int, o:Float)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New FloatObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfFloat:Int(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfFloat:Int(o:Float)
		For Local i:Int = size-1 To 0 Step -1
			If FloatObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetFloat:Float(index:Int, o:Float)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:Float = FloatObject(elements[index]).value
		If elements[index] <> Null Then
			FloatObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillFloatArray:Int(arr:Float[])
		AssertLessThan(arr.Length, size, "FloatArrayList.FillFloatArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = FloatObject(elements[i]).value
		Next
		Return size
	End
End

Class StringArrayList Extends ArrayList<StringObject>
' Methods
	Method AddString:Bool(o:String)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = New StringObject(o)
		size+=1
		modCount += 1
		Return True
	End

	Method ContainsString:Bool(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	' Overrides ArrayList
	Method Enumerator:AbstractEnumerator<StringObject>()
		Return New StringArrayListEnumerator(Self)
	End

	Method RemoveString:Bool(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToStringArray:String[]()
		Local arr:String[] = New String[size]
		For Local i:Int = 0 Until size
			arr[i] = StringObject(elements[i]).value
		Next
		Return arr
	End

	Method GetString:String(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return StringObject(elements[index]).value
	End

	Method InsertString:Void(index:Int, o:String)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New StringObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfString:Int(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfString:Int(o:String)
		For Local i:Int = size-1 To 0 Step -1
			If StringObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetString:String(index:Int, o:String)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:String = StringObject(elements[index]).value
		If elements[index] <> Null Then
			StringObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillStringArray:Int(arr:String[])
		AssertLessThan(arr.Length, size, "StringArrayList.FillStringArray: Array too small:")
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = value Then
				Remove(elements[i])
				modCount += 1
				Return True
			End
		Next
		Return False
	End
End

Function QuickSort:Void(arr:Object[], left:Int, right:Int, comp:AbstractComparator, reverse:Bool = False)
	If right > left Then
		Local pivotIndex:Int = left + (right-left)/2
		Local pivotNewIndex:Int = QuickSortPartition(arr, left, right, pivotIndex, comp, reverse)
		QuickSort(arr, left, pivotNewIndex - 1, comp, reverse)
		QuickSort(arr, pivotNewIndex + 1, right, comp, reverse)
	End
End

Function QuickSortPartition:Int(arr:Object[], left:Int, right:Int, pivotIndex:Int, comp:AbstractComparator, reverse:Bool = False)
	Local pivotValue:Object = arr[pivotIndex]
	arr[pivotIndex] = arr[right]
	arr[right] = pivotValue
	Local storeIndex:Int = left, val:Object
	For Local i:Int = left Until right
		If Comparable(arr[i]) <> Null Then
			If Not reverse And Comparable(arr[i]).Compare(pivotValue) <= 0 Or reverse And Comparable(arr[i]).Compare(pivotValue) >= 0 Then
				val = arr[i]
				arr[i] = arr[storeIndex]
				arr[storeIndex] = val
				storeIndex += 1
			End
		Else
			If Not reverse And comp.Compare(arr[i], pivotValue) <= 0 Or reverse And comp.Compare(arr[i], pivotValue) >= 0 Then
				val = arr[i]
				arr[i] = arr[storeIndex]
				arr[storeIndex] = val
				storeIndex += 1
			End
		End
	Next
	val = arr[storeIndex]
	arr[storeIndex] = arr[right]
	arr[right] = val
	Return storeIndex
End

Strict

Import assert

#Rem
Monkey Collections Framework
Based loosely on the Java Collections Framework
#End

'''' Top level Collection stuff ''''

#Rem
	AbstractCollection
	Due to limitations with generics in Monkey, ToArray cannot work with an array of type E.  We must return Object[] instead.
#End
Class AbstractCollection<E> Abstract
Private
	' A custom comparator to use for sorting and comparing items.
	Field comparator:AbstractComparator = Null

Public
	' Property to read comparator
	Method Comparator:AbstractComparator() Property
		Return comparator
	End
	' Property to write comparator
	Method Comparator:Void(comparator:AbstractComparator) Property
		Self.comparator = comparator
	End

	Method Add:Bool(o:E) Abstract
	Method AddAll:Bool(c:AbstractCollection<E>) Abstract
	Method Clear:Void() Abstract
	Method Contains:Bool(o:E) Abstract
	Method ContainsAll:Bool(c:AbstractCollection<E>) Abstract
	Method Enumerator:AbstractEnumerator<E>() Abstract
	Method FillArray:Int(arr:Object[]) Abstract ' populates the passed array and returns the number of items filled. best used for android
	Method IsEmpty:Bool() Abstract
	Method Remove:Bool(o:E) Abstract
	Method RemoveAll:Bool(c:AbstractCollection<E>) Abstract
	Method RetainAll:Bool(c:AbstractCollection<E>) Abstract
	Method Size:Int() Property Abstract
	Method Sort:Void(reverse:Bool = False, comp:AbstractComparator = Null) Abstract
	Method ToArray:Object[]() Abstract ' creates a new array of the correct size and returns it

	Method ObjectEnumerator:AbstractEnumerator<E>()
		Return Enumerator()
	End
End

#Rem
	AbstractEnumerator
	Used in the ObjectEnumerator method for calls to EachIn.
	If retrieved and used manually, the HasPrevious/PreviousObject/Remove/First/Last methods can be called.
#End
Class AbstractEnumerator<E>
Public
	Method HasNext:Bool() Abstract
	Method HasPrevious:Bool() Abstract
	Method NextObject:E() Abstract
	Method PreviousObject:E() Abstract
	Method Remove:Void() Abstract
	Method First:Void() Abstract
	Method Last:Void() Abstract
	Method Reset:Void() Abstract
End

#Rem
	Comparable
	Allows developers to sort a collection without using a Comparator.  Each class is responsible
	for providing its own logic to determine how it should be sorted.
#End
Interface Comparable
	Method Compare:Int(o:Object)
	Method CompareBool:Bool(o:Object)
End

#Rem
	AbstractComparator
	This is a way for developers to provide a custom comparison method for sorting lists.
	It's sort of like a function pointer.
#End
Class AbstractComparator Abstract
	Method Compare:Int(o1:Object, o2:Object) Abstract

	Method CompareBool:Bool(o1:Object, o2:Object)
		Return o1 = o2 Or Compare(o1, o2) = 0
	End

	Method HashCode:Int(o:Object)
		Return 0
	End
End

#Rem
	DefaultComparator
	Implements an AbstractComparator to handle primitive wrappers and strings.
#End
Global DEFAULT_COMPARATOR:DefaultComparator = New DefaultComparator
Class DefaultComparator Extends AbstractComparator
	Method Compare:Int(o1:Object, o2:Object)
		If IntObject(o1) <> Null And IntObject(o2) <> Null Then
			If IntObject(o1).value < IntObject(o2).value Then Return -1
			If IntObject(o1).value > IntObject(o2).value Then Return 1
			Return 0
		ElseIf FloatObject(o1) <> Null And FloatObject(o2) <> Null Then
			If FloatObject(o1).value < FloatObject(o2).value Then Return -1
			If FloatObject(o1).value > FloatObject(o2).value Then Return 1
			Return 0
		ElseIf StringObject(o1) <> Null And StringObject(o2) <> Null Then
			If StringObject(o1).value < StringObject(o2).value Then Return -1
			If StringObject(o1).value > StringObject(o2).value Then Return 1
			Return 0
		End
		If o1 = o2 Then Return 0
		If o1 = Null Then Return -1
		If o2 = Null Then Return 1
		Return 0 ' don't know what to do!
	End

	Method CompareBool:Bool(o1:Object, o2:Object)
		If IntObject(o1) <> Null And IntObject(o2) <> Null Then
			Return IntObject(o1).value = IntObject(o2).value
		ElseIf FloatObject(o1) <> Null And FloatObject(o2) <> Null Then
			Return FloatObject(o1).value = FloatObject(o2).value
		ElseIf StringObject(o1) <> Null And StringObject(o2) <> Null Then
			Return StringObject(o1).value = StringObject(o2).value
		End
		Return o1 = o2
	End
End

'''' List stuff ''''

#Rem
	AbstractList
	Extends AbstractCollection to implement some of the abstract methods that apply to any kind of list.
#End
Class AbstractList<E> Extends AbstractCollection<E> Abstract
Private
	' If true, bounds checking should be performed.
#if CONFIG="debug"
	Field rangeChecking:Bool = True
#else
	Field rangeChecking:Bool = False
#end

	' A counter for modifications to the list.  Used for concurrency checks.
	Field modCount:Int = 0

	' Performs a range check.
	Method RangeCheck:Void(index:Int)
		Local size:Int = Self.Size()
		' range check doesn't use assert, for speed
		If index < 0 Or index >= size Then Error("AbstractList.RangeCheck: Index out of bounds: " + index + " is not 0<=index<" + size)
	End

Public
	' Property to read rangeChecking
	Method RangeChecking:Bool() Property
		Return rangeChecking
	End
	' Property to write rangeChecking
	Method RangeChecking:Void(rangeChecking:Bool) Property
		Self.rangeChecking = rangeChecking
	End

	Method Enumerator:AbstractEnumerator<E>()
		Return New ListEnumerator<E>(Self)
	End

	Method Get:E(index:Int) Abstract
	Method Insert:Void(index:Int, o:E) Abstract
	Method InsertAll:Bool(index:Int, c:AbstractCollection<E>) Abstract
	Method IndexOf:Int(o:E) Abstract
	Method LastIndexOf:Int(o:E) Abstract
	Method RemoveAt:E(index:Int) Abstract ' Can't overload Remove since it's an inherited method, and Monkey doesn't support that.
	Method RemoveRange:Void(fromIndex:Int, toIndex:Int) Abstract
	Method Set:E(index:Int, o:E) Abstract
End

#Rem
	ListEnumerator
	Extends AbstractEnumerator to provide support for EachIn.  Blocks concurrent modification, but allows elements to be removed on the fly.
#End
Class ListEnumerator<E> Extends AbstractEnumerator<E>
Private
	Field lst:AbstractList<E>
	Field lastIndex:Int = 0
	Field index:Int = 0
	Field expectedModCount:Int = 0
Public
	Method New(lst:AbstractList<E>)
		Self.lst = lst
		expectedModCount = lst.modCount
	End

	Method CheckConcurrency:Void()
		' for speed we don't use assert
		If lst.modCount <> expectedModCount Then Error("ListEnumerator.CheckConcurrency: Concurrent list modification")
	End

	Method HasNext:Bool()
		CheckConcurrency()
		Return index < lst.Size
	End

	Method HasPrevious:Bool()
		CheckConcurrency()
		Return index > 0
	End

	Method NextObject:E()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex)
	End

	Method PreviousObject:E()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex)
	End

	Method Remove:Void()
		CheckConcurrency()
		lst.RemoveAt(lastIndex)
		If lastIndex < index Then index -= 1
		lastIndex = -1
		expectedModCount = lst.modCount
	End

	Method First:Void()
		CheckConcurrency()
		index = 0
	End

	Method Last:Void()
		CheckConcurrency()
		index = lst.Size
	End

	Method Reset:Void()
		index = 0
		expectedModCount = lst.modCount
	End
End

#Rem
	ArrayListEnumerator
	Extends ListEnumerator to avoid some method calls.
#End
Class ArrayListEnumerator<E> Extends ListEnumerator<E>
	Field alst:ArrayList<E>

	Method New(lst:ArrayList<E>)
		Super.New(lst)
		Self.alst = lst
		expectedModCount = alst.modCount
	End

	Method HasNext:Bool()
		CheckConcurrency()
		Return index < alst.size
	End

	Method NextObject:E()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return alst.elements[lastIndex]
	End

	Method PreviousObject:E()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return alst.elements[lastIndex]
	End

	Method Last:Void()
		CheckConcurrency()
		index = alst.size
	End
End

Class IntListEnumerator Extends ListEnumerator<IntObject>
Public
	Method New(lst:AbstractList<IntObject>)
		Super.New(lst)
	End

	Method NextInt:Int()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousInt:Int()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

Class FloatListEnumerator Extends ListEnumerator<FloatObject>
Public
	Method New(lst:AbstractList<FloatObject>)
		Super.New(lst)
	End

	Method NextFloat:Float()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousFloat:Float()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

Class StringListEnumerator Extends ListEnumerator<StringObject>
Public
	Method New(lst:AbstractList<IntObject>)
		Super.New(lst)
	End

	Method NextString:String()
		CheckConcurrency()
		lastIndex = index
		index += 1
		Return lst.Get(lastIndex).value
	End

	Method PreviousString:String()
		CheckConcurrency()
		index -= 1
		lastIndex = index
		Return lst.Get(lastIndex).value
	End
End

#Rem
	ArrayList
	Concrete implementation of AbstractList that uses a dynamically sized array to store elements.
	Has best performance when it is initialised with a capacity large enough to hold the expected number of elements.
#End
Class ArrayList<E> Extends AbstractList<E>
Private
	' fields
	Field elements:Object[]
	Field size:Int = 0

	' resizes the elements array if necessary to ensure it can fit minCapacity elements
	Method EnsureCapacity:Void(minCapacity:Int)
		Local oldCapacity:Int = elements.Length
		If minCapacity > oldCapacity Then
			Local newCapacity:Int = (oldCapacity * 3) / 2 + 1
			If newCapacity < minCapacity Then newCapacity = minCapacity
			elements = elements.Resize(newCapacity)
			modCount += 1
		End
	End

	Method RangeCheck:Void(index:Int)
		' range check doesn't use assert, for speed
		If index < 0 Or index >= size Then Error("ArrayList.RangeCheck: Index out of bounds: " + index + " is not 0<=index<" + size)
	End

	Field tempArr:Object[] = New Object[128] ' temp array used for internal call to ToArray (so we don't create an object)

Public
	' constructors
	Method New()
		Self.elements = New Object[10]
	End

	Method New(initialCapacity:Int)
		AssertGreaterThanOrEqual(initialCapacity, 0, "ArrayList.New: Illegal Capacity:")
		Self.elements = New Object[initialCapacity]
	End

	Method New(c:AbstractCollection<E>)
		elements = c.ToArray()
		size = elements.Length
	End

	'implements AbstractCollection

	Method Add:Bool(o:E)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = o
		size+=1
		modCount += 1
		Return True
	End

	Method AddAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return False
		Local newItemCount:Int = c.Size
		If size + newItemCount > elements.Length Then EnsureCapacity(size+newItemCount)
		If tempArr.Length < newItemCount Then tempArr = tempArr.Resize(newItemCount)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			elements[size] = tempArr[i]
			size+=1
		End
		modCount += 1
		Return newItemCount <> 0
	End

	Method Clear:Void()
		For Local i:Int = 0 Until size
			elements[i] = Null
		Next
		modCount += 1
		size = 0
	End

	Method Contains:Bool(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then Return True
		Next
		Return False
	End

	Method ContainsAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return True
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Not Self.Contains(E(tempArr[i])) Then Return False
		Next
		Return True
	End

	Method FillArray:Int(arr:Object[])
		AssertGreaterThanOrEqual(arr.Length, size, "ArrayList.FillArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = elements[i]
		Next
		Return size
	End

	Method IsEmpty:Bool()
		Return size = 0
	End

	Method Remove:Bool(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method RemoveAll:Bool(c:AbstractCollection<E>)
		If c.IsEmpty() Then Return False
		Local modified:Bool = False
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Self.Contains(E(tempArr[i])) Then
				Self.Remove(E(tempArr[i]))
			End
		Next
		If modified Then modCount += 1
		Return modified
	End

	Method RetainAll:Bool(c:AbstractCollection<E>)
		Local modified:Bool = False
		If tempArr.Length < c.Size Then tempArr = tempArr.Resize(c.Size)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = 0 Until len
			If Not Self.Contains(E(tempArr[i])) Then
				Self.Remove(E(tempArr[i]))
				modified = True
			End
		Next
		If modified Then modCount += 1
		Return modified
	End

	Method Size:Int() Property
		Return size
	End

	Method Sort:Void(reverse:Bool = False, comp:AbstractComparator = Null)
		If size <= 1 Then Return ' can't sort 0 or 1 elements
		If comp = Null Then comp = Self.Comparator
		If comp = Null Then comp = DEFAULT_COMPARATOR
		QuickSort(elements, 0, size-1, comp, reverse)
		modCount += 1
	End

	Method ToArray:Object[]()
		Local arr:Object[] = New Object[size]
		For Local i:Int = 0 Until size
			arr[i] = elements[i]
		Next
		Return arr
	End

	' implements AbstractList

	Method Get:E(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return E(elements[index])
	End

	Method Insert:Void(index:Int, o:E)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = o
		size+=1
		modCount += 1
	End

	Method InsertAll:Bool(index:Int, c:AbstractCollection<E>)
		Local newItemCount:Int = c.Size
		If newItemCount = 0 Then Return False
		If size + newItemCount > elements.Length Then EnsureCapacity(size+newItemCount)
		If tempArr.Length < newItemCount Then tempArr = tempArr.Resize(newItemCount)
		Local len:Int = c.FillArray(tempArr)
		For Local i:Int = size - 1 To index Step -1
			elements[i+newItemCount] = elements[i]
		Next
		For Local i:Int = 0 Until newItemCount
			elements[index+i] = tempArr[i]
		End
		size += newItemCount
		modCount += 1
		Return newItemCount <> 0
	End

	Method IndexOf:Int(o:E)
		For Local i:Int = 0 Until size
			If elements[i] = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOf:Int(o:E)
		For Local i:Int = size-1 To 0 Step -1
			If elements[i] = o Then Return i
		Next
		Return -1
	End

	Method RemoveAt:E(index:Int)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:E = E(elements[index])
		For Local i:Int = index Until size-1
			elements[i] = elements[i+1]
		Next
		elements[size-1] = Null
		size-=1
		modCount += 1
		Return oldValue
	End

	Method RemoveRange:Void(fromIndex:Int, toIndex:Int)
		AssertLessThanOrEqual(fromIndex, toIndex, "ArrayList.RemoveRange: fromIndex > toIndex:")
		If rangeChecking Then
			RangeCheck(fromIndex)
			RangeCheck(toIndex)
		End
		For Local i:Int = 0 Until toIndex - fromIndex
			RemoveAt(fromIndex)
		Next
	End

	Method Set:E(index:Int, o:E)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:E = E(elements[index])
		elements[index] = o
		modCount += 1
		Return oldValue
	End

	Method Enumerator:AbstractEnumerator<E>()
		Return New ArrayListEnumerator<E>(Self)
	End
End

' ArrayList wrapper classes

Class IntArrayList Extends ArrayList<IntObject>
Public
	Method AddInt:Bool(o:Int)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = New IntObject(o)
		size+=1
		modCount += 1
		Return True
	End

	Method ContainsInt:Bool(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	Method Enumerator:AbstractEnumerator<IntObject>()
		Return New IntArrayListEnumerator(Self)
	End

	Method RemoveInt:Bool(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToIntArray:Int[]()
		Local arr:Int[] = New Int[size]
		For Local i:Int = 0 Until size
			arr[i] = IntObject(elements[i]).value
		Next
		Return arr
	End

	Method GetInt:Int(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return IntObject(elements[index]).value
	End

	Method InsertInt:Void(index:Int, o:Int)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New IntObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfInt:Int(o:Int)
		For Local i:Int = 0 Until size
			If IntObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfInt:Int(o:E)
		For Local i:Int = size-1 To 0 Step -1
			If IntObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetInt:Int(index:Int, o:Int)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:Int = IntObject(elements[index]).value
		If elements[index] <> Null Then
			IntObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillIntArray:Int(arr:Int[])
		AssertLessThan(arr.Length, size, "IntArrayList.FillIntArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = IntObject(elements[i]).value
		Next
		Return size
	End
End

Class FloatArrayList Extends ArrayList<FloatObject>
Public
	Method AddFloat:Bool(o:Float)
		If size + 1 > elements.Length Then EnsureCapacity(size + 1)
		elements[size] = New FloatObject(o)
		size += 1
		modCount += 1
		Return True
	End

	Method ContainsFloat:Bool(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	Method Enumerator:AbstractEnumerator<FloatObject>()
		Return New FloatArrayListEnumerator(Self)
	End

	Method RemoveFloat:Bool(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToFloatArray:Float[]()
		Local arr:Float[] = New Float[size]
		For Local i:Int = 0 Until size
			arr[i] = FloatObject(elements[i]).value
		Next
		Return arr
	End

	Method GetFloat:Float(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return FloatObject(elements[index]).value
	End

	Method InsertFloat:Void(index:Int, o:Float)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New FloatObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfFloat:Int(o:Float)
		For Local i:Int = 0 Until size
			If FloatObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfFloat:Int(o:Float)
		For Local i:Int = size-1 To 0 Step -1
			If FloatObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetFloat:Float(index:Int, o:Float)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:Float = FloatObject(elements[index]).value
		If elements[index] <> Null Then
			FloatObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillFloatArray:Int(arr:Float[])
		AssertLessThan(arr.Length, size, "FloatArrayList.FillFloatArray: Array too small:")
		For Local i:Int = 0 Until size
			arr[i] = FloatObject(elements[i]).value
		Next
		Return size
	End
End

Class StringArrayList Extends ArrayList<StringObject>
Public
	Method AddString:Bool(o:String)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		elements[size] = New StringObject(o)
		size+=1
				modCount += 1
				Return True
			End

	Method ContainsString:Bool(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then Return True
		Next
		Return False
	End

	Method Enumerator:AbstractEnumerator<StringObject>()
		Return New StringArrayListEnumerator(Self)
	End

	Method RemoveString:Bool(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then
				RemoveAt(i)
				modCount += 1
				Return True
			End
		Next
		Return False
	End

	Method ToStringArray:String[]()
		Local arr:String[] = New String[size]
		For Local i:Int = 0 Until size
			arr[i] = StringObject(elements[i]).value
		Next
		Return arr
	End

	Method GetString:String(index:Int)
		If rangeChecking Then RangeCheck(index)
		Return StringObject(elements[index]).value
	End

	Method InsertString:Void(index:Int, o:String)
		If rangeChecking Then RangeCheck(index)
		If size+1 > elements.Length Then EnsureCapacity(size+1)
		For Local i:Int = size Until index Step -1
			elements[i] = elements[i-1]
		Next
		elements[index] = New StringObject(o)
		size+=1
		modCount += 1
	End

	Method IndexOfString:Int(o:String)
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method LastIndexOfString:Int(o:String)
		For Local i:Int = size-1 To 0 Step -1
			If StringObject(elements[i]).value = o Then Return i
		Next
		Return -1
	End

	Method SetString:String(index:Int, o:String)
		If rangeChecking Then RangeCheck(index)
		Local oldValue:String = StringObject(elements[index]).value
		If elements[index] <> Null Then
			StringObject(elements[index]).value = o ' XXX: not sure whether we can change value on the fly
		End
		modCount += 1
		Return oldValue
	End

	Method FillStringArray:Int(arr:String[])
		AssertLessThan(arr.Length, size, "StringArrayList.FillStringArray: Array too small:")
		For Local i:Int = 0 Until size
			If StringObject(elements[i]).value = value Then
				Remove(elements[i])
				modCount += 1
				Return True
			End
		Next
		Return False
	End
End

Function QuickSort:Void(arr:Object[], left:Int, right:Int, comp:AbstractComparator, reverse:Bool = False)
	If right > left Then
		Local pivotIndex:Int = left + (right-left)/2
		Local pivotNewIndex:Int = QuickSortPartition(arr, left, right, pivotIndex, comp, reverse)
		QuickSort(arr, left, pivotNewIndex - 1, comp, reverse)
		QuickSort(arr, pivotNewIndex + 1, right, comp, reverse)
	End
End

Function QuickSortPartition:Int(arr:Object[], left:Int, right:Int, pivotIndex:Int, comp:AbstractComparator, reverse:Bool = False)
	Local pivotValue:Object = arr[pivotIndex]
	arr[pivotIndex] = arr[right]
	arr[right] = pivotValue
	Local storeIndex:Int = left, val:Object
	For Local i:Int = left Until right
		If Comparable(arr[i]) <> Null Then
			If Not reverse And Comparable(arr[i]).Compare(pivotValue) <= 0 Or reverse And Comparable(arr[i]).Compare(pivotValue) >= 0 Then
				val = arr[i]
				arr[i] = arr[storeIndex]
				arr[storeIndex] = val
				storeIndex += 1
			End
		Else
			If Not reverse And comp.Compare(arr[i], pivotValue) <= 0 Or reverse And comp.Compare(arr[i], pivotValue) >= 0 Then
				val = arr[i]
				arr[i] = arr[storeIndex]
				arr[storeIndex] = val
				storeIndex += 1
			End
		End
	Next
	val = arr[storeIndex]
	arr[storeIndex] = arr[right]
	arr[right] = val
	Return storeIndex
End