Generics and Findall

T

tshad

I am confused as to why you need to use Predicate<t> in a findall method of
Generics.

I have the following which works fine.

*********************************************************
using System;
using System.Collections.Generic;
using System.Text;

namespace Generics
{
public class Racer
{
private string name;
public string Name { get{return name;}}
private string car;
public string Car {get {return car;}}
public Racer(string name, string car)
{
this.name = name;
this.car = car;
}
public override string ToString()
{
return name + ", " + car;
}

public bool GetCar(string theCar)
{
return this.car == theCar;
}

public bool GetName(string theName)
{
return this.name == theName;
}
}

public class FindRacer
{
private string car;
public FindRacer(string car)
{
this.car = car;
}
public bool DrivingCarPredicate(Racer racer)
{
return racer.Car == car;
}
}
class Program
{
public static void GetDino()
{
List<string> dinosaurs = new List<string>();

dinosaurs.Add("Compsognathus");
dinosaurs.Add("Amargasaurus");
dinosaurs.Add("Oviraptor");
dinosaurs.Add("Velociraptor");
dinosaurs.Add("Deinonychus");
dinosaurs.Add("Dilophosaurus");
dinosaurs.Add("Gallimimus");
dinosaurs.Add("Triceratops");

Console.WriteLine();
foreach (string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}

Console.WriteLine("\nTrueForAll(EndsWithSaurus): {0}",
dinosaurs.TrueForAll(EndsWithSaurus));

Console.WriteLine("\nFind(EndsWithSaurus): {0}",
dinosaurs.Find(EndsWithSaurus));

Console.WriteLine("\nFindLast(EndsWithSaurus): {0}",
dinosaurs.FindLast(EndsWithSaurus));

Console.WriteLine("\nFindAll(EndsWithSaurus):");
List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);

foreach (string dinosaur in sublist)
{
Console.WriteLine(dinosaur);
}

Console.WriteLine(
"\n{0} elements removed by RemoveAll(EndsWithSaurus).",
dinosaurs.RemoveAll(EndsWithSaurus));

Console.WriteLine("\nList now contains:");
foreach (string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}

Console.WriteLine("\nExists(EndsWithSaurus): {0}",
dinosaurs.Exists(EndsWithSaurus));
}

// Search predicate returns true if a string ends in "saurus".
private static bool EndsWithSaurus(String s)
{
if ((s.Length > 5) &&
(s.Substring(s.Length - 6).ToLower() == "saurus"))
{
return true;
}
else
{
return false;
}
}

static void Main(string[] args)
{

GetDino();

List<Racer> racers = new List<Racer>();
racers.Add(new Racer("Michael Schumacher", "Ferrari"));
racers.Add(new Racer("Juan Pablo Montoya", "McLaren-Mercedes"));
racers.Add(new Racer("Kimi Raikkonen", "McLaren-Mercedes"));
racers.Add(new Racer("Mark Webber", "Williams-BMW"));
racers.Add(new Racer("Rubens Barichello", "Ferrari"));

foreach (Racer r in racers)
{
Console.WriteLine(r);
}

FindRacer finder = new FindRacer("Ferrari");
foreach (Racer racer in racers.FindAll(new
Predicate<Racer>(finder.DrivingCarPredicate)))
{
Console.WriteLine(racer);
}

List<Racer> theList = racers.FindAll(new
Predicate<Racer>(finder.DrivingCarPredicate));

Console.Read();
}
}
}
*********************************************************

All this code works perfectly.

But for Racers, I do the FindAll method with:

List<Racer> theList = racers.FindAll(new
Predicate<Racer>(finder.DrivingCarPredicate));

In the GetDino method I use the following with no "Predicate<t>":

List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);

Why is that?

Also, I tried set up 2 predicates similar to the GetDino method and put the
methods in the Racers Class (GetCar and GetName) but I can't get it to work:

List<Racer> theList = racers.FindAll(theList.GetCar("Ferrari"));

This will give me the error:

'System.Collections.Generic.List<Generics.Racer>' does not contain a
definition for 'GetCar'

but the class Racer does contain it.

