Better thread/download management
This commit is contained in:
159
PBMap.pb
159
PBMap.pb
@@ -128,6 +128,7 @@ Module PBMap
|
|||||||
Download.i
|
Download.i
|
||||||
Time.i
|
Time.i
|
||||||
Size.i
|
Size.i
|
||||||
|
Mutex.i
|
||||||
EndStructure
|
EndStructure
|
||||||
|
|
||||||
Structure BoundingBox
|
Structure BoundingBox
|
||||||
@@ -155,6 +156,7 @@ Module PBMap
|
|||||||
|
|
||||||
Structure ImgMemCach
|
Structure ImgMemCach
|
||||||
nImage.i
|
nImage.i
|
||||||
|
Size.i
|
||||||
*Tile.Tile
|
*Tile.Tile
|
||||||
*TimeStackPtr
|
*TimeStackPtr
|
||||||
Alpha.i
|
Alpha.i
|
||||||
@@ -298,7 +300,6 @@ Module PBMap
|
|||||||
DownloadSlots.i ; Actual nb of used download slots
|
DownloadSlots.i ; Actual nb of used download slots
|
||||||
DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var
|
DownloadSlotsMutex.i ; To be sure that only one thread at a time can access to the DownloadSlots var
|
||||||
|
|
||||||
|
|
||||||
List TracksList.Tracks() ; To display a GPX track
|
List TracksList.Tracks() ; To display a GPX track
|
||||||
List Markers.Marker() ; To diplay marker
|
List Markers.Marker() ; To diplay marker
|
||||||
EditMarker.l
|
EditMarker.l
|
||||||
@@ -1056,7 +1057,7 @@ Module PBMap
|
|||||||
Procedure MemoryCacheManagement()
|
Procedure MemoryCacheManagement()
|
||||||
; MemoryCache access management
|
; MemoryCache access management
|
||||||
LockMutex(PBMap\MemoryCacheAccessNBMutex)
|
LockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
; If MemoryCache is not being used by a download thread
|
; If MemoryCache is not being used by any download thread
|
||||||
If PBMap\MemoryCacheAccessNB = 0
|
If PBMap\MemoryCacheAccessNB = 0
|
||||||
PBMap\MemoryCacheAccessNB = -1 ; Not really useful as the download thread are now blocked by the mutex, and this procedure is synchronous
|
PBMap\MemoryCacheAccessNB = -1 ; Not really useful as the download thread are now blocked by the mutex, and this procedure is synchronous
|
||||||
;UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
;UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
@@ -1109,7 +1110,7 @@ Module PBMap
|
|||||||
Protected nImage.i, LifeTime.i, MaxLifeTime.i
|
Protected nImage.i, LifeTime.i, MaxLifeTime.i
|
||||||
MaxLifeTime.i = PBMap\Options\TileLifetime
|
MaxLifeTime.i = PBMap\Options\TileLifetime
|
||||||
If FileSize(CacheFile) > 0 ; <> -1
|
If FileSize(CacheFile) > 0 ; <> -1
|
||||||
; Manage tile file lifetime
|
; Manage tile file lifetime
|
||||||
If MaxLifeTime <> -1
|
If MaxLifeTime <> -1
|
||||||
LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created
|
LifeTime = Date() - GetFileDate(CacheFile, #PB_Date_Modified) ; There's a bug with #PB_Date_Created
|
||||||
If LifeTime > MaxLifeTime
|
If LifeTime > MaxLifeTime
|
||||||
@@ -1164,62 +1165,74 @@ Module PBMap
|
|||||||
|
|
||||||
;-*** These are threaded
|
;-*** These are threaded
|
||||||
|
|
||||||
Threaded Progress = 0, Size = 0, Quit = #False
|
Threaded Progress = 0, Quit = #False
|
||||||
|
|
||||||
Procedure GetImageThread(*Tile.Tile)
|
Procedure GetImageThread(*Tile.Tile)
|
||||||
MyDebug("Thread starting for image " + *Tile\CacheFile + "(" + *Tile\key + ")", 5)
|
MyDebug("Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " starting for image " + *Tile\CacheFile, 5)
|
||||||
;*** Waits for a free download slot
|
|
||||||
LockMutex(PBMap\DownloadSlotsMutex)
|
LockMutex(PBMap\DownloadSlotsMutex)
|
||||||
While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots
|
; Is there's no free download slot, abort
|
||||||
|
If PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots
|
||||||
|
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because no free download slot.", 5)
|
||||||
|
*Tile\Size = 0 ; \Size = 0 signals that the download has failed
|
||||||
UnlockMutex(PBMap\DownloadSlotsMutex)
|
UnlockMutex(PBMap\DownloadSlotsMutex)
|
||||||
If ElapsedMilliseconds() - *Tile\Time > 10000
|
PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread
|
||||||
*Tile\Size = 0 ; \Size = 0 signals that the download has failed
|
ProcedureReturn
|
||||||
MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds waiting for a slot.", 5)
|
EndIf
|
||||||
PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread
|
|
||||||
ProcedureReturn #False
|
|
||||||
EndIf
|
|
||||||
MyDebug(" Thread for image " + *Tile\CacheFile + " waiting a download slot", 5)
|
|
||||||
Delay(20)
|
|
||||||
LockMutex(PBMap\DownloadSlotsMutex)
|
|
||||||
Wend
|
|
||||||
PBMap\DownloadSlots + 1
|
PBMap\DownloadSlots + 1
|
||||||
UnlockMutex(PBMap\DownloadSlotsMutex)
|
UnlockMutex(PBMap\DownloadSlotsMutex)
|
||||||
;***
|
; *** Waits for a free download slot
|
||||||
|
; LockMutex(PBMap\DownloadSlotsMutex)
|
||||||
|
; While PBMap\DownloadSlots >= PBMap\Options\MaxDownloadSlots
|
||||||
|
; UnlockMutex(PBMap\DownloadSlotsMutex)
|
||||||
|
; If ElapsedMilliseconds() - *Tile\Time > 10000
|
||||||
|
; *Tile\Size = 0 ; \Size = 0 signals that the download has failed
|
||||||
|
; MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds waiting for a slot.", 5)
|
||||||
|
; PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread
|
||||||
|
; ProcedureReturn #False
|
||||||
|
; EndIf
|
||||||
|
; MyDebug(" Thread for image " + *Tile\CacheFile + " waiting a download slot", 5)
|
||||||
|
; Delay(20)
|
||||||
|
; LockMutex(PBMap\DownloadSlotsMutex)
|
||||||
|
; Wend
|
||||||
|
; PBMap\DownloadSlots + 1
|
||||||
|
; UnlockMutex(PBMap\DownloadSlotsMutex)
|
||||||
|
; ***
|
||||||
; MemoryCache access management
|
; MemoryCache access management
|
||||||
LockMutex(PBMap\MemoryCacheAccessNBMutex)
|
LockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
; If MemoryCache is currently being cleaned, wait
|
; If MemoryCache is currently being cleaned, abort
|
||||||
While PBMap\MemoryCacheAccessNB = -1
|
If PBMap\MemoryCacheAccessNB = -1
|
||||||
|
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled because of cleaning.", 5)
|
||||||
|
*Tile\Size = 0 ; \Size = 0 signals that the download has failed
|
||||||
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
Delay(20)
|
PostEvent(#PB_Event_Gadget, PBMap\Window, PBmap\Gadget, #PB_MAP_TILE_CLEANUP, *Tile) ; To free memory outside the thread
|
||||||
LockMutex(PBMap\MemoryCacheAccessNBMutex)
|
ProcedureReturn
|
||||||
Wend
|
EndIf
|
||||||
; We're accessing MemoryCache
|
; We're accessing MemoryCache
|
||||||
PBMap\MemoryCacheAccessNB + 1
|
PBMap\MemoryCacheAccessNB + 1
|
||||||
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
*Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous)
|
*Tile\Download = ReceiveHTTPFile(*Tile\URL, *Tile\CacheFile, #PB_HTTP_Asynchronous)
|
||||||
If *Tile\Download
|
If *Tile\Download
|
||||||
Repeat
|
Repeat
|
||||||
;If PBMap\MemoryCacheManagement = #False ; Wait until cache cleaning is done ;TODO
|
|
||||||
Progress = HTTPProgress(*Tile\Download)
|
Progress = HTTPProgress(*Tile\Download)
|
||||||
Select Progress
|
Select Progress
|
||||||
Case #PB_Http_Success
|
Case #PB_Http_Success
|
||||||
*Tile\Size = FinishHTTP(*Tile\Download) ; \Size signals that the download is OK
|
*Tile\Size = FinishHTTP(*Tile\Download) ; \Size signals that the download is OK
|
||||||
MyDebug(" Thread for image " + *Tile\CacheFile + " finished. Size : " + Str(Size), 5)
|
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " finished. Size : " + Str(*Tile\Size), 5)
|
||||||
Quit = #True
|
Quit = #True
|
||||||
Case #PB_Http_Failed
|
Case #PB_Http_Failed
|
||||||
FinishHTTP(*Tile\Download)
|
FinishHTTP(*Tile\Download)
|
||||||
*Tile\Size = 0 ; \Size = 0 signals that the download has failed
|
*Tile\Size = 0 ; \Size = 0 signals that the download has failed
|
||||||
MyDebug(" Thread for image " + *Tile\CacheFile + " failed.", 5)
|
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " failed.", 5)
|
||||||
Quit = #True
|
Quit = #True
|
||||||
Case #PB_Http_Aborted
|
Case #PB_Http_Aborted
|
||||||
FinishHTTP(*Tile\Download)
|
FinishHTTP(*Tile\Download)
|
||||||
*Tile\Size = 0 ; \Size = 0 signals that the download has failed
|
*Tile\Size = 0 ; \Size = 0 signals that the download has failed
|
||||||
MyDebug(" Thread for image " + *Tile\CacheFile + " aborted.", 5)
|
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " aborted.", 5)
|
||||||
Quit = #True
|
Quit = #True
|
||||||
Default
|
Default
|
||||||
MyDebug(" Thread for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5)
|
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " downloading " + Str(Progress) + " bytes", 5)
|
||||||
If ElapsedMilliseconds() - *Tile\Time > 10000
|
If ElapsedMilliseconds() - *Tile\Time > 10000
|
||||||
MyDebug(" Thread for image " + *Tile\CacheFile + " canceled after 10 seconds.", 5)
|
MyDebug(" Thread nb " + Str(*Tile\GetImageThread) + " " + *Tile\key + " for image " + *Tile\CacheFile + " canceled after 10 seconds.", 5)
|
||||||
AbortHTTP(*Tile\Download)
|
AbortHTTP(*Tile\Download)
|
||||||
EndIf
|
EndIf
|
||||||
EndSelect
|
EndSelect
|
||||||
@@ -1240,6 +1253,8 @@ Module PBMap
|
|||||||
;-***
|
;-***
|
||||||
|
|
||||||
Procedure.i GetTile(key.s, URL.s, CacheFile.s)
|
Procedure.i GetTile(key.s, URL.s, CacheFile.s)
|
||||||
|
; MemoryCache access management
|
||||||
|
LockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
; Try to find the tile in memory cache
|
; Try to find the tile in memory cache
|
||||||
Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key)
|
Protected *timg.ImgMemCach = FindMapElement(PBMap\MemCache\Images(), key)
|
||||||
If *timg
|
If *timg
|
||||||
@@ -1248,16 +1263,16 @@ Module PBMap
|
|||||||
If *timg\nImage
|
If *timg\nImage
|
||||||
; Yes, returns the image's nb
|
; Yes, returns the image's nb
|
||||||
MyDebug(" as image " + *timg\nImage, 4)
|
MyDebug(" as image " + *timg\nImage, 4)
|
||||||
*timg\Tile = -1
|
|
||||||
; *** Cache management
|
; *** Cache management
|
||||||
; Retrieves the image in the time stack, push it to the end (to say it's the lastly used)
|
; Retrieves the image in the time stack, push it to the end (to say it's the lastly used)
|
||||||
ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr)
|
ChangeCurrentElement(PBMap\MemCache\ImagesTimeStack(), *timg\TimeStackPtr)
|
||||||
MoveElement(PBMap\MemCache\ImagesTimeStack(), #PB_List_Last)
|
MoveElement(PBMap\MemCache\ImagesTimeStack(), #PB_List_Last)
|
||||||
; *timg\TimeStackPtr = LastElement(PBMap\MemCache\ImagesTimeStack())
|
; *timg\TimeStackPtr = LastElement(PBMap\MemCache\ImagesTimeStack())
|
||||||
; ***
|
; ***
|
||||||
|
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
ProcedureReturn *timg
|
ProcedureReturn *timg
|
||||||
Else
|
Else
|
||||||
; No, will load it below
|
; No, try to load it from HD (see below)
|
||||||
MyDebug(" but not the image.", 4)
|
MyDebug(" but not the image.", 4)
|
||||||
EndIf
|
EndIf
|
||||||
Else
|
Else
|
||||||
@@ -1265,6 +1280,7 @@ Module PBMap
|
|||||||
*timg = AddMapElement(PBMap\MemCache\Images(), key)
|
*timg = AddMapElement(PBMap\MemCache\Images(), key)
|
||||||
If *timg = 0
|
If *timg = 0
|
||||||
MyDebug(" Can't add a new cache element.", 4)
|
MyDebug(" Can't add a new cache element.", 4)
|
||||||
|
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
ProcedureReturn #False
|
ProcedureReturn #False
|
||||||
EndIf
|
EndIf
|
||||||
; add a new time stack element at the End
|
; add a new time stack element at the End
|
||||||
@@ -1274,55 +1290,56 @@ Module PBMap
|
|||||||
If *timg\TimeStackPtr = 0
|
If *timg\TimeStackPtr = 0
|
||||||
MyDebug(" Can't add a new time stack element.", 4)
|
MyDebug(" Can't add a new time stack element.", 4)
|
||||||
DeleteMapElement(PBMap\MemCache\Images())
|
DeleteMapElement(PBMap\MemCache\Images())
|
||||||
|
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
ProcedureReturn #False
|
ProcedureReturn #False
|
||||||
EndIf
|
EndIf
|
||||||
; Associates the time stack element to the cache element
|
; Associates the time stack element to the cache element
|
||||||
PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images())
|
PBMap\MemCache\ImagesTimeStack()\MapKey = MapKey(PBMap\MemCache\Images())
|
||||||
MyDebug("Key : " + key + " added in memory cache", 4)
|
MyDebug("Key : " + key + " added in memory cache", 4)
|
||||||
; ***
|
|
||||||
EndIf
|
EndIf
|
||||||
; Is this tile not loading ?
|
; If there's no active download thread for this tile
|
||||||
If *timg\Tile <= 0
|
If *timg\Tile <= 0
|
||||||
; Is the file image on HDD ?
|
; Try To load it from HD
|
||||||
*timg\nImage = GetTileFromHDD(CacheFile.s)
|
*timg\nImage = GetTileFromHDD(CacheFile.s)
|
||||||
If *timg\nImage
|
If *timg\nImage
|
||||||
; Image found and loaded from HDD
|
; Image found and loaded from HDD
|
||||||
*timg\Alpha = 0
|
*timg\Alpha = 0
|
||||||
*timg\Tile = -1
|
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
ProcedureReturn *timg
|
ProcedureReturn *timg
|
||||||
EndIf
|
EndIf
|
||||||
EndIf
|
; If GetTileFromHDD failed, will load it (again?) from the web (see below)
|
||||||
; If there's not this tile in memory and no web loading thread
|
If *timg\nImage = 0
|
||||||
If *timg\Tile = 0
|
; Launch a new web loading thread
|
||||||
; Launch a new one
|
If PBMap\ThreadsNB < PBMap\Options\MaxThreads
|
||||||
If PBMap\ThreadsNB < PBMap\Options\MaxThreads
|
Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile))
|
||||||
Protected *NewTile.Tile = AllocateMemory(SizeOf(Tile))
|
If *NewTile
|
||||||
If *NewTile
|
With *NewTile
|
||||||
With *NewTile
|
; New tile parameters
|
||||||
; New tile parameters
|
\key = key
|
||||||
\key = key
|
\URL = URL
|
||||||
\URL = URL
|
\CacheFile = CacheFile
|
||||||
\CacheFile = CacheFile
|
\nImage = 0
|
||||||
\nImage = 0
|
\Time = ElapsedMilliseconds()
|
||||||
\Time = ElapsedMilliseconds()
|
\GetImageThread = CreateThread(@GetImageThread(), *NewTile)
|
||||||
\GetImageThread = CreateThread(@GetImageThread(), *NewTile)
|
If \GetImageThread
|
||||||
If \GetImageThread
|
*timg\Tile = *NewTile ; There's now a loading thread
|
||||||
*timg\Tile = *NewTile ; There's now a loading thread
|
*timg\Alpha = 0
|
||||||
*timg\Alpha = 0
|
MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile + " (key = " + key, 3)
|
||||||
MyDebug(" Creating get image thread nb " + Str(\GetImageThread) + " to get " + CacheFile, 3)
|
PBMap\ThreadsNB + 1
|
||||||
PBMap\ThreadsNB + 1
|
Else
|
||||||
Else
|
MyDebug(" Can't create get image thread to get " + CacheFile, 3)
|
||||||
MyDebug(" Can't create get image thread to get " + CacheFile, 3)
|
FreeMemory(*NewTile)
|
||||||
FreeMemory(*NewTile)
|
EndIf
|
||||||
EndIf
|
EndWith
|
||||||
EndWith
|
Else
|
||||||
Else
|
MyDebug(" Error, can't allocate memory for a new tile loading thread", 3)
|
||||||
MyDebug(" Error, can't allocate memory for a new tile loading thread", 3)
|
EndIf
|
||||||
|
Else
|
||||||
|
MyDebug(" Error, maximum threads nb reached", 3)
|
||||||
EndIf
|
EndIf
|
||||||
Else
|
|
||||||
MyDebug(" Error, maximum threads nb reached", 3)
|
|
||||||
EndIf
|
EndIf
|
||||||
EndIf
|
EndIf
|
||||||
|
UnlockMutex(PBMap\MemoryCacheAccessNBMutex)
|
||||||
ProcedureReturn #False
|
ProcedureReturn #False
|
||||||
EndProcedure
|
EndProcedure
|
||||||
|
|
||||||
@@ -2488,12 +2505,14 @@ Module PBMap
|
|||||||
*Tile = EventData()
|
*Tile = EventData()
|
||||||
key = *Tile\key
|
key = *Tile\key
|
||||||
*Tile\Download = 0
|
*Tile\Download = 0
|
||||||
|
PBMap\MemCache\Images(key)\Tile = *Tile\Size
|
||||||
If *Tile\Size ; <> 0
|
If *Tile\Size ; <> 0
|
||||||
|
; Web loading thread has finished successfully
|
||||||
FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile)
|
FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile)
|
||||||
PBMap\MemCache\Images(key)\Tile = -1 ; Clears the data ptr, and says that the web loading thread has finished successfully
|
PBMap\MemCache\Images(key)\Tile = -1
|
||||||
Else
|
Else
|
||||||
FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile)
|
FreeMemory(*Tile) ; Frees the data needed for the thread (*tile=PBMap\MemCache\Images(key)\Tile)
|
||||||
PBMap\MemCache\Images(key)\Tile = 0 ; Clears the data ptr, and says that the web loading thread has finished unsuccessfully
|
PBMap\MemCache\Images(key)\Tile = 0
|
||||||
EndIf
|
EndIf
|
||||||
PBMap\ThreadsNB - 1
|
PBMap\ThreadsNB - 1
|
||||||
PBMap\Redraw = #True
|
PBMap\Redraw = #True
|
||||||
@@ -2750,8 +2769,8 @@ CompilerIf #PB_Compiler_IsMainFile
|
|||||||
PBMap::InitPBMap(#Window_0)
|
PBMap::InitPBMap(#Window_0)
|
||||||
PBMap::SetOption("ShowDegrees", "1") : Degrees = 0
|
PBMap::SetOption("ShowDegrees", "1") : Degrees = 0
|
||||||
PBMap::SetOption("ShowDebugInfos", "1")
|
PBMap::SetOption("ShowDebugInfos", "1")
|
||||||
PBMap::SetDebugLevel(4)
|
PBMap::SetDebugLevel(5)
|
||||||
PBMap::SetOption("Verbose", "0")
|
PBMap::SetOption("Verbose", "1")
|
||||||
PBMap::SetOption("ShowScale", "1")
|
PBMap::SetOption("ShowScale", "1")
|
||||||
PBMap::SetOption("Warning", "1")
|
PBMap::SetOption("Warning", "1")
|
||||||
PBMap::SetOption("ShowMarkersLegend", "1")
|
PBMap::SetOption("ShowMarkersLegend", "1")
|
||||||
@@ -2894,8 +2913,8 @@ CompilerIf #PB_Compiler_IsMainFile
|
|||||||
CompilerEndIf
|
CompilerEndIf
|
||||||
|
|
||||||
; IDE Options = PureBasic 5.60 (Windows - x64)
|
; IDE Options = PureBasic 5.60 (Windows - x64)
|
||||||
; CursorPosition = 2510
|
; CursorPosition = 1181
|
||||||
; FirstLine = 2503
|
; FirstLine = 1156
|
||||||
; Folding = -------------------
|
; Folding = -------------------
|
||||||
; EnableThread
|
; EnableThread
|
||||||
; EnableXP
|
; EnableXP
|
||||||
|
Reference in New Issue
Block a user