Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Disposing of brushes

5 views
Skip to first unread message

Peter Webb

unread,
Feb 21, 2008, 2:16:51 AM2/21/08
to
I am supposed to manually dispose of some instances, such as Brushes, right?

I have a couple of questions:

1. I have the following code, and it works just fine:

penarea.DrawString(selectedslot.drawString,new Font("Arial",fontsize),
new SolidBrush(selectedslot.colour),new Point(0,this.Height/2-(int)
scale)); break;

Just how am I supposed to dispose of the new SolidBrush () ?

2. I create lots of brushes deep down in lots of places, often in loops. How
worried should I be that I am creating brushes but not disposing of them? Is
that some way to enumerate brushes at run time so I can do my own GC when I
know the system is otherwise idle? Can I at least tell in the IDE that I
don't have thousands of brushes being created but not disposed? Or is this
just examining the code?

3. Am I missing something with respect to disposing of things like brushes
and graphics? (Obviously I am, including why they aren't GCed like
everything else). Disposing of them seems a bit of a pain in the arse, but
is seldom discussed on this newsgroup.


Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 2:32:14 AM2/21/08
to
Peter Webb <webbf...@DIESPAMDIEoptusnet.com.au> wrote:
> I am supposed to manually dispose of some instances, such as Brushes, right?

Yes.

> I have a couple of questions:
>
> 1. I have the following code, and it works just fine:
>
> penarea.DrawString(selectedslot.drawString,new Font("Arial",fontsize),
> new SolidBrush(selectedslot.colour),new Point(0,this.Height/2-(int)
> scale)); break;
>
> Just how am I supposed to dispose of the new SolidBrush () ?

By not creating the brush as a method argument:

using (Font f = new Font("Arial", fontsize))
using (Brush b = new SolidBrush(selectedslot.coulour))
{
penarea.DrawString(selectedslot.drawString, f, b,
new Point(0, this.Height/2-(int)scale)
}
break;

> 2. I create lots of brushes deep down in lots of places, often in loops. How
> worried should I be that I am creating brushes but not disposing of them? Is
> that some way to enumerate brushes at run time so I can do my own GC when I
> know the system is otherwise idle? Can I at least tell in the IDE that I
> don't have thousands of brushes being created but not disposed? Or is this
> just examining the code?

You should be worried enough to dispose them yourself.

> 3. Am I missing something with respect to disposing of things like brushes
> and graphics? (Obviously I am, including why they aren't GCed like
> everything else). Disposing of them seems a bit of a pain in the arse, but
> is seldom discussed on this newsgroup.

They *are* GC'd like everything else - but only at some indeterminate
time, which may be too late. The GC reacts to *memory* pressure, but
brushes, fonts etc take GDI handles - and you could run short of those
without running short of memory.

--
Jon Skeet - <sk...@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk

KWienhold

unread,
Feb 21, 2008, 2:45:53 AM2/21/08
to
On 21 Feb., 08:16, "Peter Webb" <webbfam...@DIESPAMDIEoptusnet.com.au>
wrote:

Classes that implement IDisposable normally use unmanaged resources.
The GC can't deal with those, so they must be cleaned up manually,
that's what Dispose() is for.
If a class does implement IDisposable you should make sure to call its
Dispose method as soon as you are done with it, otherwise you might
leak memory or hold on to resources (Sql-Connections, file handles
etc.) that should have been freed.
There is no automatic way of calling Dispose (unless the class does
this in a finalizer, but you shouldn't rely on that), so every time
you aren't calling Dispose, you are leaking.

In your example, you would normally create an instance of SolidBrush
before the method call and dispose of it afterwards, either by calling
Dispose() manually or with a using-block like so:

using (SolidBrush SelectedSlotBrush = new
SolidBrush(selectedslot.colour))
{
penarea.DrawString(selectedslot.drawString,new
Font("Arial",fontsize),SelectedSlotBrush,new Point(0,this.Height/2-
(int)scale));
}
break;

hth,
Kevin Wienhold

Peter Webb

unread,
Feb 21, 2008, 2:51:25 AM2/21/08
to
Got it. Thanks. They are GCed, but that means the corresponding windows
resources have to wait for the GC, right?

It does seem strange that what appears to me to be an obvious and easily
trapped coding error does not even generate a warning in the IDE. For that
reason I assumed it was reasonable; I will now take this out of my code - I
used it in a few places.

Thanks again

Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 3:08:23 AM2/21/08
to
Peter Webb <webbf...@DIESPAMDIEoptusnet.com.au> wrote:
> Got it. Thanks. They are GCed, but that means the corresponding windows
> resources have to wait for the GC, right?

Yes.

> It does seem strange that what appears to me to be an obvious and easily
> trapped coding error does not even generate a warning in the IDE. For that
> reason I assumed it was reasonable; I will now take this out of my code - I
> used it in a few places.

It's not easily trapped though. What if you pass the resource to
something else which will take ultimate responsibility for cleaning it
up, for instance?

Christopher Ireland

unread,
Feb 21, 2008, 3:14:50 AM2/21/08
to
Peter,

> 2. I create lots of brushes deep down in lots of places, often in
> loops.

You might also like to consider creating one brush and changing its
characteristics (color etc.) for each paint. You then dispose that one brush
after painting. You will find your code will run a lot quicker than
continual creation and disposal of IDisposible objects.

--
Thank you,

Christopher Ireland
http://shunyata-kharg.doesntexist.com

"You can't reason someone out of a position they didn't reason themselves
into."
Author Unknown


KWienhold

unread,
Feb 21, 2008, 3:55:38 AM2/21/08
to
On 21 Feb., 08:32, Jon Skeet [C# MVP] <sk...@pobox.com> wrote:
> They *are* GC'd like everything else - but only at some indeterminate
> time, which may be too late. The GC reacts to *memory* pressure, but
> brushes, fonts etc take GDI handles - and you could run short of those
> without running short of memory.
>
> --
> Jon Skeet - <sk...@pobox.com>http://www.pobox.com/~skeet  Blog:http://www.msmvps.com/jon.skeet
> World class .NET training in the UK:http://iterativetraining.co.uk

I'm somewhat surprised by your response here..
Maybe I'm misunderstanding something, but since when can the GC handle
unmanaged resources, the number one reason to have IDisposable? Maybe
in this special case the finalizer will call Dispose() for you, but
that really should not be generally relied upon, should it?
As far as I understand it, the managed part of the class would
eventually be GC'ed, but any unmanaged resources will leak, though it
is entirely possible that I am missing something.
Could you elaborate please?

Kevin Wienhold

Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 4:05:47 AM2/21/08
to
KWienhold <hedo...@trashmail.net> wrote:
> On 21 Feb., 08:32, Jon Skeet [C# MVP] <sk...@pobox.com> wrote:
> > They *are* GC'd like everything else - but only at some indeterminate
> > time, which may be too late. The GC reacts to *memory* pressure, but
> > brushes, fonts etc take GDI handles - and you could run short of those
> > without running short of memory.
>
> I'm somewhat surprised by your response here..
> Maybe I'm misunderstanding something, but since when can the GC handle
> unmanaged resources, the number one reason to have IDisposable? Maybe
> in this special case the finalizer will call Dispose() for you, but
> that really should not be generally relied upon, should it?
> As far as I understand it, the managed part of the class would
> eventually be GC'ed, but any unmanaged resources will leak, though it
> is entirely possible that I am missing something.
> Could you elaborate please?

The GC itself doesn't handle unmanaged resources, but anything which
directly owns an unmanaged resource *should* clean it up in the
finalizer. I would consider any class that didn't do so to be buggy -
and given how many people *do* create brushes, fonts etc without
disposing them, I think we'd have heard something if they were actually
leaking :)

Christopher Ireland

unread,
Feb 21, 2008, 4:15:16 AM2/21/08
to
Jon,

>I would consider any class that didn't do so to be buggy -
> and given how many people *do* create brushes, fonts etc without
> disposing them, I think we'd have heard something if they were
> actually leaking :)

Maybe that depends on what one considers a leak in a GC context (we've been
here before). I know you know more about this than I do, but I believe that
some people might consider c# code that uses GDI+ IDisposible objects
without explicitly calling Dispose() leaky as this means that the objects
are collected by later GC generations which may give the appearance of a
leak, that is, inflationary memory consumption during the lifetime of the
application.

--
Thank you,

Christopher Ireland
http://shunyata-kharg.doesntexist.com

"To see what is in front of one's nose needs a constant struggle."
George Orwell


Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 4:24:38 AM2/21/08
to
Christopher Ireland <cire...@gmail.com> wrote:
> >I would consider any class that didn't do so to be buggy -
> > and given how many people *do* create brushes, fonts etc without
> > disposing them, I think we'd have heard something if they were
> > actually leaking :)
>
> Maybe that depends on what one considers a leak in a GC context (we've been
> here before). I know you know more about this than I do, but I believe that
> some people might consider c# code that uses GDI+ IDisposible objects
> without explicitly calling Dispose() leaky as this means that the objects
> are collected by later GC generations which may give the appearance of a
> leak, that is, inflationary memory consumption during the lifetime of the
> application.

I'd consider that a "soft" leak - but if failing to dispose of a Brush
*never ever* released its Windows handle, that would count as a "hard"
leak in my view.

And no, I don't have hard and fast definitions of "soft" leak vs
"hard" leak but I hope they make some kind of sense here :)