Do you have to create a whole new class (as I do with FindRacer) to get this
to work?

Thanks,

Tom
 
P

Peter Duniho

I am confused as to why you need to use Predicate<t> in a findall method
of
Generics.

I suppose that depends on your definition of "use". The parameter for the
FindAll() method is a Predicate<T>, so you must use some instance of an
appropriate Predicate<T>.

But type inference can take a method name and convert it to the necessary
instance without explicitly writing "Predicate<T>", so in that sense you
don't need to use Predicate said:
[...]
But for Racers, I do the FindAll method with:

List<Racer> theList = racers.FindAll(new
Predicate<Racer>(finder.DrivingCarPredicate));

In the GetDino method I use the following with no "Predicate<t>":

List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);

Why is that?

Because the second example takes advantage of type inference. You should
be able to get the first example to work fine in a similar way:

List said:
Also, I tried set up 2 predicates similar to the GetDino method and put
the
methods in the Racers Class (GetCar and GetName) but I can't get it to
work:

List<Racer> theList =
racers.FindAll(theList.GetCar("Ferrari"));

This will give me the error:

'System.Collections.Generic.List<Generics.Racer>' does not contain a
definition for 'GetCar'

Well, it doesn't. "theList" is an instance of List<Racer>, and it only
contains the methods declared in the generic List<T> class. Where would
it get the GetCar() method from?

If you want to use the GetCar() method as the predicate, you need to a)
have a list that contains strings rather than Racers (since the method's
argument is a string not a Racer), and b) reference the method from an
instance of Racer said:
but the class Racer does contain it.

Yes, which is why you need an instance of Racer, not an instance of
List said:
Do you have to create a whole new class (as I do with FindRacer) to get
this
to work?

No. You didn't really even need the FindRacer class. Anonymous methods
are really useful when dealing with predicates. For example, instead of:

FindRacer finder = new FindRacer("Ferrari");
List<Racer> theList = racers.FindAll(finder.DrivingCarPredicate);

with all of the overhead of declaring that FindRacer class, you could have
just used:

List<Racer> theList = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

without having to declare any new class at all.

Pete
 
T

Tom Shelton

[...]
But for Racers, I do the FindAll method with:

List<Racer> theList = racers.FindAll(new
Predicate<Racer>(finder.DrivingCarPredicate));

In the GetDino method I use the following with no "Predicate<t>":

List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);

Why is that?

No. You didn't really even need the FindRacer class. Anonymous methods
are really useful when dealing with predicates. For example, instead of:

FindRacer finder = new FindRacer("Ferrari");
List<Racer> theList = racers.FindAll(finder.DrivingCarPredicate);

with all of the overhead of declaring that FindRacer class, you could have
just used:

List<Racer> theList = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

And in C# 3.0:

List<Racer> theList = racers.FindAll (racer => racer.Car == "Farrari");
 
T

tshad

I suppose that depends on your definition of "use". The parameter for the
FindAll() method is a Predicate<T>, so you must use some instance of an
appropriate Predicate<T>.

But type inference can take a method name and convert it to the necessary
instance without explicitly writing "Predicate<T>", so in that sense you
don't need to use Predicate<T> in a call to the FindAll() method.

That would make more sense,

Why use it if you don't need it?
[...]
But for Racers, I do the FindAll method with:

List<Racer> theList = racers.FindAll(new
Predicate<Racer>(finder.DrivingCarPredicate));

In the GetDino method I use the following with no "Predicate<t>":

List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);

Why is that?
Because the second example takes advantage of type inference. You should
be able to get the first example to work fine in a similar way:

List said:
Also, I tried set up 2 predicates similar to the GetDino method and put
the
methods in the Racers Class (GetCar and GetName) but I can't get it to
work:

List<Racer> theList =
racers.FindAll(theList.GetCar("Ferrari"));

This will give me the error:

'System.Collections.Generic.List<Generics.Racer>' does not contain a
definition for 'GetCar'

Well, it doesn't. "theList" is an instance of List<Racer>, and it only
contains the methods declared in the generic List<T> class. Where would it
get the GetCar() method from?

