<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>Articles</title><link>http://www.agileprogrammer.com/dotnetguy/category/88.aspx</link><description>Articles</description><managingEditor>Brad Wilson</managingEditor><dc:language>en-US</dc:language><generator>.Text Version 0.95.2005.109</generator><item><dc:creator>Brad Wilson</dc:creator><title>Retiring dotnetdevs.com</title><link>http://www.agileprogrammer.com/dotnetguy/archive/2007/06/06/22853.aspx</link><pubDate>Wed, 06 Jun 2007 09:08:00 GMT</pubDate><guid>http://www.agileprogrammer.com/dotnetguy/archive/2007/06/06/22853.aspx</guid><description>&lt;p&gt;I'm going to be retiring dotnetdevs.com, which hasn't really had any attention paid to it since I moved to Microsoft more than 2 years ago. As such, I moved some of my articles over onto my blog's &lt;a href="http://www.agileprogrammer.com/dotnetguy/category/84.aspx"&gt;Technical Articles&lt;/a&gt; area, including:&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.agileprogrammer.com/dotnetguy/articles/IntroToHandlers.aspx"&gt;Introduction to ASP.NET Handlers&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.agileprogrammer.com/dotnetguy/articles/AttributeBasedUrlDispatch.aspx"&gt;Attribute-Based URL Dispatching in ASP.NET&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.agileprogrammer.com/dotnetguy/articles/ReflectionDemystified.aspx"&gt;Reflection Demystified&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.agileprogrammer.com/dotnetguy/articles/ReflectionVisitor.aspx"&gt;Using Reflection for the Visitor Pattern&lt;/a&gt;&lt;/p&gt;&lt;img src ="http://www.agileprogrammer.com/dotnetguy/aggbug/22853.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>Brad Wilson</dc:creator><title>How I Prevent Spam</title><link>http://www.agileprogrammer.com/dotnetguy/archive/2002/03/23/4488.aspx</link><pubDate>Sat, 23 Mar 2002 12:03:00 GMT</pubDate><guid>http://www.agileprogrammer.com/dotnetguy/archive/2002/03/23/4488.aspx</guid><description>&lt;p&gt;Every once in a while, someone will ask about ways to prevent
spam. I've found a pretty good system that I'd like to share.&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Sign up with &lt;a href='http://www.pobox.com/' target='_blank'&gt;pobox&lt;/a&gt;. This service will cost you about $15/year, and
by itself provides a fairly useful spam-filtering system. The real
benefit of the system is that you get a permanent e-mail address
even though you might change ISPs, but has other benefits for our
anti-spam system.&lt;br/&gt;
 &lt;/li&gt;
&lt;li&gt;Sign up for two aliases on your pobox. It doesn't matter that
they're going to a single mailbox on the other end, because we'll
use the addresses as a filtering system. For the purposes of
demonstration, I'll say that my two aliases are "sendmespam" and
"justforfriends".&lt;br/&gt;
 &lt;/li&gt;
&lt;li&gt;You absolutely need an intelligent mailer, or else this system
will drive you crazy. I use and highly recommend &lt;a href='http://www.ritlabs.com/the_bat/' target='_blank'&gt;The Bat!&lt;/a&gt;.
Outlook and Outlook Express just aren't going to cut it here.&lt;br/&gt;
 &lt;/li&gt;
&lt;li&gt;Sign up for all mailing lists using your "sendmespam" e-mail
address. Similarly, if you post to Usenet, use the "sendmespam"
e-mail address.&lt;br/&gt;
 &lt;/li&gt;
&lt;li&gt;Add sorting filters in your mail program for all your mailing
lists. The absolute best way to accomplish this is to look for some
invariant value in the kludges (headers) of the e-mail that's sent
to you. This is far more fool-proof than using the subject tag or
the To/Cc addresses. For instance, here's a few headers of an
example e-mail:&lt;/li&gt;
&lt;/ul&gt;&lt;blockquote dir='ltr' class='c1'&gt;
&lt;blockquote dir='ltr' class='c1'&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Delivered-To: sendmespam@pobox.moc&lt;/strong&gt;&lt;br/&gt;
To: Off Topic Windows
&amp;lt;win_tech_off_topic@yahoogroups.moc&amp;gt;&lt;br/&gt;
From: Brad Wilson &amp;lt;sendmespam@pobox.moc&amp;gt;&lt;br/&gt;
&lt;strong&gt;Mailing-List: list
win_tech_off_topic@yahoogroups.moc;&lt;br/&gt;
      contact
