Apache-ASP

 view release on metacpan or  search on metacpan

ASP.pm  view on Meta::CPAN

functionality is here for compatibility with raw cgi scripts,
and those used to this kind of coding.

When set to 0, CgiHeaders style headers will not be parsed from the 
script response.

  PerlSetVar CgiHeaders 0

=item Clean

default 0, may be set between 1 and 9.  This setting determine how much
text/html output should be compressed.  A setting of 1 strips mostly
white space saving usually 10% in output size, at a performance cost
of less than 5%.  A setting of 9 goes much further saving anywhere
25% to 50% typically, but with a performance hit of 50%.

This config option is implemented via HTML::Clean.  Per script
configuration of this setting is available via the $Response->{Clean}
property, which may also be set between 0 and 9.

  PerlSetVar Clean 0

=item CompressGzip

default 0, if true will gzip compress HTML output on the
fly if Compress::Zlib is installed, and the client browser
supports it.  Depending on the HTML being compressed, 
the client may see a 50% to 90% reduction in HTML output.
I have seen 40K of HTML squeezed down to just under 6K.
This will come at a 5%-20% hit to CPU usage per request
compressed.

Note there are some cases when a browser says it will accept
gzip encoding, but then not render it correctly.  This
behavior has been seen with IE5 when set to use a proxy but 
not using a proxy, and the URL does not end with a .html or .htm.
No work around has yet been found for this case so use at your 
own risk.

  PerlSetVar CompressGzip 1

=item FormFill

default 0, if true will auto fill HTML forms with values
from $Request->Form().  This functionality is provided
by use of HTML::FillInForm.  For more information please
see "perldoc HTML::FillInForm", and the 
example ./site/eg/formfill.asp.  

This feature can be enabled on a per form basis at runtime
with $Response->{FormFill} = 1

  PerlSetVar FormFill 1

=item TimeHiRes

default 0, if set and Time::HiRes is installed, will do 
sub second timing of the time it takes Apache::ASP to process
a request.  This will not include the time spent in the 
session manager, nor modperl or Apache, and is only a 
rough approximation at best.

If Debug is set also, you will get a comment in your
HTML output that indicates the time it took to process
that script.

If system debugging is set with Debug -1 or -2, you will
also get this time in the Apache error log with the 
other system messages.

=head2 Mail Administration

Apache::ASP has some powerful administrative email
extensions that let you sleep at night, knowing full well
that if an error occurs at the web site, you will know
about it immediately.  With these features already enabled,
it was also easy to provide the $Server->Mail(\%mail) API 
extension which you can read up about in the OBJECTS section.

=item MailHost

The mail host is the smtp server that the below Mail* config directives
will use when sending their emails.  By default Net::SMTP uses
smtp mail hosts configured in Net::Config, which is set up at
install time, but this setting can be used to override this config.

The mail hosts specified in the Net::Config file will be used as
backup smtp servers to the MailHost specified here, should this
primary server not be working.

  PerlSetVar MailHost smtp.yourdomain.com.foobar

=item MailFrom

Default NONE, set this to specify the default mail address placed 
in the From: mail header for the $Server->Mail() API extension, 
as well as MailErrorsTo and MailAlertTo.

  PerlSetVar MailFrom youremail@yourdomain.com.foobar

=item MailErrorsTo

No default, if set, ASP server errors, error code 500, that result
while compiling or running scripts under Apache::ASP will automatically
be emailed to the email address set for this config.  This allows
an administrator to have a rapid response to user generated server
errors resulting from bugs in production ASP scripts.  Other errors, such 
as 404 not found will be handled by Apache directly.

An easy way to see this config in action is to have an ASP script which calls
a die(), which generates an internal ASP 500 server error.

The Debug config of value 2 and this setting are mutually exclusive,
as Debug 2 is a development setting where errors are displayed in the browser,
and MailErrorsTo is a production setting so that errors are silently logged
and sent via email to the web admin.

  PerlSetVar MailErrorsTo youremail@yourdomain.com

=item MailAlertTo

ASP.pm  view on Meta::CPAN

call binmode on a file handle before reading, if 
its data is binary.

=item $Response->Clear()

Erases buffered ASP output.

=item $Response->Cookies($name, [$key,] $value)

Sets the key or attribute of cookie with name $name to the value $value.
If $key is not defined, the Value of the cookie is set.
ASP CookiePath is assumed to be / in these examples.

 $Response->Cookies('name', 'value'); 
  --> Set-Cookie: name=value; path=/

 $Response->Cookies("Test", "data1", "test value");     
 $Response->Cookies("Test", "data2", "more test");      
 $Response->Cookies(
	"Test", "Expires", 
	&HTTP::Date::time2str(time+86400)
	); 
 $Response->Cookies("Test", "Secure", 1);               
 $Response->Cookies("Test", "Path", "/");
 $Response->Cookies("Test", "Domain", "host.com");
  -->	Set-Cookie:Test=data1=test%20value&data2=more%20test;	\
 		expires=Fri, 23 Apr 1999 07:19:52 GMT;		\
 		path=/; domain=host.com; secure

The latter use of $key in the cookies not only sets cookie attributes
such as Expires, but also treats the cookie as a hash of key value pairs
which can later be accesses by

 $Request->Cookies('Test', 'data1');
 $Request->Cookies('Test', 'data2');

Because this is perl, you can (NOT PORTABLE) reference the cookies
directly through hash notation.  The same 5 commands above could be compressed to:

 $Response->{Cookies}{Test} = 
	{ 
		Secure	=> 1, 
		Value	=>	
			{
				data1 => 'test value', 
				data2 => 'more test'
			},
		Expires	=> 86400, # not portable, see above
		Domain	=> 'host.com',
		Path    => '/'
	};

and the first command would be:

 # you don't need to use hash notation when you are only setting 
 # a simple value
 $Response->{Cookies}{'Test Name'} = 'Test Value'; 

I prefer the hash notation for cookies, as this looks nice, and is 
quite perlish.  It is here to stay.  The Cookie() routine is 
very complex and does its best to allow access to the 
underlying hash structure of the data.  This is the best emulation 
I could write trying to match the Collections functionality of 
cookies in IIS ASP.

For more information on Cookies, please go to the source at
http://home.netscape.com/newsref/std/cookie_spec.html

=item $Response->Debug(@args)

API Extension. If the Debug config option is set greater than 0, 
this routine will write @args out to server error log.  refs in @args 
will be expanded one level deep, so data in simple data structures
like one-level hash refs and array refs will be displayed.  CODE
refs like

 $Response->Debug(sub { "some value" });

will be executed and their output added to the debug output.
This extension allows the user to tie directly into the
debugging capabilities of this module.

While developing an app on a production server, it is often 
useful to have a separate error log for the application
to catch debugging output separately.  One way of implementing 
this is to use the Apache ErrorLog configuration directive to 
create a separate error log for a virtual host. 

If you want further debugging support, like stack traces
in your code, consider doing things like:

 $Response->Debug( sub { Carp::longmess('debug trace') };
 $SIG{__WARN__} = \&Carp::cluck; # then warn() will stack trace

The only way at present to see exactly where in your script
an error occurred is to set the Debug config directive to 2,
and match the error line number to perl script generated
from your ASP script.  

However, as of version 0.10, the perl script generated from the 
asp script should match almost exactly line by line, except in 
cases of inlined includes, which add to the text of the original script, 
pod comments which are entirely yanked out, and <% # comment %> style
comments which have a \n added to them so they still work.

If you would like to see the HTML preceding an error 
while developing, consider setting the BufferingOn 
config directive to 0.

=item $Response->End()

Sends result to client, and immediately exits script.
Automatically called at end of script, if not already called.

=item $Response->ErrorDocument($code, $uri)

API extension that allows for the modification the Apache
ErrorDocument at runtime.  $uri may be a on site document,
off site URL, or string containing the error message.  

This extension is useful if you want to have scripts
set error codes with $Response->{Status} like 401

ASP.pm  view on Meta::CPAN

string data.

=item $Request->ServerVariables($name)

Returns the value of the server variable / environment variable
with name $name.  If $name is not specified, returns a ref to 
a hash of all the server / environment variables data.  The following
would be a common use of this method:

 $env = $Request->ServerVariables();
 # %{$env} here would be equivalent to the cgi %ENV in perl.

=back

=head2 $Application Object

Like the $Session object, you may use the $Application object to 
store data across the entire life of the application.  Every
page in the ASP application always has access to this object.
So if you wanted to keep track of how many visitors there where
to the application during its lifetime, you might have a line
like this:

 $Application->{num_users}++

The Lock and Unlock methods are used to prevent simultaneous 
access to the $Application object.

=over

=item $Application->Lock()

Locks the Application object for the life of the script, or until
UnLock() unlocks it, whichever comes first.  When $Application
is locked, this guarantees that data being read and written to it 
will not suddenly change on you between the reads and the writes.

This and the $Session object both lock automatically upon
every read and every write to ensure data integrity.  This 
lock is useful for concurrent access control purposes.

Be careful to not be too liberal with this, as you can quickly 
create application bottlenecks with its improper use.

=item $Application->UnLock()

Unlocks the $Application object.  If already unlocked, does nothing.

=item $Application->GetSession($sess_id)

This NON-PORTABLE API extension returns a user $Session given
a session id.  This allows one to easily write a session manager if
session ids are stored in $Application during Session_OnStart, with 
full access to these sessions for administrative purposes.  

Be careful not to expose full session ids over the net, as they
could be used by a hacker to impersonate another user.  So when 
creating a session manager, for example, you could create
some other id to reference the SessionID internally, which 
would allow you to control the sessions.  This kind of application
would best be served under a secure web server.

The ./site/eg/global_asa_demo.asp script makes use of this routine 
to display all the data in current user sessions.

=item $Application->SessionCount()

This NON-PORTABLE method returns the current number of active sessions
in the application, and is enabled by the SessionCount configuration setting.
This method is not implemented as part of the original ASP
object model, but is implemented here because it is useful.  In particular,
when accessing databases with license requirements, one can monitor usage
effectively through accessing this value.

=back

=head2 $Server Object

The server object is that object that handles everything the other
objects do not.  The best part of the server object for Win32 users is 
the CreateObject method which allows developers to create instances of
ActiveX components, like the ADO component.

=over

=item $Server->{ScriptTimeout} = $seconds

Not implemented. May never be.  Please see the 
Apache Timeout configuration option, normally in httpd.conf.  

=item $Server->Config($setting)

API extension.  Allows a developer to read the CONFIG
settings, like Global, GlobalPackage, StateDir, etc.
Currently implemented as a wrapper around 

  Apache->dir_config($setting)

May also be invoked as $Server->Config(), which will
return a hash ref of all the PerlSetVar settings. 

=item $Server->CreateObject($program_id)

Allows use of ActiveX objects on Win32.  This routine returns
a reference to an Win32::OLE object upon success, and nothing upon
failure.  It is through this mechanism that a developer can 
utilize ADO.  The equivalent syntax in VBScript is 

 Set object = Server.CreateObject(program_id)

For further information, try 'perldoc Win32::OLE' from your
favorite command line.

=item $Server->Execute($file, @args)

New method from ASP 3.0, this does the same thing as

  $Response->Include($file, @args)

and internally is just a wrapper for such.  Seems like we
had this important functionality before the IIS/ASP camp!

=item $Server->File()

Returns the absolute file path to current executing script.
Same as Apache->request->filename when running under mod_perl.

ASP API extension.

=item $Server->GetLastError()

Not implemented, will likely not ever be because this is dependent
on how IIS handles errors and is not relevant in Apache.

=item $Server->HTMLEncode( $string || \$string )

Returns an HTML escapes version of $string. &, ", >, <, are each
escapes with their HTML equivalents.  Strings encoded in this nature
should be raw text displayed to an end user, as HTML tags become 
escaped with this method.

ASP.pm  view on Meta::CPAN

Unix platform, and it is unlikely to work under other web servers 
or Win32 operating systems without further development.

To run the ./site/eg scripts as CGI scripts, you copy the 
./site directory to some location accessible by your web
server, in this example its /usr/local/apache/htdocs/aspcgi, 
then in your httpd.conf activate Apache::ASP cgi
scripts like so:

 Alias /aspcgi/ /usr/local/apache/htdocs/aspcgi/
 <Directory /usr/local/apache/htdocs/aspcgi/eg/ >
   AddType application/x-httpd-cgi .htm
   AddType application/x-httpd-cgi .html
   AddType application/x-httpd-cgi .asp
   AddType application/x-httpd-cgi .xml
   AddType application/x-httpd-cgi .ssi
   AllowOverride None
   Options +ExecCGI +Indexes
 </Directory>

Then install the asp-perl script from the distribution 
into /usr/bin, or some other directory.  This is 
so the CGI execution line at the top of those scripts
will invoke the asp-perl wrapper like so:

 #!/usr/bin/perl /usr/bin/asp-perl

The asp-perl script is a cgi wrapper that sets up the 
Apache::ASP environment in lieu of the normal mod_perl
handler request.  Because there is no Apache->dir_config()
data available under mod_cgi, the asp-perl script will load
a asp.conf file that may define a hash %Config of
data for populating the dir_config() data.  An example
of a complex asp.conf file is at ./site/eg/asp.conf

So, a trivial asp.conf file might look like:

 # asp.conf
 %Config = (
   'Global' => '.',
   'StateDir' => '/tmp/aspstate',
   'NoState' => 0,
   'Debug' => 3,
 );

The default for NoState is 1 in CGI mode, so one must
set NoState to 0 for objects like $Session & $Application
to be defined.

=item CGI.pm

CGI.pm is a very useful module that aids developers in 
the building of these applications, and Apache::ASP has been made to 
be compatible with function calls in CGI.pm.  Please see cgi.htm in the 
./site/eg directory for a sample ASP script written almost entirely in CGI.

As of version 0.09, use of CGI.pm for both input and output is seamless
when working under Apache::ASP.  Thus if you would like to port existing
cgi scripts over to Apache::ASP, all you need to do is wrap <% %> around
the script to get going.  This functionality has been implemented so that
developers may have the best of both worlds when building their 
web applications.

For more information about CGI.pm, please see the web site

  http://search.cpan.org/dist/CGI/

=item Query Object Initialization

You may create a CGI.pm $query object like so:

	use CGI;
	my $query = new CGI;

As of Apache::ASP version 0.09, form input may be read in 
by CGI.pm upon initialization.  Before, Apache::ASP would 
consume the form input when reading into $Request->Form(), 
but now form input is cached, and may be used by CGI.pm input
routines.

=item CGI headers

Not only can you use the CGI.pm $query->header() method
to put out headers, but with the CgiHeaders config option
set to true, you can also print "Header: value\n", and add 
similar lines to the top of your script, like:

 Some-Header: Value
 Some-Other: OtherValue

 <html><body> Script body starts here.

Once there are no longer any cgi style headers, or the 
there is a newline, the body of the script begins. So
if you just had an asp script like:

    print join(":", %{$Request->QueryString});

You would likely end up with no output, as that line is
interpreted as a header because of the semicolon.  When doing
basic debugging, as long as you start the page with <html>
you will avoid this problem.

=item print()ing CGI

CGI is notorious for its print() statements, and the functions in CGI.pm 
usually return strings to print().  You can do this under Apache::ASP,
since print just aliases to $Response->Write().  Note that $| has no
affect.

	print $query->header();
	print $query->start_form();

=item File Upload

CGI.pm is used for implementing reading the input from file upload.  You
may create the file upload form however you wish, and then the 
data may be recovered from the file upload by using $Request->Form().
Data from a file upload gets written to a file handle, that may in
turn be read from.  The original file name that was uploaded is the 
name of the file handle.

ASP.pm  view on Meta::CPAN

in Apache::ASP, which are natively written as perl hashes.

New as of version 2.05 is new functionality enabled with the 
CollectionItem setting, to giver better support to more recent PerlScript syntax.
This seems helpful when porting from an IIS/PerlScript code base.
Please see the CONFIG section for more info.

The following objects in Apache::ASP respond as Collections:

        $Application
	$Session
	$Request->FileUpload *
	$Request->FileUpload('upload_file') *
	$Request->Form
	$Request->QueryString
	$Request->Cookies
	$Response->Cookies
	$Response->Cookies('some_cookie')	

  * FileUpload API Extensions

And as such may be used with the following syntax, as compared
with the Apache::ASP native calls.  Please note the native Apache::ASP
interface is compatible with the deprecated PerlScript interface.

 C = PerlScript Compatibility	N = Native Apache::ASP 
  
 ## Collection->Contents($name) 
 [C] $Application->Contents('XYZ')		
 [N] $Application->{XYZ}

 ## Collection->SetProperty($property, $name, $value)
 [C] $Application->Contents->SetProperty('Item', 'XYZ', "Fred");
 [N] $Application->{XYZ} = "Fred"
	
 ## Collection->GetProperty($property, $name)
 [C] $Application->Contents->GetProperty('Item', 'XYZ')		
 [N] $Application->{XYZ}

 ## Collection->Item($name)
 [C] print $Request->QueryString->Item('message'), "<br>\n\n";
 [N] print $Request->{QueryString}{'message'}, "<br>\n\n";		

 ## Working with Cookies
 [C] $Response->SetProperty('Cookies', 'Testing', 'Extra');
 [C] $Response->SetProperty('Cookies', 'Testing', {'Path' => '/'});
 [C] print $Request->Cookies(Testing) . "<br>\n";
 [N] $Response->{Cookies}{Testing} = {Value => Extra, Path => '/'};
 [N] print $Request->{Cookies}{Testing} . "<br>\n";

Several incompatibilities exist between PerlScript and Apache::ASP:

 > Collection->{Count} property has not been implemented.
 > VBScript dates may not be used for Expires property of cookies.
 > Win32::OLE::in may not be used.  Use keys() to iterate over.
 > The ->{Item} property does not work, use the ->Item() method.

=head1 STYLE GUIDE

Here are some general style guidelines.  Treat these as tips for
best practices on Apache::ASP development if you will.

=head2 UseStrict

One of perl's blessings is also its bane, variables do not need to be
declared, and are by default globally scoped.  The problem with this in 
mod_perl is that global variables persist from one request to another
even if a different web browser is viewing a page.  

To avoid this problem, perl programmers have often been advised to
add to the top of their perl scripts:

  use strict;

In Apache::ASP, you can do this better by setting:

  PerlSetVar UseStrict 1

which will cover both script & global.asa compilation and will catch 
"use strict" errors correctly.  For perl modules, please continue to
add "use strict" to the top of them.

Because its so essential in catching hard to find errors, this 
configuration will likely become the default in some future release.
For now, keep setting it.

=head2 Do not define subroutines in scripts.

DO NOT add subroutine declarations in scripts.  Apache::ASP is optimized
by compiling a script into a subroutine for faster future invocation.
Adding a subroutine definition to a script then looks like this to 
the compiler:

  sub page_script_sub {
    ...
    ... some HTML ...
    ...
    sub your_sub {
      ...
    }
    ...
  }

The biggest problem with subroutines defined in subroutines is the 
side effect of creating closures, which will not behave as usually
desired in a mod_perl environment.  To understand more about closures,
please read up on them & "Nested Subroutines" at:

  http://perl.apache.org/docs/general/perl_reference/perl_reference.html

Instead of defining subroutines in scripts, you may add them to your sites
global.asa, or you may create a perl package or module to share
with your scripts.  For more on perl objects & modules, please see:

  http://perldoc.perl.org/perlobj.html

=head2 Use global.asa's Script_On* Events

Chances are that you will find yourself doing the same thing repeatedly
in each of your web application's scripts.  You can use Script_OnStart
and Script_OnEnd to automate these routine tasks.  These events are

ASP.pm  view on Meta::CPAN

  package My::InitHandler;
  use Apache;

  sub handler {
    my $r = shift; # get the Apache request object

    # if not a Mozilla User Agent, then disable sessions explicitly
    unless($r->headers_in('User-Agent') =~ /^Mozilla/) {
       $r->dir_config('AllowSessionState', 'Off');
    }

    return 200; # return OK mod_perl status code
  }

  1;

 </Perl>

This will configure your environment before Apache::ASP executes
and sees the configuration settings.  You can use the mod_perl
API in this way to configure Apache::ASP at runtime.

Note that the Session Manager is very robust on its own, and denial
of service attacks of the types that spiders and other web bots 
normally execute are not likely to affect the Session Manager significantly.

=item How can I use $Session to store a $dbh database handle ?

You cannot use $Session to store a $dbh handle.  This can 
be awkward for those coming from the IIS/NT world, where
you could store just about anything in $Session, but this
boils down to a difference between threads vs. processes.

Database handles often have per process file handles open,
which cannot be shared between requests, so though you 
have stored the $dbh data in $Session, all the other 
initializations are not relevant in another httpd process.

All is not lost! Apache::DBI can be used to cache 
database connections on a per process basis, and will
work for most cases.

=head2 Development

=item VBScript or JScript supported?

Only Perl scripting is supported with this module.

=item How is database connectivity handled?

Database connectivity is handled through perl's DBI & DBD interfaces.
In the UNIX world, it seems most databases have cross platform support in perl.
You can find the book on DBI programming at http://www.oreilly.com/catalog/perldbi/

DBD::ODBC is often your ticket on Win32.  On UNIX, commercial vendors
like OpenLink Software (http://www.openlinksw.com/) provide the nuts and 
bolts for ODBC.

Database connections can be cached per process with Apache::DBI.

=item What is the best way to debug an ASP application ?

There are lots of perl-ish tricks to make your life developing
and debugging an ASP application easier.  For starters,
you will find some helpful hints by reading the 
$Response->Debug() API extension, and the Debug
configuration directive.

=item How are file uploads handled?

Please see the CGI section.  File uploads are implemented
through CGI.pm which is loaded at runtime only for this purpose.
This is the only time that CGI.pm will be loaded by Apache::ASP,
which implements all other cgi-ish functionality natively.  The
rationale for not implementing file uploads natively is that 
the extra 100K in memory for CGI.pm shouldn't be a big deal if you 
are working with bulky file uploads.

=item How do I access the ASP Objects in general?

All the ASP objects can be referenced through the main package with
the following notation:

 $main::Response->Write("html output");

This notation can be used from anywhere in perl, including routines
registered with $Server->RegisterCleanup().  

You use the normal notation in your scripts, includes, and global.asa:

 $Response->Write("html output");

=item Can I print() in ASP?

Yes.  You can print() from anywhere in an ASP script as it aliases
to the $Response->Write() method.  Using print() is portable with
PerlScript when using Win32::ASP in that environment.

=item Do I have access to ActiveX objects?

Only under Win32 will developers have access to ActiveX objects through
the perl Win32::OLE interface.  This will remain true until there
are free COM ports to the UNIX world.  At this time, there is no ActiveX
for the UNIX world.

=head2 Support and Production

=item How do I get things I want done?!

If you find a problem with the module, or would like a feature added,
please mail support, as listed in the SUPPORT section, and your 
needs will be promptly and seriously considered, then implemented.

=item What is the state of Apache::ASP?  Can I publish a web site on it?

Apache::ASP has been production ready since v.02.  Work being done
on the module is on a per need basis, with the goal being to eventually
have the ASP API completed, with full portability to ActiveState PerlScript
and MKS PScript.  If you can suggest any changes to facilitate these
goals, your comments are welcome.

ASP.pm  view on Meta::CPAN

=begin html

<a href=http://www.redhat.com><img src=redhat_logo.gif border=0></a>

=end html

We're using Apache::ASP on www.redhat.com. We find Apache::ASP very
easy to use, and it's quick for new developers to get up to speed with
it, given that many people have already been exposed to the ASP object
model that Apache::ASP is based on. 

The documentation is comprehensive and easy to understand, and the
community and maintainer have been very helpful whenever we've had
questions.

  -- Tom Lancaster, Red Hat

=item Anime Wallpaper at Anime Cubed

Your suite has got our old CGI implementation beat, hands down. Our site is divided into two main areas, each run by a separate developer, and the Apache::ASP section runs head and shoulders above the other side. Anyone who is still using anything bu...

  -- Al from 'Anime Wallpaper at Anime Cubed', http://www.animecubed.com/wallpapers/ 

=item gutscheinwurst.de

I am the web master of http://www.gutscheinwurst.de , a German voucher community. 
We use Apache::Asp to run our backend & administration servers for the system. We started using Apache::ASP to see whether it is a valid alternative to IIS legacy systems. So far all expectations in regard of performance, ease of development and inte...
Thank's for such a great product :)

 -- Johnannes Leimbach

=item D. L. Fox

I had programmed in Perl for some time ... but, 
since I also knew VB, I had switched to VB in IIS-ASP for 
web stuff because of its ease of use in embedding code
with HTML ...  When I discovered
Apache-ASP, it was like a dream come true.  I would much rather code in Perl
than any other language.  Thanks for such a fine product!

=item HOSTING 321, LLC.

After discontinuing Windows-based hosting due to the high cost of software, 
our clients are thrilled with Apache::ASP and they swear ASP it's faster 
than before. Installation was a snap on our 25-server web farm with a small 
shell script and everything is running perfectly! The documentation is 
very comprehensive and everyone has been very helpful during this migration.

Thank you!

 -- Richard Ward, HOSTING 321, LLC.

=item Concept Online Ltd.

=begin html

<a href=http://www.conceptonline.com><img src=concept_online.gif border=0></a>

=end html

I would like to say that your ASP module rocks :-) We have practically stopped developing in anything else about half a year ago, and are now using Apache::ASP extensively. I just love Perl, and whereever we are not "forced" to use JSP, we chose ASP....

  -- Csongor Fagyal, Concept Online Ltd.

=item WebTime

=begin html

<a href="http://webtime-project.net"><img border=0 src="webtimelogo.jpg"></a>

=end html

As we have seen with WebTime, Apache::ASP is not only good  for the
development of website, but also for the development of webtools. Since
I first discoverd it, I made it a must-have in my society by taking
traditional PHP users to the world of perl afficionados.

Having the possibility to use Apache::ASP with mod_perl or mod_cgi make
it constraintless to use because of CGI's universality and perl's
portability.

  -- Grégoire Lejeune

=item David Kulp

First, I just want to say that I am very very impressed with Apache::ASP.  I
just want to gush with praise after looking at many other implementations of
perl embedded code and being very underwhelmed.  This is so damn slick and
clean.  Kudos! ...

... I'm very pleased how quickly I've been able to mock
up the application.  I've been writing Perl CGI off and on since 1993(!)
and I can tell you that Apache::ASP is a pleasure.  (Last year I tried
Zope and just about threw my computer out the window.)

  -- David Kulp

=item MFM Commmunication Software, Inc.

=begin html

<table border=0><tr><td>
<a href="http://www.mfm.com"><img src="communication_software.gif" border=0></a>
<p>
<a href=http://www.huff.com/>HUFF Realty</a>
<br>
<a href=http://www.starone.com/>Star One Realtors</a>
<br>
<a href=http://www.comey.com/>Comey & Shepherd Realtors</a>
<br>
<a href=http://www.unlimitedrealestate.net/>RE/MAX Unlimited Realtors</a>
<br>
<a href=http://www.cincinnatibuilders.com/>Cincinnati Builders</a>
<br>
<a href=http://www.airportdays.com/>Blue Ash Airport Days Airshow</a>
</td></tr></table>

=end html

Working in a team environment where you have HTML coders and perl
coders, Apache::ASP makes it easy for the HTML folks to change the look



( run in 0.988 second using v1.01-cache-2.11-cpan-39bf76dae61 )