I just assumed that since List is a List/Collection of Racer classes that
each class would have the method and be able to call it.

Obviously, this is not the case.
If you want to use the GetCar() method as the predicate, you need to a)
have a list that contains strings rather than Racers (since the method's
argument is a string not a Racer), and b) reference the method from an
instance of Racer, not from an instance of List<T>.
But I need the Racers class as that is what I am using for my data
collection. If I was only going to use strings, why not use an Array class.
Yes, which is why you need an instance of Racer, not an instance of


No. You didn't really even need the FindRacer class. Anonymous methods
are really useful when dealing with predicates. For example, instead of:

FindRacer finder = new FindRacer("Ferrari");
List<Racer> theList = racers.FindAll(finder.DrivingCarPredicate);

with all of the overhead of declaring that FindRacer class, you could have
just used:

List<Racer> theList = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

without having to declare any new class at all.

That worked really well.

I have been trying to see why to use delegates at all and this seems to be a
really good place.

Thanks,

Tom
 
T

tshad

tshad said:

But if I had defined:

public class RacerCollection : List<Racer> { }

Why can't I do:

RacerCollection theList3 = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

Both are List collections of Racer.

But where this will work:

List<Racer> theList = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

Why doesn't the other work? The only difference being "RacerCollection" vs
"List<Racer>". Yet both are handled the same way and have the same methods.

Thanks,

Tom
 
J

Jon Skeet [C# MVP]

tshad said:
But if I had defined:

public class RacerCollection : List<Racer> { }

Why can't I do:

RacerCollection theList3 = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

Both are List collections of Racer.

Sure - but what if you'd got other information in RacerCollection -
But where this will work:

List<Racer> theList = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

Why doesn't the other work? The only difference being "RacerCollection" vs
"List<Racer>". Yet both are handled the same way and have the same methods.

That doesn't mean they're the same type.

If I do:

class First {}

class Second {}

that doesn't mean I can do:

First f = new First();
Second s = f;
 
P

Peter Duniho

[...]
Well, it doesn't. "theList" is an instance of List<Racer>, and it only
contains the methods declared in the generic List<T> class. Where
would it
get the GetCar() method from?

I just assumed that since List is a List/Collection of Racer classes that
each class would have the method and be able to call it.

Obviously, this is not the case.

Well, if it were obvious I think maybe you wouldn't have asked the
question. :) But yes, your assumption was incorrect. List<T> doesn't
inherit any methods from the type in the collection. Nor would any
generic class inherit any methods from the generic type parameter's
class. You would always need to get an instance of that type parameter to
get at a method in that class.
But I need the Racers class as that is what I am using for my data
collection. If I was only going to use strings, why not use an Array
class.

Why not indeed? :)

My comment was only with respect to the prerequisites for getting the code
you posted to actually work. I never meant to suggest you'd _want_ to
approach your solution that way.
[...]
List<Racer> theList = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

without having to declare any new class at all.

That worked really well.

I have been trying to see why to use delegates at all and this seems to
be a
really good place.

There are lots of reasons to use delegates. They come up in a wide
variety of situations in .NET. The Predicate<T> delegate type is just one
example, and as you've seen it's very useful for the various "find"
methods on the generic classes. But they're used for event handlers
(which if you've done any GUI, you are almost certainly using), callbacks
(which are often used when doing things asynchronously, in a
multi-threaded design), and other scenarios.

Pete
 
J

Jon Skeet [C# MVP]

There are lots of reasons to use delegates. They come up in a wide
variety of situations in .NET. The Predicate<T> delegate type is just one
example, and as you've seen it's very useful for the various "find"
methods on the generic classes. But they're used for event handlers
(which if you've done any GUI, you are almost certainly using), callbacks
(which are often used when doing things asynchronously, in a
multi-threaded design), and other scenarios.

LINQ in particular uses delegates extensively. Even if you're(*) not
using LINQ now, it's worth becoming familiar on delegates so it's less
of a shock when you do :)


(*) General "you", not Peter in particular. Using "one" just sounds
pretentious.
 
P

Peter Duniho

[...]
(*) General "you", not Peter in particular. Using "one" just sounds
pretentious.

Really? I use "one" reasonably regularly, mainly so I can avoid having to
footnote comments I might make with clarifications that I'm not talking
about a specific person. :)

I didn't realize I was sounding pretentious. Oh well.

Pete
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
[...]
(*) General "you", not Peter in particular. Using "one" just sounds
pretentious.

Really? I use "one" reasonably regularly, mainly so I can avoid having to
footnote comments I might make with clarifications that I'm not talking
about a specific person. :)

