Is C++/CLI gaining any traction???

S

Shawn B.

I do not agree with you on MSFT's own confidence in organic .Net
growth. Look at Richard's analysis here:

http://www.grimes.demon.co.uk/dotnet/vistaAndDotnet.htm

You will note that MSFT has in fact removed number of services that
depend upon .Net in newer version of Vista. .Net is now relatively
matured and you would expect MSFT to be sort of the leader in accepting
it. IMO, that has not been the case.

Okay, after re-reading it. I don't know. Everyone takes one aspect of a
situation and doomday-speaks it. I don't believe MS is having problems
believing in .NET. Just read every single microsoft programmers blog and it
seems every employee has nothing but passion and faith for .NET. There
could well be far too many other issues involved than just whether something
is .NET or not. That's just an aspect and I don't believe it is
representative.

However, on their current WinFS homepage, they are pretty clear that the
newer API's will be .NET based. Not just there, but all over the Microsoft
developer blogs they are constantly talking about it. I think they released
they need to increment their way to change rather than do it all at once. I
agree. That's why Office hasn't been completely rewritten.

Anyway, Delphi programmers and C++ programmer have a major hesitation to
migrate to .NET and their arguments are two-fold: 1) .NET doesn't perform as
well as native code and 2) Microsoft hasn't rewritten any of their
applications to use .NET so they must not believe in it. I don't think
either of which are good enough reasons to avoid it. .NET performs very
well for our high-volume applications that get millions of transactions per
day. And while they haven't rewritten any of their major revenue-generating
products in .NET (why should they, they've millions invested in bug fixes
stability and enhancements already) it doesn't mean we shouldn't. Like I
said, shrinkwrap software may not be written in .NET but many internal and
server-type applications are already being done in .NET or will be soon.

Some people just want excuses and will use any they can to support their
bias. Me? I think .NET is quite capable of supporting about 90% of all the
applications that would need to be created... for numerical-heavy crunching
use a better tool, FORTRAN or C++, for everything else, C# is sufficient.
CPU clock-cycle performance isn't a necessary argument when the applications
spends 98% of its time waiting for the user to click or type, or when the
bottle neck is the network/sql server load combo.


Thanks,
Shawn
 
J

Jerry Coffin

[ ... ]
Anyway, Delphi programmers and C++ programmer have a major hesitation to
migrate to .NET and their arguments are two-fold: 1) .NET doesn't perform as
well as native code and 2) Microsoft hasn't rewritten any of their
applications to use .NET so they must not believe in it. I don't think
either of which are good enough reasons to avoid it.

That depends. Just for a quick example, I recently did a
quick test re-compiling some code to run as C++/CLI. This
particular piece of code just does number crunching on
some big matrices, so it didn't take much to make it
compile.

The result is basically disastrous. In C++, the code is
slow enough to be mildly annoying. The number crunching
normally takes anywhere from a few seconds up to around
15 or 20 minutes. Much more than that, and you run out of
memory (at least on a 32-bit OS).

Under the CLR, a fairly small dataset that takes a couple
of minutes to process with native code ran for a couple
of hours before I gave up and killed it -- I have no idea
how long it would have taken to actually finish. Just for
run, I once converted (an older version of) the code to
Java, and while the performance dropped, it wasn't nearly
this bad -- performance dropped by something like 7:1 or
so, but this was more like 30:1 (and maybe worse).
.NET performs very
well for our high-volume applications that get millions of transactions per
day.

The minute somebody starts talking about transactions per
day, it's virtually a certainty that you're dealing with
an I/O bound application. Talking about language
performance in I/O bound applications is basically
meaningless.
Some people just want excuses and will use any they can to support their
bias. Me? I think .NET is quite capable of supporting about 90% of all the
applications that would need to be created... for numerical-heavy crunching
use a better tool, FORTRAN or C++, for everything else, C# is sufficient.
CPU clock-cycle performance isn't a necessary argument when the applications
spends 98% of its time waiting for the user to click or type, or when the
bottle neck is the network/sql server load combo.

So, basically, your argument is that C# can provide good
enough performance, at least for situations where
performance just doesn't matter (at all).

I'm always left with a question though: given that C++ is
already known, and even according to the C# advocates
provides substantially superior performance, what real
advantage does C# provide to make up for its obvious
shortcomings?

