Added config import.

Added config import.

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

'
' Module diddy.diddy
'

Import functions
Import framework
Import inputcache
Import tween
Import collections
Import assert
Import gui
Import config


Added the option to make 'virtualos' a standalone module (For now).

Strict

Public

' Preprocessor related:
#VIRTUALOS_FLAG_OS = True
#VIRTUALOS_STANDALONE = True

#If TARGET = "html5"
	#VIRTUALOS_JS_TARGET = True
#End

#If VIRTUALOS_JS_TARGET
	#VIRTUALOS_IMPLEMENTED = True
	#VIRTUALOS_MAP_ENV = True
	#VIRTUALOS_MAP_FILETIMES = True
	#VIRTUALOS_EXTENSION_DL = True
	#VIRTUALOS_EXTENSION_VFILE = True
	#VIRTUALOS_EXTENSION_REMOTEPATH = True
	'#VIRTUALOS_REAL_FILEPATH = True

	#If CONFIG = "debug"
		'#VIRTUALOS_DEBUG = True
	#End
#Elseif LANG = "cpp" And TARGET <> "win8" And TARGET <> "ios"
	#VIRTUALOS_REAL = True
#End

#If VIRTUALOS_IMPLEMENTED
	#If VIRTUALOS_FLAG_OS
		#BRL_OS_IMPLEMENTED = True
	#End
#End

' Imports (Public):
#If Not VIRTUALOS_IMPLEMENTED
	#If VIRTUALOS_REAL
		Import os
	#End
#Else
	Import "native/os.${LANG}"
#End

#If VIRTUALOS_REAL_FILEPATH
	Import brl.filepath
#End

' Imports (Private):
Private

#If VIRTUALOS_IMPLEMENTED
	#If Not VIRTUALOS_STANDALONE
		Import regal.stringutil

		#If VIRTUALOS_EXTENSION_DL And VIRTUALOS_EXTENSION_VFILE
			Import regal.ioutil.stringstream
		#End
	#Else
		Import brl.databuffer
		Import brl.datastream
	#End

	Import monkey.map

	#If VIRTUALOS_JS_TARGET
		'Import dom
	#End
#End

Public