I didn't realize I was sounding pretentious. Oh well.

In some cases it's fine - but in this case I figured it sounded weird
and pretentious to me. Besides, I like footnotes :)
 
T

tshad

I am confused as to why you need to use Predicate<t> in a findall method
of
Generics.

I suppose that depends on your definition of "use". The parameter for the
FindAll() method is a Predicate<T>, so you must use some instance of an
appropriate Predicate<T>.

But type inference can take a method name and convert it to the necessary
instance without explicitly writing "Predicate<T>", so in that sense you
don't need to use Predicate said:
[...]
But for Racers, I do the FindAll method with:

List<Racer> theList = racers.FindAll(new
Predicate<Racer>(finder.DrivingCarPredicate));

In the GetDino method I use the following with no "Predicate<t>":

List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);

Why is that?

Because the second example takes advantage of type inference. You should
be able to get the first example to work fine in a similar way:

List said:
Also, I tried set up 2 predicates similar to the GetDino method and put
the
methods in the Racers Class (GetCar and GetName) but I can't get it to
work:

List<Racer> theList =
racers.FindAll(theList.GetCar("Ferrari"));

This will give me the error:

'System.Collections.Generic.List<Generics.Racer>' does not contain a
definition for 'GetCar'

Well, it doesn't. "theList" is an instance of List<Racer>, and it only
contains the methods declared in the generic List<T> class. Where would
it get the GetCar() method from?

If you want to use the GetCar() method as the predicate, you need to a)
have a list that contains strings rather than Racers (since the method's
argument is a string not a Racer), and b) reference the method from an
instance of Racer said:
but the class Racer does contain it.

Yes, which is why you need an instance of Racer, not an instance of
List said:
Do you have to create a whole new class (as I do with FindRacer) to get
this
to work?

No. You didn't really even need the FindRacer class. Anonymous methods
are really useful when dealing with predicates. For example, instead of:

FindRacer finder = new FindRacer("Ferrari");
List<Racer> theList = racers.FindAll(finder.DrivingCarPredicate);

with all of the overhead of declaring that FindRacer class, you could have
just used:

List<Racer> theList = racers.FindAll(delegate(Racer racer) { return
racer.Car == "Ferrari"; });

without having to declare any new class at all.

Pete
 
T

tshad

Jon Skeet said:
Sure - but what if you'd got other information in RacerCollection -


That doesn't mean they're the same type.

But RacerCollection inherits the List<Racer>.

I am not sure why I would do this then:

public class RacerCollection : List<Racer> { }

I see this done in other places. Does this mean I would have to do both?

public class RacerCollection : List<Racer> { }
List<Racer> racers = new List<Racer>();

and then do RacerCollection.Add and racers.Add so I can use both objects?

If I have already created my object as RacerCollection and then decide that
I want to do a FindAll - do I have to do it all over again with List<racers>
just to be able use FindAll?

Or is it that I can use RacerCollection, but only the result has to be
List<Racer>:

public class RacerCollection : List<Racer> { }
RacerCollection racers = new RacerCollection();

List<Racer> result = racers.Findall(...);

Thanks,

Tom
 
T

tshad

Sorry the other message got sent by accident.

I am not sure why OutlookExpress won't put the ">" in front of your
responses and I have to put them there myself. Is there something in your
newreader that would prevent that?

I suppose that depends on your definition of "use". The parameter for the
FindAll() method is a Predicate<T>, so you must use some instance of an
appropriate Predicate<T>.

But type inference can take a method name and convert it to the necessary
instance without explicitly writing "Predicate<T>", so in that sense you
don't need to use Predicate<T> in a call to the FindAll() method.

Then what is a Predicate<T>?