MS's tools have deteriorated so development (at least for
desktop apps) is clearly slower and clumsier. All of the
..NET stuff strikes me as being a lot like the VB used to
be, where everything tried to be forms based, whether it
made any sense or not, so at least without a lot of extra
work, everything ends up looking cookie-cutter generic.
The runtime performance isn't exactly something you can
get excited about.

I'm may be a little to young (and the wrong gender) to
play the part to perfection, but "Where's the meat?"
 
T

Tom Serface

Hi Ajay,

Most of this is hearsay, but from what I understand they actually went back
to Longhorn and removed a lot of the .NET they were trying to use because
they were having performance problems. So, from what I understand much of
Vista, and Office 12 for that matter, is still unmanaged code. I believe in
the effort to make software more trustworthy, but it seems that we are all
not so eager to do it at the cost of performance or size. I think that
curve may change over time.

Tom
 
E

Edward Diener

Don said:
I can only conclude a few things: 1) C++/CLI came too late. This should
have been the first language to come out, instead of the horrendous
managed C++.

Microsoft destroyed Managed C++ with the DLL Initialization bug. It just
happened to occur ( hardy har har ) and give C# and VB .NET a four year
head start in .NET programming. Given that head start, what do you
suppose would happen to companies when it came to moving their C++ apps
to .NET ? And please do not tell me that MS did not have a strong
interest in promoting C# over C++.
 
T

Tim Roberts

Ajay Kalra said:
I do not agree with you on MSFT's own confidence in organic .Net
growth. Look at Richard's analysis here:

http://www.grimes.demon.co.uk/dotnet/vistaAndDotnet.htm

You will note that MSFT has in fact removed number of services that
depend upon .Net in newer version of Vista. .Net is now relatively
matured and you would expect MSFT to be sort of the leader in accepting
it. IMO, that has not been the case.

On the other hand, the Media Center app in Windows Media Center Edition is
all written in .NET. It's not my favorite Microsoft application, but it is
evidence that a .NET front-end with a clever back-end can do some pretty
neat things.
 
D

David Lowndes

On the other hand, the Media Center app in Windows Media Center Edition is
all written in .NET. It's not my favorite Microsoft application, but it is
evidence that a .NET front-end with a clever back-end can do some pretty
neat things.

And be just as buggy as any other program ;)

Dave
 
E

Edward Diener

Edward said:
Microsoft destroyed Managed C++ with the DLL Initialization bug.

I should have said the Loader Lock bug, as that is its more popular name.
 
W

Willy Denoyette [MVP]

|> I've run hundreds of benchmarks comparing both C#, C++/CLI, differences
| > obtained between different runs of the benchmarks are neglectable.
|
| I've created a real application in both C# and the same in C++/CLI and the
| difference was staggering (a CPU emulator for an Apple2 emulator targeting
| .NET -- not a business application or service). It was identicle code,
not
| different in architecture or design. So there we are. So your benchmarks
| don't reveal any real benefits, but my real application that I'm doing
| something with and have vested over a year in building, actually shows
| interesting results. You written a CPU emulator? In my design, there are
| hundreds of functions that emulate a CPU instruction. These functions get
| called 9 million times per second on an unthrottled emulation (using
| C++/CLI). Using C#, and almost identical translation of the code,
comipled
| in C#, gives me 4 million iterations per socond. Big difference.
Clearly,
| the C++/CLI compiler is doing something that the C# compiler is not.
|

You keep refering to the one and only application, and based on that you
claim that C++/CLI is much faster than C# (twice as fast!) while this
http://www.grimes.demon.co.uk/dotnet/man_unman.htm proves it's not the case,
but I guess this isn't of any value for you.
I can't comment on what you have done without seeing any code, you might be
calling into native code or using unsafe constructs (bypassing security
walks) which is what IJW does, while in C# this isn't true by default. If
you want to compare both you need to turn of Securty checks in C# as well,
or you need to compile your stuff using /clr:safe , if this isn't possible
because the compiler complains about mixed mode stuff, then we are not
talking about the same thing really.

