Chapter 11

Contests and Registration


CONTENTS


Everyone loves a contest. Web site owners love contests because they can bring large numbers of visitors to the site. Contests with registration can be used to collect information about the people visiting, either for statistical purposes (to be used in improving the marketing aspects of the site) or for direct follow-up (for sales purposes).

This chapter focuses on the technical aspects of setting up a contest site, but also touches on the legal aspects of a site. A contest site may, under certain circumstances, be considered an illegal lottery. Any Webmaster building a contest site should get a legal opinion as to whether the site has taken active steps to comply with the law.

Why Have a Contest?

A few years ago, some psychologists conducted an experiment. They set up a little box for a rat and taught the rat to pull a lever for food. They taught one rat that if it pulled the lever five times, it would get a food pellet. They taught another rat that if it pulled the lever at least once during a given time period, it would get a food pellet. Still another rat was allowed to pull the lever as much as it liked-the amount of food given was entirely random, as long as the rat had pulled the lever at least once.

Then, with each rat, the experimenters stopped rewarding the behavior. They found that within a few minutes the first two rats gave up and stopped looking for food. The third rat had to be pried out of the box 24 hours later, when the experimenters tired of seeing it still pulling the lever, hoping for a payoff.

Maybe people are not so unlike rats. When we are paid by piecework or by time worked, we call what we do a "job." But the idea that there's a big payoff waiting if we just keep trying the lever evokes an element of fun-our laboratory rats might feel right at home in Las Vegas, Atlantic City, or any convenience store selling state lottery tickets.

What Is a Contest?

To better support the discussion of the legal aspects of contests coming up in the next section, this chapter uses the term sweepstakes to refer to games in which the results are determined entirely by chance, and in which the contestants have not paid anything of value to enter. The term game of skill is used to refer to games in which the outcome is not determined by chance. A lottery is like a sweepstakes in that the outcome is determined by chance, but contestants must pay in order to play.

A contest can become a lottery quite innocently. If consumers must buy your product in order to enter the contest, they have "paid something of value." Likewise, a game of skill can become a lottery when the degree to which skill is required is either removed or reduced. If the contest ends in a tie and the first-place winner is chosen at random from among the finalists, there is an element of chance. If participants paid an entrance fee or were in any other way required to put in something of value in order to play, the contest may be considered a lottery. And lotteries are illegal.

Designing the Contest Site

Contests and sweepstakes have similar objectives and execution. This section addresses the technical issues of how to set up a site that captures a "contestant's" file, as well as polling data about how users answered the survey questions. The section concludes by addressing some of the legal issues surrounding contests and sweepstakes.

Technical Issues

Due to the nature of contests and sweepstakes, pages are taken down or substantially modified after the contest is over. The examples in this section are illustrative. For an up-to-date list of sweepstakes and contest sites, see http://www.yahoo.com/Entertainment/Contests__Surveys__Polls/Giveaways/.

From a technical standpoint, a simple sweepstakes may be set up using a form linked to e-mail using a CGI script. formmail, from Matt Wright's Script Archive at http://www.worldwidemart.com/scripts/, is one such script. Visit Faulkner's Online Sweepstakes (see Fig. 11.1) at http://www.faulkner.com/form.html for a simple, effective sweepstakes.

Figure 11.1: Faulkner's Online Sweep-stakes.

A more elaborate example (still built using a mail form) is the Travel Channel's Ultimate World Tour '96 (see Fig. 11.2), at http://www.travelchannel.com/tv/travelus/ult96/. Travel Channel sponsors this contest each year, suggesting that the giveaway is meeting its expectations.

Figure 11.2: The Travel Channel's Ultimate World Tour '96.

The more elaborate contests may be thought of as having three purposes, each purpose requiring a different technical component.

Simple Promotion

Many contests are run for the purpose of getting the company's name before the public. This objective is best accomplished by heavy promotion, on and off line. Chapter 1, "How to Make a Good Site Look Great," contains pointers on announcing the site, and those pointers are of use here. For many businesses, general promotion of the contest may not be as effective as pinpoint promotion. Contests and free giveaways bring out the tire kickers-people who are interested in winning the prize but are not qualified prospects for a sale. Promote the contest in places where qualified prospects are concentrated. For example, a travel agency might announce its contest to travel-related UseNet groups and mailing lists (discreetly, of course, to avoid the appearance of spamming). Check with the moderator or list owner to make sure that such an announcement would be welcome. If the group is unmoderated, lurk for a while to get the tone of the group and then check with a few longtime members to see what they think before you announce.

Make sure the contest is easy to find-promote the contest in its own right, with a URL that goes straight to the contest page. From the contest page, provide lots of links back to the content portion of the site itself. See the Travel Channel's Ultimate World Tour, shown in Figure 11.3, as an example.

Figure 11.3: Travel Channel links from the contest page to the rest of the site.

Data Capture

A primary purpose of many sweepstakes is, of course, to gather data about the target audience. For many businesses, the cost of getting on the Web is quite small, but those businesses lack demographic information that would allow them to market as effectively as they would like.

A quick sweepstakes can serve as a poll, bringing in thousands of responses. Just remember that if the contest is promoted generally, the respondents may not be representative of the actual population that will visit your site and buy your product. This effect is reduced somewhat by promoting the sweepstakes primarily in those places where qualified prospects are to be found. If the prize is something that is mainly of interest to qualified buyers, the general population will tend to ignore the sweepstakes as well. For example, non-beekeepers are not likely to get too excited about winning one of those smoke generators that are used to quiet down the bees.

Just as with sweepstakes conducted by mail, you key the responses to find out where your online marketing is most effective. For example, if you promote a beekeeper's sweepstakes on the rec.beekeepers newsgroup (no, last time I checked, there wasn't such a newsgroup), you might give the URL as http://path/to/my/sweepstakes. cgi/ubk/. The sweepstakes.cgi script will be invoked, and the PATH_INFO variable will contain "ubk," letting you know that this person found out about the sweepstakes from the UseNet beekeeper's newsgroup.

Next, decide whether you want to merge all the results as the poll runs, or leave each result discrete and run statistical analyses on them. The first approach is easier on disk space; the second allows you to think up interesting questions and ask them of the database after the poll is over. For example, suppose the beekeepers survey turns up the fact that 80 percent of the respondents are interested in buying beekeeping supplies online, and that 20 percent of the respondents live outside the United States. You might not have anticipated such a large non-U.S. population. Now you would like to know how many of that subgroup are interested in buying online. If it is a large number, it may make sense for you to use one of the commerce systems that makes life easy for people outside the U.S. Perhaps you would like to go back and use the address field to find out how many of that subgroup are in Europe, Asia, South America, and so forth. If the data was merged as it came in, you may have to run another contest to get the answers.

On the other hand, keeping the raw data does take space. If you get 10,000 responses, and each response captures just 1,024 bytes of data, you are storing nearly 10 megabytes. One solution may be to store the raw data each day as it comes in, compress it, and archive it to tape. Have the script capture summary information. Then, when the survey is over, review the summary information and develop new questions to ask the data. Write or buy an analysis program that helps ask those questions, and feed the raw data back from the archive to the analysis tool.

For a simple example of a polling script, visit http://weber.u.washington.edu/~rif/whats_new_vote.html. Listing 11.1 shows the code to capture multiple-selection votes. This script is designed for use with the form at http:/weber.u. washington.edu/~rif/Simple_vote/poll1.html. For a look at that form, see Figure 11.4.

Figure 11.4: A polling form with radio buttons.


Listing 11.1  vote1.cgi-Keeps Track of Visitor's Votes, and Adapts for Use as a Data Collection Script in a Contest

#!/usr/local/bin/perl
###########################################################################
#
# Filename: vote1.cgi               
# Author: Richard Ian-Frese        
# e-mail: <a href="mailto:rif@u.washington.edu">rif@u.washington.edu</a>
# www: http://weber.u.washington.edu/~rif          
# Date created: November 17, 1995
# Last updated: March 5, 1996   
#
# Useage: This script receives and counts a multiple-selection vote cast 
# from an HTML form (you may view the form source code with your web 
# browser). It then returns to the voter, a simplified HTML table displaying 
# the updated  poll results, on-the-fly.  A number of support files will 
# automatically be created in the directory where this .cgi script resides.
#
# Note: For heavy useage, filelocking is recommended to insure a stable 
# database.  For light to moderate useage the program appears to function 
# reasonably well without filelocking. Controls such as voter password 
# registration/verification were not considered critical (we're not trying 
# to elect the President here).  Although a voter is eligible to vote 
# more than once in a particular poll, a simple error check is in place to 
# prevent chronic, empty string 'test' votes from adversely affecting the 
# poll outcome. Merely hitting the 'submit vote' button without casting a 
# vote for someone or something will result in a screen message, encouraging 
# (actually requiring) the voter to make a selection *before*
# being permitted to either view the current results or enter their 
# suggestions for alternative choices. This way survey questions are not 
# biased by the current voting trend.  Just keep in mind that no +/- 
# margin of voting error has been established or considered particularly
# important for the successful operation of this script (in other words, 
# don't take the stats too seriously).  Lastly, for simplicity and 
# speedy processing, each survey question maintains/updates it's own 
# database.  Successive survey questions may be hyperlinked together
# for continuity.
#
# Acknowledgments: Thanks to Nathan Dors @ UW/C&C for his kind assistance
# in tweaking the parameters. 
#
# Disclaimer:  This program is intended primarily as an example, 
# for users who want to learn to write Perl code for CGI scripts. It 
# remains freely available for personal (noncommercial) use as long as 
# this header remains intact. There are no expressed warranties implied or 
# otherwise stated. You may modify the code to suit your specific needs,
# however, running or reconfiguring the code contained herein is solely at 
# your own risk, discretion, and consequently, responsibility.
#
# Copyright (c)1995-96 Richard Ian-Frese                           
#
#############################################################################
require 'cgi-lib.pl';
select STDOUT;
# Force flushing of buffers upon write to insure reliable output
# when forking processes
$| = 1;
# This variable should reflect where you keep your file named "database1"
$database1 = "/www/d88/rif/Simple_vote/database1";
$date='date';
chop($date);
# Get input variables and environmental variables from httpd
&ReadParse;
# Return vote required message if empty string is submitted
if($in{"player"} eq "") {
        print "Content-type: text/html\n\n";
        print "<head><title>Vote Message</title></head><body>\n";
        print "<center><hr size=2 width=25%><h3>Your Vote Counts\n";
        print "</h3><hr size=2 width=25%><p>\n";
        print "To send a comment\n";
        print "or view the current poll stats,\n";
        print "your input is <i>required</i>.<p>\n";  
        print "Please <a href=\"poll1.html\">vote</a>!</center></body>";
exit; 
}
# Write forms information to "vote1.txt" file
$player = $in{"player"};
# Insure that all entries are output to table as lower case
$player =~ tr/A-Z/a-z/;
# Store and update vote stats
dbmopen(%keys,$database1,0644);
$count = $keys{$player}++;
dbmclose(%keys);
open(VOTE, ">>vote1.txt");
  print VOTE "\n$date\n";
  print VOTE "Remote Host: $ENV{\"REMOTE_HOST\"}\n";
  if ($in{"player"})   { print VOTE "Player: $in{\"player\"}\n"; } 
  if ($in{"comment"})  { print VOTE "Comment: $in{\"comment\"}\n"; } 
close(VOTE);
# Print output header and head section of HTML file
print "Content-type: text/html\n";
print "\n";
print "<HEAD><TITLE>Greatest Basketball Player 'Ever' Poll</TITLE></HEAD>\n";
# Print body of HTML file as a table-handle Netscape and LYNX formatting
print "<body><center><h3>GREATEST BASKETBALL PLAYER EVER</h3>\n"; 
print "<table border cellpadding=6 cellspacing=1>";
print "<caption><pre>Poll start: 05-Mar-96</caption><br>\n"; 
print "<tr><th align=right><b>PERCENT</b>   </th>";
print "<th align=right><b>VOTES</b>   <th align=left>";
print "  <b>PLAYER</b></th></tr><p>\n";
dbmopen(%player_database,$database1,0644);
while (($player,$count) = each(%player_database)){
 $total = $total + $count;
}
# Insure reversed numerical order of returned stats unless equal, then
# return alpha order
for each $name (reverse (sort by_count keys %player_database)) {
$percent = $player_database{$name} / $total *  (100);
printf ("<tr><td align=right> %4.1f</td>",$percent);
printf ("<td align=right>    %4d</td>",$player_database{$name});
printf ("<td align=left>       %-25s </td>",$name);
print "</tr>\n";
}
dbmclose(%keys);
print "<br><tr><th align=right>     TOTAL </th><th align=right>";
print "<b>$total</b></th></tr>\n";
print "</table></pre>\n";
# write to the administrator file named vote1view.txt 
# this file is used for viewing stats without casting a vote
open(VIEWVOTE, ">vote1view.txt");
  print VIEWVOTE "\n\n$date\n";
  print VIEWVOTE "Poll start date: 05-Mar-96\n"; 
  print VIEWVOTE "Total votes counted: $total\n";
  print VIEWVOTE "PERCENT";
  print VIEWVOTE "   VOTES";
  print VIEWVOTE "    PLAYER\n";
dbmopen(%player_database,$database1,0644);
while (($player,$count) = each(%player_database)){
 $total = ($total + $count);
}
foreach $name (reverse (sort by_count keys %player_database)) {
$percent = $player_database{$name} / $total *  (100);
  printf VIEWVOTE (" %4.1f",$percent);
  printf VIEWVOTE ("    %4d",$player_database{$name});
  printf VIEWVOTE ("       %-25s ",$name);
  print VIEWVOTE "\n";
}
dbmclose(%keys);
close(VIEWVOTE);
# This variable should reflect links to your comments page called
# "vote.txt" as well as the next, if any, survey question(s) in your poll
print "<p>[<A HREF=\"vote1.txt\">view the comments</A>]\n";
print "[<a href=\"poll.html\">go to next survey\n";
print "question]</a>]\n";
print "<p><hr size=2 width=42%><address><h6>&#169; 1995-96 Richard Ian-Frese";
print "<br><a href=\"mailto:rif@u.washington.edu\"> rif@u.washington.edu</a>";
print "</h6></address>";
# Insure numeric order of stats
sub by_count {
        ($player_database{$a} <=> $player_database{$b});
}
print "</center></body>\n";
# That's it!
exit 0;

Listing 11.2 shows a similar program from the same author; this one captures text-based data. It works with the HTML form at http://weber.u.washington.edu/~rif/Simple_vote/poll.html. Figure 11.5 shows that form.

Figure 11.5: Text fields can be used in a poll or contest to allow visitors to enter names, URLs, or other "write-in" material.


Listing 11.2  vote.cgi-Counts Text-Entry Votes

#!/usr/local/bin/perl
###########################################################################
#
# Filename: vote.cgi               
# Author: Richard Ian-Frese        
# e-mail: rif@u.washington.edu
# www: http://weber.u.washington.edu/~rif          
# Date created: November 17, 1995
# Last updated: March 5, 1996   
#
# Useage: This script receives and counts a text-entry vote cast 
# from an HTML form (you may view the form source code with your web 
# browser). It then returns to the voter, a simplified HTML table displaying 
# the updated  poll results, on-the-fly.  A number of support files will 
# automatically be created in the directory where this .cgi script resides.
#
# Note: For heavy useage, filelocking is recommended to insure a stable 
# database.  For light to moderate useage the program appears to function 
# reasonably well without filelocking. Controls such as voter password 
# registration/verification were not considered critical (we're not trying 
# to elect the President here).  Although a voter is eligible to vote 
# more than once in a particular poll, a simple error check is in place to 
# prevent chronic, empty string 'test' votes from adversely affecting the 
# poll outcome. Merely hitting the 'submit vote' button without casting a 
# vote for someone or something will result in a screen message, encouraging 
# (actually requiring) the voter to make a selection *before*
# being permitted to either view the current results or enter their 
# suggestions for alternative choices. This way survey questions are not 
# biased by the current voting trend.  Just keep in mind that no +/- 
# margin of voting error has been established or considered particularly
# important for the successful operation of this script (in other words, 
# don't take the stats too seriously).  Lastly, for simplicity and 
# speedy processing, each survey question maintains/updates it's own 
# database.  Successive survey questions may be hyperlinked together
# for continuity.
#
# Acknowledgments: Thanks to Nathan Dors @ UW-C&C for his kind assistance 
# in tweaking the parameters. 
# 
# Disclaimer:  This program is intended primarily as an example, 
# for users who want to learn to write Perl code for CGI scripts. It 
# remains freely available for personal (noncommercial) use as long as 
# this header remains intact. There are no expressed warranties implied or 
# otherwise stated. You may modify the code to suit your specific needs,
# however, running or reconfiguring the code contained herein is solely at 
# your own risk, discretion, and consequently, responsibility.
#
# Copyright (c)1995-96 Richard Ian-Frese                          
#
#############################################################################
require 'cgi-lib.pl';
select STDOUT;
# Force flushing of buffers upon write to insure reliable output
# when forking processes
$| = 1;
# This variable should reflect where *you* keep your file named "database"
$database = "/www/d88/rif/Simple_vote/database";
$date='date';
chop($date);
# Get input variables and environmental variables from httpd
&ReadParse;
# Return vote required message if empty string is submitted
if($in{"player"} eq "") {
        print "Content-type: text/html\n\n";
        print "<head><title>Vote Message</title></head><body>\n";
        print "<center><hr size=2 width=25%><h3>Your Vote Counts\n";
        print "</h3><hr size=2 width=25%><p>\n";
        print "To send a comment\n";
        print "or view the current poll stats,\n";
        print "your input is <i>required</i>.<p>\n";  
        print "Please <a href=\"poll.html\">vote</a>!</center></body>";
exit; 
}
# Write forms information to "vote.txt" file
$player = $in{"player"};
# Insure that all entries are output to table as lower case
$player =~ tr/A-Z/a-z/;
# Store and update vote stats
dbmopen(%keys,$database,0644);
$count = $keys{$player}++;
dbmclose(%keys);
open(VOTE, ">>vote.txt");
  print VOTE "\nDate: $date\n";
  print VOTE "Remote Host: $ENV{\"REMOTE_HOST\"}\n";
  if ($in{"player"})   { print VOTE "Player: $in{\"player\"}\n"; } 
  if ($in{"comment"})  { print VOTE "Comment: $in{\"comment\"}\n"; } 
close(VOTE);
# Print output header and head section of HTML file
print "Content-type: text/html\n";
print "\n";
print "<HEAD><TITLE>Greatest Basketball Player 'Ever' Poll</TITLE></HEAD>\n";
# Print body of HTML file as a table-handle Netscape and LYNX formatting
print "<body><center><h3>GREATEST BASKETBALL PLAYER EVER</h3>\n"; 
print "<table border cellpadding=6 cellspacing=1>";
print "<caption><pre>Poll start date: 05-Mar-96</caption><br>\n"; 
print "<tr><th align=right><b>PERCENT</b>   </th>";
print "<th align=right><b>VOTES</b>   <th align=left>";
print "  <b>PLAYER</b></th></tr><p>\n";
dbmopen(%player_database,$database,0644);
while (($player,$count) = each(%player_database)){
 $total = $total + $count;
}
# Insure reversed numerical order of returned stats unless equal, then
# return alpha order
foreach $name (reverse (sort by_count keys %player_database)) {
$percent = $player_database{$name} / $total *  (100);
printf ("<tr><td align=right> %4.1f</td>",$percent);
printf ("<td align=right>    %4d</td>",$player_database{$name});
printf ("<td align=left>       %-25s </td>",$name);
print "</tr>\n";
}
dbmclose(%keys);
print "<br><tr><th align=right>     TOTAL </th><th align=right>";
print "<b>$total</b></th></tr>\n";
print "</table></pre>\n";
# write to the administrator file named voteview.txt 
# this file is used for viewing stats without casting a vote
open(VIEWVOTE, ">voteview.txt");
  print VIEWVOTE "\n\n$date\n";
  print VIEWVOTE "Poll start date: 05-Mar-96\n"; 
  print VIEWVOTE "Total votes counted: $total\n";
  print VIEWVOTE "PERCENT";
  print VIEWVOTE "   VOTES";
  print VIEWVOTE "    PLAYER\n";
dbmopen(%player_database,$database,0644);
while (($player,$count) = each(%player_database)){
 $total = ($total + $count);
}
foreach $name (reverse (sort by_count keys %player_database)) {
$percent = $player_database{$name} / $total *  (100);
  printf VIEWVOTE (" %4.1f",$percent);
  printf VIEWVOTE ("    %4d",$player_database{$name});
  printf VIEWVOTE ("       %-25s ",$name);
  print VIEWVOTE "\n";
}
dbmclose(%keys);
close(VIEWVOTE);

# This variable should reflect links to your comments page called
# "vote.txt" as well as the next, if any, survey question(s) in your poll

print "<p>[<A HREF=\"vote.txt\">view the comments</A>]\n";
print "[<a href=\"poll1.html\">go to next survey\n";
print "question</a>]\n";
print "<p><hr size=2 width=42%><address><h6>&#169; 1995-96 Richard Ian-Frese";
print "<a href=\"mailto:rif@u.washington.edu\">"; 
print "<br>rif@u.washington.edu</a></address></h6>";
# Insure numeric order of stats
sub by_count {
        ($player_database{$a} <=> $player_database{$b});
}
print "</center></body>\n";
# That's it!
exit 0;

The preceding scripts are intended for informal polling, which is usually appropriate for contests and sweepstakes. The only limitation commonly placed on sweepstakes that should be enforced by the script is "one entry per person." This requirement could be met rather easily if you issue each respondent a Netscape cookie when the respondent enters the site. Then check for the presence of such a cookie before placing another entry in the database.

Note
Netscape cookies are introduced in Chapter 9, "How to Make a User's Life Simpler with Multipart Forms," and in more detail in Chapter 20, "Preserving Data" and Chapter 28, "Fully Integrated Shopping Environment."

Rather than (or in addition to) meeting this requirement at runtime, the system administrator can pass the completed file of contestants through the UNIX utility uniq. This utility eliminates duplicate lines in a sorted file, so someone who signed up twice with the same address and phone number only gets one chance in the drawing. To run uniq on a file called, say, sweepstakes.dat, type

sort sweepstakes.dat | uniq > uniqueSweepstakes.dat

Remember to eliminate any data, such as the date or time, which would make otherwise identical lines unique. If the fields are delimited by spaces or tabs and the unique fields are at the beginning of the line, substitute

uniq -n

for uniq in the line above. The -n option tells uniq to ignore the first n fields.

To restrict the contest to members of a certain group, consider issuing a password. Chapter 17, "How to Keep Portions of the Site Private," describes several methods for password-protecting portions of a site.

Awarding the Prize

While awarding the prize is not the primary purpose of the contest, if the prize is not awarded, the sweepstakes certainly loses its effectiveness (and the sweepstakes sponsors stand to lose more than that). Therefore, the sweepstakes CGI script must provide a clear audit path showing that each entry was treated in a fair and consistent manner, in accordance with the contest rules. One way to do this is to start with a simple mail form, like Formmail, and modify it to write the data to a disk file in addition to the mailer. The code fragment shown below does the job. We join the program after it has read the fields from STDIN into the associative array, FORM.

open (LOG,_">>sweepstakes.dat") || 
 &die("Sorry, an error has occurred.\n");
print LOG 
 "r{name}\t$FORM{address}\tFORM{phone}\t
  ...other information desired about each contestant...
  \n";
close(LOG);

This code fragment uses the subroutine die, introduced in Chapter 7. &die() does for CGI scripts what die does for Perl scripts in general: puts up an exit message and exits. &die() is useful because it knows how to "speak" HTML-its message constitutes a valid HTML page.

Each time the script with the preceding fragment is run, the information about the contestant is stripped out and appended to the sweepstakes file. On the day of the drawing, that file contains the pool of contestants.

Legal Issues

Nothing in this book should be considered as legal advice. The authors are not attorneys and are not qualified to address the variety of state and federal laws that bear on this topic. Before putting a contest on the Internet, get a qualified legal review to ensure that you have satisfied the law.

The folks at Arent, Fox, Kintner, Plotkin, and Kahn are lawyers-by all accounts, very good ones. They have prepared a review of the legal issues surrounding sweepstakes and contests. Their online article on the subject, prepared by Margo Block of their firm, is available at http://www.webcom.com:80/~lewrose/article/sweepmsb.html. While it is an excellent article, Arent Fox would be among the first to say that it is no substitute for sound legal advice. Before you run your contest, talk to your lawyer.

Recall that an illegal lottery is one in which contestants pay something of value in order to enter a game of chance. Here is the advice Arent Fox gives on how to make sure a game of skill demands skill:

Each state determines what information a contest sponsor must release. In a nationwide contest, the disclosure must satisfy the laws of each state. Typically, these laws require that the sponsors disclose the following:

In addition, Arent Fox recommends that the sponsors declare that the contest is "void where prohibited." If the sponsors are aware of states in which the contest would be prohibited, they should name those states. For example, if a game of skill has an entrance fee, Maryland requires that there be a free alternative method of entry.

A Worked Example

The broker at GSH has decided to offer a promotional sweepstakes. His objectives are to increase name recognition among online users and to capture demographic information about local Internet users. The prize, a trip to Hawaii, is intended to serve as a substantial incentive. On the advice of his attorney, he makes sure to include the contest rules and other disclosures online. He decides that no restrictions are necessary, except the requirement that each person enter the sweepstakes only once.

The Webmaster at GSH starts with Formmail, from Matt Wright's Script Archive. She modifies Formmail so that it appends the contact information (such as name, address, e-mail, and phone) to a "contestants" file. After the sweepstakes is over, she plans to filter that file through uniq to eliminate duplicates.

Next, she modifies Formmail so that it writes the raw data from the survey portion of the contest form to a "survey" file. This file has the fields separated by tabs, and the end of each record is marked by a newline (ASCII linefeed). She has statistical software that will read this format. This file may grow quite large-it comes from a multipart form and asks whether the respondent owns a home or rents, has children, and so forth. Depending upon their answers, respondents are steered to a page that asks them to elaborate. A typical respondent answers a dozen questions and generates about 100 bytes of survey data. The Webmaster doesn't expect the file to grow larger than about a megabyte, and she has plenty of room on the hard disk, but she resolves to watch the file, nonetheless.

Finally, the Webmaster incorporates a summary mechanism like those shown in the polling scripts. Instead of sending the results back to the user, however, she sends them to a Thank You page. Then she adapts part of the polling script to read the results and e-mail them to her every night, from the cron table. Now she can start giving management feedback on the contest each morning, even before the sweepstakes is over.