Jump to content

AutoIt for automation scripting?


Recommended Posts

Hi forum members

I stumbled over AutoIt when searching an alternative for (a tool to get rid of the necessity of) WSH for automation scripts.

The advertizing ("What is AutoIt") looks very promising to address exactly the shortcomings that sent me on the search.

And AutoIt comes with a dazzling heap of functions making you believe from first sight that getting the job done should really be a piece of cake with such a working fund.

Meanwhile I'm unsure if it is the suitable tool at all.

As (partly over)packed with helping function it now looks as... hm 'holey' in terms of concept and basic functionality.

Two nights and a day of digging into it, finding myself in always the same loops through the help, made me overcome the reserve to pose too stupid questions to the experienced folks here at this place.

(And searching through the forums gave me the perception that the use of AutoIt is not really focussed around automation, but around creating fancy stuff with media and in this AutoIt's core primarily as a shortcut to the WinAPI.)

Now to the percieved holes:

There's no date handling, right?

Array handling looks a bit inconsistent, does it? (E.g. you cannot use Array literals directly, but still deal with those created from various ...split-functions.)

On the 'split' cue: There's no corresponding StringJoin (and scripting it with the somewhat clumsy language needs a dozen lines).

There's no built in means for exception handling, is there?

While object referencing seems to fill a large area, there's no real object handling in the language, right?

(btw: increment operator would be nice - is somthing like ++$<var> ... $<var>-- planned for a future release?)

While I hope to get answers that just point me to the right spots where to find the content for above 'holes',

the primary objective is to avoid wasting more days, nights, weeks in fruitless searching...

... and if there're means to bridge them by using external code (still with the option to end up with a compiled self contained .exe as result), pointers to related documentation would be highly appreciated.

Edited by memoryoverflow

(The signature is placed on the back of this page to not disturb the flow of the thread.)

Link to comment
Share on other sites

I'm answering from the extent of my knowledge. I'm no master but as far as I know:

1) AutoIt has no native date/time handling. It has macros to get date/time but as far as calculations go, you're on your own, not unless someone has made a UDF for date/time handling.

2) I'm not exactly sure what you mean about arrays,but from my knowledge: You need to declare array with its size, to use it but you can store arrays passed from functions into a normal variable.

3)

Func _StringJoin($array)
    Local $result = ""
    For $i = 0 To UBound($array) - 1
        $result &= $array($i)
    Next
    Return $result
EndFunc

or:

Func _StringJoin($string1, $string2)
    Return $string1 & $string2
EndFunc

4)There is no catch block in AutoIt. You need to manually check for the function return value, @error and/or @extended variables (depending on the documentation provided) to see what error was committed. Then you put in code to do what you want to do about it. Note that the @error is reset at the start of every function call so you can't check it for nested function calls.

5)No clue about objects and data structures in AutoIt. All I know is that AutoIt is basically a procedural language. So I think class definitions are out.

Edited by omikron48
Link to comment
Share on other sites

Thanks for taking the time to answer, ο!

1) ... date/time handling. It has macros to get date/time ...

All I found was a heap of macros that try to fuddle with strings, which can or cannot and depending on locale, time zone and whatever, resemble a date representation, but nowhere something dealing with a date as a date.

2) I'm not exactly sure what you mean about arrays ...

AutoIt variables are variant and they can hold arrays, but e.g. try
dim $vArray = [1,2,3]

3)

Func _StringJoin($array)
    Local $result = ""
    For $i = 0 To UBound($array) - 1
        $result &= $array($i)
    Next
    Return $result
EndFunc

or:

Func _StringJoin($string1, $string2)
    Return $string1 & $string2
EndFunc
Don't deem this halfways reliable, think you need somthing like:
Func sStringJoin($sArray, $sDelimiter = ',')
    Dim $i = 0, $s = ''
    If IsArray($sArray) Then
        $s &= $sArray[0]
        For $i = 1 To UBound($sArray) - 1
            $s &= $sDelimiter & $sArray[$i]
        Next
    Else
        $s &= $sArray
    EndIf
    Return $s
EndFunc   ;==>sStringJoin
as said a dozen lines for such a stupid thing - really looking clumsy, but perhaps just due to my inability to phrase it more efficiently.

4)... You need to manually check for the function return value, @error and/or @extended variables ...

Fair enough - I rather meant a means for the self written parts, where you have to test for a dozen types of incoming data (datatype is of very limited use, since almost all data in AutoIt is encrypted in strings with no guaranteed validity of their content), as long as you cannot try to perform the planned operation on it without the risk to produce an uncatchable run-time error.

