Jump to content
Sign in to follow this  
dani

Declaring an empty array

Recommended Posts

dani

Quick question which I can't seem to answer.

Is it possible to declare an empty array -- that is, with size 0?

I ask this because I tend to use the _ArrayAdd method which yields unexpected results as in:

#include <Array.au3>

Dim $anArray[1]
_ArrayAdd($anArray, 0)
_ArrayDisplay($anArray)

The result is an array of size 2:

$anArray:
[0] => // empty
[1] => 0

This is caused by _ArrayAdd which simply takes UBound($anArray), adds 1 and then inserts the item at the new index. Understandable. This is not the problem. The problem is I cannot declare an empty array, like

Dim $anArray[]
; or
Dim $anArray[0]

Why isn't this possible?

-- Please do not post alternative solutions to get an array filled with only the number 0, I know how this can be done. I just wonder why I cannot declare an empty array. It's possible in every language I have tried to date except AutoIt.

Edited by dani

Share this post


Link to post
Share on other sites
Melba23

dani,

This has been asked before, but I cannot remember what the Devs replied as I have never had the requirement to declare an empty array. No doubt my loss! :(

However, I have used something like this which has the same effect:

#include <Array.au3>

Global $anArray ; place keeper for this variable

If IsArray($anArray) Then
    ; It is an array so add to it
    _ArrayAdd($anArray, 0)
Else
    : Not an array so delare it as such
    Global $anArray[1] = [0]
EndIf

_ArrayDisplay($anArray)

I realise it is a little bit more code, but I hope it helps. :mellow:

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
dani

Thanks Melba for your reply :mellow: However, I am aware of these workarounds -- of course :( This is exactly the kind of stuff I want to avoid as it's plain ugly. Maybe one of the devs can give a response to this.

Share this post


Link to post
Share on other sites
Fulano

I've played around with it a bit, and the best advice I can give is to take Melba's solution and wrap it into a function

#include <Array.au3>
Local $anArray


myAddArray ($anArray, 0)


_ArrayDisplay($anArray)

Func myAddArray (ByRef $ArrayVar, $Val)
If IsArray ($ArrayVar) Then
    ; It is an array so add to it
    _ArrayAdd ($ArrayVar, $Val)
Else
    ; Not an array so delare it as such
    $ArrayVar[1] = [$Val]
EndIf
EndFunc

Edit: Copying richtext doesn't work so well :mellow:

Edited by Fulano

#fgpkerw4kcmnq2mns1ax7ilndopen (Q, $0); while ($l = <Q>){if ($l =~ m/^#.*/){$l =~ tr/a-z1-9#/Huh, Junketeer's Alternate Pro Ace /; print $l;}}close (Q);[code] tag ninja!

Share this post


Link to post
Share on other sites
dani

I know how to make workarounds myself dear people -- no offensive :mellow: As Melba23 suggested me personally I have already requested to move this to Developer Chat.

I don't want to know how I should work around the issue, I want to know if it's possible to declare an empty array. If not, then I'd like to know why not. That's all :(

Share this post


Link to post
Share on other sites
Valik

Given that users including an MVP are telling you to use a so-called work-around, the answer is obviously no, you can't declare an empty array. AutoIt is dynamically typed, not statically typed. The concept of an empty array doesn't make sense for a dynamically typed language. Neither does using a function like _ArrayAdd() which is far less efficient than using a more traditional array growth strategy.

I see no reason to move this thread.

Share this post


Link to post
Share on other sites
dani

@Valik

Don't you become MVP by posting a damn lot of messages :(? No disrespect to Melba23 in any way, but it actually feels like you are kinda disrespecting me for opening a discussion to something obvious to you? With all due respect, your argument that an empty array does not make sense for a dynamically typed programming language is not a strong one by any means.

Quoting Wikipedia here:

A programming language is said to be dynamically typed, when the majority of its type checking is performed at run-time as opposed to at compile-time. In dynamic typing, values have types but variables do not; that is, a variable can refer to a value of any type. Dynamically typed languages include Erlang, Groovy, Javascript, Lisp, Lua, Objective-C, Perl (with respect to user-defined types but not built-in types), PHP, Prolog, Python, Ruby, Smalltalk and Tcl.

I do not have experience with all these languages, but I know it is possible to create empty arrays in Erlang, Groovy, Lisp, Javascript, Lua, Perl, PHP, Python, Ruby, Smalltalk and Tcl.

Are you implying the designers of said languages are all wrong?

Empty arrays can be used for anything, like returns in functions. I can imagine a function searching for files for example. As such, if no matches are found, the empty array should be returned, so the user does not have to do crazy stuff like If IsArray($var) Then X Else Y, which is insane(ly ugly).

I just want to open a discussion on the pro's and cons, and again -- virtually any language supports it so please consider it :mellow:

Edited by dani

Share this post


Link to post
Share on other sites
Valik

Don't you become MVP by posting a damn lot of messages :mellow:?

There are plenty of people with a lot of posts who are not MVPs.

No disrespect to Melba23 in any way, but it actually feels like you are kinda disrespecting me for opening a discussion to something obvious to you?

That's because you're disrespecting Melba by insisting you must have the word of a developer before you are satisfied. MVPs, while they don't know everything about the language, are pretty knowledgeable. Dismissing their replies and choosing to ignore the fact he's giving you a work-around instead of a direct answer should be your first clue that it's not possible to create an empty array.

With all due respect, your argument that an empty array does not make sense for a dynamically typed programming language is not a strong one by any means.

Neither is your insistence on having the behavior because writing functionally equivalent code is "ugly".

Are you implying the designers of said languages are all wrong?

I'm implying that in some cases it's not necessary. All the languages are different. In a language like Lua or Python (the two I am familiar with) variables are also objects. I can use a member method of a list in Python to append new elements. In Lua, the only array-like type is the table. Tables are the basic building block of Lua and all objects are actually built out of tables. Tables are more than just plain data stores. They are capable of storing data and defining methods and thanks to a bit of syntactic sugar this allows object-oriented concepts to be applied with Lua. In AutoIt, none of this stuff is possible. AutoIt variables are just plain-ole-data. There are no properties or methods bound to an object.

In other words, this is an apples to hobos comparison.

Empty arrays can be used for anything, like returns in functions. I can imagine a function searching for files for example. As such, if no matches are found, the empty array should be returned, so the user does not have to do crazy stuff like If IsArray($var) Then X Else Y, which is insane(ly ugly).

The most common thing to do to an array is iterate over the contents. Run the following code and notice it doesn't crash or do anything silly.

Local $v = ""
For $i = 0 To UBound($v) - 1
    ConsoleWrite($v[$i] & @CRLF)
Next

So, that proves that writing code that expects to iterate an array will not explode if the input is not an array. No need for those "ugly" checks there. The other common action on an array is checking the length. As demonstrated above, UBound() returns the expected result for a non-array so length checking code can be simply:

Local $v
If UBound($v) Then ConsoleWrite("Array" & @CRLF)

I don't see what is so ugly about that. I would write similar Python or Lua code for those situations.

Your argument seems centered on wanting to use an array as a list. Fine, create a few UDFs to implement a list:

Func ListCreate($nReserved = 10)
    If $nReserved <= 0 Then $nReserved = 10
    Local $a[$nReserved + 1]
    Return $a
EndFunc

Func ListPushBack(ByRef $aList, $vData)
    If UBound($aList) <= $aList[0] Then ReDim $aList[UBound($aList) * 1.5]
    $aList[$aList[0]] = $vData
    $aList[0] += 1
EndFunc

Func ListGetSize(ByRef $aList)
    Return $aList[0]
EndFunc

Func ListGetElement(ByRef $aList, $index)
    Return $aList[$index + 1]
EndFunc

Error checking removed for brevity. There may be off-by-one errors in the code leading to out-of-bounds conditions because I dry-coded it. The concept is simple, however. Define your own methods for working with a data structure. It takes care of allocation, storage and access using a (presumably) efficient growth scheme so constant reallocation isn't required. ListGetSize() is provided to return the upper bound of actual data. Element 0 is reserved to store the used length. ListGetElement() is provided to allow 0-based indexing into the data. A simple iterative loop on a pre-constructed (not-shown) list might be:

For $i = 0 To ListGetSize($aList) - 1
    ConsoleWrite(ListGetElement($aList, $i) & @CRLF)
Next
Edited by Valik
Dry-coding is fun.

Share this post


Link to post
Share on other sites
dani

I appreciate this reply Valik -- it's much more in-depth than your previous one which was elitist at best. I'll just react to some of your points whilst knowing you and I will not agree on this matter. I just want to defend myself in some of the situations you sketched.

That's because you're disrespecting Melba by insisting you must have the word of a developer before you are satisfied.

This is clearly not the matter. I respect Melba a lot, I think he is of great value to this forum. I didn't ignore what he said either -- read my reply. I thanked him but explained I did not want a workaround as I can easily create those myself. I put that on the bottom of my original post as well.

Dismissing their replies and choosing to ignore the fact he's giving you a work-around instead of a direct answer should be your first clue that it's not possible to create an empty array.

You seem to miss my point totally. I was already pretty sure it wasn't possible to create an empty array. I just asked this at first to be sure, but what I actually want to know is what followed that question. Why was chosen to not include the possibility to create the empty array. That's what I really want to know. The AutoIt language is well documented and not hard in any way, I can figure out what it can do, but obviously I cannot find the reasoning behind certain choices -- which is why I wanted to ask developers. As much as Melba knows, he didn't design the language thus cannot ever answer that question.

You might think the following is a bad example but try to get what I mean. Why did you include the possibility to create the empty string?

$var = ""

To some extend, isn't this equivalent to the empty array? If you consider the string as a collection of characters I really believe there is an analogy between arrays and strings. In such a way, the empty string could be mapped to the empty array. The empty string is present, the empty array is not. I consider this to be asymmetrical. In the same way, I think the below should work for both array and strings but does not because of the lack of the empty array:

$aString = ""
For $i = 1 To 5
  $aString &= $i
Next
ConsoleWrite($aString & @CR) ; Outputs 12345 as expected

$anArray = []
For $i = 1 To 5
  _ArrayAdd($anArray, $i)
Next
_ArrayDisplay($anArray) ; It would be nice to have the result $anArray[0] = 1, $anArray[1] = 2, $anArray[2] = 3, $anArray[3] = 4, $anArray[4] = 5

Maybe not the strongest example to pleed for the empty array, but do you catch my drift? I just find it illogical not to have it, and I wonder why. This is also the reason why I wanted it to be moved to Developer Chat. It just seems you think the only thing I want to know if it's possible to create an empty array at this time.

Neither is your insistence on having the behavior because writing functionally equivalent code is "ugly".

Perhaps. I think wanting to avoid 5 lines of code (Melba's workaround) instead of just 1 is enough to at least start a discussion. Apparently I am not allowed to question any aspect of this language, sorry.

Your argument seems centered on wanting to use an array as a list.

Well, no. I generally do not like to use workarounds like the ones posted to do something which could be done in 1 line of code, but isn't possible because of choices made by developers. That's why I asked what the reason is for omitting the empty array. That's all.

You are right it's not necessary, ofcourse. A lot isn't necessary, but don't the unnecessary things make life so much easier and fun? Heck, even AutoIt isn't necessary... Or computers for that matter, we can just do everything by hand like in the good old days.

To me, the less code the better. I love concise, to-the-point code which is beautiful to look at. Call me crazy, but if I can replace 3 lines by 1, I'm happy. I decided to Google 'Ruby philosophy' and expected a similar response from it's creator, Yukihiro Matsumoto.

The first hit actually brought me to this interview. As I thought, Matz does sort of agree with this. This explains why I love Ruby.

The Joy of Ruby

Bill Venners: In an introductory article on Ruby, you wrote, "For me the purpose of life is partly to have joy. Programmers often feel joy when they can concentrate on the creative side of programming, So Ruby is designed to make programmers happy." How can Ruby make programmers happy?

Yukihiro Matsumoto: You want to enjoy life, don't you? If you get your job done quickly and your job is fun, that's good isn't it? That's the purpose of life, partly. Your life is better.

I want to solve problems I meet in the daily life by using computers, so I need to write programs. By using Ruby, I want to concentrate the things I do, not the magical rules of the language, like starting with public void something something something to say, "print hello world." I just want to say, "print this!" I don't want all the surrounding magic keywords. I just want to concentrate on the task. That's the basic idea. So I have tried to make Ruby code concise and succinct.

Share this post


Link to post
Share on other sites
Valik

You might think the following is a bad example but try to get what I mean. Why did you include the possibility to create the empty string?

$var = ""

To some extend, isn't this equivalent to the empty array? If you consider the string as a collection of characters I really believe there is an analogy between arrays and strings. In such a way, the empty string could be mapped to the empty array. The empty string is present, the empty array is not. I consider this to be asymmetrical. In the same way, I think the below should work for both array and strings but does not because of the lack of the empty array:

Strings are not arrays of characters in AutoIt terms, otherwise you would be able to index into a string using array-index syntax. Also, supporting an empty string is trivial and requires no special code to handle the situation. Supporting an empty array requires quite a bit of code including changes to the parser to NOT throw errors on zero-length or unspecified-length arrays as well as changes to the way variables are allocated to set the array flag. Maybe, maybe if #1191 is ever implemented, the ability to create empty arrays will be possible. That ticket creates a parallel syntax for arrays as we already have for strings.

Now, for a mini-rant. I strongly disagree with all your reasoning. I consider it very poor programming that you want to create an array of empty size and append to it one item at a time. Notice in my small list implementation how it takes a hint as to the initial size? It's because I don't feel like ass-raping performance, something you don't seem to care one bit about. Also, I don't buy into your "one line versus three lines" stuff. I have absolutely no problem writing an interface to hide that 3 line implementation behind a single-line interface that hides all those nasty implementation details we hate to bother about. You can't say you want all this nice clean code and then refuse to use good programming techniques to get there. In order to get nice clean code you have to do some grunt work and write some ugly code somewhere else. This is just one of (and one of the least significant) advantages of proper separation of implementation and interface. It is clear to me that _ArrayAdd() doesn't quite work how you wish due to the language inability to create an empty array. Okay, so write your own _ArrayAdd() like functions like I did above, stick them off in a file and #include them. Use your nice clean interface and all these problems go away because you can hide them.

Remember, implementation details are very rarely important to a program's design.

Edit: Moved to Developer Chat.

Edited by Valik

Share this post


Link to post
Share on other sites
czardas

I have been reading this topic with interest. I often append an unknown number of values to a one dimensional array, and then later have to delete the first element (if and when I don't need it). I am aware that there are many methods to populate an array, but this one seems the most intuitive to me under certain specific circimstances. While I have no issues with the current implementation in AutoIt, if the option to declare an empty array was available, I would instantly switch methods.

Share this post


Link to post
Share on other sites
BrettF
PhilHibbs

I just created this ticket suggesting that since _ArrayDelete returns an empty string after the last element is deleted, _ArrayAdd should do the converse, i.e. you pass it an empty string and another value, and it replaces the empty string with a single-element array with the value in it. i.e.:

Func _ArrayAdd(ByRef $avArray, $vValue)
    If $avArray = "" Then
        Return _ArrayCreate($vValue)
    Else
        If Not IsArray($avArray) Then Return SetError(1, 0, -1)
        If UBound($avArray, 0) <> 1 Then Return SetError(2, 0, -1)

        Local $iUBound = UBound($avArray)
        ReDim $avArray[$iUBound + 1]
        $avArray[$iUBound] = $vValue
        Return $iUBound
    EndIf
EndFunc   ;==>_ArrayAdd

Caution: This uses the undocumented _ArrayCreate function, which has been flagged as redundant and to be removed in future.

Share this post


Link to post
Share on other sites
Valik

No. There are now two checks to ensure the input is valid which means every single call to that function is burdened with even more work when most of the time it's not necessary.

Share this post


Link to post
Share on other sites
PhilHibbs

No. There are now two checks to ensure the input is valid which means every single call to that function is burdened with even more work when most of the time it's not necessary.

I would have thought that if you're using an array as a dynamically-resizing list, the situation of removing the last entry from an array and then adding new ones afterwards would not be that uncommon, and wanting to start with an empty array and then fill it dynamically from some source such as the registry or reading a file would be even more common.

Share this post


Link to post
Share on other sites
dani

dani, you can't win...

I noticed :evil: Too bad, the empty array is something so obvious and sensible to have I still don't understand Valik thinks it's utter bullshit. Surely that's his good right to think but still :P

But you are right, I cannot and will not ever be able to convince him. Convincing people wasn't in any way the goal of this topic anyway. I am repeating myself for the 3rd time or so, but the only thing I wanted was the reasoning behind the devs' choice of keeping this out of AutoIt :mellow:

@PhilHibbs

Haha _ArrayDelete really returns an empty string when the last element from an array is deleted? Crazy stuff. One more reason to include the empty array :lol: I'm not sure about your suggestion though. It's makes perfect sense when you take ArrayDelete into account, but _ArrayDelete returning an empty string is the most illogical thing ever so please do not extend that behavior into _ArrayAdd. By itself -- without looking at _ArrayDelete -- it makes absolutely no sense to pass an empty string and an element which then magically turn into an array with that element. Although you then could do the kind of loops I posted before without errors.

Anyway, if something is fixed it should be fixed at the source of this small 'problem' (opinions may vary) and not at the UDF :(

I would have thought that if you're using an array as a dynamically-resizing list, the situation of removing the last entry from an array and then adding new ones afterwards would not be that uncommon, and wanting to start with an empty array and then fill it dynamically from some source such as the registry or reading a file would be even more common.

Agreed! Edited by dani

Share this post


Link to post
Share on other sites
Valik

Please don't give the "I'm repeating myself" bullshit and the "OMG you idiots it returns a string" bullshit. Stop, take your "empty arrays are the only way" hat off and realize how you would write code in both cases. Would the code look different? Yes. Would it behave differently? NO. And that's my fundamental point that you won't acknowledge. The same logic applies. Before accessing an array you have to test that your index is in range. It doesn't matter if the variable is an empty array or a string, properly written code will work in either case.

As for _ArrayAdd() and _ArrayDelete(), if you don't like them, don't use them. I'm sorry they require valid input and expect you to test the output to ensure it's still sane. I'm sorry you don't want to spend the time and effort to write a proper library to suit your own needs. I guess it's much easier to dismiss the comments of a developer and criticize the library than do your own work to come up with a working solution (even when the aforementioned developer writes half the library which should serve as a good starting point).

Too much bitching about implementation details, not enough shutting the fuck up and writing good interfaces.

Share this post


Link to post
Share on other sites
doudou

AutoIt is dynamically typed, not statically typed. The concept of an empty array doesn't make sense for a dynamically typed language.

Sorry Valik, but this is your private opinion and you are quite alone with that. There are many languages out there that are dynamically typed and they (actually all) allow empty array creation.

Consider this (VB script):

Dim a(0)
Dim b
b = Array()
WScript.Echo "Type(a)=" & VarType(a) & ", Type(b)=" & VarType(b) & ", ubound(a)=" & ubound(a) & ", ubound(b)=" & ubound(b)

Or this (PHP):

<?php
$a = array();
print "ubound(a)=" . count($a) . ", is_array(a)=" . (is_array($a) ? "true" : "false");
?>

It is of course your ineligible right to defend your methods and your creation but forgive me if I dare to challenge statements that sound like proclamation of the absolute truth.


UDFS & Apps:


DDEML.au3 - DDE Client + Server[*]
Localization.au3- localize your scripts[*]
TLI.au3 - type information on COM objects (TLBINF emulation)[*]
TLBAutoEnum.au3 - auto-import of COM constants (enums)[*]
AU3Automation - export AU3 scripts via COM interfaces
TypeLibInspector

- OleView was yesterday

Coder's last words before final release: WE APOLOGIZE FOR INCONVENIENCE 

Share this post


Link to post
Share on other sites
Valik

Sorry Valik, but this is your private opinion and you are quite alone with that. There are many languages out there that are dynamically typed and they (actually all) allow empty array creation.

Did you read my statement? I said empty arrays don't make sense, not that they aren't possible. Everything you can do with an empty array I can do without such a feature. Do you know what an empty array is? It's syntactic sugar. It's mere convenience. It means you can do lazy initialization on arrays. Show me an example of code where you are absolutely convinced beyond a shadow of a doubt that it can't be done without an empty array. I'll show you how to do it. Keep in mind, I'm talking about POD arrays here and ideally AutoIt specifically. I'm not talking about languages where the supposed empty array is really an object with methods and properties.

It is of course your ineligible right to defend your methods and your creation but forgive me if I dare to challenge statements that sound like proclamation of the absolute truth.

The only absolute truth is there are no absolute truths. However, I will say this. My statement is truth so-long as the goal of the language isn't to prove the statement false. There are a few language design decisions that can be made where empty arrays are required. However, such design decisions would be deliberate with the specific intent to disprove my statement. In none of the languages cited so far (including AutoIt) are empty arrays necessary. Useful for convenience? Perhaps. But required? No.

This is the entire crux of my position: Empty arrays are irrelevant. They offer no functionality that cannot be achieved otherwise. They simply allow multiple (and arguably visually "cleaner") ways of doing the exact same thing. My second assertion is that if you people would learn to bother to use proper program techniques, language minutia such as "empty arrays" becomes a trivial thing.

Also, to address a point in your first quote, if I'm so alone, why is it statically typed languages (or at least C and C++) don't allow empty arrays? Also, perhaps my comment about dynamic typing wasn't necessary at all since almost universally arrays are declared either via some specific syntax (As is the case with AutoIt) or a specific function. Even dynamically typed languages provide ways to statically type the data and arrays are pretty much always statically typed at some level (The syntax alone gives it away). If a language provides an empty array, great. If it's useful, I'll use it. If it doesn't, so what? That just means it provides alternate ways to do whatever I need to do (or the language is a failure - or I am for not being able to use the language). However, it is not some panacea for working with arrays. In virtually all languages it exists solely for syntactic convenience. Keep in mind as well that AutoIt draws influence from numerous places, including C++.

Now to address the original poster's initial "problem":

This is caused by _ArrayAdd which simply takes UBound($anArray), adds 1 and then inserts the item at the new index. Understandable. This is not the problem. The problem is I cannot declare an empty array, like

I think the OP is wrong, the problem isn't the lack of an empty array, the problem is the lack of proper programming techniques to provide a sensible interface. _ArrayAdd() makes some expectations - it has an invariant. That invariant is that the array is full and needs resized to insert a new element at the end. The problem with this is, there's no way for _ArrayAdd() to enforce that invariant thus it is up to the user. Clearly not all users know or are willing to ensure they are going to pass what _ArrayAdd() wants. The _ArrayAdd() function fails equally for non-full arrays where it will skip unused elements that could otherwise contain the new value. Now I refer you back to my simple list implementation posted above. With a bit of cleanup, some more functions and some error checking, it can avoid all the problems of _ArrayAdd() and clearly demonstrates it's possible to provide clean interfaces without some arbitrary syntax. This goes back to the same post where I was trying to make the point that good programming practices - including but not limited to separation of interface and implementation - makes these supposed language "deficiencies" a complete non-issue. Write up the functions, stick them in a file, use #include and you suddenly have this very clean interface that can be shared amongst numerous projects and best of all: It works exactly how you want because you wrote it.

I guess perhaps I'm expecting too much out of "scripters", however. Maybe it's unreasonable to demand they understand good programming concepts and employ them in their scripts. On the other hand, maybe it's not too much to ask if they have the wherewithal to argue over the minutia of language design. Yet on the other hand, if they know so much then it stands to reason they would know that arguing over such banal trivialities is fruitless and that just writing a proper interface to hide the uncouth implementation (and all implementations are uncouth regardless of syntactic convenience) would serve them better. Seems a bit like a chicken-egg scenario.

Edited by Valik
Added a couple sentences.

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.