How do I know if am passing an object of Predicate<T>?

Thanks,

Tom
 
T

tshad

There are lots of reasons to use delegates. They come up in a wide
variety of situations in .NET. The Predicate<T> delegate type is just one
example, and as you've seen it's very useful for the various "find"
methods on the generic classes. But they're used for event handlers
(which if you've done any GUI, you are almost certainly using), callbacks
(which are often used when doing things asynchronously, in a
multi-threaded design), and other scenarios.

I agree that there are many reasons to use them.

I am still trying to get my mind around some of the uses as some of the
examples I see, use a delegate when you can just call the same function
directly and I see no reason why they use the delegate there.

I can see why you would use it in a callback situation.

Thanks,

Tom
 
J

Jon Skeet [C# MVP]

tshad said:
But RacerCollection inherits the List<Racer>.

Yes - not the other way round. Every RacerCollection is a List<Racer>,
but not every List said:
I am not sure why I would do this then:

public class RacerCollection : List<Racer> { }

I see this done in other places. Does this mean I would have to do both?

public class RacerCollection : List<Racer> { }
List<Racer> racers = new List<Racer>();

and then do RacerCollection.Add and racers.Add so I can use both objects?

It's not at all clear what you mean by RacerCollection.Add - unless
you've created a static method.
If I have already created my object as RacerCollection and then decide that
I want to do a FindAll - do I have to do it all over again with List<racers>
just to be able use FindAll?

No, you've got it the wrong way round. You can call FindAll on a
RacerCollection just fine.
Or is it that I can use RacerCollection, but only the result has to be
List<Racer>:

public class RacerCollection : List<Racer> { }
RacerCollection racers = new RacerCollection();

List<Racer> result = racers.Findall(...);

Exactly. How would the code in List<T>.FindAll know how to create a new
instance of RacerCollection? There might be constructors which take
particular parameters, etc.

All it knows how to build is instances of List<T> - so that's what
FindAll does.
 
P

Peter Duniho

I agree that there are many reasons to use them.

I am still trying to get my mind around some of the uses as some of the
examples I see, use a delegate when you can just call the same function
directly and I see no reason why they use the delegate there.

I can't comment without a specific example. But I would agree that if
there's a straightforward way to write the code with the method being
called directly rather than through a delegate, then doing so is
preferable to using a delegate.

Delegates are useful, but they definitely can obfuscate what's going on,
depending on the situation. You're right to think that if the delegate is
not needed, then it usually will make sense not to use one.

Pete
 
P

Peter Duniho

Sorry the other message got sent by accident.

I am not sure why OutlookExpress won't put the ">" in front of your
responses and I have to put them there myself. Is there something in
your
newreader that would prevent that?

I'm not sure. You're the first person to have mentioned that problem.
What version of OE are you using? I used to use it, and never ran into an
issue with it failing to quote text properly. But I can't rule out that
there's something about the formatting of the messages I post that is
causing it some problem.

Unfortunately, not knowing what that might be, I'm at a loss as to how I
might fix it on my end.
[...]
But type inference can take a method name and convert it to the
necessary
instance without explicitly writing "Predicate<T>", so in that sense you
don't need to use Predicate<T> in a call to the FindAll() method.

Then what is a Predicate<T>?

I'm not sure what you're asking. The MSDN docs describe the type here:
http://msdn2.microsoft.com/en-us/library/bfcke1bz(vs.80).aspx

Is there something about that that doesn't answer the question?
How do I know if am passing an object of Predicate<T>?

If the method's argument is Predicate<T> and it compiles without an error,
then you are passing a Predicate<T>.

Pete
 
T

tshad

Peter Duniho said:
I'm not sure. You're the first person to have mentioned that problem.
What version of OE are you using? I used to use it, and never ran into an
issue with it failing to quote text properly. But I can't rule out that
there's something about the formatting of the messages I post that is
causing it some problem.

Unfortunately, not knowing what that might be, I'm at a loss as to how I
might fix it on my end.

I remember looking into this before and it was how the other persons reader
was sending the message. Can't remember what the problem was. I only have
this problem very rarely.

I am using OE 6.

Tom
[...]
But type inference can take a method name and convert it to the
necessary
instance without explicitly writing "Predicate<T>", so in that sense you
don't need to use Predicate<T> in a call to the FindAll() method.

Then what is a Predicate<T>?

I'm not sure what you're asking. The MSDN docs describe the type here:
http://msdn2.microsoft.com/en-us/library/bfcke1bz(vs.80).aspx

Is there something about that that doesn't answer the question?
How do I know if am passing an object of Predicate<T>?

If the method's argument is Predicate<T> and it compiles without an error,
then you are passing a Predicate<T>.

Pete
 
P

Peter Duniho

I am not sure why OutlookExpress won't put the ">" in front of your
responses and I have to put them there myself. Is there something in
your
newreader that would prevent that?

[...]
Unfortunately, not knowing what that might be, I'm at a loss as to how I
might fix it on my end.

I remember looking into this before and it was how the other persons
reader
was sending the message. Can't remember what the problem was. I only
have
this problem very rarely.

Hmmm...

I just sent email to you saying that I'd checked and on my computer OE
behaves fine. But with your more recent explanation that it only happens
some times, I took another look. And yes, for some messages I can in fact
reproduce the problem.

One difference between messages that quote correctly and those that don't
is that those that do have "Content-Transfer-Encoding: 7bit" in the
header, while those that don't have "Content-Transfer-Encoding:
Quoted-Printable". In the latter case, the message is also filled with
'='-quoted characters (but not in a way that I recognize...the message
shows fine in newsreaders though, so I assume it's at least legal encoding
:) ).

Oddly, both have UTF-8 described in the "Content-Type" field. So maybe
there's a difference in terms of what characters are actually being
posted. Maybe if the message includes only ASCII characters, it works
fine, but as soon as something that doesn't fit in ASCII is included, the
"Content-Transfer-Encoding" changes. Unfortunately for that theory, I
don't actually see anything in any of the messages I checked that couldn't
be represented in regular ASCII. It's not really clear to me what might
be causing the difference.

So, I think it's for sure either a bug in Opera (what I'm using as a
newsreader) or Outlook Express (what you're using). But I don't have a
good guess as to which is actually the case. Could be either. For that
matter, I suppose it could be both. :)