KWienhold

unread,
Feb 21, 2008, 4:28:19 AM2/21/08
to
On 21 Feb., 10:05, Jon Skeet [C# MVP] <sk...@pobox.com> wrote:
> World class .NET training in the UK:http://iterativetraining.co.uk- Zitierten Text ausblenden -
>
> - Zitierten Text anzeigen -

Thanks for the clarification, I thought that may be what you meant,
but I wasn't sure.
I agree with you though, if you implement IDisposable you should call
Dispose() in the finalizer and supress the finalizer if Dispose is
called manually.
However, I would not want to rely on other developers actually doing
this. Microsofts code is probably pretty bullet-proof in these
regards, but other third-party libraries may not be. In addition to
that, non-deterministic clean up of unmanaged resources is still
somewhat "leaky", since the finalizer is always called late and may
not even be called at all (even though I am sure you know more about
when this is likely to happen than I do).
So in general I would still strongly suggest you call Dispose yourself
when you are done, but I think there is no argument here.

Kevin Wienhold

Christopher Ireland

unread,
Feb 21, 2008, 4:33:57 AM2/21/08
to
Jon,

> I'd consider that a "soft" leak - but if failing to dispose of a Brush
> *never ever* released its Windows handle, that would count as a "hard"
> leak in my view.
>
> And no, I don't have hard and fast definitions of "soft" leak vs
> "hard" leak but I hope they make some kind of sense here :)

I think so. A "soft" leak causes inflationary memory consumption during the
lifetime of the application, whereas a "hard" leak causes an increase in
memory consumption after the application has been closed, relative the the
memory consumption before the application was run.

I think we can agree that in a ideal .NET GC context, "hard" leaks never
occur :-)

--
Thank you,

Christopher Ireland
http://shunyata-kharg.doesntexist.com

"If you cannot find the truth right where you are, where else do you expect
to find it?"
Dogen Zenji


Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 4:38:39 AM2/21/08
to
KWienhold <hedo...@trashmail.net> wrote:
> Thanks for the clarification, I thought that may be what you meant,
> but I wasn't sure.
> I agree with you though, if you implement IDisposable you should call
> Dispose() in the finalizer and supress the finalizer if Dispose is
> called manually.

You only need to do this if you directly hold unmanaged resources
though. For instance, if you hold a FileStream then it's reasonable to
implement IDisposable to forward on the call to Dispose, but not put in
a finalizer - the finalizer of FileStream should take care of it.

> However, I would not want to rely on other developers actually doing
> this. Microsofts code is probably pretty bullet-proof in these
> regards, but other third-party libraries may not be. In addition to
> that, non-deterministic clean up of unmanaged resources is still
> somewhat "leaky", since the finalizer is always called late and may
> not even be called at all (even though I am sure you know more about
> when this is likely to happen than I do).
> So in general I would still strongly suggest you call Dispose yourself
> when you are done, but I think there is no argument here.

