Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Recycling variables and performance


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
32 replies to this topic

#1 SuperVGA   Members   -  Reputation: 1118

Like
0Likes
Like

Posted 15 June 2011 - 07:09 AM

Hello everyone,

My colleague and I discussed whether it is actually faster to pre-declare and recycle as many function variables as possible.
I've been taught (and so i practice), to declare and initialize variables only when i need to use them. Preferably in a scope not covering more
than where it's potentially used. So my colleague asked if i would redeclare for-loop variable i rather than declaring it once, just because it's a prettier coding style:
for(unsigned i = 0; 10 != i; ++i)
{
}

for(unsigned i = 0; 10 != i; ++i)
{	
}

for(unsigned i = 0; 10 != i; ++i)
{	
}

As opposed to:

unsigned i;

for(i = 0; 10 != i; ++i)
{
}

for(i = 0; 10 != i; ++i)
{	
}

for(i = 0; 10 != i; ++i)
{	
}

Comments on the whole predeclare then use vs late declaration/initialization are also welcome, although I'd prefer to tell him that at least,
the triple-declaration results in at least as fast code.

Sponsor:

#2 Hodgman   Moderators   -  Reputation: 31938

Like
2Likes
Like

Posted 15 June 2011 - 07:15 AM

In the above case, there's absolutely no difference in performance. The second one is worse stylistically IMHO, because the variable i which logically only belongs inside the scope of the loop has 'leaked' outside of that scope.

This is because unsigned int is a primitive type -- creating and destroying primitive types basically has no cost; they have no constructor or destructor to call (in most cases).

http://www.parashift...nsic-types.html
http://stackoverflow...-pod-types-in-c
http://en.wikipedia...._data_structure

[Edit]
If you're dealing with objects that have expensive constructors/destructors, then things are different.
E.g. instead of making an expensive object repeatedly:
for( ... )
{
  std::vector<int> vec;//constructor
  //..
  //destructor
}
...sometimes you can make this object once, and reuse it:
{
  std::vector<int> vec;//constructor
  for( ... )
  {
     //..  vec.clear();//reset it to a default state
  }
  //destructor
}


#3 rip-off   Moderators   -  Reputation: 8762

Like
4Likes
Like

Posted 15 June 2011 - 07:35 AM

The main thing for me is correctness. Re-using variables for different purposes can cause bugs. I would always urge caution - consider whether premature optimisation is motivating such a change. If profiling indicates problems, then that is a different matter.

In the case you gave, performance shouldn't be a concern, "i" will probably be in a register.

#4 Katie   Members   -  Reputation: 1375

Like
4Likes
Like

Posted 15 June 2011 - 10:29 AM

1. The compiler will do this for you anyway if it thinks it's safe to happen.

2. You almost certainly do not have the sort of performance problems that this is likely to help with.

#5 iMalc   Crossbones+   -  Reputation: 2314

Like
1Likes
Like

Posted 15 June 2011 - 01:16 PM

When writing code for some of the embedded devices I've worked on, their compilers are a fair way behind and don't respect the for loop variable scoping rules, thue you're forced to do it the second way. Over a decade ago when working on a software 3D engine in a tight spot (rendering loop) it was significantly faster to reuse a couple of variables because it helped the compiler out with register allocation. With more recent compilers I've found that I was able to make that same code readable again with no loss of performance. So nowdays you don't have to sacrifice readability; since you get nothing good from doing so.

I must say though that I dislike your for loop condition. i < 10 always, for maximum readability. Writing it the other way around has always been a ridiculous idea. If you can remember to force yourself to reverse the condition, reducing readability, then you can instead remember to force yourself to use == instead of =. In this case though, it doesn't even apply. Also, compilers detect that sort of mistake for you, so there's really no excuse for it.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

#6 SuperVGA   Members   -  Reputation: 1118

Like
0Likes
Like

Posted 15 June 2011 - 11:50 PM

I must say though that I dislike your for loop condition. i < 10 always, for maximum readability. Writing it the other way around has always been a ridiculous idea. If you can remember to force yourself to reverse the condition, reducing readability, then you can instead remember to force yourself to use == instead of =. In this case though, it doesn't even apply. Also, compilers detect that sort of mistake for you, so there's really no excuse for it.