Unfortunately, I don't really know enough about the various character
encoding techniques used for text messages to really understand the
problem well enough to suggest a conclusive reason for why it happens,
never mind how it might be fixed.

Pete
 
P

Peter Duniho

[...]
Unfortunately, I don't really know enough about the various character
encoding techniques used for text messages to really understand the
problem well enough to suggest a conclusive reason for why it happens,
never mind how it might be fixed.

Okay, sorry for the off-topic again, but I think I've answered at least
part of the question.

I don't know why "quoted-printable" is being used as the format.
Presumably Opera is seeing something in the message that it feels
justifies the use of "quoted-printable". What that might be, I have no
idea. The only quoted characters in the message are soft line-breaks (an
'=' character followed by an actual line-break) and characters where '='
is in the actual text (i.e. they are being quoted because the '=' is the
quoting character).

If I had to guess, I'd say it's probably related to the line lengths, with
Opera wanting to use "quoted-printable" as a way to put line-breaks in the
message that don't actually force a line-break. Maybe some sort of
interaction between the line-breaks as the message was composed versus the
line-breaks Opera imposes for the purpose of limiting line-lengths for
message.

However, in any case looking at the message it appears to me that Opera is
not using an invalid format. The formatting is weird, but not wrong. OE
should be interpreting the "quoted-printable" encoding correctly, and in
fact it does when it's displaying the message. It just isn't handling it
correctly when it goes to quote the text in a reply.

I'll see if there's a setting in Opera that allows more fine-grained
control over what's going on, that would allow me to post messages in the
same way without OE's bug manifesting itself. But, given that it's a bug
in your newsreader and not mine, I don't plan to spend much time on it. :)

Anyway, I think that's enough of this tangent here. I'm happy to discuss
it further via email if you like, but out of respect for the newsgroup
topic this'll be my last message to the newsgroup on the issue.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top