I have run several benchmarks (hundreds), just like many others, and all I
can say is that the differences are minimal, sometimes C# wins and sometime
C++/CLI wins, sometimes C# produces better IL sometimes C++ does, but the
differences at run-time are minimal (+- 5%), that's all. Do you think that
the C# team isn't able to emit the same optimized IL as the C++/CLI
front-end, do you really believe both teams are competitors? Would they
build the Framework (and Most of WinFX(WPF and WCF..) using C# if C++/CLI
was that better performing?

| Anyway, I refer you to the April 2005 edition of MSDN magazine where
Stephen
| Toub discusses some of the improvements in the Visual C++ 2005 compiler
| http://msdn.microsoft.com/msdnmag/issues/04/05/VisualC2005/ .
|

This guy is a Technical Editor for MSDN Magazine, his job is to 'spread the
message' and promote MSFT products, and he did a great job. But sorry, I
don't believe everything I read, especially when it's possible to verify
what there is written.


| I quote an important paragraph (the last paragraph in the optimizations
| section):
|
| ---------
|
| In an important change for developers using .NET, the Visual C++ 2005
| optimizer performs most of the same optimizations when targeting MSIL as
it
| does when targeting the native platform, though it does so with different
| tuning. While the just-in-time (JIT) compiler today analyzes for
| optimizations at run time, allowing the C++ compiler to optimize during
the
| initial compilation can still provide significant performance benefits
(the
| C++ compiler has much more time to perform its analysis than does the
JIT).
| The Visual C++ 2005 compiler optimizes managed types for the first time,
| performing loop optimizations, expression optimizations, and inlining.
There
| are places, though, where the compiler can't optimize .NET-based code. For
| example, it has problems with strength reduction due to the
unverifiability
| of pointer arithmetic, and certain code can't be inlined due to the strict
| type and member accessibility requirements of the CLR, though it does do
| significant analysis for legal inlining opportunities. In addition,
| optimizing MSIL introduces the need to make trade-offs concerning what is
| presented to the JIT compiler. For example, you wouldn't want to unroll a
| loop and expose a plethora of variables to the JIT compiler, whereupon it
| would have to perform register allocation (an NP-complete problem). The
| Visual C++ team is working through these issues and will have a very
| well-tuned optimizing solution by the time the system is released.
|
| --------
|
|
| This directly contradicts what you've been saying.
|

Realy? Are you basing your findings on a piece written by a technical
editor, not a member of the C++ team, before the product was even released?
(note the final sentence - well-tuned optimizing solution by the time the
system is released), more, that same article mixes C++/ISO and C++/CLI
stuff, like you did when you talked about PGO which is a native code thingy
( and btw. not very valuable either).
Other sources at MSFT, (contradicting the story in MSDN Magazine), have
clearly stated that the front end of C++/CLI which simply emits IL isn't a
target for agressive optimization which may hurt the correct functioning of
the JIT compiler. And the front end doesn't do any inlining at all, why?
well he can't, if you know what inlining is all about you will understand
why it's not possible at that level in a managed world, you can't inline IL,
point. Note that the article doesn't mention any figures reflecting the
advantages because of the optimizations included in the product, you know
why?

Willy.
 
W

Willy Denoyette [MVP]

| >I do not agree with you on MSFT's own confidence in organic .Net
| > growth. Look at Richard's analysis here:
| >
| > http://www.grimes.demon.co.uk/dotnet/vistaAndDotnet.htm
| >
| > You will note that MSFT has in fact removed number of services that
| > depend upon .Net in newer version of Vista. .Net is now relatively
| > matured and you would expect MSFT to be sort of the leader in accepting
| > it. IMO, that has not been the case.
| >
| This Grimes article refers to information at was current during PDC03, as
| those make up 95% of his references.


Not true, read the article, his findings reflect several builds including
the latest CTP Feb 2006 build 5308.
What Richard is trying to say is that NetFX is just a managed API in top of
unmanaged code, nothing more. He did expect Vista to contain more managed
code at the core, which is not the case, actually Vista does not contain any
managed applications, you can even run Vista without the framework
installed. All there is are some administrative applications (the event
viewer, and the performance monitor) that are build using WinFX WPF. But
that's only a facade, the underlying code is still managed (and n case of
perfmon, it's still the sme COM server code as on XP). All other stuff is
unmanaged, not using the framework at all and that's what Richard is ranting
about.

Willy.
 
S

Shawn B.

Realy? Are you basing your findings on a piece written by a technical
editor, not a member of the C++ team, before the product was even
released?
(note the final sentence - well-tuned optimizing solution by the time the
system is released), more, that same article mixes C++/ISO and C++/CLI
stuff, like you did when you talked about PGO which is a native code
thingy
( and btw. not very valuable either).
Other sources at MSFT, (contradicting the story in MSDN Magazine), have
clearly stated that the front end of C++/CLI which simply emits IL isn't a
target for agressive optimization which may hurt the correct functioning
of
the JIT compiler. And the front end doesn't do any inlining at all, why?
well he can't, if you know what inlining is all about you will understand
why it's not possible at that level in a managed world, you can't inline
IL,
point. Note that the article doesn't mention any figures reflecting the
advantages because of the optimizations included in the product, you know
why?

Every body is quoting a source. Everybody is contradicting everybody.
Personally, I don't care what people say. I received a major performance
boost by moving to C++/CLI in a particular piece of software. I didn't say
anyway that would hold true everywhere, just in this case it does. Despite
your findings, I've received the improvements in performance. That's what I
know.

And yes, you can inline IL. Even the Delphi.NET compiler does. There's
always a restriction but I don't care to argue.

The point is your tests prove your right. My real world applications proves
its possible that the C++/CLI compiler can produce a better app.


Done,
Shawn
 
D

Don Kim

Shawn said:
Here's he clearly spells out the the VC++ compiler for .NET does a lot of
work in optimzations that the JIT is incapable of. Just another article
spelling out that the C++ compiler doesn't just emit IL and that's it.

Yeah, in the article he flatly claims the following:

"In Visual Studio 2005, the C++ compiler team went to great lengths to
make sure that all of the expertise gained from years of optimizing
native code was applied to managed code optimization. C++ gives you the
flexibility to do fine tuning such as high-performance marshaling that
is not possible with other languages. Moreover, the Visual C++ compiler
generates the best optimized MSIL of any of the .NET languages. The
result is that the best optimized code in .NET comes from the Visual C++
compiler."

Now, this being established, I wish more promotion would be done to make
companies out there knnow about this, so we're not stuck programming all
..Net with C#/VB.NET only.

-Don Kim
 
S

Stephen Howe

My real world applications proves its possible that the C++/CLI compiler
can produce a better app.

No it does not. I have seen 100's of rigged benchmarks over the years that
"prove" one langauge is faster than another. For all we know, you may have
ineptly chosen your C# compiler switches and so reached a false conclusion
by not comparing like-with-like.

Stephen Howe
 
W

Willy Denoyette [MVP]

| We all know who Kang Su Gatlin is, right?
|
| http://msdn.microsoft.com/msdnmag/issues/05/01/COptimizations/
|
|
| Here's he clearly spells out the the VC++ compiler for .NET does a lot of
| work in optimzations that the JIT is incapable of. Just another article
| spelling out that the C++ compiler doesn't just emit IL and that's it.
|
|
| Thanks,
| Shawn
|
|

Yes I do, and he is the source of the stuff that's been written by Stephen
Toub in MSDN mag two years ago. The most hilarious part in his story is the
"Whole Program Optimization" chapter, where he gives a sample of what WPO
can do with respect to inlining and constant propagation... but here is the
exact same sample that proves it's not done, but again, that's the danger of
talking about features before they ever get implemented.

// file sub.cpp
// Compile with: cl /LD /clr:safe /O2 sub.cpp
public ref class C
{
public:
int Square(int x)
{
return x*x;
}
};

// File: main.cpp
// Compile with: cl /clr:safe /O2 main.cpp
//
#using <sub.dll>
int main()
{
C^ c = gcnew C;
c->Square(42);
}

And here is the IL ...
// ILDASM output (partly)
....
..maxstack 2
IL_0000: newobj instance void ['sub']C::.ctor()
IL_0005: ldc.i4.s 42
IL_0007: call instance int32 ['sub']C::Square(int32)
IL_000c: pop
IL_000d: ldc.i4.0
IL_000e: ret
....

where do you see the constant propagation, or the inlining? ...Nowhere, but
rest assured the JIT will take care of this optimization (the constant
proagation and inlining).

I also know his team leader, and his story is somewhat different (sorry
can't tell you anything more because of NDA restriction), it's true they
have done a great job at this level in C++/CLI compared to MC++, but now
they are on par with what C# delivers, or do you think that developers on
the C# or VB team couldn't optimize the IL, provided it was possible? Don't
you think they didn't optimize aggressively and found out that the result
was a performance degradation because they interfered with the JIT.

All this stuff is nothing more than product promotion, something they needed
after the disaster called MC++? But it's strange that now the product is
rleased

Willy.
 
S

Shawn B.

My real world applications proves its possible that the C++/CLI compiler
can produce a better app.

No it does not. I have seen 100's of rigged benchmarks over the years that
"prove" one langauge is faster than another. For all we know, you may have
ineptly chosen your C# compiler switches and so reached a false conclusion
by not comparing like-with-like.

I know far more about how to configure the various switches for C# than I do
the C++ compiler. That said, I'm not an advanced C++ user and I got great
results. Who said anything about "rigging"? I needed more performance,
switched to C++/CLI, and achieved it relatively effortlessly. Everybody
keeps nagging me about various security checks in C#. Everything is
unchecked because the way my virtual CPU is programmed it can either
guarantee there will be no overflows or will check and handle them
appropriately, among many other things.

Just because you guys haven't got the same results doesn't mean I can't. I
don't know what kinds of stuff you benchmark with, but I'm not benchmarking.
I have a simple program that runs in a loop million of times persecond and
makes about 12 function call or more in each loop to do its processing, not
to mentiond the processing overhead of the virtual devices (display,
keyboard, mouse, storage).

What I am saying, is that, I'm not basing my statements on what I read. I'm
basing my statements on my experience. I have not benchmarked anything (for
the sake of doing so), I have not testing numerical crunching (wouldn't know
how to, I have no need), and have not obsorbed what everyone else is saying
as gospel. I rewrote some code in C++/CLI that looks nearly identicle
semantically with its C# predecessor and received major performance boost.
Could be that the overhead of all my function calls are to blame, could be
other things, who knows? When I run in debug mode I get the same if not
worse performance than the C# build. When I run in Release mode with some
C++/CLI compiler settings (that C# doesn't have) I get great performance
boost. Rigged or not, No matter what I do in C# I cannot get similar
performance characteristics.

I'm not really out to "prove" anything, unlike all the MVP's in this forum.
You guys experienced contrary to me, so I must be wrong. Whatever. Grow
up. Learn that there's more to the world than your limited experience and
views. I'm simply saying that things are possible outside of your
experience and limited knowledge of things.

I guess I don't care because now I have the same performance characteristics
I was hoping for and in the end, that's good enough for me, and whether you
believe it or not I don't give a d**n because it isn't your project and your
hobby and your passion. Seems your passion is to live in your box and never
accept other ideas or possibilities. Mine is exploring and growing and
improving my skills and knowledge and learning the best tool for the job.


Thanks,
Shawn
 
A

Andre Kaufmann

Willy said:
#using <sub.dll>

What is this line for ? Do you really expect other IL code to be inlined
by the C++/CLI compiler ? This compilation/inlining is part of the
..NET runtime, why should this be optimized by the C++/CLI compiler ?
Nobody wrote that global optimization should work over other languages /
external DLL's too.
int main()
{
C^ c = gcnew C;
c->Square(42);
}

And here is the IL ...
// ILDASM output (partly)
...
.maxstack 2
IL_0000: newobj instance void ['sub']C::.ctor()
IL_0005: ldc.i4.s 42
IL_0007: call instance int32 ['sub']C::Square(int32)
IL_000c: pop
IL_000d: ldc.i4.0
IL_000e: ret
...

And here is mine:

..method assembly static int32 main(string[] args) cil managed
{
// Code size 12 (0xc)
.maxstack 1
IL_0000: ldc.i4 0x6e4
IL_0005: call void [mscorlib]System.Console::WriteLine(int32)
IL_000a: ldc.i4.0
IL_000b: ret
} // end of method 'Global Functions'::main
where do you see the constant propagation, or the inlining? ...Nowhere, but
rest assured the JIT will take care of this optimization (the constant
proagation and inlining).

I see it. But not in your example.
All this stuff is nothing more than product promotion, something they needed
[...]


And what is your stuff ?

Andre
 
A

Andre Kaufmann

Willy said:
"Shawn B." <[email protected]> wrote in message
[...]
However, when calling from managed into a unmanaged accross DLL boundaries ,
the performance of C# PInvoke is better than the C++ interop, the reason for
this is that C++ interop calls GetLastWin32Error after each call, this

I cannot reproduce this behavior ?! Event if that would be >generally<
true, which I cannot reproduce, the overhead would be accessing a DWORD
value, eventually testing it. This is all what's GetLastError() is
about. IMHO you don't have to call the function. At least Microsoft
shouldn't have to. I think this overhead could be neglected, compared to
the marshaling and other code.
behavior cannot be switched off, while in PInvoke interop you can set a flag
(SetLastErrorCode=false) to turn this off.

Willy.

Andre
 
W

Willy Denoyette [MVP]

| Willy Denoyette [MVP] wrote:
|
| >
| > #using <sub.dll>
|
| What is this line for ?

used to refer to the assembly containing the metadata of the class C, but I
guess you know that.

Do you really expect other IL code to be inlined
| by the C++/CLI compiler ? This compilation/inlining is part of the
| .NET runtime, why should this be optimized by the C++/CLI compiler ?
| Nobody wrote that global optimization should work over other languages /
| external DLL's too.
|

No, I know that they can't inline (existing) IL, and that's exactly my point
and what I tried to prove, but OK, I have two separate assemblies (a DLL and
an EXE) which is somewhat misleading.

Now, I guess your sourcecode files looks like this (please correct me when
I'm wrong):

public ref class C
{
public:
int Square(int x)
{
return x*x;
}
};


#include "sub.h"
int main()
{
C^ c = gcnew C;

int r = c->Square(42);
System::Console::WriteLine(r);
}

and you compiled it like:
cl /clr:safe /O2 main.cpp


It's true the call will be inlined, but this is one compiland (a sinle
source file) and is not what the article suggest [1]. The header file is
included in the one and only source file and then compiled, right?

< [1] article snip...
The compiler can now perform analysis and optimization across multiple
source files. Without WPO, for example, the compiler can only inline
functions within a single compiland. With WPO, the compiler can inline
functions from any source file in the program.>

now if you make it two compilands (two source files).

// file sub.h, common header
public ref class C
{
public:
int Square(int x);
};

// file sub.h
#include "sub.h"
int C::Square(int x)
{
return x*x;
}

// file main.cpp
#include "sub.h"
int main()
{
C^ c = gcnew C;
int r = c->Square(42);
System::Console::WriteLine(r);
}

And compile its using:

cl /c /clr:safe /O2 sub.cpp
cl /clr:safe /O2 main.cpp sub.obj

and here is the resulting IL:

..method assembly static int32 main() cil managed
{
..entrypoint
// Code size 19 (0x13)
..maxstack 2
IL_0000: newobj instance void C::.ctor()
IL_0005: ldc.i4.s 42
IL_0007: call instance int32 C::Square(int32)
IL_000c: call void [mscorlib]System.Console::WriteLine(int32)
IL_0011: ldc.i4.0
IL_0012: ret
} // end of method 'Global Functions'::main

You see no inlining any more.

If you have other options, that would inline accross source files, I would
be happy to hear how.


Willy.
 
S

Shawn B.

#using said:
What is this line for ? Do you really expect other IL code to be inlined
by the C++/CLI compiler ? This compilation/inlining is part of the .NET
runtime, why should this be optimized by the C++/CLI compiler ?
Nobody wrote that global optimization should work over other languages /
external DLL's too.

I think you're pulling things out of your arse to make an argument. You're
own lack of understanding is causing you to "think" things up and base
you're whole argument on that. It does not inline methods in external
assemblies. It inlines source code that it can see in the *same project*
with some restrictions.

But I thought you would know that, since you're so certain, that despite
what many publications, blogs, and info an MSDN say, the C++/CLI compiler
does not optimize or inline. I don't know what kind of "test" and
"benchmarking" you've done, but you certainly haven't done any that resemble
the application I'm working on.


Thanks,
Shawn
 
S

Shawn B.

Let me just bow down to you. You're right and everyone else is wrong.
Clearly, my performance hasn't nearly doubled by rewriting it in C++/CLI
(similar code symantics, different syntax), I'm just imaging it. Clearly,
everyone that writes on the topic is wrong. Clearly, the C++/CLI compiler
doesn't do any optimzation, despite what MSDN says and quite a few others
who have tested and publicly documented their very interesting findings.

<bows to almighty Willy>


I'm just not worthy.



With Respectful Servitude,
Shawn
 

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