@iMalc: Thanks for your response! Yes, you are right; the reason I write it like that is, that I'll get a parser error if i accidentally type =, rather than == or !=, as i always leave a const expression on the left-hand side. I've been practicing this because I can be sure that the condition doesn't assign while sacrificing little or no readability.

It's nice to get some good input on the reverse thing, though, you're seeing exactly why I'm doing it, and you're right as far as the "if I can remember to reverse the condition, I can remember == also". I will take that into consideration when i write my next for-loop. ;)

One might of course argue that we empathize that the loop should take place 10 times, and therefore it's actually preferable to have it earlier on the line, even for readability.
Also I think you should meet a condition with a clearly defined == or !=, as you'll be able to determine exactly where the for-variable should stop unless you use floats. If one cannot do that, and tends to use > or < when counting integers, I think one should reconsider the for-loop entirely.

However it's great to get some proper input on the semantics, it seems being taught by old-school developers have both advantages and disadvantages. :-)

It's good to know that the issues with the early declarations have been dealt with, and my lessons as well as passing on of the late initialization -practice have been correct. Thanks Rip-off and Hodgman for supplying details.

http://www.parashift...nsic-types.html

@Hodgman: I read that. Makes good sense, as always! :) (I've ordered that book from the parashift.com -site. I always think his writing style in there is great, and hope to find it in the book, too!)

#7 EJH   Members   -  Reputation: 314

Like
1Likes
Like

Posted 16 June 2011 - 12:11 PM

10 != i


It burns!!!

#8 arbitus   Members   -  Reputation: 436

Like
0Likes
Like

Posted 16 June 2011 - 12:44 PM

One might of course argue that we empathize that the loop should take place 10 times, and therefore it's actually preferable to have it earlier on the line, even for readability.
Also I think you should meet a condition with a clearly defined == or !=, as you'll be able to determine exactly where the for-variable should stop unless you use floats. If one cannot do that, and tends to use > or < when counting integers, I think one should reconsider the for-loop entirely.


I am not sure where you learned this, but it runs quite contrary to what is considered good style by the majority of authorities on the matter, and is more error prone than the alternatives (authorities in this instance being style guides such as Code Complete and other sources such as Bjarne's own works). Since the for loop counter do more than simple incrementation, you run the risk of creating an infinite loop with the == != syntax should your termination condition be incorrect, whereas a < or > will generally terminate the loop. Also, as you mentioned, floats. Also, for loops typically operate over simple mathematical sequences (0, 1, 2, 3, 4 or 0, 3, 6, 9 etc) and sequences are usually defined as a range, such as "all positive integers less than X" rather than "all positive integers not equal to 10" (notice how one of these actually does not express the sequence we intend to use for our for loop).

#9 SuperVGA   Members   -  Reputation: 1118

Like
0Likes
Like

Posted 16 June 2011 - 02:25 PM


One might of course argue that we empathize that the loop should take place 10 times, and therefore it's actually preferable to have it earlier on the line, even for readability.
Also I think you should meet a condition with a clearly defined == or !=, as you'll be able to determine exactly where the for-variable should stop unless you use floats. If one cannot do that, and tends to use > or < when counting integers, I think one should reconsider the for-loop entirely.


I am not sure where you learned this, but it runs quite contrary to what is considered good style by the majority of authorities on the matter, and is more error prone than the alternatives (authorities in this instance being style guides such as Code Complete and other sources such as Bjarne's own works). Since the for loop counter do more than simple incrementation, you run the risk of creating an infinite loop with the == != syntax should your termination condition be incorrect, whereas a < or > will generally terminate the loop. Also, as you mentioned, floats. Also, for loops typically operate over simple mathematical sequences (0, 1, 2, 3, 4 or 0, 3, 6, 9 etc) and sequences are usually defined as a range, such as "all positive integers less than X" rather than "all positive integers not equal to 10" (notice how one of these actually does not express the sequence we intend to use for our for loop).


Actually I was taught so by a former colleague of mine who is a c++ guru and has contributed to the works of Stroustrup. I'll try to defend it as I practice it and as he originally argued well for its use. When you work with iterators for instance, you define range as a place to start and a place to end. I'm not doing anything differently by telling at exactly which value to stop at.

Are you not aware of when to stop counting? If your code is broken, and you "accidentally" skip past the value to end at, you have much bigger issues than putting a const before a variable: you cannot defend how the code will behave.

If I break something, I will instantly know because i write so that problems will show themselves at compile time.

You mention written works arguing against this practice, (error prone and against good coding style) -could you help me to the source for it? I cannot find it.

Happy for your input although this thread has somewhat strayed from the original purpose. ;-)

#10 A Brain in a Vat   Members   -  Reputation: 313

Like
0Likes
Like

Posted 16 June 2011 - 03:29 PM

10 != i

I don't do it this way, but I don't really see anything wrong with it. It's the same thing you do with iterators.
std::vector<int> vec;
for (std::vector<int>::iterator i=vec.begin(); i != vec.end(); i++)
{
....
}

It's the same thing, no?

#11 Antheus   Members   -  Reputation: 2397

Like
2Likes
Like

Posted 16 June 2011 - 03:56 PM

Inequality is used to reduce number of special cases when increment isn't being done by 1.

Human factors matter a lot more than technical details. The simplest way is to simply memoize that for loop looks like this:
for (0; n)
It means, we are working with n elements. This is then transcribed into general looping construct like this:
while (i < n) {
  // increment i
}
This form works for any increment.

For is just a specialization of general repetition, a syntactic sugar of sorts, and it translates identically:
for (int i = 0; i < n; i++)

Extended approach of checking (i >= min) && (i < max) reduces human factor impact - regardless of how insides change or what is passed into construct, the code remains stable.

And if correctness matters, then either Ada or full invariant verification must be done anyway, so again, the style of for loop becomes irrelevant.


One can argue major or minor points here, but the Principle of least surprise always applies. Don't surprise me with exotic termination conditions or extravagant for constructs. It has all to do with common approach. Since != is uncommon, I'll need to first turn off the warning light that goes off in my head and then double check to see that author truly intended what is written.

It's simple - you might have studied with The Master, but the code I'll encounter will be written by a script kiddie who treats loop conditions as guidelines rather than rules.

It's the same thing, no?

Not quite, that is legacy fallback. Correct version would be:
std::for_each();
which does the proper thing - it eliminates for/while and instead applies operator to range. Iterators are also bound to range and possibly range checked. If used properly, they can never be invalid (std::advance and similar).

has contributed to the works of Stroustrup

That guy invented C++. That's borderline insanity :P

#12 Hodgman   Moderators   -  Reputation: 31938

Like
3Likes
Like

Posted 16 June 2011 - 05:35 PM

Since the for loop counter do more than simple incrementation, you run the risk of creating an infinite loop with the == != syntax should your termination condition be incorrect, whereas a < or > will generally terminate the loop.

AFAIK, the "i != end" style is more "C++ish" than the "i < end" style.


The reason is that they mean completely different things -- the first means, iterate until the iterator equals the terminal value, the second means iterate as long as the iterator no longer appears before the terminal value in sequence.

For primitive iterators, they're much the same thing, but for complex iterators (i.e. the world of operator overloading) the second version is extremely more complex in cases where 'sequence' is costly to determine (e.g. a linked-list iterator).

The argument about stopping infinite loops in the case of a bad terminal value doesn't hold much water --- if you've got a bad terminal value, then your code is wrong. Making wrong code look like it's working is a very bad thing.

#13 arbitus   Members   -  Reputation: 436

Like
1Likes
Like

Posted 16 June 2011 - 07:09 PM

Actually I was taught so by a former colleague of mine who is a c++ guru and has contributed to the works of Stroustrup. I'll try to defend it as I practice it and as he originally argued well for its use. When you work with iterators for instance, you define range as a place to start and a place to end. I'm not doing anything differently by telling at exactly which value to stop at.


As Antheus already mentioned, using iterators in a for loop is legacy syntax. For loops predate iterators and standard library containers, and that syntax was retrofitted to emulate the foreach construct. Now that there is a proper foreach construct in the standard library, iterator syntax in a for loop for going over the elements of a container is no longer idiomatic.

Are you not aware of when to stop counting? If your code is broken, and you "accidentally" skip past the value to end at, you have much bigger issues than putting a const before a variable: you cannot defend how the code will behave.


Once again, we come back to floating point values. While using such values is less common than simple counters, there is no reason why I cannot loop over the interior of a circle in pi/variable increments and have my loop terminate once I have reached ~2pi. Or perhaps I simply want to loop from 0.0 to 1.0 by 0.1 increments, or perhaps I even want to have a variable store the way in which I want to increment that cannot be determined at compile time, but I know that I want to stop when I have exceeded such a value. Also, (i < 10) implies that the loop is valid only for numbers less than 10, (10 != i) implies that the loop is invalid for the value 10, and requires additional information to be parsed in order to fully understand the purpose and intent of the loop.

You can (somewhat rightfully) state that I should not be using a for loop, but I do not find that very compelling, primarily because of how Bjarne Stroustrup has described the for loop statement as "iterating over a sequence of numbers." A numeric sequence is an ordered list of numbers described by a discrete function, and optionally bounded. Referring to my previous post, the natural language description of a sequence whose bound is written (n < 10) is:

All positive integers less than 10.

Conversely, if the bound is (10 != n), the language is less clear:

All positive integers where 10 is not equal to n.

While anyone versed in boolean expressions can distinguish between the two, the natural language reading of one is more obvious than the other. Also, a sequence of numbers includes floating point values, or an unknown quantity (at compile time). When the sequence involves ascending values, the < operator always defines a perfect upper bound, and the the > operator a lower bound for descending values. (10 != i) simply describes a single invariant.

If I break something, I will instantly know because i write so that problems will show themselves at compile time.


I am unsure as to how (10 != i) will produce a compile time error as opposed to (i < 10).

You mention written works arguing against this practice, (error prone and against good coding style) -could you help me to the source for it? I cannot find it.


Firstly, in approximately 10 C++ specific books that I currently have sitting on my shelf (sorry, about 3 of those are various editions of the same book), none of them contain an example of a for loop using your suggested syntax. All of them use a variation of the for (int i = 0; i < 10; ++i) syntax. These books include:

Programming: Principles and Practice Using C++ - Bjarne Stroustrup
The C++ Programming Language - Bjarne Stroustrup
C++ Primer Plus - Stephen Prata (multiple editions)

I consider these three books and a similar book on the C++ Standard Library to be the definitive works on the C++ language.

In addition, I remember language covering a similar topic in Code Complete, but I do not currently have my copy on hand to quote the relevant passages.

I have multiple books on the following languages: C, Java, C#, python, etc. All of which share the C style for loop syntax, and all examples follow the exact same pattern. I like to believe that I have most of the essential and definitive treatises on the subjects they contain, and I have not seen one mention a example similar to the one you have brought up. I have worked with a few people who use it and have talked about it, but I they have always been in the minority. I suppose I could also do my own namedropping of several prominant founders of Linux and Bell Labs, but I think that is unnecessary.

As a parting word, I would also like to express how greatly I prefer functional language for syntax. The use of list and sequence syntax is much more descriptive, and I would say that the natural language parsing of functional syntax is closer to that of my suggested for syntax.

Happy for your input although this thread has somewhat strayed from the original purpose. ;-)


I certainly hope that you do not take this the wrong way, as I am a language nerd and will politely discuss any range of minutiae ad nauseum. No one is incorrect here.

#14 arbitus   Members   -  Reputation: 436

Like
0Likes
Like

Posted 16 June 2011 - 07:48 PM

AFAIK, the "i != end" style is more "C++ish" than the "i < end" style.


I have mostly seen this for iterators, save for a handful of other times, of which this thread comprises roughly 50% of that. Given the predilection of authoritative books to prefer the latter, I find it difficult to accept that the former is more "C++ish," but I am no true authority on the issue.

The reason is that they mean completely different things -- the first means, iterate until the iterator equals the terminal value, the second means iterate as long as the iterator no longer appears before the terminal value in sequence.


I slightly disagree with the wording, because it changes the boolean expression. If we are taking the boolean expression at face value, it means "iterate while the iterator is not equal to the terminal value" whereas the second is "iterate while the iterator is below the terminal value." I am adverse to using the term "iterator" in this instance, as it is more appropriate to use the term "loop counter" in the instance where we are using a number, rather than a true "iterator." In the case of a collection iterator, see below:

For primitive iterators, they're much the same thing, but for complex iterators (i.e. the world of operator overloading) the second version is extremely more complex in cases where 'sequence' is costly to determine (e.g. a linked-list iterator).


As Antheus and I have mentioned previously, when iterating over collections, you are actually referring to the foreach syntax, which now has its own construct in the standard library. Foreach and for are actually semantically different, and were only conflated because of the lack of language primitives in C and C++. Now that the primitives are adopted into the standard library, using a for statement in conjunction with a collection should only be used when dealing with a true "index" (or loop counter) rather than an iterator (in case of a simple array, or other collection allowing use of "[ ]" indexing) and only if you are not performing a true linear iteration of the collection (ie, iterating over every 3rd index).

The argument about stopping infinite loops in the case of a bad terminal value doesn't hold much water --- if you've got a bad terminal value, then your code is wrong. Making wrong code look like it's working is a very bad thing.


The mere termination of a loop should never be an indication of working code, as the loop should perform some function, and the results of that computation should be the metric by which the correctness of the loop is guaged. However, one syntax allows you to terminate when you cannot accurately predict the final absolute value by which the loop must terminate. For instance:

for (float i = 0.0f; 2 * PI != i; i += PI / 12.0)

Because of accumulating floating point inaccuracy, this could potentially fail. Also:

n = *some number based on user input that can be any positive whole number in the range 10 to 15 *
for (int i = 0; n != i; i += 3) // we want this to loop until i exceeds the user input value

Once again, when using the natural reading of a sequence function definition, we say we want to "start at x and take numbers less than the upper bound" rather than "start at x and take numbers until x is not equal to upper bound" as our sequence function does not always necessarily output the defined upper boundary, leaving the possibility to take numbers that exceed the upper bound. != defines a single invariant condition, < and > define an understood boundary.

#15 D.Chhetri   Members   -  Reputation: 181

Like
1Likes
Like

Posted 16 June 2011 - 08:04 PM

Question, I know in the high level there is really no noticeable difference but technically speaking( in the digital logic sense ) a != b has less comparisons than a < b, right?
If a and b are say 2 bit variables then the logic to compare is

a != b => a0 ⊕ b0 ∧ a1 ⊕,b1;

a < b => ( (b1 ⊕ a1 ) ∨ a1) ∨ ( (b0 ⊕ a0) ∨ a0)

I haven't done that for a while so I'm not sure if the above algebra is correct, specifically the '<' comparison.
Edge cases will show your design flaws in your code!
Visit my site
Visit my FaceBook
Visit my github

#16 Hodgman   Moderators   -  Reputation: 31938

Like
1Likes
Like

Posted 16 June 2011 - 08:09 PM

The reason is that they mean completely different things -- the first means, iterate until the iterator equals the terminal value, the second means iterate as long as the iterator no longer appears before the terminal value in sequence.

I slightly disagree with the wording, because it changes the boolean expression. If we are taking the boolean expression at face value, it means "iterate while the iterator is not equal to the terminal value" whereas the second is "iterate while the iterator is below the terminal value." I am adverse to using the term "iterator" in this instance, as it is more appropriate to use the term "loop counter" in the instance where we are using a number, rather than a true "iterator."

An iterator in C++ is just a concept. Integers don't actually fit the concept of an iterator because they can't be dereferenced, but IME it's still common to see integer-index loops written in the same style as iterator loops.

If you look at the code for for_each it will certainly be implemented via "while not equal to terminal" instead of "while below terminal", because the latter is simply incorrect with regards to this concept.

Float loops, or integers loops with a range of terminal values are of course different because they definitely don't fit into the iterator concept.

If you're just iterating through ranges of numbers, then it's a matter of style or logical requirement, but if you're writing algorithms that operate on the iterator concept, then it does become a black and white issue (sequence is not a requirement of the concept).

#17 arbitus   Members   -  Reputation: 436

Like
0Likes
Like

Posted 16 June 2011 - 08:34 PM

An iterator in C++ is just a concept. Integers don't actually fit the concept of an iterator because they can't be dereferenced, but IME it's still common to see integer-index loops written in the same style as iterator loops.


Once again, I must defer to the fact that I do not see this style used with numeric counted loops in any of the definitive reference material for the C++ language. I am open to the argument, but I find the < and > operators to be more idiomatic when describing boundary conditions. Think of this in regards to boolean logic in other statements such as if () constructs.

If you look at the code for for_each it will certainly be implemented via "while not equal to terminal" instead of "while below terminal", because the latter is simply incorrect with regards to this concept.

Float loops, or integers loops with a range of terminal values are of course different because they definitely don't fit into the iterator concept.


I understand this, which is why I specifically pointed out the difference. Iterators are different, and I do believe that I mentioned that multiple times in my previous posts. However, the example in the OP is of an integer counted loop, not an iterator example. Also, I specifically mentioned why iterating over a collection (foreach) is semantically different than the standard loop counted for. I am only disagreeing with your semantic interpretation in the case of a numeric loop counted for, which is the one presented by the OP in the OP.

#18 A Brain in a Vat   Members   -  Reputation: 313

Like
1Likes
Like

Posted 16 June 2011 - 09:36 PM

As Antheus already mentioned, using iterators in a for loop is legacy syntax. For loops predate iterators and standard library containers, and that syntax was retrofitted to emulate the foreach construct. Now that there is a proper foreach construct in the standard library, iterator syntax in a for loop for going over the elements of a container is no longer idiomatic.

How can you say this with a straight face? A proper foreach? You call std::for_each a proper foreach?

This is a proper foreach:
foreach( oneElement in someVector)
{
....
}

C# has a proper foreach. Requiring one to provide a function object is not a proper foreach.

The closest you can get to a proper foreach is using C++0x's lamba syntax:
std::vector<int> someVec = {0, 1, 2, 3, 4};

std::foreach( someVec.begin(), someVec.end(), [](int oneElement)
{
	...
});


Leaves a lot to be desired.

I'd like a real foreach in C++, but std::for_each certainly isn't one.


Using a built-in control structure to iterate over a container and using a higher-order construct that calls a function object on each member of a container are not the same thing.

It's absolutely disingenuous to claim that std::for_each is a replacement for the temporary solution of using a for loop. The syntax was not "retrofitted to emulate the foreach construct." Not only does that not make any sense, you can't provide any evidence for it. The iterator syntax is the way it is in order to emulate pointers from C, which already had iterator semantics.

Stroustrup himself prescribes a for loop as a "way of traversing a vector." See this powerpoint presentation, page 37.
http://www.stroustru..._containers.ppt

Back to (10 != i). We use != rather than < when iterating over a vector. Is this any less error prone than (10 != i)? No, it's not.

#19 A Brain in a Vat   Members   -  Reputation: 313

Like
0Likes
Like

Posted 16 June 2011 - 09:42 PM

As Antheus and I have mentioned previously, when iterating over collections, you are actually referring to the foreach syntax, which now has its own construct in the standard library. Foreach and for are actually semantically different, and were only conflated because of the lack of language primitives in C and C++. Now that the primitives are adopted into the standard library, using a for statement in conjunction with a collection should only be used when dealing with a true "index" (or loop counter) rather than an iterator (in case of a simple array, or other collection allowing use of "[ ]" indexing) and only if you are not performing a true linear iteration of the collection (ie, iterating over every 3rd index).



Are you being serious here? You are implying that one should write a function object to represent the internals of what in the past would have been a for loop? We should just have hundreds of function objects all over our code? If you're seriously implying this then I'd hate to see your code.

#20 Hodgman   Moderators   -  Reputation: 31938

Like
0Likes
Like

Posted 16 June 2011 - 09:47 PM

I understand this, ..., and I do believe that I mentioned that multiple times in my previous posts.

You don't have to keep repeating yourself after every reply. I'm not attacking you or your choice of for loop syntax...

I was just sharing my experience and adding an explanation as to why "!=" syntax is popular -- the same reason why you see more "++i" in C++ for-loops compared to the usual "i++" from C for-loops . No need to get defensive.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS