ColdFusion Tips and Tutorials

ColdFusion Tips and Tutorials. Tips on ColdFusion, AJAX, CSS, JavaScript, HTML, Design, and more.

CFUnited Developer Conference 2010
Use this code TIPSCUST to get $100 off your registration @ CFUnited! We'll see you There!


ColdFusion Tips
Page 1 2 3
148 ColdFusion, Ajax, FuseBox, Tips, and Tut
147 Included Point of View
146 Javascript - OnFocus
145 Nathan's Rules of Professional Web Desig
144 Universal Server-Side Check | Bandwidth
143 Meeting Schedule | Identification Sessio
142 Breaking Frames Without Javascript
141 Unreal Forms
140 Screen Resolution
139 Human Help
138 Better Server-Side Validation
137 Automatic Server-Side Validation
136 Regular Expression Laboratory,ColdFusion
135 Rank-Ordered Site Search
134 Building Cryptograms
133 Well-Formed Includes
132 Grouping Families for Visits
131 Display Families on a Map Grid
130 Slide Shows
129 Determine Your Database Engine
128 ColdFusion in Context: Maxlength Lies
127 Something Extra
126 Parsing Database Structure from Data Def
125 Valid Values Maintenance
124 Print 1
123 Hide Session Id
122 Downsizing Data to Access
121 Time to Load a Page, FuseBox 4
120 Order and Rank by Subset
119 Warn through E-mail & Update on Paste Sp
118 Paste Spreadsheets, ColdFusion Component
117 Review Files Having Fixed-Length Fields
116 Organized Help
115 Sequence Slider
114 Bad Bits
113 Logical Deduction
112 Whiteout
111 Forced Navigation
110 Managing Permissions
109 Time Travel
108 Test First
107 Get Distance Between Map Coordinates
106 Validating Checkboxes
105 Matrix Manipulation
104 Field Help
103 Fake Object Not Found
102 Rank Order Correlation Coefficient
101 From Calling Pairs to Calling Tree
100 Posting Notice
99 Logout Persuasion
98 Release Session Memory
97 Use Identically Named Fields
96 Web Bug
95 Password Generation
94 Core Queries
93 Use CFFTP
92 Insert, Update, and Delete
91 Stack
90 T-Value
89 Bulk Data Entry and E-mail Validation
88 Quick Reset
87 Design 1
86 Use CFFTP
85 Support Login with AutoPost
84 Login and Site Protection
83 XY Graphs in a Graphing Calculator
82 Read Encrypted Files
81 Showing Progress
80 Frugal Cross-Browser Javascript
79 Tabbed Folders
Page 1 2 3



Custom Search
ColdFusion TIPS PLUS


Issue 00144 http://www.cftipsplus.com

I. My Comments

II. ColdFusion In Context: Universal Server-Side Check
By R. Martin Ladner
martin.ladner@charter.net

III. Bandwidth Or Data Transfer – Which is Which?
By HostVoice.net

IV. Getting Your Site Submitted to Search Engines
by Aaron Turpen of Aaronz WebWorkz


I. Comments:

Well I am trying out some new things and hope you like the new emails I am sending out. I am considering opening a new website for other web design tools and languages. Please send in your recommendations. I would like to make this site and any future site as useful as possible.

Thanks for looking at my pictures.
http://www.milforddel.com/photos/

If you have any recommendations for powerpoints you would like to see let me know.
http://www.nsnd.com/ - Currently these are for churches. Should I make these free and make money from the google ads?


Keep Coding,
Nathan Stanford
http://www.cftipsplus.com

If you have suggestions for articles send them to us.
If you would like to write for cftipsplus.com
send us an email to:

NathanS<at>nsnd.com

IF YOU WANT TO BE AN AUTHOR SEND IN YOUR COLDFUSION TIPS.

Remember this is a great way to get your name known in the
ColdFusion Community.




II. ColdFusion in Context: Universal Server-Side Check
By R. Martin Ladner
martin.ladner@charter.net


Suppose you want to write just one set of programs to do standard server-side validation of every form you will write. Here's how to do that in a manner that re-uses information that supports universal client-side checks. You'll also see how to invoke custom code for unique situations.

Problem and Solution
For each field, you'll need to know a few things. Because fields are perceived by the server in an unpredictable sequence, you'll need a field's intended sequence on the form in order to present errors in the right order. You'll need to know what tests should be performed on the field. And, you'll need the field label that should appear in error messages.
One way to accomplish this is to create one hidden field for each real field to be checked. Give the hidden field the same name as the real field except for adding a _t to the hidden field's name. For the value of the hidden field, specify three things separated by tildes: a sequence value that will place the field in the proper sequence if alphabetically sorted, a list of names of tests to be applied to the field, and the field's label. The latter two pieces of information need to be available somewhere to support client-side checks anyway. The sequence value is the only additional piece of information needed to support server-side checks.

Sometimes custom checks are needed to handle unique situations on a specific form. To provide custom checks, the partial name of a page containing such checks should be known. Why a partial name? Because the same basic name can be used for a file that holds custom checks for the client side. For example, the client-side custom code might be in "Form42.js" and the server-side custom code might be in "Form42.cfm".

Notice that a form that provides test specifications in hidden fields and provides the partial name of a file containing custom code will readily support both client-side and server-side checks.

Sample Form and Destination
Put this sample form in MyForm2.cfm. Begin by stating "Customs": the partial filename of the page that contains custom code for this form. Client-side checks would be included next within script tags. Include server-side checks it the form has been submitted; they will stop processing if they see a problem. Provide a destination for the user to go to if the form is submitted successfully. Once the new destination has been included, stop processing this page.

<!--- Tell standard code the partial name
of the page that holds custom code --->
<cfset Customs="Form42">

<!---
Client-side checks would be included here
within script tags; formCheck, for example
--->

<!--- Act when the form is submitted --->
<cfparam name="form.Go" default="">
<cfif len(trim(form.Go))>
<cfinclude template="ServCheck.cfm">
<!--- which will stop on error, else... --->
<cfinclude template="MyAct.cfm">
<cfabort>
</cfif>

For this demonstration, the form is worded as an invitation to play a TV game show. Open the form. Copy the Customs variable to a hidden field to provide future flexibility. If this is not done and you choose later to have the form target be a page other than the form itself, the Customs variable needs to be received by the server-side checks in this manner. (If you'll ALWAYS submit your forms to themselves as shown in this example, you won't need to use this field. It's safest to code it now for the future.) Name the game.


<form name="MyForm" method="post">
<!---
this attribute would call client-side checks:
onSubmit="return formCheck(this)"
--->

<!--- Pass "Customs" to the server in case
the form doesn't submit to itself;
support server-side checks --->
<input type="hidden" name="Customs"
value=<cfoutput>
"#Customs#"</cfoutput>>

<!--- Time to play... --->
Let's break a deal [grin]
<p>

Provide a select box that asks if the user wants to play. Note that the first option consists of instructions to the user, not a choice. Follow it with a corresponding hidden form that provides a sequence, a list of tests (required and custom) and a label to become part of associated error messages. Note that the entire message isn't needed here, just the label. Note that a single hidden field names as many tests as you want for the corresponding "real" field.

The sequence value deserves further discussion. Because the code to sort these test specifications will look at the entire specification and not just the sequence value at the beginning of it, an alphabetical sort must be performed. Therefore, the sequence value from the form should always be evenly padded to survive an alphabetical sort and to avoid having test names influence the order of short sequence values.


Do you want to play?<br>
<select name="Play">
<option value="" selected>Decide
<option value="Yes">Yes
<option value="No">No
</select>
<input type="hidden" name="Play_t"
value="01~required custom~Play decision">

<p>

Now add a text field with its hidden field and a set of radio buttons with its hidden field.


How much money will you risk?<br>
<input type="text" name="Money" value="">
<input type="hidden" name="Money_t"
value="02~required number gezero~Money to risk">

<p>

Which do you want to open:<br>
<input type="radio" name="Door"
value="1">
door number 1,<br>
<input type="radio" name="Door"
value="2">
door number 2,<br>
<input type="radio" name="Door"
value="3">
door number 3,<br>
<input type="radio" name="Door"
value="stop">
or stop and keep the money?<br>
<input type="hidden" name="Door_t"
value="03~required~Door to open">

<p>

Toss in a textarea with its hidden field, a set of checkboxes with its hidden field, and a multiple select box with its hidden field. Be sure to use the word "multiple" in the select tag to let the user make multiple choices.


What do you think is behind it?<br>
<textarea name="Guess" rows="3" cols="45"></textarea>
<input type="hidden" name="Guess_t"
value="04~required custom~Your guess">

<p>

Pick ways that you'll show you're having fun:<br>
<input type="checkbox" name="Fun" value="sing">sing,<br>
<input type="checkbox" name="Fun" value="grin">grin<br>
<input type="hidden" name="Fun_t"
value="15~required~Ways to show you're having fun">

<p>

You'll need to change clothes during competition.
What colors will you wear?<br>
<select name="Colors" multiple>
<option value="" selected>Decide
<option value="Red">Red
<option value="White">White
<option value="Blue">Blue
</select>
<input type="hidden" name="Colors_t"
value="16~required~Clothing colors">

<p>

To provide an excuse to practice limiting the character set, ask for the user's last name. Provide a submit button and close the form.


What's your last name?
<input type="input" name="LastName">
<input type="hidden" name="LastName_t"
value="20~limited~Last name">

<input type="submit" name="Go" value="Respond">

</form>

Sample Action
Put this one line in MyAct.cfm.


SUCCESS!

Core Test
Put this code in ServCheck.cfm. You can use it for every form constructed in this manner.
Because of the way MyForm2.cfm was constructed, fields whose names end in _t contain test specifications (Specs) formatted as {sequence}~{tests}~{label} corresponding to a "real" field whose name can be determined by removing the _t from the name of the specification field (a hidden field). Therefore, you'll need code that puts them in a list (adding the name of the real field to each specification), puts the list in the specified sequence, applies the tests named by the specification, and displays errors after all fields have been checked.

Begin by initializing some variables: the specification list to be filled and sorted, the separator to be used between specifications, a value for a line separator to format the error message, and the separator (a tilde) that is used between elements of the specification.

Then, loop the keys (fieldnames) of the form structure. If the fieldname contains _t, add its contents to the specification list, define the real name of the field to be checked as the current fieldname with the _t removed, tack that on as well (separated by the element separator, and tack on the specification separator. Repeat for all fields.


<!--- Get a Specification List --->
<cfset SpecList="">
<cfset SpecSep="|">
<cfset LineSep="#chr(10)#">
<cfset ElementSep="~">
<cfloop list="#structKeyList(form)#" index="FieldName">
<cfif FieldName contains "_t">
<cfset RealName=left(FieldName,len(FieldName)-2)>
<cfset SpecList=SpecList&form[FieldName]&
ElementSep&RealName&SpecSep>

</cfif>
</cfloop>

Because the sort will look at the entire specification, not just the sequence at the beginning of it, an alphabetical (text) sort must be performed. Make it ascending (asc). Indicate the character that separates the long specification list (SpecList) into the chunks to be sorted (SpecSep).


<!--- Alphabetically sort the list;
specifications must support an alphabetical sort --->
<cfset SpecList=listSort(SpecList,"text","asc","#SpecSep#")>

Loop through the sorted string of test specifications, performing appropriate tests for each real field. Begin by parsing the specification into its list of test names (Tests), its label (Label), and the real name (RealName) of the field to be checked. Then, use the real name to get the data value to be checked.


<!--- Check each field; build the error message --->
<cfset Msg="">
<cfloop list="#SpecList#" index="Spec" delimiters="#SpecSep#">
<!--- (Parse the Spec) --->
<cfset Tests=listGetAt(Spec,2,ElementSep)>
<cfset Label=listGetAt(Spec,3,ElementSep)>
<cfset RealName=listGetAt(Spec,4,ElementSep)>

<!--- Get the data value to be checked --->
<cfset DataValue="">
<cfif structKeyExists(form,RealName)>
<cfset DataValue=structFind(form,RealName)>
</cfif>

A one-pass loop can make code easier to follow by letting you break to the end of a long sequence. Begin a one-pass loop that will span all tests. The existence of this loop lets you skip remaining tests at any point through the use of a break statement so you can proceed directly to the next specification.

After the loop begins, start testing. First, see if the field is empty. If so, and it's required - it's contained in the list of Tests for this field - complain by adding to a cumulative error message (Msg). Begin each complaint with a line separator (LineSep) so the error messages don't run together. Then for standard errors, provide the label followed by canned text for the error.

Include custom code if appropriate. The custom code will add error text to a string named TempMsg if it has any errors; so, append TempMsg to the cumulative error message.

Finally, because there is nothing else you can do with an empty input, break the loop to skip remaining tests in order to immediately work with the next field.


<!--- This one-pass loop lets you skip
to the next specification when desired --->
<cfloop from=1 to=1 index="Pass">

<!--- If empty, skip all tests but the "required"
and "custom" tests --->
<cfif not len(trim(DataValue))>
<!--- Empty --->
<cfif Tests contains "required">
<cfif not len(trim(DataValue))>
<cfset Msg=Msg&LineSep&Label&" must not be empty">
</cfif>
</cfif>
<!--- Custom... --->
<cfif Tests contains "custom">
<cfinclude template="#Customs#.cfm">
<cfset Msg=Msg&TempMsg>
</cfif>
<cfbreak>
</cfif>

If the field is not empty, then apply other standard tests named in the specification. The first of these tests should be applied automatically unless it is overridden: a check for bad characters. Regular expressions one would use in javascript to test a value can also be used with very little adjustment by ColdFusion's reFind tag. (Double pound signs. Double double quotes.) For this demo, reject angle brackets, percent signs (due to interference with database searches), pound signs, asterisks and tildes (due to interference with a standard business format known as X12 which may be used for the back end of an application), and double quotes (which some applications may not handle correctly).


<!--- If the "any" override is NOT present,
complain if input contains bad characters --->
<cfif Tests does not contain "any">
<cfif reFind("[%##\>\*\""\<~]+",DataValue)>
<cfset Msg=Msg&LineSep&Label&
' cannot contain %, ##, >
, *, ", <, or ~'>
</cfif>
</cfif>

If you've seen one test, you've seen them all; well, nearly all. Most tests can be implemented through the use of regular expressions with greater speed and brevity (if perhaps a loss of clarity for some audiences) when compared with traditional if-then logic. If the "
number" test should be made, see if the field consists of an optional sign, zero or more digits, an optional decimal point, and zero or more digits following the decimal point. (You've already skipped this test if the field is empty; so, it won't be empty.)


<!--- Complain if it should be a number but isn't --->
<cfif Tests contains "number">
<cfif not reFind("^[-+]?(([0-9]+\.?[0-9]*)|(\.[0-9]+))$",DataValue)>
<cfset Msg=Msg&LineSep&Label&" must be a number">
</cfif>
</cfif>

It would be nice to be sure a number is not negative. To see if the value is greater than or equal to zero (via a test named "
gezero"), a simple less-than test will suffice.

<!--- Complain if it should be greater than or
equal to zero but isn't --->
<cfif Tests contains "gezero">
<cfif val(DataValue) lt 0>
<cfset Msg=Msg&LineSep&Label&
"
must be greater than or equal to zero">
</cfif>
</cfif>

For this demonstration, someone's last name is unlikely to have characters other than letters and a hyphen. You can use reFindNoCase to avoid having to check letter case in the regular expression itself. If the field should use this limited character set, complain if it contains anything other than a letter a-z or a hyphen.


<!--- Complain if contents exceed limited character set --->
<cfif Tests contains "limited">
<cfif reFindNoCase("[^a-z\-]",DataValue)>
<cfset Msg=Msg&LineSep&Label&
"
must contain only letters and hyphens">
</cfif>
</cfif>

You can add as many tests as you like in the same manner as the ones above. Finish by applying the custom code if the list of tests for the field calls for this to be done. The custom code will add to TempMsg if an error has to be displayed; add TempMsg to the cumulative error message string.

To work with the next field, close two loops: the one-pass loop created for convenience, and the loop that's actually reviewing each specification.

<!--- Custom... --->
<cfif Tests contains "custom">
<cfinclude template="#Customs#.cfm">
<cfset Msg=Msg&TempMsg>
</cfif>

<!--- End one-pass loop --->
</cfloop>

<!--- Test the next field --->
</cfloop>

Because these errors will be written directly to a page instead of winding up in an alert box, no mechanism is needed to be sure the box doesn't exceed the screen. Just spit out all the errors at once. One approach would be to simply print the entire line as a variable (since you've put line separators in it). The possibly redundant (but foolproof) approach taken here is to loop the error message (if it's not empty), split it on line separator, and insert an HTML break between lines.

The final message needs to tell the user to press the back button to correct and re-submit the page. This is the most straightforward approach. End by blocking further processing of the page.


<cfif len(Msg)>
<cfloop list="#Msg#" index="Line" delimiters="#LineSep#">
<cfoutput>#Line#</cfoutput><br>
</cfloop>
Press your back button, correct any problems, and re-submit.
<cfabort>
</cfif>

Custom Tests
Put this code in Form42.cfm. The filename is based on the partial filename provided by "
Customs" in the including page and will be different for each form you create that needs custom code. The custom code will add to TempMsg if an error has to be displayed. So, empty TempMsg.
If a field requires a custom test, this page gets included without specifying which custom test is needed. So, check Realname to determine if a given test should be applied to this field. This sample defines two tests: one that looks at multiple fields, and one that performs a non-standard check of a single field. One is invoked for the field named "
Play"; the other is for the field named "Guess".


<!--- Apply appropriate custom tests; note errors --->
<cfset TempMsg="">
<cfif RealName is "Play">
<cfif DataValue is "No">
<cfif len(trim(form.Money))>
<cfset TempMsg=TempMsg&LineSep&
"
Reconsider your decision not to play. "&
"
Don't specify an amount to risk "&
"
if you won't play">
</cfif>
</cfif>
<cfelseif RealName is "Guess">
<cfif DataValue contains "nothing">
<cfset TempMsg=TempMsg&LineSep&
"
We wouldn't provide an empty showcase. "&
"
Make a better guess.">
</cfif>
</cfif>


Extensions
This is an easy way to add server-side validation to all forms you will write. Write and specify more tests as desired. Browse myform2.cfm.
If you're concerned that someone may rewrite your form, omitting or changing the type or content of its fields, here are some things to consider.

First, this problem will always be with you. Whether the user makes batch entries or interactive entries, your application shouldn't trust prices that the user can touch.
Second, code that merely checks formats and provides feedback to the user (as this code does) exists for consistency and convenience, not for protection. Code that accesses server data has the primary responsibility for protection.

Third, code that accesses server data should make sure that the user has PERMISSION for the given access. To do this, the application must reliably identify the user and the scope of the proposed activity. Don't trust an unencrypted account ID propagated through a form, URL, or cookie. Don't trust a scope that's enforced only by the select box of a form. The code that actually does the update should check the user and scope itself.

Finally, notice that you have to put the specifications somewhere. Programmers have traditionally instantiated them in newly written code for each field [groan]. The specifications would be more useful if stored in a database, however. The code in this tip that checks each field could have received its test specifications from a query as easily as from a form structure. Further, you could have used a query to define the form's field labels and attributes in the first place (and even the values of the hidden fields). [Hint, hint.] So, write these tests once and use them whenever they're needed. A good utility is a gift that keeps on giving.


=Marty=


III. Bandwidth Or Data Transfer – Which is Which?
By HostVoice.net


Too often web hosts talk about bandwidth and data transfer in the same breath but truth be known they are different although very closely related. Bandwidth is how much data can be transferred at a time and data transfer is how much data is being transferred.
Think of it this way. If bandwidth were a bridge, then the bigger the bridge is the more vehicles can pass through it. While data transfer is the number of vehicles allowed on the bridge in say a month. In essence, data transfer is the consumption of bandwidth.

How It Affects Your Site
The less bandwidth you have, the slower your site takes to load regardless of the visitor’s connection type. If you have more visitors, some of them will have to wait their turn. The least data transfer you have, the more often you’ll find your site unavailable because you’re reached the maximum allowed until a new month rolls by or you upgrade your account.

Determining Your Requirements
Usually when a host talks about bandwidth, they are referring to your transfer. So you need to figure out what is sufficient for your site to function. You’ll need to gather some information; fairly easy if you already have a site. Most of this information is available from your traffic history. If you don’t have an existing site, provide an optimistic estimate if you intend to heavily promote the site. Then get ready for some math.

Find out the daily averages of: -


  • Number of visitors / expected number of visitors

  • Page size including the graphics of the page

  • Page views / expected pages viewed by each visitor

Then, multiply them as follows:
Visitors x Page size x Page views x 30 days = Monthly Website Transfer
You should also throw in a small margin or error there to take into account email traffic and your own uploads to the server. If you offer downloads, then you should add the following:
Average/Expected downloads x File Size x 30 days = Monthly Download Transfer

Unlimited Plans
Bandwidth is very expensive. All hosts are limited by their own allocations. Thinking back to the bridge. What happens is each visitor to your site will be given a smaller lane to transfer the data, creating many tiny lanes therefore “unlimited”. The more visitors you have the smaller each lane will be, which makes each visitor wait for the page to load.

More often than not there is little choice over your bandwidth as your host controls this. Some hosts may limit the number of simultaneous connections so in affect slowing down your site and refusing some visitors. This is called throttling. If you’re concerned about this, you should ask the host how they control bandwidth usage or purchase a package with more data transfer. If you use HostVoice.net (link:http://hostvoice.net), this information is easily obtainable with one request.

Reducing Transfers
On the other hand, you can reduce your transfer amount by building simpler, more efficient websites and optimizing your graphics. Refrain from fancy flash presentations or streaming audio. Use CSS, call JavaScript externally instead of embedding in every page. Remove unwanted tags, white space and comments. Limit your META tags to those absolutely necessary. Having too many keywords is not search engine friendly. Besides many search engines will only review the first few and ignore the rest.

Another good idea is to cache your website but you might want to set an expiry date in the HTTP headers so the browser will refresh the content after a certain time. Use mod-gzip. It could save you as much as 40% of your bandwidth. Out of control robots can also suck down your bandwidth like a black hole. So use robots.txt to keep spiders in check.

By http://HostVoice.net

This article has been contributed by the team at HostVoice.net
HostVoice.net: Where Hosts Compete For Your Business
Looking for a web host? Have them compete for your business! Submit a FREE, no-risk request and receive offers within 15 minutes from qualifying hosts. Personal, Business, eCommerce, NT, Dedicated, Reseller - we’ve got it all!

For information on reproduction of this article, eMail us at info@hostvoice.net



IV. Getting Your Site Submitted to Search Engines
by Aaron Turpen of Aaronz WebWorkz

Getting listed in search engines can be a lot of work. "Free" submission tools are worth about what you pay for them and, worse, can be detrimental to your efforts. Yet you don't have the time to do it yourself by hand. What do you do?

You hire a professional.
A professional search engine marketer, submission service, and ranking specialist is a great tool for any site owner who wants to get listed, listed high on the results, and see a return on their investment. Sadly, there are a lot of scam artists and beginners out there passing themselves off as "
professionals" in this field. How do you find a good one?

First, look for informative content and straight-forward pricing on the professional's website. A well-made, professional website with informative content and easy-to-understand pricing structures is the mark of a truly professional submitter.

Avoid submission sites that give too good to be true claims and too-low-to-believe pricing. Any service that makes claims that they can put you at the top of all engines or "guarantees" the #1 spot anywhere is lying. However, a guarantee of "top ranking" (usually defined as being in the first twenty in a keyword response) is realistic and believable.

Be careful of sites that use the term search engine and "pay per click" in the same context. These are submitters who will promote your site through Pay Per Click engines and not through actual search engines or directories. There is a definite difference in longevity and price between the two types of marketing.

Watch for submitters who have time-based plans and contracts. These are the true professionals that know what it really takes to get you listed for the long-term. Search engine marketing is a continual process. If you do it once and forget about it, it will soon forget about you too and you'll see your visitors and sales drop as time goes on. A great marketer will ask for a contract to review your site weekly, monthly, or quarterly for ranking statistics and offer extensions of contract when your results begin to fall.

On the same token, watch for a company that's been around versus one that's new and possibly "fly by night." If they disappear, you'll have to start over with a new company again, going through the initial setup headaches required.

Above all, once you find a good marketer, KEEP THAT MARKETER! Don't get dicey over pricing and drop a good marketer just because you've found another who's $10 cheaper. In the end, you'll lose money on the deal, I guarantee.

So who would I recommend for your search engine marketing needs? The two marketing companies listed below are good search engine marketers I have used in the past or recommended to clients. They are tried, true, and good at what they do. Their prices range according to the services offered. Find the one that fits your needs and try them out!

1st Search Ranking
http://www.1stSearchRanking.com/t.cgi?1sr&1778

Submit Fire
http://www.qksrv.net/click-1357406-10286016



Publisher and Creator:
Nathan Stanford,
NathanS<at>nsnd.com
http://www.cftipsplus.com

Macromedia and ColdFusion are U.S. registered trademarks.


Copyright (c) 2000 - 2004
CFTIPSPLUS.COM and NSND.COM

Permission is granted to circulate this publication via
MANUAL forwarding by email to friends provided that the text is
forwarded in its entirety and no fee is charged.

Photo of Nathan Stanford
Nathan Stanford
LinkedIn

R. Marty Ladner's
Site