5)That's basically what I meant: heavy object referencing, but no handling, other than manipulating single properties one by one.

Edited by memoryoverflow

(The signature is placed on the back of this page to not disturb the flow of the thread.)

Link to comment
Share on other sites

There's no date handling, right?

You are wrong!

Look into helpfile at User Defined Functions/Date Management

Array handling looks a bit inconsistent, does it? (E.g. you cannot use Array literals directly, but still deal with those created from various ...split-functions.)

On the 'split' cue: There's no corresponding StringJoin (and scripting it with the somewhat clumsy language needs a dozen lines).

Look into helpfile at User Defined Functions/Array Management/_ArrayConcatenate()

There's no built in means for exception handling, is there?

For normal code there is really no exception handling but for COM objects there is error handler, see ObjEvent ( "AutoIt.Error" [, "function name"] )

for normal code you may use If @error then ...

While object referencing seems to fill a large area, there's no real object handling in the language, right?

There is no object programming in Autoit and it will not be done.

Look at things on NOT ToDo list on bugtracker/wiki

http://www.autoitscript.com/trac/autoit/wiki/AutoItNotOnToDoList

(btw: increment operator would be nice - is somthing like ++{:content:}lt;var> ... {:content:}lt;var>-- planned for a future release?)

Look at this:

$i = 1
$i += 1
Edited by Zedna
Link to comment
Share on other sites

(And searching through the forums gave me the perception that the use of AutoIt is not really focussed around automation, but around creating fancy stuff with media and in this AutoIt's core primarily as a shortcut to the WinAPI.)

Primary focus of Autoit is on automatizing other processes/windows/controls.

This is area where Autoit's power is better than other languages.

As time goes on Autoit has risen from automatizing tool to almost general programming language

due to its reach native/User Defined functions.

Link to comment
Share on other sites

Hi Zedna - and thanks a lot for bothering!

You are wrong!

Look into helpfile at User Defined Functions/Date Management

All I found was a heap of macros that try to fuddle with strings, which can or cannot and depending on locale, time zone and whatever, resemble a date representation, but nowhere something dealing with a date as a date.

But... a few more hours of searching and trial & error have revealed more useful functions.

E.g. for the test case of SystemTime I found:

$lResult = 1000 * _DateDiff( 's', $sDateTimeZero, _NowCalc()) + DllStructGetData(_Date_Time_GetSystemTime(), 8)

as an equivalent for the usual getTime()

which will yield the normal dateTime as

$nDateTime = $lResult / 86400000

which will have to be tested for behaviour during the nights of daylight saving time switches (yielding UTC it shouldn't be affected, but...)

Look into ... _ArrayConcatenate()

Will do - thanks for the tip. Didn't so far, since I didn't expect to find the delimiter there.

for normal code you may use If @error then ...

You mean that execution of my program will continue, if the vulnerable line is followed by an If @error ...? Could live with that. To make it clearer:
$var = 1 / $parameter
If @error then SetError(1 ,'div/0', 0)
Would this avoid being thrown out of execution of the calling routine, if $parameter happened to be zero?

There is no object programming in Autoit ... bugtracker/wiki

Meanwhile I've found and scanned that tracker, too. And it hadn't been a feature request, however I'd like to see it, just, as stated, an attempt to shorten further fruitless searching.

... and, I think I've at least found how to incorporate external code, if you're ready to keep it in an external file (which isn't exactly what I was looking for, but... perhaps better than nothing).

Look at this: $i += 1

If you looked at my example, you'd seen that I'm familiar with operation-assignment operaters.

If, on the other hand, something like (sorry for the otherwise stupid example):

While $i -=1
or
Until Not $Array[$i+=1]
is possible, that would, however ugly, make up for it.

Primary focus of Autoit is on automatizing other processes/windows/controls...

Sure, and meanwhile I've got the picture that most users are automizing/hacking games with it, while my focus is on administration.

And please, don't get me wrong: I highly appreciate AutoIt's strength in that realm.

I'm just looking to find the bridges for the percieved gaps, which make coding with it so cumbersome.

Whatever I do with it needs at least threefold of lines I need in any other language I use.

Edited by memoryoverflow

(The signature is placed on the back of this page to not disturb the flow of the thread.)

Link to comment
Share on other sites

I think you're looking for The function _ArrayToString.

I don't think most people use AutoIT to automate games. It's just a lot of people come here, spend no effort of their own and demand "Someone tell me how to make WoW detect where my character is". Most people I see posting here are actually trying to do real stuff.

I'm still unclear on your

While $i -=1

and

Until Not $Array[$i+=1]

examples

Link to comment
Share on other sites

Don't:

dim $vArray = [1,2,3]

Do:

Dim $vArray[3] = [1,2,3]

Cumbersome or "neat"? Each language has their own syntax, and so does AutoIt. Little unimportant things like $i++ are unplanned.

... and this will freak out with $vArray[3] = 4, won't it?

Well, "neat" is certainly a matter of taste. For me, compacter code is more readable and far more easy to maintain.

(Perhaps that would change if I had the place to use a 42" display.)

But just compare the above example:

1000 * _DateDiff( 's', $sDateTimeZero, _NowCalc()) + DllStructGetData(_Date_Time_GetSystemTime(), 8)

vs.

as an equivalent for the usual

getTime()

Which one is "neat"?

And I'm happy to have found the AutoIt-version at all.

And I didn't call the incrementation "important", just a handy thingy to make better code and (here I may be wrong, although I've written parsers in the past) I'd estimated an implementation as hardly an effort.

Edited by memoryoverflow

(The signature is placed on the back of this page to not disturb the flow of the thread.)

Link to comment
Share on other sites

What about this :D

#include <Date.au3>

$tCur = _Date_Time_GetLocalTime()
MsgBox(4096, "Current date/time .: ",  _Date_Time_SystemTimeToDateTimeStr($tCur))

And why would you do :

$vArray[3] = 4

How can you give the value 4 in a 3-element array ?

Edited by Inverted
Link to comment
Share on other sites

Func GetTime()
    Return 1000 * _DateDiff( 's', "1970/01/01 00:00:00", _NowCalc()) + @msec
EndFunc

That's slightly faster and now you get to use GetTime() as you please.

AutoIT is a lot of different things to different people, and as such it's impossible to have all the functions everyone wants. As it is now, there's already a ton of built in functions that I hardly touch. If all the bundled UDFs were standard in the main executable, it'd be even larger. As it is, I've never had the need to know how many milliseconds have elapsed since 1970. AutoIT primarily focuses on what it's good at, which is automation of Windows applications, and being a general purpose language comes second. Like every language there's pros and cons.

Why don't you suggest that such a "GetTime" function be included in the date.au3 UDF?

I'm still confused about what you want to accomplish with the incrementation. Can you give a simple example showing how you wish it worked, and how you have to code it now?

Link to comment
Share on other sites

... and this will freak out with $vArray[3] = 4, won't it?

Hopefully AutoIt will catch this "buffer overflow" at compile time and, if you used a variable as index, at runtime.

Not all well_known_programming_language_in_a_single_letter do so, even if Petalines of this language are still current.

Every language has its beauties but also its ugliness, all of them blattant or hidden. "Clever" one-liner C certainly caused too much bugs, among other examples.

All in all, today's AutoIt is much more than a simple admin scripting tool. Beside the language itself, I find that the overhelming number of available UDFs aimed toward that many tasks makes it an unvaluable tool.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

If you're planning on calling "GetTime()" a lot, and are worried about the excessive overhead of calling the UDF functions, have a look at this.

#include <date.au3>
Global $GetTimeFirstCall=0, $GetTimeTimer=0

$timer1=TimerInit()
$time1=GetTime()
$timer1=TimerDiff($timer1)

Sleep(5000)

$timer2=TimerInit()
$time2=GetTime()
$timer2=TimerDiff($timer2)
ConsoleWrite($timer1& @cr& $time1& @CR& $timer2& @CR & $time2&@CR)



Func GetTime()
    If $GetTimeFirstCall=0 Then
        $GetTimeTimer=TimerInit()
        $GetTimeFirstCall=1000 * _DateDiff( 's', "1970/01/01 00:00:00", _NowCalc()) + @MSEC
        Return $GetTimeFirstCall
    Else
        Return Int($GetTimeFirstCall+TimerDiff($GetTimeTimer))
    EndIf
    
EndFunc

In the (crude) example I attached, the first call to GetTime() takes 1.5ms on my machine, yet each subsequent call takes 0.07ms.

Link to comment
Share on other sites

$tCur = _Date_Time_GetLocalTime()
MsgBox(4096, "Current date/time .: ",  _Date_Time_SystemTimeToDateTimeStr($tCur))
I thought this woud yield a string rather than a number. Am I wrong?

And why would you do :

$vArray[3] = 4

How can you give the value 4 in a 3-element array ?

What about this: Because I might have no idea to what dimension the arry will grow during run time?

That is exactly the "problem" with half-backed dynamical array handling.

Here you'd need to test Upper() explicitely and do the ReDim explicitely - again extra lines with no effect other than to please the syntax checker. But again, not really a problem. I'm just testing how to get it to maximum efficiency.

Func GetTime()
    Return 1000 * _DateDiff( 's', "1970/01/01 00:00:00", _NowCalc()) + @msec
EndFunc

That's slightly faster and now you get to use GetTime() as you please.

Hey that's neat! Have obviously overlooked the @msec macro.

(But was worthwhile to learn about AutoIt's DllStruct syntax. (The documentation isn't complete there, but as often, trial & error are your hated friends.))

AutoIT is a lot of different things to different people...

Why don't you suggest that such a "GetTime" function be included in the date.au3 UDF?

I think it should go in an extra library rather than adding to the heap of (mostly) locale dependant string manipulation functions, which are apt to fail to special user settings.

As such, I'd rather complete the full set myself and then propose it as a new library.

I'm still confused about what you want to accomplish with the incrementation. Can you give a simple example showing how you wish it worked, and how you have to code it now?

It's nothing but a line saver: While using the variable's value, you increment (or decrement) it on the fly, either before evaluation (++i or --i) or after (i++ or i--). It saves 1 to 2 lines in loop constructs, 1 line elsewhere. If you'd ever coded in other languages than early Basics, you'd know it. But again - it's no road block being forced to spend some extra lines.

Hopefully AutoIt will catch this "buffer overflow" at compile time and, if you used a variable as index, at runtime.

It can assign arrays fully dynamical when the variable is filled from split functions, so it has to have some robustness, which lets the necessity for the expliciteness in the declaration look inconsistant.

Again, rather cosmetics and a thing to get used to than anything like a road block.

All in all, today's AutoIt is much more than a simple admin scripting tool. Beside the language itself, I find that the overhelming number of available UDFs aimed toward that many tasks makes it an unvaluable tool.

Fully agreed! (I just would use 'aside' rather than 'beside' the Basic... :D)

And currently I see the interpreter / compiler possibilities (self contained exe), the shortcuts to the WinAPI, the nice SciTE integration, extendability via UDFs ... as even bigger wealth than the host of existing UDFs.

(The signature is placed on the back of this page to not disturb the flow of the thread.)

Link to comment
Share on other sites

If you're planning on calling "GetTime()" a lot...

No I'm not. SystemTime was just an example or exercise to get from a date-string to a number based date, with which calculations and locale independence are so much easier and more reliable.

Whenever you want to present it, you can easily format it to any locale (or specific pattern with regexes) you want with a single call.

Why do you think that so many UDFs require English (or even American English) with standard settings to work reliably?

Trying to handle dates through strings is a deadlock, blocking internationalisation to a good extent.

(The signature is placed on the back of this page to not disturb the flow of the thread.)

Link to comment
Share on other sites

Time, well, define "time"!

It can be a can of worms, depending on your needs and the granularity/precision you and your users/partners need.

For instance string date as per ISO 8601 is all I need for my business applications, but only down to the minute and using only Paris time. Getting time to the second and under involves _much_ more complication.

My other "activity" involves a personal time base with two Rubidium cloks a crystal one and two GPS time receivers. Here the time scale and requirements are very different.

In both cases, AutoIt helps me a lot with only little stable code.

There I compute a date range to build a "where" condition for SQLite "select", with straightforward code:

Switch $daterng
                Case 0      ; exact date
                    $cond &= "= "&X($date)
                Case 1      ; date +/- 1 day
                    $cond &= "between "&X(_DateAdd('D', -1, $date))&" and "&X(_DateAdd('D', 1, $date))
                Case 2      ; date +/- 2 day
                    $cond &= "between "&X(_DateAdd('D', -2, $date))&" and "&X(_DateAdd('D', 2, $date))
                Case 3      ; date +/- 3 day
                    $cond &= "between "&X(_DateAdd('D', -3, $date))&" and "&X(_DateAdd('D', 3, $date))
                Case 4      ; date +/- 5 day
                    $cond &= "between "&X(_DateAdd('D', -5, $date))&" and "&X(_DateAdd('D', 5, $date))
                Case 5      ; date +/- 7 day
                    $cond &= "between "&X(_DateAdd('D', -7, $date))&" and "&X(_DateAdd('D', 7, $date))
                Case 6      ; date +/- 15 day
                    $cond &= "between "&X(_DateAdd('D', -15, $date))&" and "&X(_DateAdd('D', 15, $date))
                Case 7      ; current week
                    $adate = StringSplit(_NowCalcDate(), '/', 2)
                    $date = _DateAdd('D', - _DateToDayOfWeekISO($adate[0], $adate[1], $adate[2]), _NowCalcDate())
                    $cond &= "between "&X($date)&" and "&X(_NowCalcDate())
                Case 8      ; last week
                    $adate = StringSplit(_NowCalcDate(), '/', 2)
                    $date = _DateAdd('D', - (7 + _DateToDayOfWeekISO($adate[0], $adate[1], $adate[2])), _NowCalcDate())
                    $cond &= "between "&X($date)&" and "&X(_DateAdd('D', 6, $date))
                Case 9      ; week of given date
                    $adate = StringSplit($date, '/', 2)
                    $date = _DateAdd('D', - _DateToDayOfWeekISO($adate[0], $adate[1], $adate[2]), $date)
                    $cond &= "between "&X($date)&" and "&X(_DateAdd('D', 6, $date))
                Case 10     ; current month
                    $cond &= "between "&X(StringLeft(_NowCalcDate(), 8) & "01")&" and "&X(_NowCalcDate())
                Case 11     ; last month
                    $date = StringLeft(_DateAdd('M', -1, StringLeft(_NowCalcDate(), 8) & "01"), 8)
                    $cond &= "between "&X($date & "01")&" and "&X($date & "31")
                Case 12     ; full month of given date
                    $date = StringLeft(StringLeft($date, 8) & "01", 8)
                    $cond &= "between "&X($date & "01")&" and "&X($date & "31")
            EndSwitch

OTOH, for my instrumentation "activity" I rely on Visa UDF for managing the various GPIB intruments here (which is a _lot_). Time there is something completely different! Averaging time with a star correlation in this domain is where more than a handful of ps (picoseconds) drift can be alarming.

For anything between, several factors introduce layers of difficulties, up to the point that time can get almost unmanageable. Repeatedly varying time saving rules and their varying geographic target, varying time zones and their varying frontiers, leap seconds can all make it almost impossible to come up with a function which would return the actual local time, for any coordinate point on some earth model and any Un*x epoch as parameters.

But the language and the storage type used are essentially irrelevant for the problem. It all depends on your needs. Then the required code, primitives and complexity can be hidden in a suitable (for you) UDF.

Aside vs beside: point taken; I'm not an english speaker, so please bear with my inadequate usages.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

Bonsoir jchd

Agreed, managing DateTime can be a bitch - but fuddling with strings, many of them object to personal user settings, is the worst way of all.

For my needs, I'll set up a library with a few functions that aren't prone to fail in an international environment or due to user settings. Only for visual output I'll have to retrieve format by locale or user, time zone and daylight saving. Formatting is a piece of cake with regexe. Much harder to get stability into the other way, retrieving a DateTime by decoding a string that might mean one.

The usability of the UDFs is partly diminished by most of them being defined in a very special way. With a slightly more generic approach you can replace on average 3-5 of them (sometimes very differently named) by one (with one more optional parameter).

As for your beautyful native language, no need to hide. I'm not a native English speaker either, so please bear with me, too.

(The signature is placed on the back of this page to not disturb the flow of the thread.)

Link to comment
Share on other sites

I'm sure you can build a decent set of functions for date/time. You seem to have enough experience to come up with reasonable features.

Your top posts gave the impression you were very disappointed with the language. Of course you won't find native OO nor features comparable to many powerful languages. Since you were talking of admin tasks, I would still encourage you to try it for real.

I'm a relatively new user of AutoIt. At first I was also finding it a bit clumsy. I gave it a try for what I believed should remain just a small utility. Weeks and months went by and, as my requirements sneakily became more demanding, I found myself quite pleased to recognized that I could follow tracks with AutoIt, even offering features I wouldn't have considered possible at first.

Yet AutoIt isn't perfect nor "all-purpose" but this can be said of whatever language you pick.

Have fun.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

... I've got the picture that most users are automizing/hacking games with it, while my focus is on administration. ...

I've never attempted a mental tally as to which group posts more? Gamers or non-gamers. But I would think that gamers make more posts per problem/question than those using AutoIt in the workplace. Of course, some people use AutoIt for both.

I remember each of your points having been raised before, but I do not recall the outcome of the discussion. This kind of stuff is over my head and I would just as soon keep it that way. I use AutoIt to control windows and send data from one app to another. It saves us a lot of man hours. I can use it without a lot of formal training and it is very forgiving when I don't think about the "number" 1 being a string.

Type casting? Backhand? Reach? Tuck? :-)

Welcome to the forum.

[size="1"][font="Arial"].[u].[/u][/font][/size]

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...