package CGI;
require 5.004;
use Carp 'croak';

# See the bottom of this file for the POD documentation.  Search for the
# string '=head'.

# You can run this file through either pod2man or pod2html to produce pretty
# documentation in manual or html file format (these utilities are part of the
# Perl 5 distribution).

# Copyright 1995-1998 Lincoln D. Stein.  All rights reserved.
# It may be used and modified freely, but I do request that this copyright
# notice remain attached to the file.  You may modify this module as you 
# wish, but if you redistribute a modified version, please attach a note
# listing the modifications you have made.

# The most recent version and complete docs are available at:
#   http://stein.cshl.org/WWW/software/CGI/

$CGI::revision = '$Id: CGI.pm,v 1.127 2003/06/18 19:57:21 lstein Exp $';
$CGI::VERSION='2.98';

# HARD-CODED LOCATION FOR FILE UPLOAD TEMPORARY FILES.
# UNCOMMENT THIS ONLY IF YOU KNOW WHAT YOU'RE DOING.
# $CGITempFile::TMPDIRECTORY = '/usr/tmp';
use CGI::Util qw(rearrange make_attributes unescape escape expires);

#use constant XHTML_DTD => ['-//W3C//DTD XHTML Basic 1.0//EN',
#                           'http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd'];

use constant XHTML_DTD => ['-//W3C//DTD XHTML 1.0 Transitional//EN',
                           'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'];

{
  local $^W = 0;
  $TAINTED = substr("$0$^X",0,0);
}

my @SAVED_SYMBOLS;

$MOD_PERL = 0; # no mod_perl by default

# >>>>> Here are some globals that you might want to adjust 1)
    $NPH = 0;

    # Set this to 1 to enable debugging from @ARGV
    # Set to 2 to enable debugging from STDIN
    $DEBUG = 1;

    # Set this to 1 to make the temporary files created
    # during file uploads safe from prying eyes
    # or do...
    #    1) use CGI qw(:private_tempfiles)
    #    2) CGI::private_tempfiles(1);
    $PRIVATE_TEMPFILES = 0;

    # Set this to 1 to cause files uploaded in multipart documents
    # to be closed, instead of caching the file handle
    # or:
    #    1) use CGI qw(:close_upload_files)
    #    2) $CGI::close_upload_files(1);
    # Uploads with many files run out of file handles.
    # Also, for performance, since the file is already on disk,
    # it can just be renamed, instead of read and written.
    $CLOSE_UPLOAD_FILES = 0;

    # Set this to a positive value to limit the size of a POSTing
    # to a certain number of bytes:
    $POST_MAX = -1;

    # Change this to 1 to disable uploads entirely:
    $DISABLE_UPLOADS = 0;

    # Automatically determined -- don't change
    $EBCDIC = 0;

    # Change this to 1 to suppress redundant HTTP headers
    $HEADERS_ONCE = 0;

    # separate the name=value pairs by semicolons rather than ampersands
    $USE_PARAM_SEMICOLONS = 1;

    # Do not include undefined params parsed from query string
    # use CGI qw(-no_undef_params);
    $NO_UNDEF_PARAMS = 0;

    # Other globals that you shouldn't worry about.
    undef $Q;
    $BEEN_THERE = 0;
    undef @QUERY_PARAM;
    undef %EXPORT;
    undef $QUERY_CHARSET;
    undef %QUERY_FIELDNAMES;

    # prevent complaints by mod_perl
    1;
}

# ------------------ START OF THE LIBRARY ------------

# make mod_perlhappy
initialize_globals();

# FIGURE OUT THE OS WE'RE RUNNING UNDER
# Some systems support the $^O variable.  If not
# available then require() the Config library
unless ($OS) {
    unless ($OS = $^O) {
  require Config;
  $OS = $Config::Config{'osname'};
    }
}
if ($OS =~ /^MSWin/i) {
  $OS = 'WINDOWS';
} elsif ($OS =~ /^VMS/i) {
  $OS = 'VMS';
} elsif ($OS =~ /^dos/i) {
  $OS = 'DOS';
} elsif ($OS =~ /^MacOS/i) {
    $OS = 'MACINTOSH';
} elsif ($OS =~ /^os2/i) {
    $OS = 'OS2';
} elsif ($OS =~ /^epoc/i) {
    $OS = 'EPOC';
} elsif ($OS =~ /^cygwin/i) {
    $OS = 'CYGWIN';
} else {
    $OS = 'UNIX';
}

# Some OS logic.  Binary mode enabled on DOS, NT and VMS
$needs_binmode = $OS=~/^(WINDOWS|DOS|OS2|MSWin|CYGWIN)/;

# This is the default class for the CGI object to use when all else fails.
$DefaultClass = 'CGI' unless defined $CGI::DefaultClass;

# This is where to look for autoloaded routines.
$AutoloadClass = $DefaultClass unless defined $CGI::AutoloadClass;

# The path separator is a slash, backslash or semicolon, depending
# on the paltform.
$SL = {
     UNIX    => '/',  OS2 => '\\', EPOC      => '/', CYGWIN => '/',
     WINDOWS => '\\', DOS => '\\', MACINTOSH => ':', VMS    => '/'
    }->{$OS};

# This no longer seems to be necessary
# Turn on NPH scripts by default when running under IIS server!
# $NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/;
$IIS++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/;

# Turn on special checking for Doug MacEachern's modperl
if (exists $ENV{MOD_PERL}) {
  eval "require mod_perl";
  # mod_perl handlers may run system() on scripts using CGI.pm;
  # Make sure so we don't get fooled by inherited $ENV{MOD_PERL}
  if (defined $mod_perl::VERSION) {
    if ($mod_perl::VERSION >= 1.99) {
      $MOD_PERL = 2;
      require Apache::RequestRec;
      require Apache::RequestUtil;
      require APR::Pool;
    } else {
      $MOD_PERL = 1;
      require Apache;
    }
  }
}

# Turn on special checking for ActiveState's PerlEx
$PERLEX++ if defined($ENV{'GATEWAY_INTERFACE'}) && $ENV{'GATEWAY_INTERFACE'} =~ /^CGI-PerlEx/;

# Define the CRLF sequence.  I can't use a simple "\r\n" because the meaning
# of "\n" is different on different OS's (sometimes it generates CRLF, sometimes LF
# and sometimes CR).  The most popular VMS web server
# doesn't accept CRLF -- instead it wants a LR.  EBCDIC machines don't
# use ASCII, so \015\012 means something different.  I find this all 
# really annoying.
$EBCDIC = "\t" ne "\011";
if ($OS eq 'VMS') {
  $CRLF = "\n";
} elsif ($EBCDIC) {
  $CRLF= "\r\n";
} else {
  $CRLF = "\015\012";
}

if ($needs_binmode) {
    $CGI::DefaultClass->binmode(main::STDOUT);
    $CGI::DefaultClass->binmode(main::STDIN);
    $CGI::DefaultClass->binmode(main::STDERR);
}

%EXPORT_TAGS = (
    ':html2'=>['h1'..'h6',qw/p br hr ol ul li dl dt dd menu code var strong em
         tt u i b blockquote pre img a address cite samp dfn html head
         base body Link nextid title meta kbd start_html end_html
         input Select option comment charset escapeHTML/],
    ':html3'=>[qw/div table caption th td TR Tr sup Sub strike applet Param 
         embed basefont style span layer ilayer font frameset frame script small big Area Map/],
                ':html4'=>[qw/abbr acronym bdo col colgroup del fieldset iframe
                            ins label legend noframes noscript object optgroup Q 
                            thead tbody tfoot/], 
    ':netscape'=>[qw/blink fontsize center/],
    ':form'=>[qw/textfield textarea filefield password_field hidden checkbox checkbox_group 
        submit reset defaults radio_group popup_menu button autoEscape
        scrolling_list image_button start_form end_form startform endform
        start_multipart_form end_multipart_form isindex tmpFileName uploadInfo URL_ENCODED MULTIPART/],
    ':cgi'=>[qw/param upload path_info path_translated url self_url script_name cookie Dump
       raw_cookie request_method query_string Accept user_agent remote_host content_type
       remote_addr referer server_name server_software server_port server_protocol
       virtual_host remote_ident auth_type http
       save_parameters restore_parameters param_fetch
       remote_user user_name header redirect import_names put 
       Delete Delete_all url_param cgi_error/],
    ':ssl' => [qw/https/],
    ':cgi-lib' => [qw/ReadParse PrintHeader HtmlTop HtmlBot SplitParam Vars/],
    ':html' => [qw/:html2 :html3 :html4 :netscape/],
    ':standard' => [qw/:html2 :html3 :html4 :form :cgi/],
    ':push' => [qw/multipart_init multipart_start multipart_end multipart_final/],
    ':all' => [qw/:html2 :html3 :netscape :form :cgi :internal :html4/]
    );

# to import symbols into caller
sub import {
    my $self = shift;

    # This causes modules to clash.
    undef %EXPORT_OK;
    undef %EXPORT;

    $self->_setup_symbols(@_);
    my ($callpack, $callfile, $callline) = caller;

    # To allow overriding, search through the packages
    # Till we find one in which the correct subroutine is defined.
    my @packages = ($self,@{"$self\:\:ISA"});
    foreach $sym (keys %EXPORT) {
  my $pck;
  my $def = ${"$self\:\:AutoloadClass"} || $DefaultClass;
  foreach $pck (@packages) {
      if (defined(&{"$pck\:\:$sym"})) {
    $def = $pck;
    last;
      }
  }
  *{"${callpack}::$sym"} = \&{"$def\:\:$sym"};
    }
}

sub compile {
    my $pack = shift;
    $pack->_setup_symbols('-compile',@_);
}

sub expand_tags {
    my($tag) = @_;
    return ("start_$1","end_$1") if $tag=~/^(?:\*|start_|end_)(.+)/;
    my(@r);
    return ($tag) unless $EXPORT_TAGS{$tag};
    foreach (@{$EXPORT_TAGS{$tag}}) {
  push(@r,&expand_tags($_));
    }
    return @r;
}

#### Method: new
# The new routine.  This will check the current environment
# for an existing query string, and initialize itself, if so.
####
sub new {
  my($class,@initializer) = @_;
  my $self = {};
  bless $self,ref $class || $class || $DefaultClass;
  if (ref($initializer[0])
      && (UNIVERSAL::isa($initializer[0],'Apache')
    ||
    UNIVERSAL::isa($initializer[0],'Apache::RequestRec')
   )) {
    $self->r(shift @initializer);
  }
  if ($MOD_PERL) {
    $self->r(Apache->request) unless $self->r;
    my $r = $self->r;
    if ($MOD_PERL == 1) {
      $r->register_cleanup(\&CGI::_reset_globals);
    }
    else {
      # XXX: once we have the new API
      # will do a real PerlOptions -SetupEnv check
      $r->subprocess_env unless exists $ENV{REQUEST_METHOD};
      $r->pool->cleanup_register(\&CGI::_reset_globals);
    }
    undef $NPH;
  }
  $self->_reset_globals if $PERLEX;
  $self->init(@initializer);
  return $self;
}

# We provide a DESTROY method so that the autoloader
# doesn't bother trying to find it.
sub DESTROY { }

sub r {
  my $self = shift;
  my $r = $self->{'.r'};
  $self->{'.r'} = shift if @_;
  $r;
}

#### Method: param
# Returns the value(s)of a named parameter.
# If invoked in a list context, returns the
# entire list.  Otherwise returns the first
# member of the list.
# If name is not provided, return a list of all
# the known parameters names available.
# If more than one argument is provided, the
# second and subsequent arguments are used to
# set the value of the parameter.
####
sub param {
    my($self,@p) = self_or_default(@_);
    return $self->all_parameters unless @p;
    my($name,$value,@other);

    # For compatibility between old calling style and use_named_parameters() style, 
    # we have to special case for a single parameter present.
    if (@p > 1) {
  ($name,$value,@other) = rearrange([NAME,[DEFAULT,VALUE,VALUES]],@p);
  my(@values);

  if (substr($p[0],0,1) eq '-') {
      @values = defined($value) ? (ref($value) && ref($value) eq 'ARRAY' ? @{$value} : $value) : ();
  } else {
      foreach ($value,@other) {
    push(@values,$_) if defined($_);
      }
  }
  # If values is provided, then we set it.
  if (@values) {
      $self->add_parameter($name);
      $self->{$name}=[@values];
  }
    } else {
  $name = $p[0];
    }

    return unless defined($name) && $self->{$name};
    return wantarray ? @{$self->{$name}} : $self->{$name}->[0];
}

sub self_or_default {
    return @_ if defined($_[0]) && (!ref($_[0])) &&($_[0] eq 'CGI');
    unless (defined($_[0]) && 
      (ref($_[0]) eq 'CGI' || UNIVERSAL::isa($_[0],'CGI')) # slightly optimized for common case
      ) {
  $Q = $CGI::DefaultClass->new unless defined($Q);
  unshift(@_,$Q);
    }
    return wantarray ? @_ : $Q;
}

sub self_or_CGI {
    local $^W=0;                # prevent a warning
    if (defined($_[0]) &&
  (substr(ref($_[0]),0,3) eq 'CGI' 
   || UNIVERSAL::isa($_[0],'CGI'))) {
  return @_;
    } else {
  return ($DefaultClass,@_);
    }
}

########################################
# THESE METHODS ARE MORE OR LESS PRIVATE
# GO TO THE __DATA__ SECTION TO SEE MORE
# PUBLIC METHODS
########################################

# Initialize the query object from the environment.
# If a parameter list is found, this object will be set
# to an associative array in which parameter names are keys
# and the values are stored as lists
# If a keyword list is found, this method creates a bogus
# parameter list with the single parameter 'keywords'.

sub init {
  my $self = shift;
  my($query_string,$meth,$content_length,$fh,@lines) = ('','','','');

  my $initializer = shift;  # for backward compatibility
  local($/) = "\n";

    # set autoescaping on by default
    $self->{'escape'} = 1;

    # if we get called more than once, we want to initialize
    # ourselves from the original query (which may be gone
    # if it was read from STDIN originally.)
    if (defined(@QUERY_PARAM) && !defined($initializer)) {
  foreach (@QUERY_PARAM) {
      $self->param('-name'=>$_,'-value'=>$QUERY_PARAM{$_});
  }
  $self->charset($QUERY_CHARSET);
  $self->{'.fieldnames'} = {%QUERY_FIELDNAMES};
  return;
    }

    $meth=$ENV{'REQUEST_METHOD'} if defined($ENV{'REQUEST_METHOD'});
    $content_length = defined($ENV{'CONTENT_LENGTH'}) ? $ENV{'CONTENT_LENGTH'} : 0;

    $fh = to_filehandle($initializer) if $initializer;

    # set charset to the safe ISO-8859-1
    $self->charset('ISO-8859-1');

  METHOD: {

      # avoid unreasonably large postings
      if (($POST_MAX > 0) && ($content_length > $POST_MAX)) {
  # quietly read and discard the post
    my $buffer;
    my $max = $content_length;
    while ($max > 0 && (my $bytes = read(STDIN,$buffer,$max cgi_error("413 Request entity too large");
    last METHOD;
      }

      # Process multipart postings, but only if the initializer is
      # not defined.
      if ($meth eq 'POST'
    && defined($ENV{'CONTENT_TYPE'})
    && $ENV{'CONTENT_TYPE'}=~m|^multipart/form-data|
    && !defined($initializer)
    ) {
    my($boundary) = $ENV{'CONTENT_TYPE'} =~ /boundary=\"?([^\";,]+)\"?/;
    $self->read_multipart($boundary,$content_length);
    last METHOD;
      } 

      # If initializer is defined, then read parameters
      # from it.
      if (defined($initializer)) {
    if (UNIVERSAL::isa($initializer,'CGI')) {
        $query_string = $initializer->query_string;
        last METHOD;
    }
    if (ref($initializer) && ref($initializer) eq 'HASH') {
        foreach (keys %$initializer) {
      $self->param('-name'=>$_,'-value'=>$initializer->{$_});
        }
        last METHOD;
    }
    
    if (defined($fh) && ($fh ne '')) {
        while () {
      chomp;
      last if /^=/;
      push(@lines,$_);
        }
        # massage back into standard format
        if ("@lines" =~ /=/) {
      $query_string=join("&",@lines);
        } else {
      $query_string=join("+",@lines);
        }
        last METHOD;
    }

    # last chance -- treat it as a string
    $initializer = $$initializer if ref($initializer) eq 'SCALAR';
    $query_string = $initializer;

    last METHOD;
      }

      # If method is GET or HEAD, fetch the query from
      # the environment.
      if ($meth=~/^(GET|HEAD)$/) {
    if ($MOD_PERL) {
      $query_string = $self->r->args;
    } else {
        $query_string = $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
        $query_string ||= $ENV{'REDIRECT_QUERY_STRING'} if defined $ENV{'REDIRECT_QUERY_STRING'};
    }
    last METHOD;
      }

      if ($meth eq 'POST') {
    $self->read_from_client(\*STDIN,\$query_string,$content_length,0)
        if $content_length > 0;
    # Some people want to have their cake and eat it too!
    # Uncomment this line to have the contents of the query string
    # APPENDED to the POST data.
    # $query_string .= (length($query_string) ? '&' : '') . $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
    last METHOD;
      }

      # If $meth is not of GET, POST or HEAD, assume we're being debugged offline.
      # Check the command line and then the standard input for data.
      # We use the shellwords package in order to behave the way that
      # UN*X programmers expect.
      $query_string = read_from_cmdline() if $DEBUG;
  }

# YL: Begin Change for XML handler 10/19/2001
    if ($meth eq 'POST'
        && defined($ENV{'CONTENT_TYPE'})
        && $ENV{'CONTENT_TYPE'} !~ m|^application/x-www-form-urlencoded|
  && $ENV{'CONTENT_TYPE'} !~ m|^multipart/form-data| ) {
        my($param) = 'POSTDATA' ;
        $self->add_parameter($param) ;
      push (@{$self->{$param}},$query_string);
      undef $query_string ;
    }
# YL: End Change for XML handler 10/19/2001

    # We now have the query string in hand.  We do slightly
    # different things for keyword lists and parameter lists.
    if (defined $query_string && length $query_string) {
  if ($query_string =~ /[&=;]/) {
      $self->parse_params($query_string);
  } else {
      $self->add_parameter('keywords');
      $self->{'keywords'} = [$self->parse_keywordlist($query_string)];
  }
    }

    # Special case.  Erase everything if there is a field named
    # .defaults.
    if ($self->param('.defaults')) {
  undef %{$self};
    }

    # Associative array containing our defined fieldnames
    $self->{'.fieldnames'} = {};
    foreach ($self->param('.cgifields')) {
  $self->{'.fieldnames'}->{$_}++;
    }
    
    # Clear out our default submission button flag if present
    $self->delete('.submit');
    $self->delete('.cgifields');

    $self->save_request unless defined $initializer;
}

# FUNCTIONS TO OVERRIDE:
# Turn a string into a filehandle
sub to_filehandle {
    my $thingy = shift;
    return undef unless $thingy;
    return $thingy if UNIVERSAL::isa($thingy,'GLOB');
    return $thingy if UNIVERSAL::isa($thingy,'FileHandle');
    if (!ref($thingy)) {
  my $caller = 1;
  while (my $package = caller($caller++)) {
      my($tmp) = $thingy=~/[\':]/ ? $thingy : "$package\:\:$thingy"; 
      return $tmp if defined(fileno($tmp));
  }
    }
    return undef;
}

# send output to the browser
sub put {
    my($self,@p) = self_or_default(@_);
    $self->print(@p);
}

# print to standard output (for overriding in mod_perl)
sub print {
    shift;
    CORE::print(@_);
}

# get/set last cgi_error
sub cgi_error {
    my ($self,$err) = self_or_default(@_);
    $self->{'.cgi_error'} = $err if defined $err;
    return $self->{'.cgi_error'};
}

sub save_request {
    my($self) = @_;
    # We're going to play with the package globals now so that if we get called
    # again, we initialize ourselves in exactly the same way.  This allows
    # us to have several of these objects.
    @QUERY_PARAM = $self->param; # save list of parameters
    foreach (@QUERY_PARAM) {
      next unless defined $_;
      $QUERY_PARAM{$_}=$self->{$_};
    }
    $QUERY_CHARSET = $self->charset;
    %QUERY_FIELDNAMES = %{$self->{'.fieldnames'}};
}

sub parse_params {
    my($self,$tosplit) = @_;
    my(@pairs) = split(/[&;]/,$tosplit);
    my($param,$value);
    foreach (@pairs) {
  ($param,$value) = split('=',$_,2);
  next unless defined $param;
  next if $NO_UNDEF_PARAMS and not defined $value;
  $value = '' unless defined $value;
  $param = unescape($param);
  $value = unescape($value);
  $self->add_parameter($param);
  push (@{$self->{$param}},$value);
    }
}

sub add_parameter {
    my($self,$param)=@_;
    return unless defined $param;
    push (@{$self->{'.parameters'}},$param) 
  unless defined($self->{$param});
}

sub all_parameters {
    my $self = shift;
    return () unless defined($self) && $self->{'.parameters'};
    return () unless @{$self->{'.parameters'}};
    return @{$self->{'.parameters'}};
}

# put a filehandle into binary mode (DOS)
sub binmode {
    CORE::binmode($_[1]);
}

sub _make_tag_func {
    my ($self,$tagname) = @_;
    my $func = qq(
  sub $tagname {
         my (\$q,\$a,\@rest) = self_or_default(\@_);
         my(\$attr) = '';
   if (ref(\$a) && ref(\$a) eq 'HASH') {
      my(\@attr) = make_attributes(\$a,\$q->{'escape'});
      \$attr = " \@attr" if \@attr;
    } else {
      unshift \@rest,\$a if defined \$a;
    }
  );
    if ($tagname=~/start_(\w+)/i) {
  $func .= qq! return "";} !;
    } elsif ($tagname=~/end_(\w+)/i) {
  $func .= qq! return ""; } !;
    } else {
  $func .= qq#
      return \$XHTML ? "\L" : "\L" unless \@rest;
      my(\$tag,\$untag) = ("\L","\L\E");
      my \@result = map { "\$tag\$_\$untag" } 
                              (ref(\$rest[0]) eq 'ARRAY') ? \@{\$rest[0]} : "\@rest";
      return "\@result";
            }#;
    }
return $func;
}

sub AUTOLOAD {
    print STDERR "CGI::AUTOLOAD for $AUTOLOAD\n" if $CGI::AUTOLOAD_DEBUG;
    my $func = &_compile;
    goto &$func;
}

sub _compile {
    my($func) = $AUTOLOAD;
    my($pack,$func_name);
    {
  local($1,$2); # this fixes an obscure variable suicide problem.
  $func=~/(.+)::([^:]+)$/;
  ($pack,$func_name) = ($1,$2);
  $pack=~s/::SUPER$//;  # fix another obscure problem
  $pack = ${"$pack\:\:AutoloadClass"} || $CGI::DefaultClass
      unless defined(${"$pack\:\:AUTOLOADED_ROUTINES"});

        my($sub) = \%{"$pack\:\:SUBS"};
        unless (%$sub) {
     my($auto) = \${"$pack\:\:AUTOLOADED_ROUTINES"};
     eval "package $pack; $$auto";
     croak("$AUTOLOAD: $@") if $@;
           $$auto = '';  # Free the unneeded storage (but don't undef it!!!)
       }
       my($code) = $sub->{$func_name};

       $code = "sub $AUTOLOAD { }" if (!$code and $func_name eq 'DESTROY');
       if (!$code) {
     (my $base = $func_name) =~ s/^(start_|end_)//i;
     if ($EXPORT{':any'} || 
         $EXPORT{'-any'} ||
         $EXPORT{$base} || 
         (%EXPORT_OK || grep(++$EXPORT_OK{$_},&expand_tags(':html')))
             && $EXPORT_OK{$base}) {
         $code = $CGI::DefaultClass->_make_tag_func($func_name);
     }
       }
       croak("Undefined subroutine $AUTOLOAD\n") unless $code;
       eval "package $pack; $code";
       if ($@) {
     $@ =~ s/ at .*\n//;
     croak("$AUTOLOAD: $@");
       }
    }       
    CORE::delete($sub->{$func_name});  #free storage
    return "$pack\:\:$func_name";
}

sub _selected {
  my $self = shift;
  my $value = shift;
  return '' unless $value;
  return $XHTML ? qq( selected="selected") : qq( selected);
}

sub _checked {
  my $self = shift;
  my $value = shift;
  return '' unless $value;
  return $XHTML ? qq( checked="checked") : qq( checked);
}

sub _reset_globals { initialize_globals(); }

sub _setup_symbols {
    my $self = shift;
    my $compile = 0;

    # to avoid reexporting unwanted variables
    undef %EXPORT;

    foreach (@_) {
  $HEADERS_ONCE++,         next if /^[:-]unique_headers$/;
  $NPH++,                  next if /^[:-]nph$/;
  $NOSTICKY++,             next if /^[:-]nosticky$/;
  $DEBUG=0,                next if /^[:-]no_?[Dd]ebug$/;
  $DEBUG=2,                next if /^[:-][Dd]ebug$/;
  $USE_PARAM_SEMICOLONS++, next if /^[:-]newstyle_urls$/;
  $XHTML++,                next if /^[:-]xhtml$/;
  $XHTML=0,                next if /^[:-]no_?xhtml$/;
  $USE_PARAM_SEMICOLONS=0, next if /^[:-]oldstyle_urls$/;
  $PRIVATE_TEMPFILES++,    next if /^[:-]private_tempfiles$/;
    $CLOSE_UPLOAD_FILES++,   next if /^[:-]close_upload_files$/;
  $EXPORT{$_}++,           next if /^[:-]any$/;
  $compile++,              next if /^[:-]compile$/;
  $NO_UNDEF_PARAMS++,      next if /^[:-]no_undef_params$/;
  
  # This is probably extremely evil code -- to be deleted some day.
  if (/^[-]autoload$/) {
      my($pkg) = caller(1);
      *{"${pkg}::AUTOLOAD"} = sub { 
    my($routine) = $AUTOLOAD;
    $routine =~ s/^.*::/CGI::/;
    &$routine;
      };
      next;
  }

  foreach (&expand_tags($_)) {
      tr/a-zA-Z0-9_//cd;  # don't allow weird function names
      $EXPORT{$_}++;
  }
    }
    _compile_all(keys %EXPORT) if $compile;
    @SAVED_SYMBOLS = @_;
}

sub charset {
  my ($self,$charset) = self_or_default(@_);
  $self->{'.charset'} = $charset if defined $charset;
  $self->{'.charset'};
}

###############################################################################
################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND ####################
###############################################################################
$AUTOLOADED_ROUTINES = '';      # get rid of -w warning
$AUTOLOADED_ROUTINES=    new($self,$boundary,$length,$filehandle);
}
END_OF_FUNC

'read_from_client' =>  {$name};
        CORE::delete $self->{'.fieldnames'}->{$name};
        $to_delete{$name}++;
    }
    @{$self->{'.parameters'}}=grep { !exists($to_delete{$_}) } $self->param();
    return wantarray ? () : undef;
}
END_OF_FUNC

#### Method: import_names
# Import all parameters into the given namespace.
# Assumes namespace 'Q' if not specified
####
'import_names' => param) {
  # protect against silly names
  ($var = $param)=~tr/a-zA-Z0-9_/_/c;
  $var =~ s/^(?=\d)/_/;
  local *symbol = "${namespace}::$var";
  @value = $self->param($param);
  @symbol = @value;
  $symbol = $value[0];
    }
}
END_OF_FUNC

#### Method: keywords
# Keywords acts a bit differently.  Calling it in a list context
# returns the list of keywords.  
# Calling it in a scalar context gives you the size of the list.
####
'keywords' => {'keywords'}=[@values] if @values;
    my(@result) = defined($self->{'keywords'}) ? @{$self->{'keywords'}} : ();
    @result;
}
END_OF_FUNC

# These are some tie() interfaces for compatibility
# with Steve Brenner's cgi-lib.pl routines
'Vars' =>   header();
}
END_OF_FUNC

'HtmlTop' => start_html(@p);
}
END_OF_FUNC

'HtmlBot' => end_html(@p);
}
END_OF_FUNC

'SplitParam' =>    new(@_);
}
END_OF_FUNC

'STORE' => param(-name=>$tag,-value=>\@vals);
}
END_OF_FUNC

'FETCH' => param($_[1]);
    return join("\0",$_[0]->param($_[1]));
}
END_OF_FUNC

'FIRSTKEY' => {'.iterator'}=0;
    $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++];
}
END_OF_FUNC

'NEXTKEY' => {'.parameters'}->[$_[0]->{'.iterator'}++];
}
END_OF_FUNC

'EXISTS' => {$_[1]};
}
END_OF_FUNC

'DELETE' => delete($_[1]);
}
END_OF_FUNC

'CLEAR' =>  add_parameter($name);
  push(@{$self->{$name}},@values);
    }
    return $self->param($name);
}
EOF

#### Method: delete_all
# Delete all parameters
####
'delete_all' => param();
    $self->delete(@param);
}
EOF

'Delete' => delete(@p);
}
EOF

'Delete_all' => delete_all(@p);
}
EOF

#### Method: autoescape
# If you want to turn off the autoescaping features,
# call this method with undef as the argument
'autoEscape' => {'escape'};
    $self->{'escape'} = $escape;
    $d;
}
END_OF_FUNC


#### Method: version
# Return the current version
####
'version' =>  {'.url_param'})) {
  $self->{'.url_param'}={}; # empty hash
  if ($ENV{QUERY_STRING} =~ /=/) {
      my(@pairs) = split(/[&;]/,$ENV{QUERY_STRING});
      my($param,$value);
      foreach (@pairs) {
    ($param,$value) = split('=',$_,2);
    $param = unescape($param);
    $value = unescape($value);
    push(@{$self->{'.url_param'}->{$param}},$value);
      }
  } else {
      $self->{'.url_param'}->{'keywords'} = [$self->parse_keywordlist($ENV{QUERY_STRING})];
  }
    }
    return keys %{$self->{'.url_param'}} unless defined($name);
    return () unless $self->{'.url_param'}->{$name};
    return wantarray ? @{$self->{'.url_param'}->{$name}}
                     : $self->{'.url_param'}->{$name}->[0];
}
END_OF_FUNC

#### Method: Dump
# Returns a string in which all the known parameter/value 
# pairs are represented as nested lists, mainly for the purposes 
# of debugging.
####
'Dump' => ' unless $self->param;
    push(@result,"");
    foreach $param ($self->param) {
  my($name)=$self->escapeHTML($param);
  push(@result,"$param");
  push(@result,"");
  foreach $value ($self->param($param)) {
      $value = $self->escapeHTML($value);
            $value =~ s/\n/\n/g;
      push(@result,"$value");
  }
  push(@result,"");
    }
    push(@result,"");
    return join("\n",@result);
}
END_OF_FUNC

#### Method as_string
#
# synonym for "dump"
####
'as_string' =>  param) {
  my($escaped_param) = escape($param);
  my($value);
  foreach $value ($self->param($param)) {
      print $filehandle "$escaped_param=",escape("$value"),"\n";
  }
    }
    foreach (keys %{$self->{'.fieldnames'}}) {
          print $filehandle ".cgifields=",escape("$_"),"\n";
    }
    print $filehandle "=\n";    # end of record
}
END_OF_FUNC


#### Method: save_parameters
# An alias for save() that is a better name for exportation.
# Only intended to be used with the function (non-OO) interface.
####
'save_parameters' =>  new(@_);
}
END_OF_FUNC

#### Method: multipart_init
# Return a Content-Type: style header for server-push
# This has to be NPH on most web servers, and it is advisable to set $| = 1
#
# Many thanks to Ed Jordan  for this
# contribution, updated by Andrew Benham (adsb@bigfoot.com)
####
'multipart_init' => {'separator'} = "$CRLF--$boundary$CRLF";
    $self->{'final_separator'} = "$CRLF--$boundary--$CRLF";
    $type = SERVER_PUSH($boundary);
    return $self->header(
  -nph => 1,
  -type => $type,
  (map { split "=", $_, 2 } @other),
    ) . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $self->multipart_end;
}
END_OF_FUNC


#### Method: multipart_start
# Return a Content-Type: style header for server-push, start of section
#
# Many thanks to Ed Jordan  for this
# contribution, updated by Andrew Benham (adsb@bigfoot.com)
####
'multipart_start' => unescapeHTML($value)/e;
    }
    push(@header,@other);
    my $header = join($CRLF,@header)."${CRLF}${CRLF}";
    return $header;
}
END_OF_FUNC


#### Method: multipart_end
# Return a MIME boundary separator for server-push, end of section
#
# Many thanks to Ed Jordan  for this
# contribution
####
'multipart_end' => {'separator'};
}
END_OF_FUNC


#### Method: multipart_final
# Return a MIME boundary separator for server-push, end of all sections
#
# Contributed by Andrew Benham (adsb@bigfoot.com)
####
'multipart_final' => {'final_separator'} . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $CRLF;
}
END_OF_FUNC


#### Method: header
# Return a Content-Type: style header
#
####
'header' => {'.header_printed'}++ and $HEADERS_ONCE;

    my($type,$status,$cookie,$target,$expires,$nph,$charset,$attachment,$p3p,@other) = 
  rearrange([['TYPE','CONTENT_TYPE','CONTENT-TYPE'],
          'STATUS',['COOKIE','COOKIES'],'TARGET',
                            'EXPIRES','NPH','CHARSET',
                            'ATTACHMENT','P3P'],@p);

    $nph     ||= $NPH;
    if (defined $charset) {
      $self->charset($charset);
    } else {
      $charset = $self->charset;
    }

    # rearrange() was designed for the HTML portion, so we
    # need to fix it up a little.
    foreach (@other) {
        # Don't use \s because of perl bug 21951
        next unless my($header,$value) = /([^ \r\n\t=]+)=\"?(.+?)\"?$/;
        ($_ = $header) =~ s/^(\w)(.*)/"\u$1\L$2" . ': '.$self->unescapeHTML($value)/e;
    }

    $type ||= 'text/html' unless defined($type);
    $type .= "; charset=$charset" if $type ne '' and $type =~ m!^text/! and $type !~ /\bcharset\b/ and $charset ne '';

    # Maybe future compatibility.  Maybe not.
    my $protocol = $ENV{SERVER_PROTOCOL} || 'HTTP/1.0';
    push(@header,$protocol . ' ' . ($status || '200 OK')) if $nph;
    push(@header,"Server: " . &server_software()) if $nph;

    push(@header,"Status: $status") if $status;
    push(@header,"Window-Target: $target") if $target;
    if ($p3p) {
       $p3p = join ' ',@$p3p if ref($p3p) eq 'ARRAY';
       push(@header,qq(P3P: policyref="/w3c/p3p.xml", CP="$p3p"));
    }
    # push all the cookies -- there may be several
    if ($cookie) {
  my(@cookie) = ref($cookie) && ref($cookie) eq 'ARRAY' ? @{$cookie} : $cookie;
  foreach (@cookie) {
            my $cs = UNIVERSAL::isa($_,'CGI::Cookie') ? $_->as_string : $_;
      push(@header,"Set-Cookie: $cs") if $cs ne '';
  }
    }
    # if the user indicates an expiration time, then we need
    # both an Expires and a Date header (so that the browser is
    # uses OUR clock)
    push(@header,"Expires: " . expires($expires,'http'))
  if $expires;
    push(@header,"Date: " . expires(0,'http')) if $expires || $cookie || $nph;
    push(@header,"Pragma: no-cache") if $self->cache();
    push(@header,"Content-Disposition: attachment; filename=\"$attachment\"") if $attachment;
    push(@header,map {ucfirst $_} @other);
    push(@header,"Content-Type: $type") if $type ne '';
    my $header = join($CRLF,@header)."${CRLF}${CRLF}";
    if ($MOD_PERL and not $nph) {
        $self->r->send_cgi_header($header);
        return '';
    }
    return $header;
}
END_OF_FUNC


#### Method: cache
# Control whether header() will produce the no-cache
# Pragma directive.
####
'cache' => {'cache'} = $new_value;
    }
    return $self->{'cache'};
}
END_OF_FUNC


#### Method: redirect
# Return a Location: style header
#
####
'redirect' => self_url;
    my(@o);
    foreach (@other) { tr/\"//d; push(@o,split("=",$_,2)); }
    unshift(@o,
   '-Status'  => '302 Moved',
   '-Location'=> $url,
   '-nph'     => $nph);
    unshift(@o,'-Target'=>$target) if $target;
    unshift(@o,'-Type'=>'');
    my @unescaped;
    unshift(@unescaped,'-Cookie'=>$cookie) if $cookie;
    return $self->header((map {$self->unescapeHTML($_)} @o),@unescaped);
}
END_OF_FUNC


#### Method: start_html
# Canned HTML header
#
# Parameters:
# $title -> (optional) The title for this HTML document (-title)
# $author -> (optional) e-mail address of the author (-author)
# $base -> (optional) if set to true, will enter the BASE address of this document
#          for resolving relative references (-base) 
# $xbase -> (optional) alternative base at some remote location (-xbase)
# $target -> (optional) target window to load all links into (-target)
# $script -> (option) Javascript code (-script)
# $no_script -> (option) Javascript  tag (-noscript)
# $meta -> (optional) Meta information tags
# $head -> (optional) any other elements you'd like to incorporate into the  tag
#           (a scalar or array ref)
# $style -> (optional) reference to an external style sheet
# @other -> (optional) any other named parameters you'd like to incorporate into
#           the  tag.
####
'start_html' => escapeHTML($title || 'Untitled Document');
    $author = $self->escape($author);
    $lang = 'en-US' unless defined $lang;
    my(@result,$xml_dtd);
    if ($dtd) {
        if (defined(ref($dtd)) and (ref($dtd) eq 'ARRAY')) {
            $dtd = $DEFAULT_DTD unless $dtd->[0] =~ m|^-//|;
        } else {
            $dtd = $DEFAULT_DTD unless $dtd =~ m|^-//|;
        }
    } else {
        $dtd = $XHTML ? XHTML_DTD : $DEFAULT_DTD;
    }

    $xml_dtd++ if ref($dtd) eq 'ARRAY' && $dtd->[0] =~ /\bXHTML\b/i;
    $xml_dtd++ if ref($dtd) eq '' && $dtd =~ /\bXHTML\b/i;
    push @result,qq() if $xml_dtd; 

    if (ref($dtd) && ref($dtd) eq 'ARRAY') {
        push(@result,qq([0]"\n\t "$dtd->[1]">));
    } else {
        push(@result,qq());
    }
    push(@result,$XHTML ? qq($title)
                        : ($lang ? qq() : "") 
                    . "$title");
  if (defined $author) {
    push(@result,$XHTML ? ""
                : "");
  }

    if ($base || $xbase || $target) {
  my $href = $xbase || $self->url('-path'=>1);
  my $t = $target ? qq/ target="$target"/ : '';
  push(@result,$XHTML ? qq() : qq());
    }

    if ($meta && ref($meta) && (ref($meta) eq 'HASH')) {
  foreach (keys %$meta) { push(@result,$XHTML ? qq() 
      : qq()); }
    }

    push(@result,ref($head) ? @$head : $head) if $head;

    # handle the infrequently-used -style and -script parameters
    push(@result,$self->_style($style)) if defined $style;
    push(@result,$self->_script($script)) if defined $script;

    # handle -noscript parameter
    push(@result,
$noscript

END
    ;
    my($other) = @other ? " @other" : '';
    push(@result,"");
    return join("\n",@result);
}
END_OF_FUNC

### Method: _style
# internal method for generating a CSS style section
####
'_style' =>  */-->\n" : " -->\n";

    if (ref($style)) {
     my($src,$code,$verbatim,$stype,$foo,@other) =
         rearrange([SRC,CODE,VERBATIM,TYPE],
                    '-foo'=>'bar',    # trick to allow dash to be omitted
                    ref($style) eq 'ARRAY' ? @$style : %$style);
     $type  = $stype if $stype;
     my $other = @other ? join ' ',@other : '';

     if (ref($src) eq "ARRAY") # Check to see if the $src variable is an array reference
     { # If it is, push a LINK tag for each one
         foreach $src (@$src)
       {
         push(@result,$XHTML ? qq()
                             : qq()) if $src;
       }
     }
     else
     { # Otherwise, push the single -src, if it exists.
       push(@result,$XHTML ? qq()
                           : qq()
            ) if $src;
      }
      if ($verbatim) {
         push(@result, "\n$verbatim\n");
    }
      push(@result,style({'type'=>$type},"$cdata_start\n$code\n$cdata_end")) if $code;
    } else {
         my $src = $style;
         push(@result,$XHTML ? qq()
                             : qq());
    }
    @result;
}
END_OF_FUNC

'_script' => 'bar', # a trick to allow the '-' to be omitted
         ref($script) eq 'ARRAY' ? @$script : %$script);
            # User may not have specified language
            $language ||= 'JavaScript';
            unless (defined $type) {
                $type = lc $language;
                # strip '1.2' from 'javascript1.2'
                $type =~ s/^(\D+).*$/text\/$1/;
            }
  } else {
      ($src,$code,$language, $type) = ('',$script,'JavaScript', 'text/javascript');
  }

    my $comment = '//';  # javascript by default
    $comment = '#' if $type=~/perl|tcl/i;
    $comment = "'" if $type=~/vbscript/i;

    my ($cdata_start,$cdata_end);
    if ($XHTML) {
       $cdata_start    = "$comment$src) if $src;
     push(@satts,'language'=>$language) unless defined $type;
     push(@satts,'type'=>$type);
     $code = "$cdata_start$code$cdata_end" if defined $code;
     push(@result,script({@satts},$code || ''));
    }
    @result;
}
END_OF_FUNC

#### Method: end_html
# End an HTML document.
# Trivial method for completeness.  Just returns ""
####
'end_html' => ";
}
END_OF_FUNC


################################
# METHODS USED IN BUILDING FORMS
################################

#### Method: isindex
# Just prints out the isindex tag.
# Parameters:
#  $action -> optional URL of script to run
# Returns:
#   A string containing a  tag
'isindex' => " : "";
}
END_OF_FUNC


#### Method: startform
# Start a form
# Parameters:
#   $method -> optional submission method to use (GET or POST)
#   $action -> optional URL of script to run
#   $enctype ->encoding to use (URL_ENCODED or MULTIPART)
'startform' => url(-absolute=>1,-path=>1);
       if (length($ENV{QUERY_STRING})>0) {
           $action .= "?$ENV{QUERY_STRING}";
       }
    }
    $action =~ s/\"/%22/g;  # fix cross-site scripting bug reported by obscure
    $action = qq(action="$action");
    my($other) = @other ? " @other" : '';
    $self->{'.parametersToAdd'}={};
    return qq/\n/;
}
END_OF_FUNC


#### Method: start_form
# synonym for startform
'start_form' =>   startform(%p);
    } else {
  my($method,$action,@other) = 
      rearrange([METHOD,ACTION],@p);
  return $self->startform($method,$action,&MULTIPART,@other);
    }
}
END_OF_FUNC


#### Method: endform
# End a form
'endform' => ") : "\n";
    } else {
    return wantarray ? ("",$self->get_fields,"","") : 
                        "".$self->get_fields ."\n";
    }
}
END_OF_FUNC


#### Method: end_form
# synonym for endform
'end_form' =>  param($name)) ? $self->param($name) : $default);

    $current = defined($current) ? $self->escapeHTML($current,1) : '';
    $name = defined($name) ? $self->escapeHTML($name) : '';
    my($s) = defined($size) ? qq/ size="$size"/ : '';
    my($m) = defined($maxlength) ? qq/ maxlength="$maxlength"/ : '';
    my($other) = @other ? " @other" : '';
    # this entered at cristy's request to fix problems with file upload fields
    # and WebTV -- not sure it won't break stuff
    my($value) = $current ne '' ? qq(value="$current") : '';
    return $XHTML ? qq() 
                  : qq();
}
END_OF_FUNC

#### Method: textfield
# Parameters:
#   $name -> Name of the text field
#   $default -> Optional default value of the field if not
#                already defined.
#   $size ->  Optional width of field in characaters.
#   $maxlength -> Optional maximum number of characters.
# Returns:
#   A string containing a  field
#
'textfield' => _textfield('text',@p);
}
END_OF_FUNC


#### Method: filefield
# Parameters:
#   $name -> Name of the file upload field
#   $size ->  Optional width of field in characaters.
#   $maxlength -> Optional maximum number of characters.
# Returns:
#   A string containing a  field
#
'filefield' => _textfield('file',@p);
}
END_OF_FUNC


#### Method: password
# Create a "secret password" entry field
# Parameters:
#   $name -> Name of the field
#   $default -> Optional default value of the field if not
#                already defined.
#   $size ->  Optional width of field in characters.
#   $maxlength -> Optional maximum characters that can be entered.
# Returns:
#   A string containing a  field
#
'password_field' => _textfield('password',@p);
}
END_OF_FUNC

#### Method: textarea
# Parameters:
#   $name -> Name of the text field
#   $default -> Optional default value of the field if not
#                already defined.
#   $rows ->  Optional number of rows in text area
#   $columns -> Optional number of columns in text area
# Returns:
#   A string containing a  tag
#
'textarea' => param($name)) ? $self->param($name) : $default);

    $name = defined($name) ? $self->escapeHTML($name) : '';
    $current = defined($current) ? $self->escapeHTML($current) : '';
    my($r) = $rows ? qq/ rows="$rows"/ : '';
    my($c) = $cols ? qq/ cols="$cols"/ : '';
    my($other) = @other ? " @other" : '';
    return qq{$current};
}
END_OF_FUNC


#### Method: button
# Create a javascript button.
# Parameters:
#   $name ->  (optional) Name for the button. (-name)
#   $value -> (optional) Value of the button when selected (and visible name) (-value)
#   $onclick -> (optional) Text of the JavaScript to run when the button is
#                clicked.
# Returns:
#   A string containing a  tag
####
'button' => escapeHTML($label);
    $value=$self->escapeHTML($value,1);
    $script=$self->escapeHTML($script);

    my($name) = '';
    $name = qq/ name="$label"/ if $label;
    $value = $value || $label;
    my($val) = '';
    $val = qq/ value="$value"/ if $value;
    $script = qq/ onclick="$script"/ if $script;
    my($other) = @other ? " @other" : '';
    return $XHTML ? qq()
                  : qq();
}
END_OF_FUNC


#### Method: submit
# Create a "submit query" button.
# Parameters:
#   $name ->  (optional) Name for the button.
#   $value -> (optional) Value of the button when selected (also doubles as label).
#   $label -> (optional) Label printed on the button(also doubles as the value).
# Returns:
#   A string containing a  tag
####
'submit' => escapeHTML($label);
    $value=$self->escapeHTML($value,1);

    my($name) = ' name=".submit"' unless $NOSTICKY;
    $name = qq/ name="$label"/ if defined($label);
    $value = defined($value) ? $value : $label;
    my $val = '';
    $val = qq/ value="$value"/ if defined($value);
    my($other) = @other ? " @other" : '';
    return $XHTML ? qq()
                  : qq();
}
END_OF_FUNC


#### Method: reset
# Create a "reset" button.
# Parameters:
#   $name -> (optional) Name for the button.
# Returns:
#   A string containing a  tag
####
'reset' => escapeHTML($label);
    $value=$self->escapeHTML($value,1);
    my ($name) = ' name=".reset"';
    $name = qq/ name="$label"/ if defined($label);
    $value = defined($value) ? $value : $label;
    my($val) = '';
    $val = qq/ value="$value"/ if defined($value);
    my($other) = @other ? " @other" : '';
    return $XHTML ? qq()
                  : qq();
}
END_OF_FUNC


#### Method: defaults
# Create a "defaults" button.
# Parameters:
#   $name -> (optional) Name for the button.
# Returns:
#   A string containing a  tag
#
# Note: this button has a special meaning to the initialization script,
# and tells it to ERASE the current query string so that your defaults
# are used again!
####
'defaults' => escapeHTML($label,1);
    $label = $label || "Defaults";
    my($value) = qq/ value="$label"/;
    my($other) = @other ? " @other" : '';
    return $XHTML ? qq()
                  : qq//;
}
END_OF_FUNC


#### Method: comment
# Create an HTML 
# Parameters: a string
'comment' => ";
}
END_OF_FUNC

#### Method: checkbox
# Create a checkbox that is not logically linked to any others.
# The field value is "on" when the button is checked.
# Parameters:
#   $name -> Name of the checkbox
#   $checked -> (optional) turned on by default if true
#   $value -> (optional) value of the checkbox, 'on' by default
#   $label -> (optional) a user-readable label printed next to the box.
#             Otherwise the checkbox name is used.
# Returns:
#   A string containing a  field
####
'checkbox' => {'.fieldnames'}->{$name} || 
           defined $self->param($name))) {
  $checked = grep($_ eq $value,$self->param($name)) ? $self->_checked(1) : '';
    } else {
  $checked = $self->_checked($checked);
    }
    my($the_label) = defined $label ? $label : $name;
    $name = $self->escapeHTML($name);
    $value = $self->escapeHTML($value,1);
    $the_label = $self->escapeHTML($the_label);
    my($other) = @other ? " @other" : '';
    $self->register_parameter($name);
    return $XHTML ? qq{$the_label}
                  : qq{$the_label};
}
END_OF_FUNC


#### Method: checkbox_group
# Create a list of logically-linked checkboxes.
# Parameters:
#   $name -> Common name for all the check boxes
#   $values -> A pointer to a regular array containing the
#             values for each checkbox in the group.
#   $defaults -> (optional)
#             1. If a pointer to a regular array of checkbox values,
#             then this will be used to decide which
#             checkboxes to turn on by default.
#             2. If a scalar, will be assumed to hold the
#             value of a single checkbox in the group to turn on. 
#   $linebreak -> (optional) Set to true to place linebreaks
#             between the buttons.
#   $labels -> (optional)
#             A pointer to an associative array of labels to print next to each checkbox
#             in the form $label{'value'}="Long explanatory label".
#             Otherwise the provided values are used as the labels.
# Returns:
#   An ARRAY containing a series of  fields
####
'checkbox_group' => previous_or_default($name,$defaults,$override);

  if ($linebreak) {
    $break = $XHTML ? "" : "";
  }
  else {
  $break = '';
  }
    $name=$self->escapeHTML($name);

    # Create the elements
    my(@elements,@values);

    @values = $self->_set_values_and_labels($values,\$labels,$name);

    my($other) = @other ? " @other" : '';
    foreach (@values) {
  $checked = $self->_checked($checked{$_});
  $label = '';
  unless (defined($nolabels) && $nolabels) {
      $label = $_;
      $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
      $label = $self->escapeHTML($label);
  }
        my $attribs = $self->_set_attributes($_, $attributes);
  $_ = $self->escapeHTML($_,1);
        push(@elements,$XHTML ? qq(${label}${break})
                              : qq/${label}${break}/);
    }
    $self->register_parameter($name);
    return wantarray ? @elements : join(' ',@elements)            
        unless defined($columns) || defined($rows);
    $rows = 1 if $rows && $rows  {'escape'};
         $toencode =~ s{&}{&}gso;
         $toencode =~ s{}{>}gso;
         $toencode =~ s{"}{"}gso;
         my $latin = uc $self->{'.charset'} eq 'ISO-8859-1' ||
                     uc $self->{'.charset'} eq 'WINDOWS-1252';
         if ($latin) {  # bug in some browsers
                $toencode =~ s{'}{'}gso;
                $toencode =~ s{\x8b}{‹}gso;
                $toencode =~ s{\x9b}{›}gso;
                if (defined $newlinestoo && $newlinestoo) {
                     $toencode =~ s{\012}{
}gso;
                     $toencode =~ s{\015}{
}gso;
                }
         }
         return $toencode;
}
END_OF_FUNC