win_tech_off_topic-owner@yahoogroups.moc&lt;/strong&gt;&lt;br/&gt;
Date: Fri, 22 Mar 2002 16:59:43 -0700&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;&lt;ul&gt;
&lt;li dir='ltr'&gt;You can see by the headers above a couple of
interesting things (I bolded them to highlight them). The one we're
interested in right now is the "Mailing-List:" header that Yahoo
adds. You can see there are some good invariant things in there we
can sort on. A couple good choices would be like
"win_tech_off_topic-owner@yahoogroups.moc" or even "list
win_tech_off_topic@yahoogroups.moc". Using either one of these will
guarantee your messages land in the right folders when being
sorted. Do this for all your mailing lists.&lt;br/&gt;
 &lt;/li&gt;
&lt;li dir='ltr'&gt;Now what you're left with is trying to figure out
which non-mailing-list e-mails are valid, and which aren't. The
obvious next rule is that any e-mail to "justforfriends" must be
valid, because I only give that out to my most trusted friends.
Pobox was nice enough to tack that "Delivered-To:" header on all
the e-mail addresses, so you know exactly which address it came to,
even if someone has included your in their BCC list. Very
helpful!&lt;br/&gt;
 &lt;/li&gt;
&lt;li dir='ltr'&gt;Finally, you have the "sendmespam" e-mails that
aren't apparently to one of your mailing lists. What I've done is
set up an automatic rule that sends people who send email to my
"sendmespam" e-mail address an e-mail that informs them that they
sent e-mail to an address I don't monitor. It looks like this:&lt;/li&gt;
&lt;/ul&gt;&lt;blockquote dir='ltr' class='c1'&gt;
&lt;blockquote dir='ltr' class='c1'&gt;
&lt;p dir='ltr' class='c2'&gt;&lt;em&gt;You have sent e-mail to an address that
does not accept e-mail. This address is used solely for posting to
mailing lists and newsgroups. This unfortunate situation is brought
about because of excessive spam.&lt;/em&gt;&lt;/p&gt;
&lt;p dir='ltr' class='c2'&gt;&lt;em&gt;Please follow this web link and send me
e-mail via the web:&lt;/em&gt;&lt;/p&gt;
&lt;p dir='ltr' class='c2'&gt;&lt;em&gt;   &lt;/em&gt; &lt;a href='http://www.agileprogrammer.com/dotnetguy/contact.aspx'&gt;&lt;em&gt;http://www.techieswithcats.com/contact.shtml&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p dir='ltr' class='c2'&gt;&lt;em&gt;I will respond to you as quickly as
possible.&lt;/em&gt;&lt;/p&gt;
&lt;p dir='ltr' class='c2'&gt;&lt;em&gt;I sincerely apologize for the
inconvenience, and wish that such a lame thing weren't necessary
for my own "e-mail sanity".&lt;/em&gt;&lt;/p&gt;
&lt;p dir='ltr' class='c2'&gt;&lt;em&gt;PLEASE NOTE: If this mail is a mass
mailing, please remove me from your mailing list immediately.
E-mail to this address is no longer read by a human. You aren't
reaching me.&lt;/em&gt;&lt;/p&gt;
&lt;p dir='ltr' class='c2'&gt;&lt;em&gt;Cordially,&lt;br/&gt;
Brad&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;&lt;ul&gt;
&lt;li dir='ltr'&gt;The web page doesn't reveal anything about my
"justforfriends" e-mail address. If the person goes to the trouble
of actually sending me an e-mail via the web site, then obviously
they're not a spammer, but I don't want a spider to pick my address
out of the source code for the web page. After I get an e-mail via
the web, then I tell the person in question about my
"justforfriends" e-mail address.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;That's solved my spam problem. I used to get a lot spam every
day, and putting this system in place has made it so I read zero
spam every day. The spammers get back an e-mail from a bogus
account (so we don't get into a mail loop) telling them to come
visit my web site if they're a real person, and send me e-mail that
way. They never do. :) The spam gets deleted right out of my system
before I even have a chance to see it.&lt;/p&gt;&lt;p&gt;The reason you want to use a program like The Bat! is because
now you're subscribed to all these mailing lists with a different
e-mail address than you normally use. By using The Bat!, I set up
address book entries for all my mailing lists, and using the
scripting system present in The Bat!, I automatically force my
"From:" address to change to the "sendmespam" address whenever I
send an e-mail to a mailing list. Without this, I probably would
never have done this, because I would constantly be getting bounce
messages from the mailing list about not knowing who I am. This has
definitely made the entire system possible.&lt;/p&gt;&lt;p&gt;Hope this helps you become spam free! Feel free to ask any
questions...&lt;/p&gt;&lt;img src ="http://www.agileprogrammer.com/dotnetguy/aggbug/4488.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>Brad Wilson</dc:creator><title>Free Code: C# Message Board Classes</title><link>http://www.agileprogrammer.com/dotnetguy/archive/2002/03/09/4487.aspx</link><pubDate>Sat, 09 Mar 2002 00:09:00 GMT</pubDate><guid>http://www.agileprogrammer.com/dotnetguy/archive/2002/03/09/4487.aspx</guid><description>&lt;p&gt;Part 3 in the "Source Code For Free" series.&lt;br/&gt;
[ Download the source code to the message board classes &lt;a href='http://www.agileprogrammer.com/uploads/bradwils/MessageBoard.zip'&gt;here&lt;/a&gt;.
]&lt;/p&gt;&lt;p&gt;For me, one of the best values of the web is the vast amount of
information that's available. I don't necessarily mean news
information, as that's more or less always been here, but rather
the ability for domain experts to give opinions and have them
preserved for all time. The best thing is, these experts don't have
to be your typical "certified and published Ph.D candidate" person;
they can be anybody (like me or you), who has a lot of experience
and wants to share it.&lt;/p&gt;&lt;p&gt;That's one of the reasons I started my web log, and one of the
reasons the first major change I made to it was to allow discussion
on my topics. I want to know what people think! I want that sense
of verbal give-and-take that comes from two seasoned and
knowledgeable people duking it out for supremacy in a steel cage
match! No, wait...&lt;/p&gt;&lt;p&gt;Anyway, right after I put my discussion functionality on my web
site, &lt;a href='http://www.sellsbrothers.com/'&gt;Chris Sells&lt;/a&gt; asked
me if I could release the code so he could do it. He wanted to go
one step further, though, and host a full blown discussion group
where the members set the topics, like the groups hosted by
&lt;a href='http://www.fogcreek.com/'&gt;FogCreek&lt;/a&gt; (example &lt;a href='http://discuss.fogcreek.com/CityDesk/'&gt;1&lt;/a&gt;, &lt;a href='http://discuss.fogcreek.com/JoelOnSoftware/'&gt;2&lt;/a&gt;, &lt;a href='http://discuss.fogcreek.com/TechInterview/'&gt;3&lt;/a&gt;). I hope Joel's
not too mad that I stole his little arrow. ; )&lt;/p&gt;&lt;p&gt;Inside the source code for this project you'll find an example,
which amounts to a handful of ASP.net pages. I used to have a live
version of the message board, but since moving to a Unix host I've
had to remove it. Bear in mind that the sample code is designed for
clarity and simplicity, and shouldn't be taken as a best-practices
endorsement for the coding style. :-)&lt;/p&gt;&lt;p&gt;Using the classes is a relatively easy thing. The root class is
MessageBoard. You can get lists of topics, which are Topic objects.
From topics, you can get lists of posts, which are Post objects.
It's all pretty self-documenting via the sample, so I won't go into
it here. I recommend looking at the sample and then posting
comments if you have any questions.&lt;/p&gt;&lt;p&gt;Enjoy!&lt;/p&gt;&lt;img src ="http://www.agileprogrammer.com/dotnetguy/aggbug/4487.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>Brad Wilson</dc:creator><title>Free Code: Win32 Lightweight Lock</title><link>http://www.agileprogrammer.com/dotnetguy/archive/2001/12/10/4485.aspx</link><pubDate>Mon, 10 Dec 2001 00:47:00 GMT</pubDate><guid>http://www.agileprogrammer.com/dotnetguy/archive/2001/12/10/4485.aspx</guid><description>&lt;p&gt;Part 2 in the "Source Code For Free" series.&lt;br/&gt;
[ Download the source code to the lightweight lock &lt;a href='http://www.agileprogrammer.com/uploads/bradwils/LightweightLock.zip'&gt;
here&lt;/a&gt;. ]&lt;/p&gt;&lt;p&gt;The one obvious omissing for threading locks from Win32 is a
"multi-reader, single-writer" (MRSW) lock. These locks are very
useful for collections of data that are often read, and can be read
simultaneously by many threads, but must be protected when being
written to. Since the majority of what is done with data is
reading, using a standard lock like a Critical Section or a Mutex
unnecessarily limits reader access to the data to one thread at a
time.&lt;/p&gt;&lt;p&gt;Some discussion went around on the &lt;a href='http://discuss.microsoft.com/archives/atl.html'&gt;ATL mailing
list&lt;/a&gt; some months back about what a good MRSW lock for Win32
might look like. There are many options, depending on your
performance needs and cross-process synchronization needs.&lt;/p&gt;&lt;p&gt;I elected to write an extremely fast (albeit dangerous) lock
class for my MRSW lock. I would not recommend this lock for people
who are new to threading, because it can easily be deadlocked or
misused if you aren't extremely comfortable with the way the lock
works.&lt;/p&gt;&lt;p&gt;The interface to the class looks like this:&lt;/p&gt;&lt;pre&gt;
class LightweightLock
{
public:
  // Construction/destruction
  LightweightLock();
  ~LightweightLock();
 
