 |
ActivePerl User Guide |
 |
|
Using PPM to install modules
Using PPM to install modules
How to install and upgrade modules using PPM
The Programmer's Package Manager (PPM), formerly known as the Perl Package Manager,
provides a command line interface for managing your modules and extensions (packages).
PPM is used to access package repositories (or collections of packages on other machines),
install and remove packages from your system, as well as update previously installed packages
with the latest versions.
The PPM 3.0 release introduces a complete rewrite of PPM, featuring many
additions and improvements. To maintain compatibility
and provide a smooth migration path, PPM3 will coexist with the current PPM.
Both PPM versions 2 and PPM version 3 (PPM3) are installed when you install
ActivePerl.
Before you run PPM or PPM3, you must either be connected to the Internet or have access
to a local repository, like a hard drive
or the
ActiveState ActiveCD. If your Internet connection is via a firewall or proxy,
you must set the environment variable "HTTP_proxy" to the name of the proxy
server. If your proxy server requires a username and password, use the environment
variables "HTTP_proxy_user" and "HTTP_proxy_pass". See
PPM, Proxies and Firewalls for more information.
To run PPM version 2, enter ppm in a command prompt window
(Windows), or ppm3 at the shell prompt (Linux / Solaris).
Quick start: at the PPM3 command prompt, type
search *
to get a listing of all available packages, then type install
<package name>, where <package name> is the name of a
package displayed by the search command. To list the packages you have previously
installed using PPM3, use the query * command.
Those using PPM can type 'search' to get a
listing of all available packages, then type 'install <packagename>',
where <packagename> is the name of a package displayed by the
'search' command. To list the packages you have previously
installed using PPM, use the 'query' command.
Note to PPM users: If you find the listing of packages scrolls by too quickly, you may want to
use the command 'set more <number>' to pause the listing
after <number> packages have been displayed. Use the 'set save'
command to save this configuration for future PPM sessions.
The first time you run PPM or PPM3, the ActiveState package repository will be your default repository.
If you change your default repository, that change will be saved. PPM3 users can can select a different
repository with the repository command. PPM users will use
the 'set' command. See
Where are the package repositories? below.
Items in <angle brackets> are arguments that can be used with the commands, while items
in [square brackets] are optional elements. PPM3 will recognize and accept shortened versions of the
commands, as long as enough letters are typed to be recognized by PPM3. For example,
"des" can be typed instead of "describe".
describe |
|
Describes default/current package |
describe <number> |
|
Describes package <number> in the current search set |
describe <range> |
|
Describes packages in the given <range> from the current search set |
describe <name> |
|
Describes named package |
describe <glob pattern> |
|
Performs a new search using <glob pattern> |
When used, describe returns information about a package, including the name of the package,
the author's name and a brief description (called an "Abstract") about the package. For example, when you enter:
describe libnet
PPM3 will return:
===============================
Package 1
Name: libnet
Version: 1.07.03
Author: Graham Barr
Abstract: Collection of Network protocol modules
Implementations:
1.sun4-solaris-thread-multi
2.i686-linux-thread-multi
3.MSWIn32-x86-multi-thread
===============================
When the describe command is called without arguments, it returns information about the first
package in the current search. If there is no default search set, you'll be
prompted to use search to find a package.
If describe is called with a numeric argument, that number is set as the default package
and the information about that package is returned. If the number given doesn't exist, you'll be prompted
to use search to find a package. Also, you can use describe to give
descriptions of several packages. For example:
describe 4-7
will give you descriptions of packages 4 through 7, in the current search request. You can also enter:
describe 3-4,10
to get information on packages 3, 4 and 10.
When the describe command is given a name with a wildcard (such as "*" or "?")
it executes the search command with the given argument. With this, you can type
something like describe Tk* and the search will give you the name(s) of any packages
that match your search parameters.
See Also:
Properties
When you leave the PPM3 environment, the current settings are saved.
See Also:
Quit
help |
|
lists available commands |
help <command> |
|
lists detailed help about a specific command |
The help command provides a brief description of the commands available
within PPM3. For help on a specific command, enter help followed by the command.
For example, enter help settings or help set for a detailed description of the
settings command.
There are some extra help topics built into PPM3. They can be accessed within the PPM3 environment as follows:
HELP COMMAND |
|
DESCRIPTION |
|
|
help ppm_migration |
|
shows more details about the changes from previous versions of PPM |
|
help quickstart |
|
an easy-to-follow guide to getting started with PPM3 |
|
help prompt |
|
provides a detailed explanation about the PPM3 prompt |
|
help queryformat |
|
gives the user extra tips and hints about making effective searches/queries in PPM3 |
|
install |
|
Installs default package |
|
install <number> |
|
Installs packages by a specific number |
install <range> |
|
Installs packages in the given numeric range <range>. |
install <name> |
|
Installs named package |
The install command is used to install packages from the
repository. You can install packages by name or number (the number is given by
the repository or search request), or a default package can be established
through use of the describe command. There is also a set of
modifiers that can be used with the install command:
-force -noforce
-follow -nofollow
The force and follow commands determine how
packages are installed:
FORCE |
|
FOLLOW |
|
RESULT |
|
false |
|
false |
|
Checks to see if the package is installed and if it is, PPM3 stops. If there are any missing prerequisites, the installation
will fail. |
|
false |
|
true |
|
Checks to see if the package is installed and if it is, PPM3 stops. If there are any missing prerequisites, they
are automatically installed. |
|
true |
|
false |
|
If the package is installed, PPM3 will reinstall the package. If there are any missing prerequisites, the installation will fail. NOTE:
This is the default setting when PPM3 is first installed. |
|
true |
|
true |
|
If the package is installed, PPM3 will reinstall the package. If there are any missing prerequisites, they
are automatically installed. |
|
If you do not specify any options, install uses the default settings. Set or view the
current defaults using the settings command.
For example:
install foo
will install the package named "foo", using the default settings. You can over-ride the
defaults with the install modifiers.
For example:
install foo -force
will install the "foo" package, even if it has already been installed. If both -force and -follow
are set to "true", all the prerequisites for any package you install will be installed. For example, the installation of a tk-related package,
like "tk-ach" which is 8.4 kB will be preceded by the installation of Tk, which is 1.7 MB.
You can also install by package number. The numbering of the packages is based on the current repository or current search request.
For example:
install 6
installs package number 6. You can install more than one package at one time:
install 3-5
installs packages 3, 4 and 5. You can also type install 3-6,8 to receive packages 3,4,5,6 and 8.
profile |
|
lists profiles available on the repository |
profile <number> |
|
switches to the given profile |
profile add <name> |
|
creates a new profile on the repository |
profile del <number> |
|
deletes the given profile |
profile save |
|
saves the client state to the current profile |
profile restore |
|
restores the current profile |
With profiles, package installation and management is easy to oversee. By
using profiles, you can save your favorite perl packages in a single profile
or group packages by function in different profiles. This also makes installation of
packages easier, as you only need to access one or two profiles, instead of many
individual packages.
Managing your profiles can be done through PPM3 or via the ActiveState Interactive website.
Note: The profile commands are only available if the current repository is a PPM3 repository.
properties |
|
Describes default installed package |
properties <number> |
|
Describes installed package <number> |
properties <package name> |
|
Describes named installed package |
properties <glob pattern> |
|
Performs a new query using <glob pattern> |
Similar to the describe command,
properties provides information on an installed package, but with
more details than those available with describe. In addition to the summary information,
properties will display the installation date and a URL showing
the location of the package within the repository.
Note: When properties is called with arguments including a
wildcard, it prints a message telling you that it is about to forward the
whole command-line to query; then it does.
With this, you can type "properties Tk*" or "prop Tk*".
For example, typing properties libnet will give you:
Name: libnet
Version: 1.07.03
Author: Graham Barr
Abstract: Collection of Network protocol modules
InstDate: Fri Oct 2 16:15:15 1998
Location: http://ppm.ActiveState.com/cgibin/PPM/ppmserver.pl?urn:/PPMServer
See Also:
Describe
Quit is another command used to close the PPM application. Like the exit
command; when you close PPM3, the current settings will be saved.
See Also:
Exit
query |
|
Displays list of previous queries |
query <number> |
|
Displays results of previous query |
query <glob pattern> |
|
Performs a new query using <glob pattern> |
query * |
|
Displays a list of all installed packages |
The query command displays either a list of all installed packages or a shortened list,
based on the <glob pattern> entered. You can also check the list of past queries or the results of a past query.
Note: Depending on the value of "case-sensitivity", the query may or may not be case-sensitive.
See "help settings" for how to affect the case sensitivity.
See Also:
Settings
remove |
|
Deletes default installed package |
remove <number> |
|
Deletes a package by a specific number |
remove <range> |
|
Deletes a <range> of packages |
remove <name> |
|
Deletes a package by a specific name |
The remove command deletes packages from your current target.
Packages can be removed by package name or by their numerical listing. For example:
remove XML-DOM
will delete the XML-DOM package from your target. Also, you can remove package by number:
remove 6
and the 6th package in your current query will be removed. If you have no query requests established, you'll be required to
use query to find a package before you delete it. It's important to remember that removing
packages also clears all previous query requests, since the numerical sequence stored in any query will no longer be true
once package(s) have been removed.
Packages can also be removed in groups; for example:
remove 4-7
will delete packages 4, 5, 6, and 7 from your target. You can also skip packages in the removal process:
remove 3-5, 7
this will delete packages 3, 4, 5 and 7...but it will leave 6 intact. Remember to run a new query whenever
you remove a package from your target.
Please note that wildcards like "*" or "?" cannot be used with the remove command.
See Also:
Uninstall
repository |
|
displays all repositories |
repository [set] <number> |
|
sets the specified repository active |
repository add [name] <repository location> |
|
adds a new repository |
repository del <number> |
|
deletes the specified repository |
repository describe [number] |
|
displays the name, location and type of the specified (or
current) repository |
When used with no arguments, repository (or "rep") will list the
repositories currently within the PPM3 settings. The default repository is highlighted with a leading "*".
For example, when you enter:
rep
PPM3 will return something resembling this:
Repositories:
* 1. ActiveCD.
2. ActiveState Package Repository
With the example above, entering rep set 2 will make the
second repository (ActiveState Package
Repository) the active repository. Adding another repository is done like this:
rep add <NAME> <LOCATION>
for example:
rep add TheoryX5 http://theoryx5.uwinnipeg.ca/cgi-bin/ppmserver?urn:/PPMServer
with "TheoryX5" being the name of the repository (for easy reference) and the location noted by
the http location. If you were to enter rep again, you would see:
ppm>rep
Repositories:
1. ActiveCD
* 2. ActiveState Package Repository
3. TheoryX5
If you wanted to remove the ActiveCD repository, you would type rep del 1,
to remove the 1st repository. To get more information on a particular repository, type
res describe to get information on the current repository or res describe
<number> to get information on a specific repository.
For example:
rep describe 2
will return:
Describing Repository 2:
Name: ActiveState Package Repository
Location: http://ppm.ActiveState.com/cgibin/PPM/ppmserver.pl?urn:/PPMServer
Type: PPMServer 2.00
search |
|
Displays list of previous searches |
search <number> |
|
Displays results of search <number> |
search <glob pattern> |
|
Performs a new search |
search <field>=<glob pattern> |
|
Searches for all packages matching the field - the available fields are ABSTRACT, NAME or TITLE, AUTHOR and VERSION -
NAME is the default search setting |
search * |
|
Searches for all packages in the current repository |
Search is used to look through the repository for packages. With PPM, you can
perform powerful and detailed searches. Here are some examples:
COMMAND |
|
MEANING |
|
SAMPLE RESULTS |
|
search CGI
|
|
Search for 'CGI' anywhere in the name |
|
Apache-CGI CGI-Application CGI-ArgChecker
|
|
search CGI*
|
|
Search for 'CGI' at beginning of name |
|
CGI-Application CGI-ArgChecker
|
|
search AUTHOR=smith
|
|
Search for all modules authored by someone with 'smith' in their name or email |
|
Apache-ProxyPass Business-ISBN
|
|
search ABSTRACT=compress
|
|
Search for 'compress' anywhere in the abstract |
|
Apache-GzipChain IO-Zlib
|
|
search CGI or ABSTRACT=web
|
|
Search for 'CGI' in the name, or 'web' in the abstract |
|
CGI-XMLForm HTML-Clean
|
|
search XML and (parser or ABSTRACT=pars) and not XPath
|
|
Search for 'XML' in the name and either 'parser' in the name or 'pars' in the abstract, but not with 'XPath' in the name |
|
XML-Node XML-Parser-EasyTree
|
|
search Data::Grove
|
|
PPM Server 3.0 repositories only: Search by module name, even if unrelated to the containing package |
|
libxml-perl
|
|
search *
|
|
Browse all packages in the repository |
|
Affix-Infix2Postfix AI-Fuzzy AI-NeuralNet-BackProp
[... 1700+ more]
|
|
You can recall previous searches with the search <number> command, as PPM stores past searches.
settings |
|
displays current options |
settings <name> |
|
displays the current setting of the given <name> |
settings <name> <value> |
|
sets <name> to <value> |
The settings command gives you access to the different options that PPM has available. This can
be modified to better suit your needs when using PPM.
Available settings:
NAME |
|
VALUE |
|
DESCRIPTION |
|
case-sensitivity |
|
"0" or "1" |
|
If set to "1", searches and queries are case-sensitive. |
|
download-chunksize |
|
integer |
|
If this is set to a positive, non-zero integer, PPM updates the status after each "integer"
of bytes transferred during an install or upgrade. |
|
follow-install |
|
"0" or "1" |
|
See install for details. |
|
force-install |
|
"0" or "1" |
|
See install for details. |
|
page-lines |
|
integer |
|
The number of lines to display per page. If a result has fewer than "page-lines", it will be printed
directly to the screen regardless of the "pager" setting. |
|
pager |
|
path |
|
The path to an external pager program used to page long displays. If left blank, the internal pager is used. |
|
prompt-context |
|
"0" or "1" |
|
If "1", enables the prompt to change based on the current state of PPM, i.e. showing current target, query, etc.
|
|
prompt-slotsize |
|
integer |
|
If prompt-verbose is "1", this defines the width of each slot in the prompt. For instance, "4" means to
use 4 character-wide slots. |
|
prompt-verbose |
|
"0" or "1" |
|
If "0", uses numbers to represent the context in the prompt; much shorter. If prompt-context is set
to "0", there will be no visible difference in the prompt-verbose settings. |
|
sort-field |
|
field |
|
The field by which to sort search and query results. Valid fields are ABSTRACT, NAME or TITLE, AUTHOR and VERSION.
Note: these fields are case-sensitive. |
|
tempdir |
|
path |
|
A temporary directory into which packages are downloaded and expanded during "install" and "upgrade". |
|
trace-file |
|
path |
|
A file to which PPM will write tracing information. |
|
trace-level |
|
integer |
|
If 0 or negative, tracing is disabled. Any positive integer
results in tracing information. Higher numbers mean more tracing
information. |
|
PPM options: If you are looking for old options understood by previous version of PPM, please see
"help ppm_migration".
Note: When you assign a value, PPM saves its configuration. That means all values automatically
persist across sessions. Also, setting names may be abbreviated to uniqueness. Instead of
typing "case-sensitivity", you may type "case".
target |
|
Displays a list of targets |
target <number> |
|
Sets <number> as default target |
target describe [number] |
|
Describes the given (or default) target |
target set <key> <val> |
|
Sets the target's <key> to <val> |
A target is a location where packages are installed, a directory where the packages you want
to install are placed when they're downloaded from the repository. For example, entering:
target
will return:
Targets:
1. ActivePerl 618
* 2. ActivePerl 630
This shows us that we have 2 targets available to us and that the second target (ActivePerl 630) is
currently the default, as noted by the asterisk. The ability to choose different targets allows
PPM to manage several installations of Perl from one command-line.
Note: Currently, PPM only supports Perl but will be expanded for other languages in the near
future. You can have several versions of Perl on your system and each version will be
recognized as a unique target by PPM.
tree |
|
displays the dependency-tree of the default package |
tree <number> |
|
displays the dependency-tree of the given <number> |
tree <range> |
|
displays a <range> of dependency trees |
tree <name> |
|
displays the dependency-tree of the named package |
The tree command is used to show the what is known as the "dependncy tree" of a given package. That is,
a list of additional packages that are required to make a given package perform as expected. For example, entering:
tree SOAP-lite
would return something that looks like this:
====================
SOAP-Lite 0.46
|__MIME-tools 5.316
| |__MailTools 1.15
| \__IO-stringy 1.216
|
\__MIME-Lite 2.105
====================
As we can see, SOAP-Lite would require 4 other packages to be installed with it.
When tree is called without a <name> or <number>, tree will return the
dependency tree of the first package in the default search result. If there is no default search, you will be requested to
use search to find a package.
uninst |
|
Removes default installed package |
uninst <number> |
|
Removes installed package <number> |
uninst <range> |
|
Removes a <range> of installed packages |
uninst <name> |
|
Removes named installed package |
Like the remove command, uninstall enables you to delete installed
packages. This can be done by name or by the numerical listing of packages. Also like the remove command, uninstalling any
packages will clear all previous query requests.
See Also: Remove
upgrade [*] |
|
Lists upgrades available for all installed packages |
upgrade <number> |
|
Upgrades installed package <number> |
upgrade <range> |
|
Upgrades a <range> of installed packages |
upgrade <package> |
|
Upgrades the named <package> |
There are several modifiers to the upgrade command, as well:
OPTION |
|
DESCRIPTION |
|
Install |
|
Installs, rather than lists, available upgrades |
|
Precious |
|
Allows upgrading of "precious" packages |
|
Force |
|
See install |
|
Follow |
|
See install |
|
By default, upgrade typed by itself only lists the available upgrades. To actually install all available
upgrades, enter:
upgrade -install
To enable upgrading "precious" packages, type:
upgrade -install -precious
Version |
|
displays the installed PPM version number. |
A summary of PPM version 2 commands is shown below. Type help
<command> at the PPM prompt for usage details. Items in [brackets]
are optional.
| Command |
Function |
| genconfig |
prints a minimal PPM configuration file to STDOUT
[Note: genconfig only works from the command-line] |
| help [command] |
lists available commands, or help on 'command'. |
| install package1 [package2...] |
installs specified packages. |
| quit |
exits the program. |
| query [pattern] |
lists installed packages, or packages containing pattern. |
| query /abstract [pattern] |
lists descriptions of installed packages, or package
descriptions containing pattern. |
| remove package1 [package2...] |
removes the specified packages from the system. |
| search [pattern] |
lists available packages, or packages containing pattern. |
| search /abstract [pattern] |
lists descriptions of available packages, or package
descriptions containing pattern. |
| set |
set/display current options. |
| set save |
save current options. |
| verify [package1...] |
verifies currently installed packages are up to date. |
| verify /upgrade [package1...] |
installs available package upgrades. |
| version |
displays the PPM version number |
A pattern is a search string just like the regular expressions - for example
if you search for with this command
search ODBC|DBI
(which means 'search for packages in which the characters ODBC and/or the
characters DBI are present in that order') you get a result like this
Apache-DBI
DBD-ODBC
DBI
FindBin
Win32-ODBC
Note that if you use 'search /abstract [pattern]' the search will only
include the ABSTRACT section of the package files.
By default, PPM will use the ActiveState package repository, but there are
other repositories on the Internet. At the moment there are these repositories:
Note: most of these repositories are for ActivePerl 5xx builds only; they
may not be compatible with ActivePerl 6xx builds. Check these repositories for the latest updates:
| http://ppm-ia.ActiveState.com/PPM/ppmserver.plex?urn:/PPM/Server/SQL |
New 3.0 Repository
from ActiveState |
| http://www.ActiveState.com/cgibin/PPM/ppmserver.plex?urn:/PPMServer |
The default package repository from ActiveState |
| http://theoryx5.uwinnipeg.ca/cgi-bin/ppmserver?urn:/PPMServer |
University of Winnipeg |
| http://Jenda.Krynicky.cz/perl |
Jan Krynicky's package
repository |
| http://www.roth.net/perl/packages/ |
Roth Consulting's package
repository |
| http://www.xray.mpe.mpg.de/~ach/ptk/ppm |
Achim Bohnet's package
repository |
| http://rto.dk/packages/ |
RTO's packages repository
(mostly mirrors of the above) |
|
| http://www.fastnetltd.ndirect.co.uk/Perl/zips/ |
Fastnet Software Ltd's packages
- not directly accessible from PPM at present |
For PPM3 users
To use these package repositories you start PPM3 and at the prompt type:
repository add NAME URL
where NAME is a name by which you want to reference the repository
from PPM and URL is the URL to the repository. Please note that NAME is
optional, as PPM will assign a name to the repository for you. For example, entering:
repository add JENDA http://Jenda.Krynicky.cz/perl
will create a repository for you, by the name of JENDA and give you access to the modules
available there.
For PPM users
To use these package repositories you start PPM and at the prompt type
set repository NAME URL
where NAME is a name by which you want to reference the repository
from PPM and URL is the URL to the repository. You could for example type
set repository JENDA http://Jenda.Krynicky.cz/perl
The next time you do a 'search' you will not only search the ActiveState
package repository but also the repositories you have added. Before you exit PPM
you should save the changes to the configuration by issuing the command 'set
save'.
If you want to make a PPM package for use on other machine you can do it like
this:
Specify the AUTHOR and ABSTRACT parameters in the Makefile.PL. However you
should only pass them to WriteMakefile if the version of the perl is greater
than 5.005 - older perls do not have these parameters added and do not expect to
see them. This is an example Makefile.PL:
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
'NAME' => 'Term::Control',
'VERSION_FROM' => 'Control.pm', # finds $VERSION
($] ge '5.005') ? (
'AUTHOR' => 'Johnny Doel (johnny@doel.org)',
'ABSTRACT' => 'Control the
IO for terminals',
) : (),
);
Then you make the archive with the commands
perl Makefile.PL
nmake
The resulting files are placed in the blib directory that is created when you
run nmake. These files should be packed into an archive like this:
tar cvf package.tar blib
gzip --best package.tar
You now have an archive called package.tar.gz. Then you generate the
PPD file by:
nmake ppd
You have to edit the resulting PPD file and add the location of the package
archive into <CODEBASE HREF="" />. The location is relative to
the PPD file.
You can get nmake from http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe.
If you use a proxy server or firewall, you might have trouble running PPM.
Here is the solution.
NOTE: If none of the changes in this document work for you,
you may download individual packages from here
[ActivePerl 613 and later] or here
[ActivePerl 522 and earlier] and install them according to the directions
in the README file contained within the ZIP file. If you want, you can also
keep a local repository, with several .ppd files in a permanent repository
directory, and their .tar.gz files in an x86 directory beneath that.
-
Set Environment Vars
Up to three environment variables need to be set.
Under Windows 2000
Right click on "My Computer", click on "Properties" and select the
"Advanced" tab. Click the button marked "Environment Variables"
and make the following changes in the "System Variables" window:
- With the "New" button, add the setting HTTP_proxy, with your proxy name as the
value (you must include "
http://"), followed by a colon and
the proxy port, if applicable; e.g., "http://proxy:8080"
- If you require a user name and/or password to access your proxy, use the "New" button
to add the settings HTTP_proxy_user and HTTP_proxy_pass, with your user name and
password as the respective values.
Under Windows NT
Right click on "My Computer", click on
"Properties", select the "Environment" tab. These are your
environment settings. Make the following changes:
- Add the setting HTTP_proxy, with your proxy name as the value (you
must include "
http://"), followed by a colon and
the proxy port, if applicable; e.g., "http://proxy:8080"
- If you require a user name and/or password to access your proxy, add the
settings HTTP_proxy_user and HTTP_proxy_pass, with your user name and
password as the respective values.
Under Windows 9x
In your AUTOEXEC.BAT file, place the following lines then reboot so the changes can take effect:
- SET HTTP_proxy=<your proxy server (you must include
"
http://", followed by a colon and the proxy
port, if applicable; e.g., SET HTTP_proxy=http://proxy:8080
- SET HTTP_proxy_user=<your user name> (if required)
- SET HTTP_proxy_pass=<your password> (if required)
-
Try using PPM
With your internet connection active, try using PPM again. Try to install a
small package, like File-Slurp. You'll know that it still fails if you see an
error stating that it can't find a ppd file for the specified package.
-
Further Information and Help
If there were problems with any of the above hints, please see
Troubleshooting
for information regarding further help.
This FAQ was originally assembled and maintained by Evangelo Prodromou. It
has been revised and updated by Brian Jepson of O'Reilly & Associates, David
Grove, David Dmytryshyn, and Murray Nesbitt of ActiveState, Henning Michael Møller-Nielsen
of RTO, Kevin Meltzer, and David Sparks of ActiveState.
This FAQ is in the public domain. If you use it, however, please ensure that
you give credit to the original authors.
|