Absolutely :)

Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 4:41:41 AM2/21/08
to
Christopher Ireland <cire...@gmail.com> wrote:
> > I'd consider that a "soft" leak - but if failing to dispose of a Brush
> > *never ever* released its Windows handle, that would count as a "hard"
> > leak in my view.
> >
> > And no, I don't have hard and fast definitions of "soft" leak vs
> > "hard" leak but I hope they make some kind of sense here :)
>
> I think so. A "soft" leak causes inflationary memory consumption during the
> lifetime of the application, whereas a "hard" leak causes an increase in
> memory consumption after the application has been closed, relative the the
> memory consumption before the application was run.
>
> I think we can agree that in a ideal .NET GC context, "hard" leaks never
> occur :-)

It looks like I haven't actually been clear at all :)

1) I'm talking about GDI handles being leaked, not memory
2) The "soft" leak would mean that GDI handles weren't cleaned up
in a timely fashion, relying on the finalizer. If the finalizer
didn't run in time, you could run out of GDI handles.
3) The "hard" leak would mean that the finalizer wouldn't clean up
GDI handles at all: any time you failed to call Dispse(), you would
end up with a "lost" GDI handle which wouldn't be recovered until
the application closed
4) A leak which still exists after the application has been closed
would count as an OS leak, IMO!

KWienhold

unread,
Feb 21, 2008, 4:51:45 AM2/21/08
to
On 21 Feb., 10:38, Jon Skeet [C# MVP] <sk...@pobox.com> wrote:
> You only need to do this if you directly hold unmanaged resources
> though. For instance, if you hold a FileStream then it's reasonable to
> implement IDisposable to forward on the call to Dispose, but not put in
> a finalizer - the finalizer of FileStream should take care of it.
>

Again, that depends on how much you trust the class to do the right
thing ;)
I'd probably still call Dispose on it in my finalizer, if the class
had been designed well odds are that the class would supress its own
finalizer after that, so the overhead should be minimal, if the class
had not been designed well, chances are there wasn't a finalizer in
the first place...
I realize that this is extremly defensive, most of the time your
solution would be cleaner and probably better, especially when you are
dealing with framework classes, but I'm a little paranoid about these
things I guess ;)

Kevin Wienhold

Christopher Ireland

unread,
Feb 21, 2008, 4:53:22 AM2/21/08
to
Jon,

> It looks like I haven't actually been clear at all :)

Je je je ..

> 1) I'm talking about GDI handles being leaked, not memory

Where are GDI handles held?

> 2) The "soft" leak would mean that GDI handles weren't cleaned up
> in a timely fashion, relying on the finalizer. If the finalizer
> didn't run in time, you could run out of GDI handles.

My soft leak would be assuming that all finalizers would be run in a timely
fashion (an *ideal* GC environment) but that not explicitly calling Dispose
would mean that they would be called by later generations (gen3, is it?) of
the GC, giving the appearance of a leak, that is, inflationary memory
consumption during application run.

> 3) The "hard" leak would mean that the finalizer wouldn't clean up
> GDI handles at all: any time you failed to call Dispse(), you would
> end up with a "lost" GDI handle which wouldn't be recovered until
> the application closed

Yes, this is a "hard" leak in my opinion as well. GC simply fails to call
the finalizer in a timely fashion meaning that memory is not released even
after the application has been closed.

> 4) A leak which still exists after the application has been closed
> would count as an OS leak, IMO!

Mmm, IMO, if the GC is responsible for memory allocation during the run of a
.NET application than any memory which hasn't been released after the
application has been closed is responsibility of the GC!

--
Thank you,

Christopher Ireland
http://shunyata-kharg.doesntexist.com

"Why are you unhappy?
Because 99.9 per cent
Of everything you think,
And of everything you do,
Is for yourself -
And there isn't one."
Terence Gray


Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 4:58:17 AM2/21/08
to
KWienhold <hedo...@trashmail.net> wrote:
> On 21 Feb., 10:38, Jon Skeet [C# MVP] <sk...@pobox.com> wrote:
> > You only need to do this if you directly hold unmanaged resources
> > though. For instance, if you hold a FileStream then it's reasonable to
> > implement IDisposable to forward on the call to Dispose, but not put in
> > a finalizer - the finalizer of FileStream should take care of it.
>
> Again, that depends on how much you trust the class to do the right
> thing ;)
> I'd probably still call Dispose on it in my finalizer, if the class
> had been designed well odds are that the class would supress its own
> finalizer after that, so the overhead should be minimal, if the class
> had not been designed well, chances are there wasn't a finalizer in
> the first place...

I believe the guidelines actually say you shouldn't call any methods on
reference types in finalizers, just in case the instance has already
been finalized.

> I realize that this is extremly defensive, most of the time your
> solution would be cleaner and probably better, especially when you are
> dealing with framework classes, but I'm a little paranoid about these
> things I guess ;)

There are pages and pages of guidelines these days. I seem to remember
that Joe Duffy's blog has a pretty recent (2007) set.

Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 5:01:09 AM2/21/08
to
Christopher Ireland <cire...@gmail.com> wrote:
> > It looks like I haven't actually been clear at all :)
>
> Je je je ..
>
> > 1) I'm talking about GDI handles being leaked, not memory
>
> Where are GDI handles held?

I see what you're getting at, but the problem isn't that extra memory
is being taken up: you can run out of handles without running out of
memory.

> > 2) The "soft" leak would mean that GDI handles weren't cleaned up
> > in a timely fashion, relying on the finalizer. If the finalizer
> > didn't run in time, you could run out of GDI handles.
>
> My soft leak would be assuming that all finalizers would be run in a timely
> fashion (an *ideal* GC environment) but that not explicitly calling Dispose
> would mean that they would be called by later generations (gen3, is it?) of
> the GC, giving the appearance of a leak, that is, inflationary memory
> consumption during application run.

Okay, we mostly agree - except that in my view the worse problem is
that you use up handles.

> > 3) The "hard" leak would mean that the finalizer wouldn't clean up
> > GDI handles at all: any time you failed to call Dispse(), you would
> > end up with a "lost" GDI handle which wouldn't be recovered until
> > the application closed
>
> Yes, this is a "hard" leak in my opinion as well. GC simply fails to call
> the finalizer in a timely fashion meaning that memory is not released even
> after the application has been closed.

After the application has been closed it's up to the OS to clean things
up, not the GC.

But in the scenario I was considering, the GC had called the finalizer
but the finalizer had failed to free the GDI handle.

> > 4) A leak which still exists after the application has been closed
> > would count as an OS leak, IMO!
>
> Mmm, IMO, if the GC is responsible for memory allocation during the run of a
> .NET application than any memory which hasn't been released after the
> application has been closed is responsibility of the GC!

No - the GC isn't even *running* after the application has been closed.
The GC is part of the application.

KWienhold