  // Public interface
  void LockForReading();
  void UnlockForReading();
  void LockForWriting();
  void UnlockForWriting();
};
&lt;/pre&gt;&lt;p&gt;All in all, it's pretty simple. The lock is created in the
constructor, and released in the destructor. It does not perform
any memory allocations or call any kernel functions, so it can be
safely used as a global or static. Readers call LockForReading and
UnlockForReading, and writers call LockForWriting and
UnlockForWriting. These methods will "spin" until the requested
activity becomes legal. &lt;strong&gt;EXTREMELY IMPORTANT:&lt;/strong&gt; If
you already have a reader lock, and attempt to acquire a writer
lock, you WILL deadlock! Release your reader lock before acquiring
your writer lock to prevent this.&lt;/p&gt;&lt;p&gt;The implementation is actually rather simple. It uses two
integers, which are used as counter flags for readers and writers.
While readers can be numerous simultaneously, you can only ever
have one writer at a time. By default, the lock has 0 readers and 0
writers, and upon destruction in debug mode, it will throw an
assertion if there are any outstanding locks held.&lt;/p&gt;&lt;p&gt;Reader locking works like this. First, we wait until there are
no writers. Then we acquire a read lock (which increases the reader
count), and then re-check for writers (just in case pre-emption has
caused a writer to get in in-between). If a writer pre-empted us,
then we decrease the reader count again, and start over. If you're
wondering why we wait until there are no writers before getting the
read lock, since we know that we could be pre-empted, the answer
is: performance. Acquiring the read lock interlocks the CPUs on an
SMP system, which is an unnecessarily expensive task when we know
we would fail (because there are writers); thus, we wait until we
have a good chance of success.&lt;/p&gt;&lt;p&gt;Unlocking a reader lock is as simple as decreasing the reader
count.&lt;/p&gt;&lt;p&gt;Writer locking works like this. First, we wait until there are
no writers, acquiring the writer lock when there are none (so
telling any future writers that they must "wait in line"). Then, we
wait until there are no readers. Readers who had read locks prior
to our acquiring a write lock can continue to read, and we will
wait until they are all finished reading. New readers, on the other
hand, will recognize that a writer exists and will wait for us.
This prevents writer starvation. Writers that must wait for other
writers are served in a no-preference order (meaning, it's
essentially luck of the draw while writer will come next, without
regard to the length of time spent in the "writer queue").&lt;/p&gt;&lt;p&gt;Unlocking a writer lock is as simple as setting the writer flag
to "no writers".&lt;/p&gt;&lt;p&gt;It is trivial to construct "wrapper" classes that can be used to
auto-acquire and release reader and writer locks, so as to be used
on the stack for robustness in the face of exceptions. This is left
as an exercise for the reader (no pun intended).&lt;/p&gt;&lt;p&gt;Also, the "spinning" mechanism (what's done when we're waiting)
is a call to Sleep(0), which basically just allows other threads to
run. This could cause problems if you need to do other activities
while waiting, such as pumping messages. I have provided a simple
override system, wherein you can #define __LW_LOCK_SPIN to be any
set of code you wish (more complicated spinning needs are beyond
the scope of this article, but you can contact me and I'd be happy
to discuss possible modifications to the class).&lt;/p&gt;&lt;p&gt;That's it in a nutshell. Please send comments, and enjoy!&lt;/p&gt;&lt;img src ="http://www.agileprogrammer.com/dotnetguy/aggbug/4485.aspx" width = "1" height = "1" /&gt;</description></item><item><dc:creator>Brad Wilson</dc:creator><title>Free Code: Win32 Bitmap Wrapper</title><link>http://www.agileprogrammer.com/dotnetguy/archive/2001/12/09/4484.aspx</link><pubDate>Sun, 09 Dec 2001 08:40:00 GMT</pubDate><guid>http://www.agileprogrammer.com/dotnetguy/archive/2001/12/09/4484.aspx</guid><description>&lt;p&gt;Part 1 in the "Source Code For Free" series.&lt;br/&gt;
[ Download the source code to the bitmap wrapper &lt;a href='http://www.agileprogrammer.com/uploads/bradwils/BitmapWrapper.zip'&gt;here&lt;/a&gt;.
]&lt;/p&gt;&lt;p&gt;One of the more frustrating limitations in Win32 bitmap support
(at least, if you target the older OSes without making Internet
Explorer requirements) is the lack of support for converting DDBs
to DIBs, painting with transparency, and using a bitmap template
for skinnable application that support non-rectangular windows.
Over the years, I've refined this bitmap wrapper class to handle
all these things. The one thing this wrapper does not handle is
RLE-encoded bitmaps.&lt;/p&gt;&lt;p&gt;Bitmap is a self-cleaning bitmap wrapper. You load bitmaps via
one of three methods:&lt;/p&gt;&lt;pre&gt;
bool LoadDIBitmap( UINT nResourceId, HMODULE hMod = NULL );
bool LoadDIBitmap( LPCTSTR lpszResourceName, HMODULE hMod = NULL );
bool LoadDIBFile( LPCTSTR lpszFilename );
&lt;/pre&gt;&lt;p&gt;The first two are used to load bitmap resources from the
resource table, either by numeric ID or by name. In both cases, the
HMODULE is optional; if left off, then the resource table of the
current executable is searched.&lt;/p&gt;&lt;p&gt;The third is used to load a bitmap from disk. This can load "old
style" bitmaps (first introduced in OS/2 and Windows 1.x) and "new
style" bitmaps (introduced in Windows 3.0). This should cover all
on-disk representations.&lt;/p&gt;&lt;p&gt;Once the bitmap is loaded, it can also be saved to disk:&lt;/p&gt;&lt;pre&gt;
bool SaveDIBFile( LPCTSTR lpszFilename );
&lt;/pre&gt;&lt;p&gt;Now that you have a bitmap in hand, there are a number of
information functions you can use on it:&lt;/p&gt;&lt;pre&gt;
DWORD Width();&lt;br/&gt;
DWORD Height();
int ColorDepth();
int Colors();
HPALETTE GetPalette();
bool CopyPalette( HPALETTE* pPalette );
&lt;/pre&gt;&lt;p&gt;Width and Height should be self-explanatory.&lt;/p&gt;&lt;p&gt;ColorDepth returns the color depth in bits (an 8-bit bitmap will
return "8"), whereas Colors returns the actual number of colors (an
8-bit bitmap will return "256"). Note that a 32-bit bitmap (rare,
but possible, especially in screen-capture situations) will return
"32" for its ColorDepth, but "0" for its Colors, because of the
overrun of space.&lt;/p&gt;&lt;p&gt;If the bitmap is paletted, you can get a copy of the internal
palette (with GetPalette), or ask the bitmap to make a copy of the
palette for you (with CopyPalette).&lt;/p&gt;&lt;p&gt;You also have a number of painting options, depending on your
needs. The simplest is:&lt;/p&gt;&lt;pre&gt;
bool PaintDIB( HDC hdc, LPRECT lpDCRect = NULL,
    LPRECT lpDIBRect = NULL );