# unescape HTML -- used internally
'unescapeHTML' => {'.charset'} ? $self->{'.charset'} =~ /^(ISO-8859-1|WINDOWS-1252)$/i
                                            : 1;
    # thanks to Randal Schwartz for the correct solution to this one
    $string=~ s[&(.*?);]{
  local $_ = $1;
  /^amp$/i  ? "&" :
  /^quot$/i ? '"' :
        /^gt$/i   ? ">" :
  /^lt$/i   ? " "
    if defined($elements[$column*$rows + $row]);
  }
  $result .= "";
    }
    $result .= "";
    return $result;
}
END_OF_FUNC


#### Method: radio_group
# Create a list of logically-linked radio buttons.
# Parameters:
#   $name -> Common name for all the buttons.
#   $values -> A pointer to a regular array containing the
#             values for each button in the group.
#   $default -> (optional) Value of the button to turn on by default.  Pass '-'
#               to turn _nothing_ on.
#   $linebreak -> (optional) Set to true to place linebreaks
#             between the buttons.
#   $labels -> (optional)
#             A pointer to an associative array of labels to print next to each checkbox
#             in the form $label{'value'}="Long explanatory label".
#             Otherwise the provided values are used as the labels.
# Returns:
#   An ARRAY containing a series of  fields
####
'radio_group' => param($name))) {
  $checked = $self->param($name);
    } else {
  $checked = $default;
    }
    my(@elements,@values);
    @values = $self->_set_values_and_labels($values,\$labels,$name);

    # If no check array is specified, check the first by default
    $checked = $values[0] unless defined($checked) && $checked ne '';
    $name=$self->escapeHTML($name);

    my($other) = @other ? " @other" : '';
    foreach (@values) {
  my($checkit) = $checked eq $_ ? qq/ checked="checked"/ : '';
  my($break);
  if ($linebreak) {
          $break = $XHTML ? "" : "";
  }
  else {
    $break = '';
  }
  my($label)='';
  unless (defined($nolabels) && $nolabels) {
      $label = $_;
      $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
      $label = $self->escapeHTML($label,1);
  }
  my $attribs = $self->_set_attributes($_, $attributes);
  $_=$self->escapeHTML($_);
  push(@elements,$XHTML ? qq(${label}${break})
                              : qq/${label}${break}/);
    }
    $self->register_parameter($name);
    return wantarray ? @elements : join(' ',@elements) 
           unless defined($columns) || defined($rows);
    return _tableize($rows,$columns,$rowheaders,$colheaders,@elements);
}
END_OF_FUNC


#### Method: popup_menu
# Create a popup menu.
# Parameters:
#   $name -> Name for all the menu
#   $values -> A pointer to a regular array containing the
#             text of each menu item.
#   $default -> (optional) Default item to display
#   $labels -> (optional)
#             A pointer to an associative array of labels to print next to each checkbox
#             in the form $label{'value'}="Long explanatory label".
#             Otherwise the provided values are used as the labels.
# Returns:
#   A string containing the definition of a popup menu.
####
'popup_menu' => param($name))) {
  $selected = $self->param($name);
    } else {
  $selected = $default;
    }
    $name=$self->escapeHTML($name);
    my($other) = @other ? " @other" : '';

    my(@values);
    @values = $self->_set_values_and_labels($values,\$labels,$name);

    $result = qq/\n/;
    foreach (@values) {
        if (/_set_attributes($_, $attributes);
  my($selectit) = defined($selected) ? $self->_selected($selected eq $_) : '';
  my($label) = $_;
  $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
  my($value) = $self->escapeHTML($_);
  $label=$self->escapeHTML($label,1);
            $result .= "$label\n";
        }
    }

    $result .= "";
    return $result;
}
END_OF_FUNC


#### Method: optgroup
# Create a optgroup.
# Parameters:
#   $name -> Label for the group
#   $values -> A pointer to a regular array containing the
#              values for each option line in the group.
#   $labels -> (optional)
#              A pointer to an associative array of labels to print next to each item
#              in the form $label{'value'}="Long explanatory label".
#              Otherwise the provided values are used as the labels.
#   $labeled -> (optional)
#               A true value indicates the value should be used as the label attribute
#               in the option elements.
#               The label attribute specifies the option label presented to the user.
#               This defaults to the content of the  element, but the label
#               attribute allows authors to more easily use optgroup without sacrificing
#               compatibility with browsers that do not support option groups.
#   $novals -> (optional)
#              A true value indicates to suppress the val attribute in the option elements
# Returns:
#   A string containing the definition of an option group.
####
'optgroup' => _set_values_and_labels($values,\$labels,$name,$labeled,$novals);
    my($other) = @other ? " @other" : '';

    $name=$self->escapeHTML($name);
    $result = qq/\n/;
    foreach (@values) {
        if (/_set_attributes($_, $attributes);
            my($label) = $_;
            $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
            $label=$self->escapeHTML($label);
            my($value)=$self->escapeHTML($_,1);
            $result .= $labeled ? $novals ? "$label\n"
                                          : "$label\n"
                                : $novals ? "$label\n"
                                          : "$label\n";
        }
    }
    $result .= "";
    return $result;
}
END_OF_FUNC


#### Method: scrolling_list
# Create a scrolling list.
# Parameters:
#   $name -> name for the list
#   $values -> A pointer to a regular array containing the
#             values for each option line in the list.
#   $defaults -> (optional)
#             1. If a pointer to a regular array of options,
#             then this will be used to decide which
#             lines to turn on by default.
#             2. Otherwise holds the value of the single line to turn on.
#   $size -> (optional) Size of the list.
#   $multiple -> (optional) If set, allow multiple selections.
#   $labels -> (optional)
#             A pointer to an associative array of labels to print next to each checkbox
#             in the form $label{'value'}="Long explanatory label".
#             Otherwise the provided values are used as the labels.
# Returns:
#   A string containing the definition of a scrolling list.
####
'scrolling_list' => _set_values_and_labels($values,\$labels,$name);

    $size = $size || scalar(@values);

    my(%selected) = $self->previous_or_default($name,$defaults,$override);
    my($is_multiple) = $multiple ? qq/ multiple="multiple"/ : '';
    my($has_size) = $size ? qq/ size="$size"/: '';
    my($other) = @other ? " @other" : '';

    $name=$self->escapeHTML($name);
    $result = qq/\n/;
    foreach (@values) {
  my($selectit) = $self->_selected($selected{$_});
  my($label) = $_;
  $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
  $label=$self->escapeHTML($label);
  my($value)=$self->escapeHTML($_,1);
        my $attribs = $self->_set_attributes($_, $attributes);
        $result .= "$label\n";
    }
    $result .= "";
    $self->register_parameter($name);
    return $result;
}
END_OF_FUNC


#### Method: hidden
# Parameters:
#   $name -> Name of the hidden field
#   @default -> (optional) Initial values of field (may be an array)
#      or
#   $default->[initial values of field]
# Returns:
#   A string containing a 
####
'hidden' =>