#If VIRTUALOS_IMPLEMENTED
	' Constant variable(s) (Public):

	' File-types (Must be the same across borders):
	Const FILETYPE_NONE:=		0
	Const FILETYPE_FILE:=		1
	Const FILETYPE_DIR:=		2

	Const FILETIME_UNAVAILABLE:= 0

	' Constant variable(s) (Private):
	Private

	#If VIRTUALOS_STANDALONE
		Const STRING_INVALID_LOCATION:= -1
	#End

	Public

	' External bindings:
	Extern

	' Global variable(s) (External) (Private):
	Extern Private

	' If you are supporting these extensions, please provide '__OS_Storage'.
	#If VIRTUALOS_EXTENSION_VFILE
		#If VIRTUALOS_JS_TARGET
			Global __OS_Storage:StorageHandle="__os_storage"
		#End
	#End

	Extern

	' Classes (External) (Private):
	Extern Private

	' API:
	' Nothing so far.

	' Extensions:
	#If VIRTUALOS_EXTENSION_VFILE
		#If VIRTUALOS_JS_TARGET
			Class StorageHandle = "Storage" ' Extends DOMObject
				' Methods:
				' Nothing so far.
			End
		#Else
			#Error "Unable to resolve type: 'StorageHandle'"
		#End
	#End

	Extern

	' Functions (External):

	' API:
	Function HostOS:String()
	Function AppPath:String()
	Function AppArgs:String[]()
	Function RealPath:String(Path:String)
	Function FileType:Int(Path:String)
	Function FileSize:Int(Path:String)

	#If Not VIRTUALOS_MAP_FILETIMES
		Function FileTime:Int(Path:String)

		Function CopyFile:Bool(Src:String, Dst:String)
		Function DeleteFile:Bool(Path:String)
	#Else
		Function _CopyFile:Bool(Src:String, Dst:String)="CopyFile"
		Function _DeleteFile:Bool(Path:String)="DeleteFile"
	#End

	Function LoadString:String(Path:String)
	Function SaveString:Int(Str:String, Path:String)
	Function LoadDir:String[](Path:String)
	Function CreateDir:Bool(Path:String)
	Function DeleteDir:Bool(Path:String)
	Function ChangeDir:Int(Path:String)
	Function CurrentDir:String()

	#If Not VIRTUALOS_MAP_ENV
		Function SetEnv:Int(Name:String, Value:String)
		Function GetEnv:String(Name:String)
	#End

	Function Execute:Int(CMD:String)

	#If Not VIRTUALOS_DEBUG
		Function ExitApp:Int(RetCode:Int)
	#Else
		Function _ExitApp:Int(RetCode:Int)="ExitApp"
	#End

	' Extensions:
	#If VIRTUALOS_EXTENSION_REMOTEPATH
		Function __OS_ToRemotePath:String(RealPath:String)="__os_toRemotePath"
	#End

	#If VIRTUALOS_EXTENSION_DL
		Function __OS_Download:String(URL:String)="__os_download"

		' Virtual file-system (JavaScript) extensions:
		#If VIRTUALOS_EXTENSION_VFILE ' VIRTUALOS_JS_TARGET
			Function __OS_DownloadFileUsingRep:String(Storage:StorageHandle, URL:String, Rep:String)="__os_downloadFileUsingRep"
			Function __OS_DownloadFile:String(Storage:StorageHandle, RealPath:String)="__os_downloadFile"
		#End
	#End

	#If VIRTUALOS_EXTENSION_VFILE
		Function __OS_StorageSupported:Bool()="__os_storageSupported"
		Function __OS_CreateFileLink:Void(Rep:String)="__os_createFileLink"
	#End

	Public

	' Global variable(s) (Private):
	Private

	#If VIRTUALOS_MAP_ENV
		Global __OS_Env:= New StringMap<String>()
	#End

	#If VIRTUALOS_MAP_FILETIMES
		Global __OS_FileTimes:= New StringMap<Int>()
	#End

	Public

	' Functions (Monkey) (Public):

	' API:
	#If VIRTUALOS_MAP_ENV
		Function SetEnv:Void(name:String, value:String)
			__OS_Env.Set(name, value)

			Return
		End

		Function GetEnv:String(name:String)
			Return __OS_Env.Get(name)
		End
	#End

	#If VIRTUALOS_MAP_FILETIMES
		Function FileTime:Int(Path:String)
			Return __OS_FileTimes.Get(RealPath(Path)) ' FILETIME_UNAVAILABLE
		End

		Function CopyFile:Bool(Src:String, Dst:String)
			Local Result:= _CopyFile(Src, Dst)

			If (Result) Then
				__OS_SetFileTime(RealPath(Dst), FileTime(Src)) ' ; Return True
			Endif

			Return Result ' False
		End

		Function DeleteFile:Bool(Path:String)
			Local Result:= _DeleteFile(Path)

			If (Result) Then
				__OS_RemoveFileTime(RealPath(Path))
			Endif

			Return Result
		End
	#End

	Function LoadDir:String[](Path:String, Recursive:Bool, Hidden:Bool=False)
		Local Dirs:= New StringDeque()
		Local Files:= New StringDeque()

		' Add an initial value for safety.
		Dirs.PushFirst("")

		While (Not Dirs.IsEmpty)
			Local Dir:= Dirs.PopFirst()

			For Local F:= Eachin LoadDir(Path + "/" + Dir)
				If ((Not Hidden) And F.StartsWith(".")) Then
					Continue
				Endif

				If (Dir.Length > 0) Then
					F = Dir + "/" + F
				Endif

				Select (FileType(Path + "/" + F))
					Case FILETYPE_FILE
						Files.PushLast(F)
					Case FILETYPE_DIR
						If (Recursive) Then
							Dirs.PushLast(F)
						Else
							Files.PushLast(F)
						Endif
				End Select
			Next
		Wend

		Return Files.ToArray()
	End

	Function CopyDir:Bool(SourcePath:String, DestinationPath:String, Recursive:Bool=True, Hidden:Bool=False)
		If (FileType(SourcePath) <> FILETYPE_DIR) Then
			Return False
		Endif

		Local Files:= LoadDir(SourcePath)

		Select (FileType(DestinationPath))
			Case FILETYPE_NONE
				If (Not CreateDir(DestinationPath)) Then
					Return False
				Endif
			Case FILETYPE_FILE
				Return False
		End Select

		For Local F:= Eachin Files
			If ((Not Hidden) And F.StartsWith(".")) Then
				Continue
			Endif

			Local SrcP:= (SourcePath + "/" + F)
			Local DstP$= (DestinationPath + "/" + F)

			Select (FileType(SrcP))
				Case FILETYPE_FILE
					If (Not CopyFile(SrcP, DstP)) Then
						Return False
					Endif
				Case FILETYPE_DIR
					If (Recursive And (Not CopyDir(SrcP, DstP, Recursive, Hidden))) Then
						Return False
					Endif
			End Select
		Next

		' Return the default response.
		Return True
	End

	Function DeleteDir:Bool(Path$, Recursive:Bool)
		If (Not Recursive) Then
			Return DeleteDir(Path)
		Endif

		Select (FileType(Path))
			Case FILETYPE_NONE
				Return True
			Case FILETYPE_FILE
				Return False
		End Select

		For Local F:= Eachin LoadDir(Path)
			If (F = "." Or F = "..") Then
				Continue
			Endif

			Local FPath:= (Path + "/" + F)

			If (FileType(FPath) = FILETYPE_DIR) Then
				If (Not DeleteDir(FPath, True)) Then
					Return False
				Endif
			Else
				If (Not DeleteFile(FPath)) Then
					Return False
				Endif
			Endif
		Next

		Return DeleteDir(Path)
	End

	#If Not VIRTUALOS_REAL_FILEPATH
		Function StripDir:String(Path:String)
			Local I:= Path.FindLast("/")

			If (I = STRING_INVALID_LOCATION) Then
				I = Path.FindLast( "\" )
			Endif

			If (I <> STRING_INVALID_LOCATION) Then
				Return Path[I+1..]
			Endif

			Return Path
		End

		Function ExtractDir:String(Path:String)
			Local I:= Path.FindLast("/")

			If (I = STRING_INVALID_LOCATION) Then
				I = Path.FindLast("\")
			Endif

			If (I <> STRING_INVALID_LOCATION) Then
				Return Path[..I]
			Endif

			Return ""
		End

		Function StripExt:String(Path:String)
			Local I:= Path.FindLast(".")
			Local SecondarySearchPos:= (I+1)

			If ((I <> STRING_INVALID_LOCATION) And (Path.Find("/", SecondarySearchPos) = STRING_INVALID_LOCATION) And (Path.Find("\", SecondarySearchPos)= STRING_INVALID_LOCATION)) Then
				Return Path[..I]
			Endif

			Return Path
		End

		Function ExtractExt:String(Path:String)
			Local I:= Path.FindLast(".")
			Local SecondarySearchPos:= (I+1)

			If ((I <> STRING_INVALID_LOCATION) And (Path.Find("/", SecondarySearchPos) = STRING_INVALID_LOCATION) And (Path.Find("\", SecondarySearchPos)= STRING_INVALID_LOCATION)) Then
				Return Path[SecondarySearchPos..]
			Endif

			Return ""
		End

		Function StripAll:String(Path:String)
			Return StripDir(StripExt(Path))
		End
	#End

	' Debugging related:
	#If VIRTUALOS_DEBUG
		Function ExitApp:Int(RetCode:Int)
			DebugStop()

			_ExitApp(RetCode)

			Return 0
		End
	#End

	' Extensions:
	#If VIRTUALOS_MAP_FILETIMES
		Function __OS_SetFileTime:Void(RealPath:String, Time:Int)
			__OS_FileTimes.Set(RealPath, Time)

			Return
		End

		Function __OS_RemoveFileTime:Void(RealPath:String)
			__OS_FileTimes.Remove(RealPath)

			Return
		End
	#End

	#If VIRTUALOS_EXTENSION_VFILE
		#If VIRTUALOS_EXTENSION_DL
			Function __OS_AddFileSystem:Void(URL:String)
				Local FileData:= __OS_Download(URL)

				#If Not VIRTUALOS_STANDALONE
					Local SS:= New StringStream(FileData, ,,,, True)
				#Else
					Local Buf:= New DataBuffer(FileData.Length)

					Buf.PokeString(0, FileData)

					Local SS:= New DataStream(Buf)
				#End

				__OS_ParseFileSystem(SS)

				Return
			End
		#End

		Function __OS_ParseFileSystem:Void(S:Stream) ' StringStream
			__OS_ParseFileSystem(S, New StringStack())

			Return
		End

		Function __OS_ParseFileSystem_Update_ContextRep:String(Context:Stack<String>)
			Local Rep:String

			For Local Folder:= Eachin Context
				Rep += (Folder + "/")
			Next

			Return Rep
		End

		' A simple parser that takes each line of a 'Stream', and decodes a folder structure from the input.
		' The 'OpenPrefix' argument is used to toggle adding an extra slash before generated paths.
		Function __OS_ParseFileSystem:Void(S:Stream, Context:Stack<String>, OpenPrefix:Bool=True) ' StringStream
			' Constant variable(s):
			#If Not VIRTUALOS_STANDALONE
				Const DIVIDER:= ASCII_CHARACTER_SPACE
			#Else
				Const DIVIDER:= 32
			#End

			' Local variable(s):
			Local LastMasterPath:String

			Local Cache_Context:String

			While (Not S.Eof) ' Eof()
				Local Origin:= S.Position
				Local IsFileDescriptor:Bool

				' Not the best of methods:
				Local FirstChar:= S.ReadString(1) ' S.ReadByte() ' S.ReadChar()

				Select FirstChar
					Case "~n", "~r", "~t", " " ' 10, 13, 9, 32
						Continue
					Case "!" ' 33
						IsFileDescriptor = True
					Case "{" ' 123
						Context.Push(LastMasterPath)

						' Update the current context-cache.
						Cache_Context = __OS_ParseFileSystem_Update_ContextRep(Context)

						Continue
					Case "}" ' 125
						If (Not Context.IsEmpty) Then
							Context.Pop()
						Endif

						Cache_Context = __OS_ParseFileSystem_Update_ContextRep(Context)

						Continue
					Default
						IsFileDescriptor = False

						S.Seek(Origin)
				End Select

				Local Line:= S.ReadLine() ' Line.Replace("~t", "")

				Local Entries:String[] = Line.Split(",")

				If (Not IsFileDescriptor) Then
					LastMasterPath = Entries[Entries.Length-1]
				Endif

				' Not using 'EachIn' for performance reasons:
				For Local I:= 0 Until Entries.Length
					Local E:= Entries[I]
					Local E_Length:= E.Length

					E = Cache_Context + SmartClip(E, DIVIDER, E_Length)

					' Extensions:
					Local Time_First:= E.Find("[")

					If (Time_First <> STRING_INVALID_LOCATION) Then
						Local Processed_E:= E[..Time_First]

						#If VIRTUALOS_MAP_FILETIMES
							Local Time_Second:= E.Find("]")

							If (Time_Second <> STRING_INVALID_LOCATION) Then
								Local FTime:= Int(E[Time_First+1..Time_Second])

								If (FTime <> FILETIME_UNAVAILABLE) Then
									__OS_SetFileTime(RealPath(Processed_E), FTime)
								Endif
							Endif
						#End

						E = Processed_E
					Endif

					If (IsFileDescriptor) Then
						__OS_CreateFileLink(RealPath(E)) ' __OS_DownloadFile(__OS_Storage, RealPath(E))
					Else
						CreateDir(E)
					Endif
				Next
			Wend

			Return
		End
	#Else
		Function __OS_StorageSupported:Bool()
			Return False
		End
	#End

	' Functions (Monkey) (Private):
	Private

	#If VIRTUALOS_STANDALONE
		' Ripped from 'regal.stringutil':
		Function SmartClip:String(Input:String, Symbol:Int)
			Return SmartClip(Input, Symbol, Input.Length)
		End

		Function SmartClip:String(Input:String, Symbol:Int, Length:Int)
			' Local variable(s):
			Local FinalChar:= (Length - 1)

			Local XClip:Int
			Local YClip:Int

			If (Input[0] = Symbol) Then
				XClip = 1
			Else
				XClip = 0
			Endif

			If (Input[FinalChar] = Symbol) Then
				YClip = FinalChar
			Else
				YClip = Length
			Endif

			If (XClip <> 0 Or YClip <> 0) Then
				Return Input[XClip..YClip]
			Endif

			Return Input
		End
	#End

	Public
#End

Strict

Public

' Preprocessor related:
#VIRTUALOS_FLAG_OS = True

#If TARGET = "html5"
	#VIRTUALOS_JS_TARGET = True
#End

#If VIRTUALOS_JS_TARGET
	#VIRTUALOS_IMPLEMENTED = True
	#VIRTUALOS_MAP_ENV = True
	#VIRTUALOS_MAP_FILETIMES = True
	#VIRTUALOS_EXTENSION_DL = True
	#VIRTUALOS_EXTENSION_VFILE = True
	#VIRTUALOS_EXTENSION_REMOTEPATH = True
	'#VIRTUALOS_REAL_FILEPATH = True

	#If CONFIG = "debug"
		'#VIRTUALOS_DEBUG = True
	#End
#Elseif LANG = "cpp" And TARGET <> "win8" And TARGET <> "ios"
	#VIRTUALOS_REAL = True
#End

#If VIRTUALOS_IMPLEMENTED
	#If VIRTUALOS_FLAG_OS
		#BRL_OS_IMPLEMENTED = True
	#End
#End

' Imports (Public):
#If Not VIRTUALOS_IMPLEMENTED
	#If VIRTUALOS_REAL
		Import os
	#End
#Else
	Import "native/os.${LANG}"
#End

#If VIRTUALOS_REAL_FILEPATH
	Import brl.filepath
#End

' Imports (Private):
Private

#If VIRTUALOS_IMPLEMENTED
	Import regal.stringutil

	#If VIRTUALOS_EXTENSION_DL And VIRTUALOS_EXTENSION_VFILE
		Import regal.ioutil.stringstream
	#End

	Import monkey.map

	#If VIRTUALOS_JS_TARGET
		'Import dom
	#End
#End

Public

#If VIRTUALOS_IMPLEMENTED
	' Constant variable(s):

	' File-types (Must be the same across borders):
	Const FILETYPE_NONE:=		0
	Const FILETYPE_FILE:=		1
	Const FILETYPE_DIR:=		2

	Const FILETIME_UNAVAILABLE:= 0

	' External bindings:
	Extern

	' Global variable(s) (External) (Private):
	Extern Private

	' If you are supporting these extensions, please provide '__OS_Storage'.
	#If VIRTUALOS_EXTENSION_VFILE
		#If VIRTUALOS_JS_TARGET
			Global __OS_Storage:StorageHandle="__os_storage"
		#End
	#End

	Extern

	' Classes (External) (Private):
	Extern Private

	' API:
	' Nothing so far.

	' Extensions:
	#If VIRTUALOS_EXTENSION_VFILE
		#If VIRTUALOS_JS_TARGET
			Class StorageHandle = "Storage" ' Extends DOMObject
				' Methods:
				' Nothing so far.
			End
		#Else
			#Error "Unable to resolve type: 'StorageHandle'"
		#End
	#End

	Extern

	' Functions (External):

	' API:
	Function HostOS:String()
	Function AppPath:String()
	Function AppArgs:String[]()
	Function RealPath:String(Path:String)
	Function FileType:Int(Path:String)
	Function FileSize:Int(Path:String)

	#If Not VIRTUALOS_MAP_FILETIMES
		Function FileTime:Int(Path:String)

		Function CopyFile:Bool(Src:String, Dst:String)
		Function DeleteFile:Bool(Path:String)
	#Else
		Function _CopyFile:Bool(Src:String, Dst:String)="CopyFile"
		Function _DeleteFile:Bool(Path:String)="DeleteFile"
	#End

	Function LoadString:String(Path:String)
	Function SaveString:Int(Str:String, Path:String)
	Function LoadDir:String[](Path:String)
	Function CreateDir:Bool(Path:String)
	Function DeleteDir:Bool(Path:String)
	Function ChangeDir:Int(Path:String)
	Function CurrentDir:String()

	#If Not VIRTUALOS_MAP_ENV
		Function SetEnv:Int(Name:String, Value:String)
		Function GetEnv:String(Name:String)
	#End

	Function Execute:Int(CMD:String)

	#If Not VIRTUALOS_DEBUG
		Function ExitApp:Int(RetCode:Int)
	#Else
		Function _ExitApp:Int(RetCode:Int)="ExitApp"
	#End

	' Extensions:
	#If VIRTUALOS_EXTENSION_REMOTEPATH
		Function __OS_ToRemotePath:String(RealPath:String)="__os_toRemotePath"
	#End

	#If VIRTUALOS_EXTENSION_DL
		Function __OS_Download:String(URL:String)="__os_download"

		' Virtual file-system (JavaScript) extensions:
		#If VIRTUALOS_EXTENSION_VFILE ' VIRTUALOS_JS_TARGET
			Function __OS_DownloadFileUsingRep:String(Storage:StorageHandle, URL:String, Rep:String)="__os_downloadFileUsingRep"
			Function __OS_DownloadFile:String(Storage:StorageHandle, RealPath:String)="__os_downloadFile"
		#End
	#End

	#If VIRTUALOS_EXTENSION_VFILE
		Function __OS_StorageSupported:Bool()="__os_storageSupported"
		Function __OS_CreateFileLink:Void(Rep:String)="__os_createFileLink"
	#End

	Public

	' Global variable(s) (Private):
	Private

	#If VIRTUALOS_MAP_ENV
		Global __OS_Env:= New StringMap<String>()
	#End

	#If VIRTUALOS_MAP_FILETIMES
		Global __OS_FileTimes:= New StringMap<Int>()
	#End

	Public

	' Functions (Monkey):

	' API:
	#If VIRTUALOS_MAP_ENV
		Function SetEnv:Void(name:String, value:String)
			__OS_Env.Set(name, value)

			Return
		End

		Function GetEnv:String(name:String)
			Return __OS_Env.Get(name)
		End
	#End

	#If VIRTUALOS_MAP_FILETIMES
		Function FileTime:Int(Path:String)
			Return __OS_FileTimes.Get(RealPath(Path)) ' FILETIME_UNAVAILABLE
		End

		Function CopyFile:Bool(Src:String, Dst:String)
			Local Result:= _CopyFile(Src, Dst)

			If (Result) Then
				__OS_SetFileTime(RealPath(Dst), FileTime(Src)) ' ; Return True
			Endif

			Return Result ' False
		End

		Function DeleteFile:Bool(Path:String)
			Local Result:= _DeleteFile(Path)

			If (Result) Then
				__OS_RemoveFileTime(RealPath(Path))
			Endif

			Return Result
		End
	#End

	Function LoadDir:String[](Path:String, Recursive:Bool, Hidden:Bool=False)
		Local Dirs:= New StringDeque()
		Local Files:= New StringDeque()

		' Add an initial value for safety.
		Dirs.PushFirst("")

		While (Not Dirs.IsEmpty)
			Local Dir:= Dirs.PopFirst()

			For Local F:= Eachin LoadDir(Path + "/" + Dir)
				If ((Not Hidden) And F.StartsWith(".")) Then
					Continue
				Endif

				If (Dir.Length > 0) Then
					F = Dir + "/" + F
				Endif

				Select (FileType(Path + "/" + F))
					Case FILETYPE_FILE
						Files.PushLast(F)
					Case FILETYPE_DIR
						If (Recursive) Then
							Dirs.PushLast(F)
						Else
							Files.PushLast(F)
						Endif
				End Select
			Next
		Wend

		Return Files.ToArray()
	End

	Function CopyDir:Bool(SourcePath:String, DestinationPath:String, Recursive:Bool=True, Hidden:Bool=False)
		If (FileType(SourcePath) <> FILETYPE_DIR) Then
			Return False
		Endif

		Local Files:= LoadDir(SourcePath)

		Select (FileType(DestinationPath))
			Case FILETYPE_NONE
				If (Not CreateDir(DestinationPath)) Then
					Return False
				Endif
			Case FILETYPE_FILE
				Return False
		End Select

		For Local F:= Eachin Files
			If ((Not Hidden) And F.StartsWith(".")) Then
				Continue
			Endif

			Local SrcP:= (SourcePath + "/" + F)
			Local DstP$= (DestinationPath + "/" + F)

			Select (FileType(SrcP))
				Case FILETYPE_FILE
					If (Not CopyFile(SrcP, DstP)) Then
						Return False
					Endif
				Case FILETYPE_DIR
					If (Recursive And (Not CopyDir(SrcP, DstP, Recursive, Hidden))) Then
						Return False
					Endif
			End Select
		Next

		' Return the default response.
		Return True
	End

	Function DeleteDir:Bool(Path$, Recursive:Bool)
		If (Not Recursive) Then
			Return DeleteDir(Path)
		Endif

		Select (FileType(Path))
			Case FILETYPE_NONE
				Return True
			Case FILETYPE_FILE
				Return False
		End Select

		For Local F:= Eachin LoadDir(Path)
			If (F = "." Or F = "..") Then
				Continue
			Endif

			Local FPath:= (Path + "/" + F)

			If (FileType(FPath) = FILETYPE_DIR) Then
				If (Not DeleteDir(FPath, True)) Then
					Return False
				Endif
			Else
				If (Not DeleteFile(FPath)) Then
					Return False
				Endif
			Endif
		Next

		Return DeleteDir(Path)
	End

	#If Not VIRTUALOS_REAL_FILEPATH
		Function StripDir:String(Path:String)
			Local I:= Path.FindLast("/")

			If (I = STRING_INVALID_LOCATION) Then
				I = Path.FindLast( "\" )
			Endif

			If (I <> STRING_INVALID_LOCATION) Then
				Return Path[I+1..]
			Endif

			Return Path
		End

		Function ExtractDir:String(Path:String)
			Local I:= Path.FindLast("/")

			If (I = STRING_INVALID_LOCATION) Then
				I = Path.FindLast("\")
			Endif

			If (I <> STRING_INVALID_LOCATION) Then
				Return Path[..I]
			Endif

			Return ""
		End

		Function StripExt:String(Path:String)
			Local I:= Path.FindLast(".")
			Local SecondarySearchPos:= (I+1)

			If ((I <> STRING_INVALID_LOCATION) And (Path.Find("/", SecondarySearchPos) = STRING_INVALID_LOCATION) And (Path.Find("\", SecondarySearchPos)= STRING_INVALID_LOCATION)) Then
				Return Path[..I]
			Endif

			Return Path
		End

		Function ExtractExt:String(Path:String)
			Local I:= Path.FindLast(".")
			Local SecondarySearchPos:= (I+1)

			If ((I <> STRING_INVALID_LOCATION) And (Path.Find("/", SecondarySearchPos) = STRING_INVALID_LOCATION) And (Path.Find("\", SecondarySearchPos)= STRING_INVALID_LOCATION)) Then
				Return Path[SecondarySearchPos..]
			Endif

			Return ""
		End

		Function StripAll:String(Path:String)
			Return StripDir(StripExt(Path))
		End
	#End

	' Debugging related:
	#If VIRTUALOS_DEBUG
		Function ExitApp:Int(RetCode:Int)
			DebugStop()

			_ExitApp(RetCode)

			Return 0
		End
	#End

	' Extensions:
	#If VIRTUALOS_MAP_FILETIMES
		Function __OS_SetFileTime:Void(RealPath:String, Time:Int)
			__OS_FileTimes.Set(RealPath, Time)

			Return
		End

		Function __OS_RemoveFileTime:Void(RealPath:String)
			__OS_FileTimes.Remove(RealPath)

			Return
		End
	#End

	#If VIRTUALOS_EXTENSION_VFILE
		#If VIRTUALOS_EXTENSION_DL
			Function __OS_AddFileSystem:Void(URL:String)
				Local FileData:= __OS_Download(URL)

				Local SS:= New StringStream(FileData, ,,,, True)

				__OS_ParseFileSystem(SS)

				Return
			End
		#End

		Function __OS_ParseFileSystem:Void(S:Stream) ' StringStream
			__OS_ParseFileSystem(S, New StringStack())

			Return
		End

		Function __OS_ParseFileSystem_Update_ContextRep:String(Context:Stack<String>)
			Local Rep:String

			For Local Folder:= Eachin Context
				Rep += (Folder + "/")
			Next

			Return Rep
		End

		' A simple parser that takes each line of a 'Stream', and decodes a folder structure from the input.
		' The 'OpenPrefix' argument is used to toggle adding an extra slash before generated paths.
		Function __OS_ParseFileSystem:Void(S:Stream, Context:Stack<String>, OpenPrefix:Bool=True) ' StringStream
			' Constant variable(s):
			Const DIVIDER:= ASCII_CHARACTER_SPACE

			' Local variable(s):
			Local LastMasterPath:String

			Local Cache_Context:String

			While (Not S.Eof) ' Eof()
				Local Origin:= S.Position
				Local IsFileDescriptor:Bool

				' Not the best of methods:
				Local FirstChar:= S.ReadString(1) ' S.ReadByte() ' S.ReadChar()

				Select FirstChar
					Case "~n", "~r", "~t", " " ' 10, 13, 9, 32
						Continue
					Case "!" ' 33
						IsFileDescriptor = True
					Case "{" ' 123
						Context.Push(LastMasterPath)

						' Update the current context-cache.
						Cache_Context = __OS_ParseFileSystem_Update_ContextRep(Context)

						Continue
					Case "}" ' 125
						If (Not Context.IsEmpty) Then
							Context.Pop()
						Endif

						Cache_Context = __OS_ParseFileSystem_Update_ContextRep(Context)

						Continue
					Default
						IsFileDescriptor = False

						S.Seek(Origin)
				End Select

				Local Line:= S.ReadLine() ' Line.Replace("~t", "")

				Local Entries:String[] = Line.Split(",")

				If (Not IsFileDescriptor) Then
					LastMasterPath = Entries[Entries.Length-1]
				Endif

				' Not using 'EachIn' for performance reasons:
				For Local I:= 0 Until Entries.Length
					Local E:= Entries[I]
					Local E_Length:= E.Length

					E = Cache_Context + SmartClip(E, DIVIDER, E_Length)

					' Extensions:
					Local Time_First:= E.Find("[")

					If (Time_First <> STRING_INVALID_LOCATION) Then
						Local Processed_E:= E[..Time_First]

						#If VIRTUALOS_MAP_FILETIMES
							Local Time_Second:= E.Find("]")

							If (Time_Second <> STRING_INVALID_LOCATION) Then
								Local FTime:= Int(E[Time_First+1..Time_Second])

								If (FTime <> FILETIME_UNAVAILABLE) Then
									__OS_SetFileTime(RealPath(Processed_E), FTime)
								Endif
							Endif
						#End

						E = Processed_E
					Endif

					If (IsFileDescriptor) Then
						__OS_CreateFileLink(RealPath(E)) ' __OS_DownloadFile(__OS_Storage, RealPath(E))
					Else
						CreateDir(E)
					Endif
				Next
			Wend

			Return
		End
	#Else
		Function __OS_StorageSupported:Bool()
			Return False
		End
	#End
#End


Added FlxG.SwitchState function

Added FlxG.SwitchState function

Strict

Import flxgame
Import flxcamera
Import flxu

Import plugin.timermanager

Class FlxG

	Const LIBRARY_NAME:String = "Monkey flixel"

	Const LIBRARY_MAJOR_VERSION:Int = 1

	Const LIBRARY_MINOR_VERSION:Int = 0

	Const DATA_PREFIX:String = "flx_"

	Const RED:Int = $FFFF0012

	Const GREEN:Int = $FF00F225

	Const BLUE:Int = $FF0090E9

	Const PINK:Int = $FFF01EFF

	Const WHITE:Int = $FFFFFFFF

	Const BLACK:Int = $FF000000

	Global deviceWidth:Int

	Global deviceHeight:Int

	Global width:Int

	Global height:Int

	Global cameras:Stack<FlxCamera>

	Global camera:FlxCamera

	Global plugins:Stack<FlxBasic>

	Global elapsed:Float

	Global timeScale:Float

	Global visualDebug:Bool

	Global globalSeed:Int

	Global framerate:Int

	Global _deviceScaleFactorX:Float = 1

	Global _deviceScaleFactorY:Float = 1

	Global _bgColor:FlxColor = FlxColor.ARGB(FlxG.BLACK)

	Global _game:FlxGame

	Global _lastDrawingColor:Int

	Global _lastDrawingBlend:Int

Public
	Function Random:Float()
		FlxG.globalSeed = (FlxG.globalSeed * 1664525 + 1013904223)|0
		Return FlxU.Srand(FlxG.globalSeed)
	End Function

	Function GetRandom:FlxBasic(objects:FlxBasic[], startIndex:Int = 0, length:Int = 0)
		If (objects <> Null) Then
			Local l:Int = length

			If (l = 0 Or l > objects.Length() - startIndex) Then
				l = objects.Length() - startIndex
			End if

			If (l > 0) Return objects[startIndex + int(FlxG.Random()*l)]
		End If

		Return Null
	End Function

	#Rem
	Function GetRandom:Object(objects:Object[], startIndex:Int = 0, length:Int = 0)
		GetRandom is not currently supported in Monkey. Use FlxArray.GetSafeRandom method
	End Function
	#End

	Function SwitchState:Void(state:FlxState)
		FlxG._game._requestedState = state
	End Function

	Function AddCamera:FlxCamera(newCamera:FlxCamera)
		FlxG.cameras.Push(newCamera)
		Return newCamera
	End Function

	Function RemoveCamera:Void(camera:FlxCamera, destroy:Bool = True)
		FlxG.cameras.RemoveEach(camera)
		If (destroy) camera.Destroy()
	End Function

	Function ResetCameras:Void(newCamera:FlxCamera = Null)
		Local cam:FlxCamera
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			cam = FlxG.cameras.Get(i)
			cam.Destroy()
			i+=1
		Wend

		FlxG.cameras.Clear()
		If (newCamera = Null) newCamera = New FlxCamera(0, 0, FlxG.width, FlxG.height)

		FlxG.camera = FlxG.AddCamera(newCamera)
	End Function

	Function Flash:Void(color:Int = FlxG.WHITE, duration:Float = 1, onComplete:FlxFunction = Null, force:Bool = False)
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			FlxG.cameras.Get(i).Flash(color, duration, onComplete, force)
			i+=1
		Wend
	End Function

	Function Fade:Void(color:Int = FlxG.BLACK, duration:Float = 1, onComplete:FlxFunction = Null, force:Bool = False)
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			FlxG.cameras.Get(i).Fade(color, duration, onComplete, force)
			i+=1
		Wend
	End Function

	Function Shake:Void(intensity:Float = 0.05, duration:Float = 0.5, onComplete:FlxFunction = Null, force:Bool = True, direction:Int = FlxCamera.SHAKE_BOTH_AXES)
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			FlxG.cameras.Get(i).Shake(intensity, duration, onComplete, force, direction)
			i+=1
		Wend
	End Function

	Function BgColor:Int()
		If (FlxG.camera = Null Or Not FlxG.camera.alive) Return FlxG._bgColor.argb
		Return FlxG.camera.BgColor
	End Function

	Function BgColor:Void(color:Int)
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			FlxG.cameras.Get(i).BgColor = color
			i+=1
		Wend

		FlxG._bgColor.SetARGB(color)
	End Function

	Function AddPlugin:FlxBasic(plugin:FlxBasic)
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			If (pluginList.Get(i).ToString() = plugin.ToString()) Then
				Return plugin
			End If

			i+=1
		Wend

		pluginList.Push(plugin)
		Return plugin
	End Function

	Function GetPlugin:FlxBasic(creator:FlxClass)
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local plugin:FlxBasic
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (creator.InstanceOf(plugin)) Return plugin

			i+=1
		Wend

		Return Null
	End Function

	Function RemovePlugin:FlxBasic(plugin:FlxBasic)
		plugins.RemoveEach(plugin)
		Return plugin
	End Function

	Function RemovePluginType:Bool(creator:FlxClass)
		Local results:Bool = False
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local i:Int = pluginList.Length() - 1

		While(i >= 0)
			If (creator.InstanceOf(pluginList.Get(i))) Then
				pluginList.Remove(i)
				results = True
			End If

			i-=1
		Wend

		Return results
	End Function

	Function Init:Void(game:FlxGame, width:Int, height:Int, zoom:Float)
		FlxG._game = game
		FlxG.width = width
		FlxG.height = height

		FlxCamera.defaultZoom = zoom
		FlxG.cameras = New Stack<FlxCamera>()

		plugins = New Stack<FlxBasic>
		AddPlugin(New TimerManager())
	End Function

	Function Reset:Void()
		FlxG.timeScale = 1
		FlxG.elapsed = 0
		FlxG.globalSeed = Rnd(1, 10000000)
	End Function

	Function UpdateCameras:Void()
		Local cam:FlxCamera
		Local cams:Stack<FlxCamera> = FlxG.cameras
		Local i:Int = 0
		Local l:Int = cams.Length()

		While(i < l)
			cam = cams.Get(i)
			If (cam <> Null And cam.exists And cam.active) cam.Update()
			i+=1
		Wend
	End Function

	Function UpdatePlugins:Void()
		Local plugin:FlxBasic
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.exists And plugin.active) plugin.Update()
			i+=1
		Wend
	End Function

	Function DrawPlugins:Void()
		Local plugin:FlxBasic
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.exists And plugin.visible) plugin.Draw()
			i+=1
		Wend
	End Function

End Class

Strict

Import flxgame
Import flxcamera
Import flxu

Import plugin.timermanager

Class FlxG

	Const LIBRARY_NAME:String = "Monkey flixel"

	Const LIBRARY_MAJOR_VERSION:Int = 1

	Const LIBRARY_MINOR_VERSION:Int = 0

	Const DATA_PREFIX:String = "flx_"

	Const RED:Int = $FFFF0012

	Const GREEN:Int = $FF00F225

	Const BLUE:Int = $FF0090E9

	Const PINK:Int = $FFF01EFF

	Const WHITE:Int = $FFFFFFFF

	Const BLACK:Int = $FF000000

	Global deviceWidth:Int

	Global deviceHeight:Int

	Global width:Int

	Global height:Int

	Global cameras:Stack<FlxCamera>

	Global camera:FlxCamera

	Global plugins:Stack<FlxBasic>

	Global elapsed:Float

	Global timeScale:Float

	Global visualDebug:Bool

	Global globalSeed:Int

	Global framerate:Int

	Global _deviceScaleFactorX:Float = 1

	Global _deviceScaleFactorY:Float = 1

	Global _bgColor:FlxColor = FlxColor.ARGB(FlxG.BLACK)

	Global _game:FlxGame

	Global _lastDrawingColor:Int

	Global _lastDrawingBlend:Int

Public
	Function Random:Float()
		FlxG.globalSeed = (FlxG.globalSeed * 1664525 + 1013904223)|0
		Return FlxU.Srand(FlxG.globalSeed)
	End Function

	Function GetRandom:FlxBasic(objects:FlxBasic[], startIndex:Int = 0, length:Int = 0)
		If (objects <> Null) Then
			Local l:Int = length

			If (l = 0 Or l > objects.Length() - startIndex) Then
				l = objects.Length() - startIndex
			End if

			If (l > 0) Return objects[startIndex + int(FlxG.Random()*l)]
		End If

		Return Null
	End Function

	#Rem
	Function GetRandom:Object(objects:Object[], startIndex:Int = 0, length:Int = 0)
		GetRandom is not currently supported in Monkey. Use FlxArray.GetSafeRandom method
	End Function
	#End

	Function AddCamera:FlxCamera(newCamera:FlxCamera)
		FlxG.cameras.Push(newCamera)
		Return newCamera
	End Function

	Function RemoveCamera:Void(camera:FlxCamera, destroy:Bool = True)
		FlxG.cameras.RemoveEach(camera)
		If (destroy) camera.Destroy()
	End Function

	Function ResetCameras:Void(newCamera:FlxCamera = Null)
		Local cam:FlxCamera
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			cam = FlxG.cameras.Get(i)
			cam.Destroy()
			i+=1
		Wend

		FlxG.cameras.Clear()
		If (newCamera = Null) newCamera = New FlxCamera(0, 0, FlxG.width, FlxG.height)

		FlxG.camera = FlxG.AddCamera(newCamera)
	End Function

	Function Flash:Void(color:Int = FlxG.WHITE, duration:Float = 1, onComplete:FlxFunction = Null, force:Bool = False)
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			FlxG.cameras.Get(i).Flash(color, duration, onComplete, force)
			i+=1
		Wend
	End Function

	Function Fade:Void(color:Int = FlxG.BLACK, duration:Float = 1, onComplete:FlxFunction = Null, force:Bool = False)
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			FlxG.cameras.Get(i).Fade(color, duration, onComplete, force)
			i+=1
		Wend
	End Function

	Function Shake:Void(intensity:Float = 0.05, duration:Float = 0.5, onComplete:FlxFunction = Null, force:Bool = True, direction:Int = FlxCamera.SHAKE_BOTH_AXES)
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			FlxG.cameras.Get(i).Shake(intensity, duration, onComplete, force, direction)
			i+=1
		Wend
	End Function

	Function BgColor:Int()
		If (FlxG.camera = Null Or Not FlxG.camera.alive) Return FlxG._bgColor.argb
		Return FlxG.camera.BgColor
	End Function

	Function BgColor:Void(color:Int)
		Local i:Int = 0
		Local l:Int = FlxG.cameras.Length()

		While(i < l)
			FlxG.cameras.Get(i).BgColor = color
			i+=1
		Wend

		FlxG._bgColor.SetARGB(color)
	End Function

	Function AddPlugin:FlxBasic(plugin:FlxBasic)
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			If (pluginList.Get(i).ToString() = plugin.ToString()) Then
				Return plugin
			End If

			i+=1
		Wend

		pluginList.Push(plugin)
		Return plugin
	End Function

	Function GetPlugin:FlxBasic(creator:FlxClass)
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local plugin:FlxBasic
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (creator.InstanceOf(plugin)) Return plugin

			i+=1
		Wend

		Return Null
	End Function

	Function RemovePlugin:FlxBasic(plugin:FlxBasic)
		plugins.RemoveEach(plugin)
		Return plugin
	End Function

	Function RemovePluginType:Bool(creator:FlxClass)
		Local results:Bool = False
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local i:Int = pluginList.Length() - 1

		While(i >= 0)
			If (creator.InstanceOf(pluginList.Get(i))) Then
				pluginList.Remove(i)
				results = True
			End If

			i-=1
		Wend

		Return results
	End Function

	Function Init:Void(game:FlxGame, width:Int, height:Int, zoom:Float)
		FlxG._game = game
		FlxG.width = width
		FlxG.height = height

		FlxCamera.defaultZoom = zoom
		FlxG.cameras = New Stack<FlxCamera>()

		plugins = New Stack<FlxBasic>
		AddPlugin(New TimerManager())
	End Function

	Function Reset:Void()
		FlxG.timeScale = 1
		FlxG.elapsed = 0
		FlxG.globalSeed = Rnd(1, 10000000)
	End Function

	Function UpdateCameras:Void()
		Local cam:FlxCamera
		Local cams:Stack<FlxCamera> = FlxG.cameras
		Local i:Int = 0
		Local l:Int = cams.Length()

		While(i < l)
			cam = cams.Get(i)
			If (cam <> Null And cam.exists And cam.active) cam.Update()
			i+=1
		Wend
	End Function

	Function UpdatePlugins:Void()
		Local plugin:FlxBasic
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.exists And plugin.active) plugin.Update()
			i+=1
		Wend
	End Function

	Function DrawPlugins:Void()
		Local plugin:FlxBasic
		Local pluginList:Stack<FlxBasic> = FlxG.plugins
		Local i:Int = 0
		Local l:Int = pluginList.Length()

		While(i < l)
			plugin = pluginList.Get(i)
			If (plugin.exists And plugin.visible) plugin.Draw()
			i+=1
		Wend
	End Function

End Class


Broken transitions fixed

Broken transitions fixed

Strict

' All transitions where ported from the Kivy project
' See: https://github.com/kivy/kivy/blob/master/kivy/animation.py#L366

Interface Transition
    Method Calculate:Float(progress:Float)
End

Class TransitionLinear Implements Transition
    Method Calculate:Float(progress:Float)
        Return progress
    End
End

Class TransitionInQuad Implements Transition
    Method Calculate:Float(progress:Float)
        Return Pow(progress, 2)
    End
End

Class TransitionOutQuad Implements Transition
    Method Calculate:Float(progress:Float)
        Return -1 * progress * (progress - 2)
    End
End

Class TransitionInOutQuad Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return 0.5 * Pow(progress, 2)

        progress -= 1
        Return -0.5 * (progress * (progress - 2) - 1)
    End
End

Class TransitionInCubic Implements Transition
    Method Calculate:Float(progress:Float)
        Return Pow(progress, 3)
    End
End

Class TransitionOutCubic Implements Transition
    Method Calculate:Float(progress:Float)
        progress -= 1
        Return Pow(progress, 3) + 1
    End
End

Class TransitionInOutCubic Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return 0.5 * Pow(progress, 3)

        progress -= 2
        Return 0.5 * (Pow(progress, 3) + 2)
    End
End

Class TransitionInQuart Implements Transition
    Method Calculate:Float(progress:Float)
        Return Pow(progress, 4)
    End
End

Class TransitionOutQuart Implements Transition
    Method Calculate:Float(progress:Float)
        progress -= 1
        Return -1 * (Pow(progress, 4) - 1)
    End
End

Class TransitionInOutQuart Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return 0.5 * Pow(progress, 4)

        progress -= 2
        Return -0.5 * (Pow(progress, 4) - 2)
    End
End

Class TransitionInSine Implements Transition
    Method Calculate:Float(progress:Float)
        Return -1 * Cosr(progress * HALFPI) + 1
    End
End

Class TransitionOutSine Implements Transition
    Method Calculate:Float(progress:Float)
        Return Sinr(progress * HALFPI)
    End
End

Class TransitionInOutSine Implements Transition
    Method Calculate:Float(progress:Float)
        Return -0.5 * (Cosr(progress * PI) - 1.0)
    End
End

Class TransitionInExpo Implements Transition
    Method Calculate:Float(progress:Float)
        If progress = 0 Then Return 0
        Return Pow(2, 10 * (progress - 1.0))
    End
End

Class TransitionOutExpo Implements Transition
    Method Calculate:Float(progress:Float)
        If progress = 1 Then Return 1
        Return -Pow(2, -10 * progress) + 1
    End
End

Class TransitionInOutExpo Implements Transition
    Method Calculate:Float(progress:Float)
        If progress = 0 Then Return 0
        If progress = 1 Then Return 1

        progress *= 2
        If progress < 1 Then Return 0.5 * Pow(2, 10 * (progress - 1.0))

        progress -= 1
        Return 0.5 * (-Pow(2, -10 * progress) + 2)
    End
End

Class TransitionInCirc Implements Transition
    Method Calculate:Float(progress:Float)
        Return -1 * (Sqrt(1 - Pow(progress, 2)) - 1)
    End
End

Class TransitionOutCirc Implements Transition
    Method Calculate:Float(progress:Float)
        progress -= 1
        Return Sqrt(1 - Pow(progress, 2))
    End
End

Class TransitionInOutCirc Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return -0.5 * (Sqrt(1 - Pow(progress, 2)) - 1)

        progress -= 2
        Return 0.5 * (Sqrt(1 - Pow(progress, 2)) + 1)
    End
End

Class TransitionInElastic Implements Transition
    Private

    Const P:Float = 0.3
    Const S:Float = P / 4

    Public

    Method Calculate:Float(progress:Float)
        If progress = 1 Then Return 1
        progress -= 1

        Return -(Pow(2, 10 * progress) * Sinr((progress - S) * TWOPI / P))
    End
End

Class TransitionOutElastic Implements Transition
    Private

    Const P:Float = 0.3
    Const S:Float = P / 4

    Public

    Method Calculate:Float(progress:Float)
        If progress = 1 Then Return 1
        Return Pow(2, -10 * progress) * Sinr((progress - S) * TWOPI / P) + 1
    End
End

Class TransitionInOutElastic Implements Transition
    Private

    Const P:Float = 0.45
    Const S:Float = P / 4

    Public

    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress = 2 Then Return 1

        If progress < 1 Then
            progress -= 1
            Return -0.5 * (Pow(2, 10 * progress) * Sinr((progress - S) * TWOPI / P))
        Else
            progress -= 1
            Return Pow(2, -10 * progress) * Sinr((progress - S) * TWOPI / P) * 0.5 + 1
        End
    End
End

Class TransitionInBack Implements Transition
    Method Calculate:Float(progress:Float)
        Return Pow(progress, 2) * (2.70158 * progress - 1.70158)
    End
End

Class TransitionOutBack Implements Transition
    Method Calculate:Float(progress:Float)
        progress -= 1
        Return Pow(progress, 2) * (2.70158 * progress + 1.70158) + 1
    End
End

Class TransitionInOutBack Implements Transition
    Private

    Const S:Float = 1.70158 * 1.525

    Public

    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return 0.5 * (Pow(progress, 2) * ((S + 1) * progress - S))

        progress -= 2
        Return 0.5 * (Pow(progress, 2) * ((S + 1) * progress + S) + 2)
    End
End

Function OutBounce:Float(progress:Float)
    If progress < (1 / 2.75) Return 7.5625 * Pow(progress, 2)

    If progress < (2 / 2.75)
        progress -= 1.5 / 2.75
        Return 7.5625 * Pow(progress, 2) + 0.75
    End

    If progress < (2.5 / 2.75)
        progress -= 2.25 / 2.75
        Return 7.5625 * Pow(progress, 2) + 0.9375
    End

    progress -= 2.625 / 2.75
    Return 7.5625 * Pow(progress, 2) + 0.984375
End

Function InBounce:Float(progress:Float)
    Return 1 - OutBounce(1 - progress)
End

Class TransitionInBounce Implements Transition
    Method Calculate:Float(progress:Float)
        Return InBounce(progress)
    End
End

Class TransitionOutBounce Implements Transition
    Method Calculate:Float(progress:Float)
        Return OutBounce(progress)
    End
End

Class TransitionInOutBounce Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return InBounce(progress) * 0.5

        Return OutBounce(progress - 1) * 0.5 + 0.5
    End
End

Strict

' All transitions where ported from the Kivy project
' See: https://github.com/kivy/kivy/blob/master/kivy/animation.py#L366

Interface Transition
    Method Calculate:Float(progress:Float)
End

Class TransitionLinear Implements Transition
    Method Calculate:Float(progress:Float)
        Return progress
    End
End

Class TransitionInQuad Implements Transition
    Method Calculate:Float(progress:Float)
        Return Pow(progress, 2)
    End
End

Class TransitionOutQuad Implements Transition
    Method Calculate:Float(progress:Float)
        Return -1 * progress * (progress - 2)
    End
End

Class TransitionInOutQuad Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return 0.5 * Pow(progress, 2)

        progress -= 1
        Return -0.5 * (progress * (progress - 2) - 1)
    End
End

Class TransitionInCubic Implements Transition
    Method Calculate:Float(progress:Float)
        Return Pow(progress, 3)
    End
End

Class TransitionOutCubic Implements Transition
    Method Calculate:Float(progress:Float)
        progress -= 1
        Return Pow(progress, 3) + 1
    End
End

Class TransitionInOutCubic Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return 0.5 * Pow(progress, 3)

        progress -= 2
        Return 0.5 * (Pow(progress, 3) + 2)
    End
End

Class TransitionInQuart Implements Transition
    Method Calculate:Float(progress:Float)
        Return Pow(progress, 4)
    End
End

Class TransitionOutQuart Implements Transition
    Method Calculate:Float(progress:Float)
        progress -= 1
        Return -1 * (Pow(progress, 4) - 1)
    End
End

Class TransitionInOutQuart Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return 0.5 * Pow(progress, 4)

        progress -= 2
        Return -0.5 * (Pow(progress, 4) - 2)
    End
End

Class TransitionInSine Implements Transition
    Method Calculate:Float(progress:Float)
        Return -1 * Cos(progress * HALFPI) + 1.0
    End
End

Class TransitionOutSine Implements Transition
    Method Calculate:Float(progress:Float)
        Return Sin(progress * HALFPI)
    End
End

Class TransitionInOutSine Implements Transition
    Method Calculate:Float(progress:Float)
        Return -0.5 * (Cos(progress * PI) - 1.0)
    End
End

Class TransitionInExpo Implements Transition
    Method Calculate:Float(progress:Float)
        If progress = 0 Then Return 0
        Return Pow(2, 10 * (progress - 1.0))
    End
End

Class TransitionOutExpo Implements Transition
    Method Calculate:Float(progress:Float)
        If progress = 1 Then Return 1
        Return -Pow(2, -10 * progress) + 1
    End
End

Class TransitionInOutExpo Implements Transition
    Method Calculate:Float(progress:Float)
        If progress = 0 Then Return 0
        If progress = 1 Then Return 1

        progress *= 2
        If progress < 1 Then Return 0.5 * Pow(2, 10 * (progress - 1.0))

        progress -= 1
        Return 0.5 * (-Pow(2, -10 * progress) + 2)
    End
End

Class TransitionInCirc Implements Transition
    Method Calculate:Float(progress:Float)
        Return -1 * (Sqrt(1 - Pow(progress, 2)) - 1)
    End
End

Class TransitionOutCirc Implements Transition
    Method Calculate:Float(progress:Float)
        progress -= 1
        Return Sqrt(1 - Pow(progress, 2))
    End
End

Class TransitionInOutCirc Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return -0.5 * (Sqrt(1 - Pow(progress, 2)) - 1)

        progress -= 2
        Return 0.5 * (Sqrt(1 - Pow(progress, 2)) + 1)
    End
End

Class TransitionInElastic Implements Transition
    Private

    Const P:Float = 0.3
    Const S:Float = P / 4

    Public

    Method Calculate:Float(progress:Float)
        If progress = 1 Then Return 1
        progress -= 1

        Return -(Pow(2, 10 * progress) * Sin((progress - S) * TWOPI / P))
    End
End

Class TransitionOutElastic Implements Transition
    Private

    Const P:Float = 0.3
    Const S:Float = P / 4

    Public

    Method Calculate:Float(progress:Float)
        If progress = 1 Then Return 1
        progress -= 1

        Return Pow(2, -10 * progress) * Sin((progress - S) * TWOPI / P) + 1
    End
End

Class TransitionInOutElastic Implements Transition
    Private

    Const P:Float = 0.45
    Const S:Float = P / 4

    Public

    Method Calculate:Float(progress:Float)
        If progress = 1 Then Return 1

        progress = progress * 2 - 1
        If progress < 1 Then
            Return -0.5 * (Pow(2, 10 * progress) * Sin((progress - S) * TWOPI / P))
        End

        Return Pow(2, -10 * progress) * Sin((progress - S) * TWOPI / P) * 0.5 + 1
    End
End

Class TransitionInBack Implements Transition
    Method Calculate:Float(progress:Float)
        Return Pow(progress, 2) * (2.70158 * progress - 1.70158)
    End
End

Class TransitionOutBack Implements Transition
    Method Calculate:Float(progress:Float)
        progress -= 1
        Return Pow(progress, 2) * (2.70158 * progress + 1.70158) + 1
    End
End

Class TransitionInOutBack Implements Transition
    Private

    Const S:Float = 1.70158 * 1.525

    Public

    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return 0.5 * (Pow(progress, 2) * ((S + 1) * progress - S))

        progress -= 2
        Return 0.5 * (Pow(progress, 2) * ((S + 1) * progress + S) + 2)
    End
End

Function OutBounce:Float(progress:Float)
    If progress < (1 / 2.75) Return 7.5625 * Pow(progress, 2)

    If progress < (2 / 2.75)
        progress -= 1.5 / 2.75
        Return 7.5625 * Pow(progress, 2) + 0.75
    End

    If progress < (2.5 / 2.75)
        progress -= 2.25 / 2.75
        Return 7.5625 * Pow(progress, 2) + 0.9375
    End

    progress -= 2.625 / 2.75
    Return 7.5625 * Pow(progress, 2) + 0.984375
End

Function InBounce:Float(progress:Float)
    Return 1 - OutBounce(1 - progress)
End

Class TransitionInBounce Implements Transition
    Method Calculate:Float(progress:Float)
        Return InBounce(progress)
    End
End

Class TransitionOutBounce Implements Transition
    Method Calculate:Float(progress:Float)
        Return OutBounce(progress)
    End
End

Class TransitionInOutBounce Implements Transition
    Method Calculate:Float(progress:Float)
        progress *= 2
        If progress < 1 Then Return InBounce(progress) * 0.5

        Return OutBounce(progress - 1) * 0.5 + 0.5
    End
End