&lt;/pre&gt;&lt;p&gt;This will paint the bitmap to the given DC. lpDCRect is the
rectangle for the destination paint on the DC; if you leave it off,
the bitmap will be painted 1:1, starting in the left corner of the
DC. lpDIBRect is the rectangle for the source paint from the
bitmap; if you leave it off, the entire bitmap will be used for the
paint operation. As with all GDI operations, rectangles have the
actual left and top coordinates, but the bottom and right
coordinates should be one-more than normal (so for instance, the
default DIB rectangle is (0,0) to (width,height), rather than (0,0)
to (width-1,height-1) as non-GDI users might expect). For
performance reasons, if the paint operation is 1:1, then GDI's
SetDIBitsToDevice is used; if the paint operation stretches the
results, then GDI's StretchDIBits is called under the covers (after
setting the COLORONCOLOR stretching mode).&lt;/p&gt;&lt;p&gt;If your bitmap has a "transparent" color, which should allow
whatever is under the transparent pixels to show through, then you
can use:&lt;/p&gt;&lt;pre&gt;
bool TransparentPaint( HDC hdc, COLORREF clrTransparent,
    LPRECT lpDCRect = NULL, LPRECT lpDIBRect = NULL );
&lt;/pre&gt;&lt;p&gt;This API works exactly like PaintDIB, except for the additional
clrTransparent argument.&lt;/p&gt;&lt;p&gt;Finally, if you are creating a "skinnable" user interface from a
bitmap, Bitmap can help you. In Win32, you can use the SetWindowRgn
API to create non-rectangular windows. Bitmap provides an API that
can look at a piece of a bitmap, and generate a window region from
it. It uses a transparent color, like TransparentPaint, to indicate
what parts of the bitmap are the "hollow" parts of the UI; any
other color is a "solid" part of the UI. This allows you to create
a very complex UI simply by painting it into a bitmap, and letting
Bitmap generate the region automatically for you:&lt;/p&gt;&lt;pre&gt;
HRGN GenerateWindowRegion( COLORREF clrTransparent,
    int x = 0, int y = 0, int cx = -1, int cy = -1 );