unread,
Feb 21, 2008, 5:10:02 AM2/21/08
to
On 21 Feb., 10:58, Jon Skeet [C# MVP] <sk...@pobox.com> wrote:
> I believe the guidelines actually say you shouldn't call any methods on
> reference types in finalizers, just in case the instance has already
> been finalized.

Hmm.. That's a valid point of course, so I guess not calling Dispose
on everything in your finalizer is the better solution, since the
chance of actually having a class that holds onto an unmanaged
resource but doesn't have a finalizer are rather slim.
For some reason I never really thought about this, I may just have
some bugs waiting to happen there...

> There are pages and pages of guidelines these days. I seem to remember
> that Joe Duffy's blog has a pretty recent (2007) set.

Thanks for the pointer, I'll look it up :)

Kevin Wienhold

Christopher Ireland

unread,
Feb 21, 2008, 5:16:19 AM2/21/08
to
Jon,

> Okay, we mostly agree - except that in my view the worse problem is
> that you use up handles.

It is interesting that you should say that. I hadn't appreciated that there
was a finite set of GDI handles. Would you be so kind as to send me a link
to something I can read about this? It is very relevant to the area in which
I work.

> After the application has been closed it's up to the OS to clean
> things up, not the GC.
>
> But in the scenario I was considering, the GC had called the finalizer
> but the finalizer had failed to free the GDI handle.

Yes, I see. One scenario would be a defect in the finalizer code, and the
other would be a defect in the GC code that calls the finalizer.

> No - the GC isn't even *running* after the application has been
> closed. The GC is part of the application.

I guess this is the greyest area for me. Say there was a defect in the GC,
either one of the two scenarios described above, in that the GC wasn't
releasing memory. From what I understand of what you've written, you seem to
be suggesting that even in this case it is the responsibility of the OS to
recuperate the memory once the application has closed.

This goes against what I've understood of memory allocation working in
environments which don't have managed memory capabilities. I believe I've
seen cases where applications use up a chunk of memory making it unavailable
to the OS; the memory use after running the application was greater than the
memory use before running the application. In these cases, therefore, it
seemed to me that the OS was not responsible and was even incapable of
recuperating such memory and it was the responsibility of the programmer of
the application to make sure such things didn't happen.

Thank you for helping me deepen my understanding on this subject!

--
Thank you,

Christopher Ireland
http://shunyata-kharg.doesntexist.com

"When I was 10, my pa told me never to talk to strangers. We haven't spoken
since."
Steven Wright


Jon Skeet [C# MVP]

unread,
Feb 21, 2008, 5:26:24 AM2/21/08
to
Christopher Ireland <cire...@gmail.com> wrote:
> > Okay, we mostly agree - except that in my view the worse problem is
> > that you use up handles.
>
> It is interesting that you should say that. I hadn't appreciated that there
> was a finite set of GDI handles. Would you be so kind as to send me a link
> to something I can read about this? It is very relevant to the area in which
> I work.

http://msdn2.microsoft.com/en-us/library/ms724291(VS.85).aspx
has some detail. I'm afraid I don't know much about it really - just
that it's a potential issue.

> > After the application has been closed it's up to the OS to clean
> > things up, not the GC.
> >
> > But in the scenario I was considering, the GC had called the finalizer
> > but the finalizer had failed to free the GDI handle.
>
> Yes, I see. One scenario would be a defect in the finalizer code, and the
> other would be a defect in the GC code that calls the finalizer.

Exactly.

> > No - the GC isn't even *running* after the application has been
> > closed. The GC is part of the application.
>
> I guess this is the greyest area for me. Say there was a defect in the GC,
> either one of the two scenarios described above, in that the GC wasn't
> releasing memory. From what I understand of what you've written, you seem to
> be suggesting that even in this case it is the responsibility of the OS to
> recuperate the memory once the application has closed.

Absolutely. The OS shouldn't allow a process which has been killed to
still take up memory.

> This goes against what I've understood of memory allocation working in
> environments which don't have managed memory capabilities. I believe I've
> seen cases where applications use up a chunk of memory making it unavailable
> to the OS; the memory use after running the application was greater than the
> memory use before running the application. In these cases, therefore, it
> seemed to me that the OS was not responsible and was even incapable of
> recuperating such memory and it was the responsibility of the programmer of
> the application to make sure such things didn't happen.

The OS is responsible for memory allocation to individual processes,
and for noticing when processes die etc - and releasing appropriate
resources. To take a non-memory example, if an application (managed or
otherwise) has a file open and locked, but then the application dies,
the file handle should be released by the OS, and the file unlocked.

> Thank you for helping me deepen my understanding on this subject!

I'm just sorry I can't give more links about this.

Christopher Ireland

unread,
Feb 21, 2008, 5:39:25 AM2/21/08
to
Jon,

> http://msdn2.microsoft.com/en-us/library/ms724291(VS.85).aspx
> has some detail. I'm afraid I don't know much about it really - just
> that it's a potential issue.

Thanks for the link, Jon! I didn't know that.

> The OS is responsible for memory allocation to individual processes,
> and for noticing when processes die etc - and releasing appropriate
> resources. To take a non-memory example, if an application (managed or
> otherwise) has a file open and locked, but then the application dies,
> the file handle should be released by the OS, and the file unlocked.

I see. I had thought it was the responsibility of the programmer (in
non-managed memory environments) or the GC (in .NET) to make sure all memory
and resources used by the application were released before the application
closed. Glad to hear I can now blame the OS ;-)

> I'm just sorry I can't give more links about this.

This is the problem. If more accurate information about this area was
available I'm pretty sure I wouldn't need to use up kind people's time, such
as yours, asking them to help me clarify it!

--
Thank you,

Christopher Ireland
http://shunyata-kharg.doesntexist.com

"The only good is knowledge and the only evil is ignorance."
Socrates


0 new messages