&lt;/pre&gt;&lt;p&gt;The x, y, cx, and cy arguments are the portions of the bitmap
you want to use for the window region. x and y default to the upper
left corner of the bitmap; cx and cy default to the width and
height of the bitmap, respectively. The result is a window region
that can be directly passed into SetWindowRgn.&lt;/p&gt;&lt;p&gt;That's it in a nutshell. Please send comments, and enjoy!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; I have updated the license on all my
Win32 C++ classes to be less restrictive, including the bitmap
wrapper. If you have downloaded a previous version, please feel
free to download the new version for the new license
information.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; Here's the license for the code:&lt;/p&gt;&lt;blockquote&gt;
/////////////////////////////////////////////////////////////////////////////&lt;br/&gt;

//&lt;br/&gt;
// Copyright (C) 1995-2002 Brad Wilson&lt;br/&gt;
//&lt;br/&gt;
// This material is provided "as is", with absolutely no
warranty&lt;br/&gt;
// expressed or implied. Any use is at your own risk. Permission
to&lt;br/&gt;
// use or copy this software for any purpose is hereby granted
without&lt;br/&gt;
// fee, provided the above notices are retained on all
copies.&lt;br/&gt;
// Permission to modify the code and to distribute modified code
is&lt;br/&gt;
// granted, provided the above notices are retained, and a notice
that&lt;br/&gt;
// the code was modified is included with the above copyright
notice.&lt;br/&gt;
//&lt;br/&gt;
/////////////////////////////////////////////////////////////////////////////&lt;/blockquote&gt;&lt;p&gt;Enjoy!&lt;/p&gt;&lt;img src ="http://www.agileprogrammer.com/dotnetguy/aggbug/4484.aspx" width = "1" height = "1" /&gt;</description></item></channel></rss>