
++
As a researcher and modeler, it is becoming progressively easier to communicate ideas and disseminate information through non-traditional media such as the internet. GAMS-X and GAMS-Xi have been created not only as a modeling aid for GAMS programmers, but as a tool to enable the modeler to communicate models to peers over the ever-expanding internet.
GAMS-X itself is composed of three basic tools: GAMS-Tk, GAMS-CGI, and GAMS-X Script.
GAMS-Tk, probably the first tool that new users will become acquainted with, is a graphical user interface (see figure ) designed for use with GAMS models. GAMS-Tk can be used to visually create and present sets of model scenarios, as well as generate customized graphs and LATEX- and HTML-ready documents.
GAMS-Xi, the individual model user's utility for viewing and working with models created in GAMS-X, is composed solely of the GAMS-Tk interface.
GAMS-CGI, which many GAMS users may be familiar with through internet sites such as http://nash.colorado.edu located at the University of Colorado at Boulder, is an online modeling environment which allows users to generate scenarious and solve instances of GAMS models over the internet (see figure ).
Both visual environments, GAMS-Tk and GAMS-CGI, are transparently integrated so that modelers who have a web server installed can work in the same modeling environment locally through GAMS-Tk or remotely via any computer connected to the internet. Furthermore, modelers who have installed GAMS-CGI can communicate model results in real time over the internet in a password-protected environment to anyone with a web browser at their disposal.
GAMS-Tk also allows GAMS-CGI administrators to administrate GAMS-CGI sites from within a visual environment rather than relying on arcane command-line syntax.
The last, but certainly not the least, member of the GAMS-X family is GAMS-X Script, a scripting environment which allows modelers to write simple GAMS-X scripts which can do anything that can be done in GAMS-Tk or GAMS-CGI, but from within a scripting environment that supports complex data structures, flow control, and the most robust text maniuplation and report generation environment available through Perl, the Practical Extraction and Report Language.
With GAMS-X Script, GAMS-CGI allows the modeler to separate him or herself from the details of online model presentation. The modeler may be disinterested in the mundane details of web site construction and graphic design. The GAMS-CGI programming environment itself incorporates the Perl CGI module, a popular and almost ubiquitous web programming tool written in Perl, the most widely used web programming language in the world. Thus, with GAMS-X, a modeler who prefers a more robust online environment than the default screens provided in GAMS-CGI may avail him or herself of the services of a web programmer with knowledge of Perl CGI, but who knows nothing about GAMS, thereby divorcing the modeler from the sordid details of website development and maintenance.
So as a modeling aid, GAMS-X allows the modeler to quickly and easily generate model scenarios and graphical output. Through the GAMS-Tk graphical user interface, a modeler can visually prepare model scenarios and groupings of model scenarios. Through the GAMS-X programming environment, large numbers of scenarios can easily be generated and their results compared.
As a communication tool, GAMS-X allows the modeler to post a GAMS model on the internet at any site on which GAMS-X is installed, generate customized graphs with the click of a button, or to prepare LATEX- or HTML-ready documents with model results.
If you have never used GAMS-X before, the first thing that you will want to do is download and install GAMS-X. Instructions are available in section , with links to the installation files in the HTML version of this document. After you have installed GAMS-X, you should install the Ramsey model, included with the GAMS-X distribution, in GAMS-Tk. For more etail on running GAMS-Tk and installing the Ramsey model, see chapter .
As you will see, GAMS-X has been designed to take advantage of the new face of computing, providing GAMS modelers with tools that just a few years ago would not have been possible. We hope you enjoy this new product.
Support for the development of the GAMS-X family of modeling tools has been generously provided by the GAMS Development Corporation, but it is not officially supported the the GAMS Corporation.
GAMS-X is the name given to a bundle of products which include the GAMS-X scripting methods, a scripting interface to the GAMS-X modeling environment, GAMS-Tk, the GAMS-X graphical user interface, and GAMS-CGI, the GAMS-X web interface and programming environment.
These products have been developed with several guiding principles in mind:
I am always open to comments or suggestions. Please feel free to contact me by email at collin.starkweather@colorado.edu. Please keep in mind that I am a graduate student, and there are often constraints on my time which do not permit me to respond as quickly as I would like to all of my mail.
You may feel free to skip this section unless you really want to know.
The GAMS-X system is an integrated collection of Perl modules, GAMS include files, and standalone executables. It makes use of at least 3 applications1 and 5 languages2.
GAMS-X encompasses the following set of Perl modules and accompanying executables and batch files for their use:
GAMS::Ini provides an object whose methods define the environment (e.g., directory and file structure) in which the GAMS module operates.
GAMS provides an object interface for GAMS::CGI and GAMS::Tk, and inherits the GAMS::Ini object.
GAMS::Tools provides a suit of tools to to administrate a GAMS-X site and provided methods for creating formatted input and output. It inherits the GAMS (and hence GAMS::Ini) object.
GAMS::CGI provides a full suite of tools to implement the General Algebraic Modeling System Common Gateway Interface by which GAMS models can be posted online. The GAMS::CGI object inherets the GAMS (and hence GAMS::Ini) object.
GAMS::Tk provides a GUI (graphical user interface) based on the Tcl/Tk scripting language for the GAMS module and includes a full suite of tools for the model builder and GAMS-CGI webmaster. The GAMS::Tk object inherets the GAMS::Tools (and hence GAMS and GAMS::Ini) object.
As this document is intended to be a comprehensive overview of GAMS-X for users, administrators, and developers, there is a tremendous amount of information contained herein requiring widely varying levels of competence on the part of the reader. Thus, this document is not meant to be read from cover to cover.
If you are a GAMS-CGI user, you may want to simply read chapter , the GAMS-CGI User's Guide.
If you are a GAMS modeler who is interested in presenting model results over the internet or via a local visual interface, but have no interest in the sordid details associated with creating the interface, you may only want to read chapter . This chapter explains how to adapt your GAMS code to accomodate inputs, outputs, and graphs and how to prepare your model for installation at a GAMS-CGI site anywhere in the world.
If you are a modeler who would like to use GAMS-X as a modeling aid for the quick generation of scenarios and web- or LATEX-ready graphics and documents, you will also want to read section , which contains instructions for downloading and installing GAMS-X, and chapter , the GAMS-Tk User's Guide.
If you are going to be administering a GAMS-CGI site, you will want to read section , which contains instructions for downloading and installing GAMS-X, chapters and , which explains how to administrate models via GAMS-Tk, and chapter , which explains how to administrate a GAMS-CGI site. You may also find the Administrator FAQs found in section helpful.
If you are developing the web interface to a GAMS model, you will want to read chapter , which explains how to create or customize GAMS-CGI programs.
If you are an experienced CGI programmer, you will want to read chapter on GAMS-CGI as well as appendices and , which contain information on Perl CGI programming from within the GAMS-CGI environment. You will be pleased to note that the GAMS-CGI object inherits the familiar Perl CGI object and all of its methods. You may also find section , which provides some examples of fully customized GAMS-CGI pages, of interest.
You must first decide which flavor of GAMS-X you would like to
install.
GAMS-X comes in two flavors: GAMS-X and GAMS-Xi.
The full GAMS-X package is written in Perl, a powerful and popular
open-source scripting language. In order to have access to the web site
customization tools (see chapter ,
section , and
appendices and for more
details), you will need the full installation, and hence you will
need to install Perl3.
GAMS-Xi, on the other hand, consists of a set of precompiled
binaries, and does not require that Perl be installed to function
properly. The i stands for ``individual,'' and is a stripped-down single-user
edition with a much smaller feature set than the full
install.4
However, the most powerful features of GAMS-X, such as
online modeling and scripting capabilities, are not available with the
precompiled binaries.
The differences can be summarized as follows:
Links to all of the files necessary to download and install GAMS-X can be
found in the HTML version of this document located on the GAMS-X homepage,
http://www.gams.com/gams-x .
Since the full installation involves only three steps taking five or
ten minutes to install instead of the one step installation of
GAMS-Xi, and provides a much more robust environment, it comes highly
recommended to all windows users.
Links to all of the files mentioned are included in the HTML version
of this document.
You must be connected to the web to use the Perl Package Manager.5
If you have any problems, consult the FAQs in section
. You may find FAQ
particularly helpful if you are having problems with the Perl Package
Manager. If you are still having problems, contact me at the above
email address.
GAMS-X has not yet been ported to Unix. A port is planned that would
be completed sometime around January 2000 and would support a true
multiuser environment and additional functionality not found in the
Windows version.
If you are interested in using GAMS-X with Unix,
please send me some
I would be happy to chat, particularly if you are a coder and would
like to volunteer assistance with the port.
As this is a brand-new product, and doubtless will improve as it is
used in a variety of modeling situations, regular updates will be
posted to remedy bugs and enhance the existing base of GAMS-X
features.
An update is not necessary if you have just installed GAMS-X.
If the date of your version of GAMS-Tk is more than a few days older
than the update, you could benefit from the update.
2.3 Downloading and Installation
2.3.1 The GAMS-X Homepage
GAMS-X (Unix) GAMS-X
(WinNT/2K) GAMS-X (Win9x) GAMS-Xi (Windows)
Recommended for Modelers X X X
Recommended for Users X
Multiowner X
Multiuser X X X
Single User X
Online Modeling Facilities X X
Automatic Online Updating X X X
Commnand-line Utilities X X X
Scripting capabilities X X X
Requires Perl X X X
Does not require Perl X
2.3.2 Windows
2.3.3 System Requirements
Installation Options
Installing GAMS-X
PPM
at the prompt
(PPM stands for Perl Package Manager)
install Storable GD GIFgraph Tk
from the PPM prompt.
Installing GAMS-Xi
2.3.4 Unix
2.3.5 Upgrading from GAMS-X Version 2.x
Do I need an update?
How to Find Your GAMS-X Version Number
Run GAMS-Tk and select the Help.About GAMS-Tk menu option.
Alternatively, you could write a simple GAMS-X script like the following:
use GAMS::Script; print "I am running GAMS-X version ", $GAMS::Ini::VERSION, "\n";
For more information on creating GAMS-X scripts, see chapter .
Before updating your version of GAMS-X:
To update your version of GAMS-X:
You have a choice between the easy way and the hard way, with the hard way not really being that hard after all. You can use the easy way if you are connected to the internet.
Unfortunately, GAMS-X is such a radical departure from the original GAMS-CGI that an upgrade from GAMS-CGI 1.x to GAMS-X version 2.0 is not available. You can uninstall GAMS-CGI with the application uninstal (Unix) or uninstal.bat (Windows), located in the GAMS-CGI version 1.x root directory. The existing GAMS-CGI users will be lost and the installed models deleted, so if you have any files in the old GAMS-CGI users or models directories that you need to hold on to, be sure to back them up.
It is strongly recommended that you uninstall GAMS-CGI 1.x before installing GAMS-X.
If you have CGI.DAT files with case and casebook information that you would like to preserve, you may use the cgi2x.pl script located in your GAMS-X scripts directory to convert the files to GAMS-X data file format. For help using cgi2x.pl, run the script without any arguments by typing cgi2x.pl (in Windows NT) or perl cgi2x.pl (in Windows 95/98) from a command prompt.
GAMS-CGI does not solve the cases itself, as complicated models may take several minutes to solve. (Noone likes to be kept waiting while they are browsing the web!) Therefore, it simply submits previously unsolved cases to the GAMS-CGI daemon and goes on about its business. The GAMS-CGI daemon is not a fearsome underworld denizen, but rather a program which submits new cases to GAMS as they are created and updates GAMS-CGI with the solutions to the cases as they become available.
Thus, in order to for GAMS-CGI users to be able to solve new cases, you must have started the GAMS-CGI daemon.
Note that if you do not want the daemon running in perpetuity, you may simply include a numeric argument in a call to the daemon, in which case it will only search for GAMS jobs for the number of seconds specified by the numeric argument. This is a convenient trick: If, for example, you want to solve all of the unsolved cases but don't want to take the time to create a script invoking the Solver method or the GAMS-Tk Tools.Solver menu option, you need only type gams-cgid.pl 1 (or, in Windows 95/98, perl gams-cgid.pl 1) from the GAMS-X root directory.
NB: The GAMS-CGI daemon should not be run while GAMS-Tk or GAMS-X scripts are running. GAMS-Tk will try to warn you if it detects the GAMS-CGI daemon running, but GAMS-X scripts do not have the ability to look for the daemon. I cannot emphasize this cautionary note too much.
The GAMS-X program gams-cgid.pl, located in the GAMS-X root directory, must be constantly run in the background. Simply double-click on it in Windows Explorer or open a DOS prompt and type perl gams-cgid.pl from the command line.
The GAMS-X program gams-cgid.pl, located in the GAMS-X root directory, should be run as an NT service. This can be accomplished using the application Srvany provided with the Microsoft Windows NT Resource Kit ([]). See the Srvany documentation and your NT user's manual for more information.6
The file gams-cgid.pl, which is placed in each GAMS-X owner's GAMS-X root directory, must be running as a daemon. For more information on launching daemons, see [].
Windows users may either select Uninstall GAMS-X from the GAMS-X group in the Windows Start menu, double-click on the gams-xuninst.pl file located in the GAMS-X root directory from Windows Explorer, or type gams-xuninst.pl (or perl gams-xuninst.pl in Windows 95/98) from the command prompt from within the GAMS-X root directory.
If you have problems running the GAMS-X uninstall utility from the Windows Start menu, please refer to FAQ .
Please forward any comments/suggestions/bug reports to Collin Starkweather at .
Since, with the exception of GAMS-CGI, this package represents the introduction of a number of new software products, there will doubtless be a bug or two left to be found.
I am quite anxious to remedy any bugs that remain. Please forward any bugs to me at the above email address. If you are able to pare any bugs down to the form of a simple and easily-digestible example, your efforts in this regard would be much appreciated.
This section of the guide is intended primarily for GAMS programmers
who would like to use the GAMS-X scripting capabilities, the GAMS-Tk
visual modeling interface, or produce a web-based version of one or
more of their GAMS models. The topics covered here include an
overview of the system design philosophy, and a detailed statement of
programming syntax for using the libinclude program X.gms.
GAMS-X is a general-purpose tool intended to facilitate report
writing and user-interaction with computational models. Experienced
GAMS programmers navigate GAMS input and listing files using a text
editor or similar tool, but problems often arise when they need to
provide non-technical users access to their model. GAMS-X is a
"bare-bones" model interface. It serves the same function as a custom
Visual Basic or Delphi front-end for a GAMS models, but it is much
easier to use for GAMS programmers than these languages. In exchange
for reducing the cost of model implementation, GAMS-X places some
restrictions on interface complexity. For example, GAMS-X provides
no hierarchy of inputs and outputs. It is our belief that there is a
need for a "quick and clean" model interface, and in this regard
GAMS-X will be of considerable value to many GAMS programmers.
It is our expectation that most models implemented under GAMS-X
will have already been used as part of a focused analysis, typically
in the form of an academic paper, government report or memoradum. The
model-builder, having formulated and implemented the model, turns to
GAMS-X as a means of communicating results to a (possibly)
non-technical audience.
By using GAMS-X, the modeler is providing other analysts an
opportunity to evaluate robustness of the reported results. It also
provides a convenient framework for informed debate on the issues by
providing other analysts with the opportunity to conduct their own
assessment of the model based on alternative input data.
In order to prepare a model for use with GAMS-X, the modeler must
decide which inputs she will offer to the model user, and for each of
those inputs she must also choose a set of possible values which can
be selected. The modeler also must choose which numerical outputs
(including both tabular reports and plots) are to be displayed and
how these are to be formatted.
So deciding how to present your model to the world boils down to
three basic questions:
To the user of a model installed in GAMS-X, the GAMS model is simply
a black box. A set of input values is provided, the model is run,
and the outputs are given back to the user.
Many first-time users tend to treat the choice of GAMS-X inputs like
Jackson Pollock would treat a canvas; that is, they throw at the
model user every conceivable piece of information without regard to
relevance or focus.7 While this is
certainly possible, the modeler should think of GAMS-X as a
communication tool.
Having chosen inputs and outputs, the model builder may also specify
an initial set of case definitions and casebooks. These cases and
comparison reports are a starting point for internet users who load
the model for the first time.
Defining the inputs, outputs, and plots is done from within your GAMS
file with $libinclude statements.
While perusing the remainder of this chapter, you will find it worthwhile
to refer to appendix , which contains the GAMS
code for the sample Ramsey model included with the installation.
A model file defines a GAMS-X input with a statement like:
This statement defines an input which may be subsequently referenced
in the GAMS code as "%BET%". This syntax is based on the GAMS
$setglobal syntax which defines an environment variable named BET.
Whenever the GAMS compiler encounters %BET% in the source code, it
replaces this symbol with the assigned character string. In this
example, operating in default mode, "%BET%" is replaced by "0.95".
(N.B. The X INPUT statement does not define a GAMS parameter with
the name "BET", although the string referenced as %BET% may be used
to initialize a scalar parameter as illustrated below.)
The definition of an X input requires a default value and a
description. This description is displayed for the internet user. At
least one, and possibly as many as four alternative values may be
specified for each input. In the statement shown above, the
alternative strings which may be represented by %BET% are 0.9, 0.925
and 0.97.
Once an X input has been defined, it may be used to stand for a
numeric value or set element later in the program. For example, it is
simple to have an X input stand for a scalar parameter, for example:
It is also possible to employ non-numeric inputs. For example:
defines an input item which may be referenced as %FTA_
USC%. This
string takes on a default value ``NO'', and an alternative value ``YES''.
This item can subsequently be used to define elements of a dynamic
set, as in:
Finally, if a continuously variable input is desired, the input may
be declared with a maximum and minimum value with a statement such
as:
Note that with continuously variable inputs, only numeric input
values will be allowed; i.e., if anything other than a digit, +, -, .
e, or E is encountered, an error will be returned. Also pay close
attention to the order of the MAX MIN: MAX
must be declared before MIN.
Formally, an X input statement must be entered on a single line with
at least three arguments:
The symbol name must be valid GAMS name. Some form of description and
at least one alternative value must be provided.
A GAMS program defines a GAMS-X output with statements like:
This statement defines a scalar output, the value of which
corresponds to the level value of variable utility. If an output item
is a declared parameter, the title of that parameter is automatically
transfered to the X tables. If, however, a level value or maginal
value is to be passed to the X table, a title must be specified
explicitly as shown above.
The modeler is responsible to chosing an appropriate numeric format
for output. The default presentation is fixed format with two
decimals. If fewer or more decimal places are required, this can be
specified using the GAMS global environment variable
xsol_
nd. Once specified, the decimal format applies to all
subsequent X outputs unless xsol_
nd is redefined.
A vector or matrix (one or two-dimensional) parameter may be
specified as an X output. For example:
declares and assigns a report parameter with a single dimension.
Because the output item is a parameter, GAMS-X automatically adopts
the parameter title as the X title. The title may be replaced using
the xtitle variable. Unlike xsol_
nd, the
xtitle is reset to blank after each X output statement.
When a one- or two-dimensional output item is specified, the sets
defining the parameter domain are specified in the X output
statement. The previous example is based on a one-dimensional domain.
The following example uses a two-dimensional domain in which one of
the domain dimensions is defined using a dynamic set:
Formally, an X output statement must be entered on a single line with
at least three arguments:
The output item must be a numeric value such as a parameter, level
value or marginal value. Output items may have no more than two
dimensions.
GAMS-X provides some rudimentary tools for graphical reporting. A
typical plotting statement would be:
As is the case for X output, an explicit title must be specified if
the item to be plotted is anything other than a parameter. When a
parameter is plotted, xtitle may be omitted.
The syntax of a plot statement is:
The domain set defines a set of points over which the item is
defined, typically years in dynamic models. The label set defines a
subset of the domain set for x-axis labels should be printed. In the
previous example, when the sets T and TL are defined as:
Then the resulting plot appears as in figure
Chapter 3
The GAMS-X Model Builder's Guide
3.1 Using GAMS-X with GAMS Models
3.1.1 Design Philosophy
3.1.2 Defining Inputs
$libinclude X INPUT BET 0.95 "Discount factor" 0.90 0.925 0.975
SCALAR BET Discount factor /%BET%/;
$libinclude X INPUT FTA_USC NO "FTA includes USA and Canada" YES
SET FTA(R) Regions entering a free trade agreement;
FTA("USC") = %FTA_USC%;
$libinclude X INPUT BET 0.95 "Discount Factor" MAX 0.975 MIN 0.95
$libinclude X INPUT symbol default "description" alt1 [alt2 ..alt4 ]
3.1.3 Defining Outputs
$setglobal xsol_nd 4
$setglobal xtitle "Intertemporal utility"
$libinclude X OUTPUT UTILITY.L
parameter CONSUM Consumption (trillion rupees per year);
CONSUM(TL) = C.L(TL);
$libinclude X OUTPUT CONSUM TL
PARAMETERS CROPREP Crop report summary;
SETS CREP Columns being reported
/ LANDUSE, OUTPUT, REVENUE /,
CT(*) Dynamic set including set C and "TOTAL";
CT(C) = YES;
CT("TOTAL") = YES;
CROPREP("LANDUSE",C) = XCROP.L(C);
CROPREP("OUTPUT",C) = XCROP.L(C)*YIELD(C);
CROPREP("REVENUE",C) = CROPREP("OUTPUT",C)*PRICE(C);
CROPREP(CREP,"TOTAL") = SUM(C, CROPREP(CREP,C));
$LIBINCLUDE X OUTPUT CROPREP CREP CT
$LIBINCLUDE X OUTPUT item [first_set [second_set]]
3.1.4 Defining Plots
$setglobal xtitle "Consumption (trillion rupees per year)"
$libinclude X PLOT C.L T TL
$libinclude X PLOT item domain_set [label_set]
SET T Annual time periods /1990*2050/,
TL(T) Label periods (decades) /1990,2000,2010,2020,2030,2040,2050/;
Note that the plot statement defines a set of plot series, which are then by default plotted across any cases that appear in a GAMS-Tk or GAMS-CGI casebook, customized plots may be generated that graph a set of series across a single case. For more information on the GAMS-X custom plotting facilities, please refer to chapter .
Plot options may also be defined by defining a plot_ opts global variable corresponding to the name of a set whose elements are the names of plot options and whose descriptors are their values. For example:
set plotopts / type bars height 500 /; $setglobal plot_opts plotopts $setglobal xtitle "Consumption (trillion rupees per year)" $libinclude X PLOT C.L T TL
Before concluding with the GAMS-X Model Builder's Guide, it is necessary to issue a caveat:
GAMS-X is not currently designed to handle dynamically generated plotting and output sets. That is, the size of output sets and plot sets may not change based on the set of inputs submitted by a user.
The GAMS-X visual interface serves as both a modeling aid for GAMS
modelers, allowing them to easily generate cases and casebooks which
are then instantly viewable over the web as well as customized
graphs, but as an administrative tool for GAMS-X administrators,
allowing them to create, edit and delete users and install and
uninstall models. It is also transparently integrated to GAMS-CGI,
so that not only is all of the functionality of GAMS-CGI available
within the GAMS-Tk environment, but any changes made in the GAMS-Tk
environment are instantly effected in the GAMS-CGI environment and
vice-versa.
As a visual application, it is meant to be as self-documenting as
possible, with help buttons included with the various menu options to
guide the user. Thus, the documentation that follows will consist
primarily of brief explanations of the various GAMS-Tk menu options.
You are encouraged to explore GAMS-Tk on your own and experiment with
the various menu options.
To use GAMS-Tk, type gams-tk.pl (or perl gams-tk.pl
in Windows 95/98) from the command line or click on it from Windows
Explorer.
You will notice when first starting GAMS-Tk that the GAMS-CGI site is
automatically paused, which is necessary to ensure that changes made
within GAMS-Tk don't interfere with any users' actions in GAMS-CGI.
This is a necessary precaution, and can't be avoided.
By the same logic, as a GAMS-Tk user you should note that user and
model states (that is, the information associated with GAMS-X users
and models) are loaded when GAMS-Tk is started, and saved when it is
exited. Thus, it is a good idea not to run any GAMS-X scripts while
GAMS-Tk is running so that changes made by the scripts are not
overwritten when GAMS-Tk exits.
I hope you enjoy this new product.
Chapter 4
The GAMS-Tk User's Guide
4.1 Getting Started
When you first start GAMS-Tk, you will notice a blank window staring back at you. This is not a cause for alarm; rather, you simply haven't given GAMS-Tk anything to show you.
So the first thing you want to do is to create a user account. Select the Tools.User.Create (see figure ) menu option, fill in some information, and click on the OK button.
Next, you'll want to install the Ramsey model that comes with GAMS-X just to make sure that the installation went smoothly. To do this, select the Tools.Model.Install menu option (see figure ). In the Model Install dialog box, enter Ramsey as the model name, then click on the Browse button beside the GAMS File entry box.
Go into the working directory, then select the Ramsey directory, then select the file Ramsey.gms. You will notice that the Model Description and GAMS-X Data File entry boxes are filled in for you. The Model Description is taken from the $TITLE statement in the Ramsey GAMS file, and if a *.gmx file is found in the same directory are the GAMS file, that is selected for the GAMS-X data file.
The GAMS-X data file is a file that you can generate with the File.Save.Model As.GAMS-X Data File menu option, and takes a ``snapshot'' of the cases and casebooks associated with the user account that you are currently viewing in GAMS-Tk. This is an easy way to transfer a set of cases and casebooks between GAMS-X sites, and with the Ramsey model allows us to present you with some default cases and casebooks.
When you select the 'OK' button, all of the GAMS output from solving the default Ramsey model and its cases will appear in the command prompt, just as if you had typed
gams Ramsey.gms
from the command line.8
Once you select the 'OK' button, you will notice at the command prompt that GAMS is solving the Ramsey model. Depending on the speed of your computer, this may not take more that a few seconds.
After the Ramsey model has solved, you will suddenly be faced with the default Ramsey cases in the casebook called STUDY1, including a table of the inputs selected for the cases, the outputs generated by the cases, and a window of the plots defined in the Ramsey GAMS code.
If you would like to take a look at the other casebook, STUDY2, select the Goto.Casebooks.STUDY2 menu option.
Now you might like to generate a new case of your own using the Edit.Case.New menu option (see figure ). Select a name for the case and the values of inputs that you would like (you can choose from the lists of inputs by double-clicking on a value in the lists below the entry boxes) and click on OK. The case you have created will appear under the heading ``Unsolved.'' This means that you still have to submit it to GAMS.
Cases are not by default submitted to GAMS when they are created because models may take quite some time to solve, and you don't want to be kept waiting! When you are ready to solve this new case (and any others you have generated) select the Tools.Solver menu option.
You might want to keep the command prompt in the background again when you before you click on the 'OK' button. That way, you can see the GAMS output from the solution of your case.
When you click on 'OK', GAMS-Tk will submit the new case to GAMS and, when it has finished solving, update your inputs and outputs table with the values that GAMS generated for your case and refresh the plots with the new case included.
The rest is just exploring. Have some fun!
The central GAMS-Tk view is the Casebook window (figure ), which contains the GAMS-Tk menubar as well as the summary of the current casebook.
If the model defines a set of plots (see chapter ), a plot window will be created as well (figure ).
From the Casebook window, the GAMS-Tk user is given access to the full array of options available to GAMS-CGI users, including case and casebook generation, as well as additional features not available to GAMS-CGI users, such as customized plotting facilities, LATEX and HTML page generation, model and case listing editing facilities, GAMS-X data file generation facilities, and all of the administrative tools needed by the GAMS-X site administrator.
The file menu provides a user the ability to save the current casebook configuration as a LATEX or HTML file, or to save models as GAMS-X data files. GAMS-X data files are convenient compact representation of the current model, including all of the casebook and case data, and can be used to transfer models installed in GAMS-X easily between GAMS-X sites. You will see how useful they can be if you read section .
Users can also exit GAMS-Tk through the file menu.
The Goto menu provides access to all of the user accounts, the models that have been installed, and the casebooks associated with the current user and model.
Thus, if a GAMS-Tk user wants to switch to another account, activating the Goto.Users menu option will drop down a list of user accounts on the site.
Similarly, if the GAMS-Tk user wants to look at another model, selecting Goto.Models will reveal a list of the installed models on the site from which another model may be selected.
If the user has created a set of casebooks, the Goto.Casebooks menu option will provide a dropdown list of all of the current user's casebooks.
The edit menu allows editing of cases and casebooks for a user and model.
From the Edit.Case menu, a new case may be created, an existing case that does not appear in the current casebook can be imported into the current casebook, a case found in the current casebook can be deleted, and/or any cases that have been removed from all of a user's casebook can be deleted from the user's account.
When the Edit.Case.New menu option is selected, the user will be presented with a window that prompts the user for a case name and allows new case inputs to be defined (see figure ).
Double-clicking on a value from the list below a case input will select that input value. The user can also enter a value in the text field above the list of input values.
From the Edit.Casebook menu, a new casebook may be created or a casebook from which all of the cases have been removed may be deleted from the user's account. In addition, the description associated with a casebook may be edited.
When the Edit.Casebook.New menu option is selected, the user will be presented with a window that prompts the user for a casebook name and description (see figure ).
After creating a new casebook, existing cases may be added to the casebook with the Edit.Case.Import menu option or by creating new cases through the Edit.Case.New menu option.
To change the description of an existing casebook, the Edit.Casebook.Revise Description menu option may be selected. The user will then be prompted for a new casebook description (see figure ).
The view menu give the user access to the documentation and GAMS source code for the currently loaded model as well as listing files for the cases that have been submitted to GAMS. GAMS-Tk users can also access a listing of the currently installed models and a casebook and case index for the current user and model.
The View.Model Index menu option creates a window similar to the GAMS-CGI Model Index page, listing the models that have been installed as well as their descriptions. See figure .
The View.Casebook Index menu option creates a windows similar to the GAMS-CGI Casebook Index page, listing the current user's casebook in the current model, as well as the cases and in which casebook they appear. See figure .
The View.Model Documentation menu option opens the model documentation page through the web browser (specified by the Browser configuration variable - see section for more information). This is the same documentation file that GAMS-CGI viewers will see when they click on the Model Documentation button on the Casebook Index or Casebook page.
The View.GAMS Source Code menu option opens the GAMS model file for the current model through the text editor specified by the TextEditor configuration variable. This is an excellent tool for model developers.
Finally, the View.GAMS Listing File menu option provides access to all of the listing files for the cases that have been submitted to GAMS through the user's text editor as used with the View.GAMS Source Code menu option above.
There is a nice trick that GAMS-Tk users can use to quickly view listing files: Just clicking on a case name (to the right of ``Item \\ Case'') will allow users to view the listing file of any case that has been submitted to GAMS.
The tools menu provides a host of administrative tools to GAMS-X site administrators, allowing them to create, edit, and delete models and user accounts as well as configure the current GAMS-X site. Since these options are discussed in detail in chapter , they will not be discussed here.
The tools menu also provides the model developer with a set of tools to create customized graphs and solve cases that have not yet been submitted to GAMS.
The Tools.Plotting menu option give the model developer the opportunity to either create plots of multiple plot series against a single case or multiple cases against a single series (see figure ).
Through the customized plotting facility, a whole array of plot customization options allow users to format the plots in just about any way they like, changing size of the plot or its fonts. The users may even put logos on the plots if they are so inclined. For more information on customized plot formatting options, refer to appendix .
When a new case is submitted, it is listed in the user's
The Tools.Solver menu option gives the user an option to submit all of the cases that have not yet been submitted to GAMS (see for an example).
Finally, the The Tools.Resolver menu option gives the user an option to completely change the configuration of a model, whether that means changing some equations, changing the number of inputs, outputs, or plots, or changing the plotting package from GIFgraph to Gnuplot, then resolve all of the outstanding cases.
Note that when the Resolver
The help menu allows users to check the current version of their GAMS-Tk installation as well as access sections of the HTML version of this manual.
When plots have been defined by the $libinclude X plot GAMS statement (for more information, see chapter ), a plots window will appear to display the default plots defined in the model. Note that customized plots may also be created through the Tools.Plotting menu option (for more information, see section 4.7).
In section 3, GAMS syntax was
introduced to define inputs, outputs, and plots to be associated with
a model. We now move from the modeler's perspective to that of the
GAMS-X programmer, administrator and user.
Central concepts to the understanding of the GAMS-X site are those of
user, casebook, and case.
Simply put, a GAMS-X user is an account on a GAMS-X site. As both
internet and local interfaces accompany GAMS-X, users can be accounts
established by a modeler locally for model development or they can
be accounts established by users who access their modeling
environment over the web.
A GAMS-X casebook is defined as a collection of cases. Users may use
casebooks to package sets of cases that they have generated.
Associated with the casebooks are any plots defined by the modeler.
A GAMS-X case corresponds to a set of GAMS-X inputs. When a user
selects from among the model input options, a case is generated and
submitted to GAMS to be solved. When GAMS has finished solving a
case, GAMS-X updates the case information with the outputs defined by
the modeler.
The visual tools accompanying GAMS-X (GAMS-CGI and GAMS-Tk) both use
the user-casebook-case idea to present GAMS models, and the GAMS-X
programming methods defined in all use
the user, model, casebook, and case syntax in defining the data
structures. For example, to see what the output UTILITY.L
for a case named MyCase in a casebook named
MyCasebook created by the user Grog for the model
Ramsey, a GAMS-X user could do one of three things:
As you can see, all of the tools available to the GAMS-X user,
including GAMS-X Script, GAMS-Tk, and GAMS-CGI are transparently
integrated, and that cases and casebooks defined and solved in the
GAMS-X scripting environment are mirrored in the GAMS-Tk and
GAMS-CGI visual environments, and vice-versa.
As GAMS-Tk and GAMS-CGI are robust enough to justify their own
chapters, the remainder of this chapter will focus on GAMS-X Script,
the real power behind GAMS-X. Those users who are just getting
started are encouraged to visit chapter 4
on GAMS-Tk and to explore GAMS-Tk to get a feel for
the GAMS-X environment before continuing with the remainder of this
chapter.
The remainder of this chapter will introduce a simple example of the
power and flexibility of GAMS-X scripting, provide an introduction
with all you need to know about the Perl scripting language to use
the GAMS-X scripting environment, and then work through a fully
developed example utilitizing the Ramsey model. Both the Ramsey
model and the sample script detailed in this chapter are provided
with the basic GAMS-X installation.
Chapter 5
The GAMS-X Scripting Guide
5.1 Overview of the GAMS-X Environment
print $GAMS->Cases('Grog','Ramsey')->{'MyCase'}->{Output}->{'UTILITY.L'};
5.2 Programming in GAMS-X
GAMS-Tk and GAMS-CGI provide visual interfaces that allow modelers, users, and webmasters to create and manage GAMS models. However, model developers require much more versatility in their modeling tools than can be provided with a visual environment. GAMS-X scripting is the answer to that need, providing all of the tools available in GAMS-Tk and GAMS-CGI in a scripting environment, as well as all of the advantages of a high-level programming language such as advanced data structures, control flow procedures, easy formatting of textual output, and access to a well-developed and well-documented module library with such tools as PDL (Perl Data Language), OLE9, and Windows COM objects.
As a Perl module, GAMS-X supports a rich programming environment for those who are willing to learn just as much Perl as can be explained in a few pages.
For example, suppose you want to analyze the sensitivity of a model to its parametrization. Once the model has been installed in GAMS-X, a modeler can create a short text file that will not only generate a hundred cases, but graph them and generate a data file so that the same set of cases can be instantly reproduced at any GAMS-X (and hence GAMS-CGI) site around the world. All that is required is
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
for $i (1..100) {
$GAMS->Set( -Case => "Case $i", -Inputs { K => $i / 100 } );
$GAMS->AddCase;
}
Then to print out the results from all of the cases which returned a value of UTILITY.L greater than 8.0, a simple snippet of code such as the following would do the trick:
foreach $Case (grep $_->{Output}->->{'UTILITY.L'} > 8.0, @{$GAMS->UserState}) {
print "Intertemporal utility for case $Case->{Name} is $Case->{Output}->{'UTILITY.L'}.\n"
}
Much more powerful feats are possible in the GAMS-X programming environment, but before going on more serious business, we should take a very brief diversion into Perl-style syntax.
As you know if you have already installed GAMS-X, Perl is an extremely powerful, popular, and free programming language. It was created by Larry Wall, endowed with a C-style syntax with an almost free-form programming feel.
Perl can be either scripted or compiled, unlike many programming languages such as C++ or Java. Scripted languages are those that simply accept a text file as input and execute the input contained therein, much like GAMS. GAMS-X, as a child of Perl, is itself scripted in the Perl syntax. Compiled languages, on the other hand, must be passed through a compiler, which turns the code into an executable format understandable by the computer. GAMS-X Lite is the compiled version of GAMS-X, and therefore has no scripting capabilities.
At one time, scripted languages were considered the poor cousins of compiled languages, mostly due to the fact RAM was in short supply, making the use of an extra meg for a script interpreter impractical, and processors were slow, resulting in significant performance losses due to the parsing of scripts prior to their execution. However, with the cheap memory and ultra-fast processing available to modern PCs, scripting languages have come into their own, and are almost ubiquitous (though most people don't actually know when they are running a script!) due to their suitability for web applications.
In order to use the GAMS-X scripting capabilities, you really only need to know a few Perl commands which are easily recognizable by anyone with even a passing knowledge of programming and easily understandable by those with no programming knowledge at all.
NB: Before continuing, please note that your humble programmer has noticed that Netscape Navigator 3.04 (but, mysteriously, not Netscape Communicator 4.5) tends to have problems with some sections of the code examples (i.e., the occasional word in the code examples disappears), and that it is best to use the PDF version of this document rather than the HTML version to learn the information in this section and the next if you suspect that some words are missing from the code examples.
The first two commands, use and new , will appear at the top of every GAMS-X script. Use simply informs the compiler that one of either the GAMS, GAMS-Ini, GAMS-Tools, or GAMS-CGI modules will be used. Note that GAMS-Ini is a part of GAMS and that GAMS is a part of GAMS-Tools and GAMS-CGI. Thus, anything available in the GAMS-Ini or GAMS modules is available when you use the GAMS-Tools or GAMS-CGI modules.
The new command simply informs the module that you are getting ready to do something, and that it should load the appropriate routines and environment. In technobabble, it instantiates a blessed reference to a named anonymous hash.10 You could also say that it instantiates a thingy that knows what it is.
Let's call our example script myexample.pl. Simply open a file in your favorite text editor, such as Emacs or Windows Notepad, type the following lines, and save the file with the name myexample.pl.
use GAMS::Script; $GAMS = new GAMS::Script;
We now have a GAMS object ready to work with, though we haven't actually done anything with it yet. (More on that later ...) The GAMS object itself is the $GAMS in the code above. $GAMS is an example of a scalar, one of three data types available in Perl. A scalar can consist of a string of characters, such as ``Grog'', a number, such as 5, or a reference to another data type, such as an object (in this case the GAMS object). If you don't know what a reference is, don't worry. You won't need to know what one is in order to use it.
So to define a simple scalar such as the message ``Hello World!'' in Perl, you would type
$scalar = "Hello World!";
Note that all statements in Perl, as in GAMS, are terminated by a semicolon.
The other two data types in Perl are lists and associative arrays. A list is exactly what it sounds like, an ordered list of things, and is differentiated from a scalar by the use of an @ rather than a $. The things in the list are scalars, which in turn can be references to other lists or objects or whatever.
Thus to define a list, you would type
@list = ( "I am a string", "The next item is a number", 5);
To look at a particular item in the list, for example the first entry of the above list, use the syntax $list[·], where the · represents the index of the list starting from 0. To print The next item is a number from the above list, the print command could be used as follows:
print $list[1];
A convenient Perl construction that can be used in tandem with the print command is the << operator, which causes Perl to replace the << with all of the lines of text that follow up to a line with only the string following the << on it.
For example, the statement
print <<"EndOfHTML"; <HTML> <BODY> Hi there. I am an HTML document. Everything will be printed up to a line containing only "EndOfHTML". </BODY> </HTML> EndOfHTML
With the << operator, it is easy to nest HTML documents in your Perl script.
Furthermore, a list can be looped over using a foreach statement. For example, the command
foreach $item (@list) {
print $item, "\n";
}
would print each item in the list. In the example, the foreach command causes Perl to start at the beginning of the list and put each item in the list in the scalar $item. Then the first print command prints the item ($item). The second print command uses a newline character \n to create a new line before going through the next iteration of the loop to keep all of the things being printed from bunching up on the same line. The newline character is an example of an escape character, which include tabs and backspaces, among others.
Note that loops can also be created with the standard C syntax, where the first statement in parenthesis initializes a scalar ($i=0), the second declares a condition which, when false, causes the loop will be exited ($i<100), and the third which increments or decrements the looping scalar ($i++, which, in C syntax, is the same as the statement $i=$i+1). For example:
for ($i=0;$i<100;$i++) {
print $i;
print "\n";
}
which would print the numbers 0 to 99.
Two important commands used with lists are sort and reverse. The sort command sorts the list alphabetically while reverse sort reverses the order of the sort command.
The third Perl data type, an associative array, is simply a collection of key-value pairs, and is differentiated from scalars and lists by means of a %.11 If, for example, there are people named Joe and Mary with IDs 1 and 2, their IDs could be put into an associative array as follows:
%array = ( "Joe" => 1, "Mary" => 2 );
This statement indicates that the key Joe is to be associated with the value 1 and Mary is to be associated with the number 2.
Now to print the value associated with the name Joe, the command
print $array{"Joe"};
would print the number 1.
Notice that curly brackets, rather than the square brackets of lists, are used to index items in associative arrays.
Three important commands used with associative arrays are keys, values, and exists. The keys command returns a list of all of the keys in an associative array.
Thus the code
@keys = keys %array;
foreach $key (@keys) {
print "The key is $key\n";
print "The value is $array{$key}\n";
}
will print all of the keys in the array %array. Note in this example the ability of Perl to nest variables in strings. Here, the value of $array{$key} is put into the string before the string is printed. This is called string interpolation. In Perl, the primary difference between using single and double quotes is string interpolation: When a string is defined using double quotes, any variables contained within it are interpolated, whereas when a string is defined using single quotes, variables are not interpolated. Thus the commands
$string = "World"; print "Hello $string!";
would print Hello World! whereas the commands
$string = "World"; print 'Hello $string!';
would print Hello $string!.
Also note that to print the names in alphabetical order, the command
@keys = keys %array;
could be replaced with
@keys = sort keys %array;
The values command is much like the keys command, only a list of the values of an array are returned.
The exists command seems unimportant, but is very useful when working with GAMS-X scripts. Perl dynamically creates variables as they are used; that is, just typing $var creates the variable $var. Similarly, if the key to an associative array doesn't exists, and you want to see if it does with a statement like
if (not $array{'mykey'}) { print "I can't find mykey!" }
then you have just defeated the purpose of your if statement, as the $array{'mykey'} dynamically created a variable called %array if one didn't already exist and then created a key called mykey in %array with a blank value. Instead, you should use
if (not exists $array{'mykey'}) { print "I can't find mykey!" }
This is useful in GAMS-X scripting, for example, if you want to check whether a user exists. Then the command would be
if (not exists $GAMS->Users->{'ID'}->{'Grog'}) {
print "Grog does not have an account on this site!"
}
If, instead, you had used the statement
if (not $GAMS->Users->{'ID'}->{'Grog'}) {
print "Grog does not have an account on this site!"
}
then you have just created a blank user account for Grog if one did not already exist.
Finally, we will discuss pointers. Pointers are simply scalars that point at another type of variable. There are many technical advantages to using pointers which are beyond the scope of this little tutorial; thus, only their use will be described.
Pointers basically point at a memory address, which may be the start of a list or an associative array or object or whatever. In fact, in the example above, the statement $GAMS = new GAMS, $GAMS is a pointer, or a scalar that points at a GAMS object. In order to use them, you need to indicate what you want the pointer to point at. So, for example, if you have a pointer $pointer that points at a list , to look at the third element of using the variable, you would type
print $list[2];
Recall that the first element of a list is 0, a convention that follows from the C programming language.
On the other hand, if you want to look at the third element of using the pointer variable $pointer, you need to show that you are pointing at something with an ->:
print $pointer->[2]
Similarly, if $pointer points at an associative array, to look at the value of the array corresponding to the key Grog, you would use the following syntax:
print $pointer->{"Grog"};
To create a pointer to a list, use square brackets instead of parentheses, and to create a pointer to an associative array, use curly braces instead of parentheses. For example:
$list_pointer = [ "I", "am", "a", "pointer", "to", "a", "list" ];
and
$associative_array_pointer = { "I am a key" => "I am a value" };
You will notice throughout the documentation on GAMS-X scripting that pointers are used. Thus, when you use the command
print $GAMS->Cases->{'HIGHB'}->{Output}->{'UTILITY.L'}
you are actually printing the value of the UTILITY.L key of the Output pointer, which is the value of the Output key of the 'HIGHB' pointer, which the the value of the 'HIGHB' key of the pointer to an array returned by the Cases method. It almost makes my head spin, but I hope you get the idea.
One note of caution to those who have not used pointers before: Because they point at a memory address rather than an actual chunk of data, you can inadvertantly modify something that you did not intend to if you are not careful. For example,
@list1 = ( 1, 2 ); @list2 = @list1; $list2[0] = "Hello World!"; print $list1[0];
simply prints the number 1, whereas the script
@list1 = ( 1, 2 ); $pointer = \@list1; $pointer->[0] = "Hello World!"; print $list1[0];
prints "Hello World!".12 Thus the following caveat: If you are not comfortable working with pointers, don't make any changes to variables that are pointers or variables set equal to pointers! You will not need to worry about this when working with GAMS-X scripts unless you are doing something out of the ordinary. If you just rely on the GAMS-X methods to make changes in cases and casebooks, you should have no problems.
One last note on pointers: You will find it extremely useful to be able to extract the lists and associative arrays which GAMS-X methods return. To do this, simply surround the method name with curly braces { and } and put an @ (for a list) or % (for an associative array) in front. For example,
@list = @{$GAMS->UserState('Grog','Ramsey')->{Case}};
%array = %{$GAMS->Cases('Grog','Ramsey')};
So far, the use and new commands have been described, along with three Perl data types and the for, print, sort, reverse, keys, and values commands have been covered. Furthermore, pointers to lists and associative arrays have been discussed. This finishes off our brief tour of ``everything you need to know about Perl to use GAMS-X.''
We are now ready to move on to a few quick examples of GAMS-X scripts. These snippets of code are just to whet your appetite. A fully developed example script, included in the scripts subdirectory of the basic GAMS-X installation, is described in the next section.
All of the actions performed by these example scripts are accomplished by the use of is called a method, which is simply something that an object, such as the GAMS or GAMS-CGI object, does. To invoke a method, simply follow the name of the object (e.g., $GAMS in the example above) with an arrow -> and the name of the method. You may want to at some point peruse the list of all of the GAMS methods given in appendix .
Now let's say you want to know what the output UTILITY.L is for a case called HIGHB corresponding to a high capital value share. You know that the case HIGHB is contained in your user Grog's account. Then all that is required is a simple and intuitive statement using the Cases method. The complete script would be
use GAMS::Script;
$GAMS = new GAMS::Script;
print "The utility for the user Grog's case HIGHB in the model Ramsey is: ";
print $GAMS->Cases("Grog","Ramsey")->{"HIGHB"}->{Output}->{"UTILITY.L"}
Once you have saved the file as myexample.pl, you can type
myexample.pl
from the command line to see the results. If you are using Windows 95/98, you will have to type
perl myexample.pl
if you are at a DOS prompt to see the results.
That's all there is to it! Now let's do a couple of quick examples that make use of the real power of GAMS-X scripting.
These examples are just for show. A full-blown example, including just about all of the basics you need to know to work with models, will be presented in the next section.
Suppose that now you want to generate 100 cases in GAMS-X. Doing so through either of the visual interfaces, GAMS-Tk or GAMS-CGI, would take a prohibitive amount of time. But with GAMS-X, there is no fussing with batch files or using put statements to create data files for graphing or presentations. Simply use the Set and NewCase methods:
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => "Grog", -Model => "Ramsey" );
for ($i=0;$i<100;$i++) {
$GAMS->Set(
-Case => "Case $i",
-CaseInputs => { "BET" => ( 0.9 + $i / 7500) }
);
$GAMS->NewCase;
}
Now the cases have been created in GAMS-X.13
Suppose now that you now wanted to plot consumption, given by the GAMS parameter UTILITY.L, over all 100 cases in groups of three. You could simply append the following lines to the above script:
for ($i=0;$i<97;$i++) {
$File = "Plot$i.gif";
$User = "Grog";
$Model = "Ramsey";
$Cases = ["Case $i","Case ".$i+1,"Case ".$i+2];
$Plot = "KK.M";
$PlotOptions = {
"type" => "bars",
"height" => 400,
"width" => 600
};
$GAMS->MultiPlot($File,$User,$Model,$Cases,$Plot,$PlotOptions);
}
You will notice the dot operator . in the above example (e.g., "Case ".$i+2). This is simply the Perl concatenation operator, and joins two strings as one.
As will be discussed in chapter , the scripting capabilities of GAMS-X also provide administrators with almost total control over their online modeling environment and web programmers the ability to completely customize an online modeling environment. For example, if a webmaster wants to restrict access to the model Ramsey to the user Grog, the GAMS-CGI script gams-cgi.pl could be modified with the following snippet of code:
if ($GAMS->Model eq 'Ramsey') {
unless ($GAMS->User eq 'Grog') {
$GAMS->Gripe("Access is denied.");
}
}
Keep in mind that the information on Perl presented here only scratches the tippy tip of the tip of the iceburg that is Perl. Once your model has been put into GAMS-X, you have all the considerable power of Perl at your fingertips, from the mathematical functions of the PDL (Perl Data Language) module to the graphics abilities of JPL (Java Perl), a module which allows for Perl to be nested in Java, to Windows object linking and embedding and COM objects through the Win32::OLE and PerlCOM packages, to the email and web facilities abilities of Perl through the Net::SMTP, Net::FTP, and LWP modules.
For more information, I recommend that you visit the Perl website http://www.perl.com , and, if you are a Windows user, the ActiveState website http://www.activestate.com , and check out any of the Perl books available in bookstores. For those who are not already proficient programmers, I recommend []. [] is also an excellent reference. For experienced programmers, [] is a excellent and comprehensive, albeit technically sophisticated, overview of the Perl programming language.
The purpose of this section is to lead you through a small GAMS-X script which will perform a number of operations that you will find useful when using GAMS-X, including creating a new user, installing a model, creating a new casebook for the model, creating some new cases for the model, solving the cases, sorting the cases, putting the sorted cases in the casebook, saving a GAMS-X data file, creating some customized plots for your model, and exiting GAMS-X. It sounds like quite alot of work, but as you'll see, it really is not.
In the course of the script, all of the cases and casebooks that are created when the Ramsey model, included with the default GAMS-X installation, is installed through GAMS-Tk, will be generated.
These activities will familiarize you with the most important GAMS-X methods, though there are many, many others at your disposal.
You should read through the example in full, then go back and try it out if you want. If you would like to see the full text of the example, see appendix .
For a full listing of the GAMS-X data structures, see appendix . There are also many examples in this appendix that you might find useful.
For a full listing of available GAMS-X methods, see appendices through
Before getting started, if you have a GAMS-Tk window open, you should be sure to pause GAMS-Tk using the Tools.Site.Pause GAMS-Tk menu option before running any GAMS-X scripts. For more information on pausing GAMS-Tk, see chapter 4.
We first need to inform Perl that we are working with the GAMS methods. Thus, start your script with two lines you will come to know very well as you work more with GAMS-X:
use GAMS::Script; $GAMS = new GAMS::Script;
Now, as the GAMS-Tools module inherits the GAMS-Ini and GAMS objects, you have all of the GAMS-Ini, GAMS, and GAMS-Tools methods available at your disposal.
The first thing you will want to do is create a new user. Since the GAMS-Tk and GAMS-CGI visual environments are built around user accounts, you need to have created a user account to be able to view your model using the GAMS-X visual tools.
You can use the AddUser method to create a new user, which takes as arguments the user's name, the user's password, a password confirmation (just to make sure!), the user's affiliation, the user's email address, and the user's home IP (used by GAMS-CGI).
So to create our user, we can use the GAMS Set method in conjunction with the AddUser method as follows to create a user named Grog by adding the following lines to the script:
$GAMS->Set(
-User => "Grog",
-Password => "grog!",
-PasswordConfirmation => "grog!",
-Affiliation => "University of Grog",
-Email => 'grog@spot',
-UserHome => "Local Host"
);
$GAMS->AddUser;
Note the use of single quotes in defining the email address. This is because lists are defined by the @ symbol in Perl. If double-quotes are used, Perl would try to find a list called @spot and interpolate it into the email string. With single quotes, no interpolation is performed.
If you need to have an @ symbol in a double-quoted string, you can escape the @ character by using the forward-slash like so: "grog\@spot".
Equivalently, we could have used the lines
$GAMS->AddUser(
"Grog",
"grog!",
"grog!",
"University of Grog",
'grog@spot',
"Local Host"
);
Note that the UserHome parameter is optional.
Now that you have a user account to work in, you will want to install a model. For this example, the Ramsey model provided with the default GAMS-X installation will be used. If you have already installed the Ramsey model, you can uninstall it in GAMS-Tk by using the Tools.Model.Uninstall menu option, or by reading the next section on uninstalling models with GAMS-X scripts.
The GAMS-Tools method Install is used to install a model, and takes as arguments the model name, the description, the name of the GAMS file to associate with the model, the name of an HTML file to associate with the model documentation, and the name of a GAMS-X data file. Note that the last two arguments are optional. If the documentation argument is not included, a simple HTML file will be created informing users that no documentation is associated with the model, and if the GAMS-X data file is not included, the default case (that is, the case which takes as its inputs the default input values) will simply be generated.
So now to install our model (assuming that the file Ramsey.gms is located in the C:\gams-x\working directory, which is the case if GAMS-X is installed in the C:\gams-x directory on your computer), include the following lines with the script:
$GAMS->Install( 'Ramsey', 'Ramsey Model of Optimal Economic Growth', 'C:\gams-x\working\Ramsey\Ramsey.gms' );
You have now installed the model Ramsey.
If now at some point you need to uninstall the Ramsey model, simply include the model name as an argument to the Uninstall method:
$GAMS->Uninstall( 'Ramsey' );
You can also remove the user account for the user Grog with the Kill method:
$GAMS->Kill( 'Grog' );
There is a nice trick you can use to do the same thing from the command line: The M flag causes Perl to automatically load the module whose name follows the M, and the e flag causes Perl to automatically execute the command that follows the e.
Thus you could also uninstall the Ramsey model by typing, from the command line,
perl -MGAMS::Tools -e "$GAMS=new GAMS::Tools;$GAMS->Uninstall('Ramsey');"
Similarly, you could remove the user Grog's account by typing from the command line
perl -MGAMS::Tools -e "$GAMS=new GAMS::Tools;$GAMS->Kill('Grog');"
We now want to create a couple of casebooks for the Ramsey model. To create new casebooks, the GAMS NewCasebook method can be used.
The NewCasebook method takes as arguments a user name, a model name, the name of the casebook, and, optionally, a description of the casebook.
So to create two new casebooks named STUDY1 and STUDY2, we can add the following lines to our little script:
$GAMS->Set(
-User => "Grog",
-Model => "Ramsey",
-Casebook => "STUDY1",
-Description => "Comparing a high capital value share and high labor growth rate"
);
$GAMS->NewCasebook;
$GAMS->Set(
-Casebook => "STUDY2",
-Description => "Comparing a high labor growth rate and low discount factor"
);
$GAMS->NewCasebook;
Note that the second Set method call does not include the User and Model arguments, as those parameters have already been set by the first call.
Now we want to create some new cases for the model. In order to create a new case, we have to define a set of inputs.
Normally we would have to set a user and model for which a case is defined, but we already did that in section above. Note that only the input that differs from the default is set. All of the inputs not explicitly defined are set to their defaults.
print "Creating case HIGHB . . .\n";
$GAMS->Set(
-Case => "HIGHB",
-CaseInputs => { "B" => 0.30 }
);
$GAMS->NewCase;
print "Creating case HIGHG . . .\n";
$GAMS->Set(
-Case => "HIGHG",
-CaseInputs => { "G" => 0.06 }
);
$GAMS->NewCase;
print "Creating case LOWBET . . .\n";
$GAMS->Set(
-Case => "LOWBET",
-CaseInputs => { "BET" => 0.90 }
);
$GAMS->NewCase;
NB: While GAMS syntax is case-insensitive, GAMS-X syntax, consistent with that of Perl, is not. Therefore if you create a GAMS-X input with a GAMS statement like
$libinclude X INPUT BET 0.95 "Discount Factor" MAX 0.975 MIN 0.95
you can refer to the input later in your GAMS file with a statement like
SCALARS BET DISCOUNT FACTOR /%bet%/
whereas in GAMS-X, you must use the capitalization used in declaring the input in GAMS (i.e., BET rather than bet). For example,
print $GAMS->Inputs('Grog','Ramsey')->{'bet'}->{Default};
would print nothing whereas
print $GAMS->Inputs('Grog','Ramsey')->{'BET'}->{Default};
would print the default value of the input BET (i.e., 0.95).
If you want to define multiple inputs, simply separate them by a comma. For example,
$GAMS->Set(
-Case => "HIGHB&LOWBET",
-CaseInputs => { "G" => 0.6, "BET" => 0.90 }
);
Notice the use of curly braces following the CaseInputs option. While reading the documentation on GAMS-X scripting, pay close attention to whether parentheses, curly braces, or square brackets are used. They each carry a quite different meaning.
Now that the cases have been created, we need to submit them to GAMS by calling the Solver method. The Solver method does a couple of things: First, it looks for any cases that have not been submitted to GAMS and submits them to GAMS. Second, it updates that GAMS-X database to reflect the solutions of the cases, including any plots that have been defined.
To invoke the Solver method, we need only include the line
$GAMS->Solver;
Now that we have a batch of freshly solved cases to work with, we need to bundle them somehow for viewing. To be able to see cases in GAMS-Tk and GAMS-CGI, they need to be included in casebooks.
$GAMS->Set(
-Case => "HIGHB",
-Casebook => "STUDY1"
);
$GAMS->Book;
$GAMS->Set(
-Case => "HIGHB"
);
$GAMS->Book;
The Book method does not generate the casebook plots, so it is important if you have plots to be seen, that when you finish putting cases into a casebook, you create new plots for the casebook with the CasebookPlot method
$GAMS->CasebookPlot;
Now let's put some cases into the casebook STUDY2 ...
$GAMS->Set(
-Case => "HIGHG",
-Casebook => "STUDY2"
);
$GAMS->Book;
$GAMS->Set(
-Case => "LOWBET"
);
$GAMS->Book;
$GAMS->CasebookPlot;
Now if you were to run the little script we have so far, then start GAMS-Tk (or open a web browser and log in to your GAMS-CGI site), you would see the user Grog with all of the Ramsey cases and casebooks installed as they have been defined. However, to finish with our example, we will have our script do some things that really show off the abilities of GAMS-X scripting.
Suppose that now you want to sort the cases. With three cases, this is not such an important task, but with a hundred or a thousand cases, this can be quite important.
To accomplish this task, we use the Perl grep function in combination with the Perl $_ variable and Perl's pattern matching facility. These are fairly advanced concepts, and so won't be discussed here except via the example that follows.
Suppose that you want to look for all of the cases that were submitted to GAMS and did not result in a GAMS error (all of the cases should meet this criteria if your GAMS solvers are correctly installed), have a capital value share greater than 0.25 (the case HIGHB meets this criteria), an output of intertemporal utility greater than 1 (all of the cases will meet this criteria) and includes the letter H in the case name in either upper or lower case (just for kicks!). This can be done with just one statement:
@MySortedCases =
grep $_->{'Status'} eq 'Solved',
grep $_->{'Input'}->{'B'} > 0.25,
grep $_->{'Output'}->{'UTILITY.L'} > 1,
grep /H/i, @{$GAMS->UserState->{'Case'}};
Just to confirm that we have got what we are looking for, we should print out the case names:
if (@MySortedCases) {
# . . . that is, if there are any cases in the @MySortedCases list
foreach $Case (@MySortedCases) {
print "The case $Case->{'Name'} meets my sorting criteria.\n";
}
} else {
print "No cases meet my sorting criteria!\n";
}
Here the UserState->{'Case'} reference returns a pointer to the list of cases for the current user and model. The surrounding @{·} turns the pointer into a list.14 Then the last grep statement extracts all of the cases that have an H in their name, and hands that list (in this case, HIGHB and HIGHG) off to the second grep statement. The second grep statement finds all of the cases in that list that have output of intertemporal utility greater than 1 and hands that list (still including HIGHB and HIGHG, since they both meet the utility criteria) off to the first grep, which finds all of the cases with a capital value share greater than 0.25. The print statement should print the statement
The case HIGHB meets my sorting criteria.
Now suppose that you want to bundle up your cases and casebooks with your model and send them off to your friend Wonk in Reykjavik, Iceland. You can just save the current case and casebook configuration as a GAMS-X data file, then forward that with your GAMS model, and he can install and play with it on his own GAMS-X installation.
To do so, simply invoke the WriteData method, included with the GAMS-Tools module, with a filename as an argument.
The WriteData method also takes a user name and model name as its second and third argument, but since that has already been set with the Set method above, they can be omitted.
Here's the code:
$MyDataFile = 'C:\temp\Ramsey.gmx'; print "Writing GAMS-X data file to $MyDataFile . . .\n"; $GAMS->WriteData( $MyDataFile );
You will note that single-quotes were used rather than double-quotes in defining the string containing the file name. That is because Perl uses the DOS directory divider (the forward-slash) as an escape character when double-quotes are used.
If you need to include the forward-slash in a double-quoted string (if you are using string interpolation, for instance), you can do something like this:
$MyDataFile = "C:\\temp\\Ramsey.gmx";
I prefer to use the single-quotes for readablity.
Now you notice that the plots provided by default are not exactly what you want. Instead, you would like to plot many series across a single case.15 To do so, you can use the MultiPlot method.
First, you will want to define a pointer to a list of the plot series that you would like to see. You can do that with the statement
$Plots = [ "C.L", "I.L", "CC.M" ];
which creates a list of plot series whose names correspond to the ``Consumption (trillion rupees per year)'', ``Investment (trillion rupees per year)'', and ``Present value of consumption'' plot series.
Next, if you want any of the plot options set to anything other than their defaults, you should set the plot options. The plot options are defined by a pointer to an associative array in the same way the the CaseInputs option was defined above.
$PlotOptions = {
"height" => 400,
"width" => 500,
"type" => "bars"
};
Now you can create the plot with the following statements:
$GIFFile = 'C:\temp\MyPlots.gif';
print "Generating customized plot in file $GIFFile . . .\n";
$GAMS->MultiPlot(
$GIFFile,
"Grog",
"Ramsey",
"HIGHB",
$Plots,
$PlotOptions
);
Perl, which is reputed to stand for Pathologically Eclectic Rubbish Lister, was originally conceived as the Practical Extraction and Report Language. This means that you can easily generate nicely formatted output through the C-style printf commands as well as the Perl format command.
An example might go something like:
print <<"eop";
Here is a listing of the cases I have just generated as well as the
value of the output UTILITY.L, all nicely formatted for my viewing
pleasure:
Case UTILITY.L CONSUM(1990) CONSUM(2050) KK(1990) KK(2050)
---- --------- ------------ ------------ -------- --------
eop
format MYFORMAT =
@|||||||||||||| @###.#### @###.#### @###.#### @##.#### @##.####
$Name, $UTILITY, $CONSUM1990, $CONSUM2050, $KK1990, $KK2050
.
$~ = MYFORMAT;
for $Case (@{$GAMS->UserState("Grog","Ramsey")->{'Case'}}) {
$Name = $Case->{'Name'};
$UTILITY = $Case->{'Output'}->{'UTILITY.L'};
$CONSUM1990 = $Case->{'Output'}->{'CONSUM(1990)'};
$CONSUM2050 = $Case->{'Output'}->{'CONSUM(2050)'};
$KK1990 = $Case->{'Plot'}->{'KK.L'}->[0];
$KK2050 = $Case->{'Plot'}->{'KK.L'}->[60];
write;
}
This example uses some fairly esoteric Perl commands such as format and $~. For more information on formatting output in Perl, please refer to your Perl documentation.
As a last step, we need to invoke the Quit method. This method makes sure that all of the new information generated by the script is saved. As a rule, you should end any GAMS-X scripts that make changes in a user or model state with the Quit method.
To finish the script, add the following lines:
print "Quitting . . .\n"; $GAMS->Quit;
We now have a simple script, no more than a couple pages long including print statements, that creates a new user account, installs a model, creates some cases and solves them, creates some casebooks, sorts the cases and puts them in the casebooks, and generates a customized plot. Not too bad for a few minutes of typing!
The full text of the script is given in appendix and is included in the scripts subdirectory of the GAMS-X distribution. After running the example, you might enjoy running GAMS-Tk and viewing the results.
As this example demonstrates, GAMS-X scripting gives those who are willing to learn just a little bit of programming syntax the power to easily create personalize GAMS-X reports and utilities. In fact, Tom Rutherford both learned the GAMS-X scripting system and created the case.bat and book.bat utilities included in the scripts directory of the GAMS-X distribution in less than an hour!
If you find the GAMS-X scripting system useful, and create scripts that you think would be helpful to other GAMS-X users, please forward them to me at .
This chapter will discuss GAMS-X administration from two perspectives: Administration using the GAMS-X scripting language and administration using the GAMS-Tk visual interface. The visual interface is much more convenient to use for mundane administrative tasks, but the scripting capabilities provide a much wider range of functionality to the administrator.
The GAMS-X site configuration includes all of the configuration variables defined in the GAMS-X initialization file (see section ), and controls such widely diverse aspects of the GAMS-X environment as the directory structure, the appearance of GAMS-Tk, the appearance of GAMS-CGI, and the location of the GAMS-X help files.
To retrieve and/or modify configuration variables in GAMS-Tk, use the Tools.Site.Configure menu option. A window will appear with all of your configuration variables (see figure ). Simply click on the name of a configuration variable if you want to change its value.
To retrieve them in the form of an associative array in GAMS-X script, use the Configuration method. For example:
print "All of the GAMS-X configuration variables are as follows:\n\n";
foreach $key (sort keys %{$GAMS->Configuration}) {
print "$key: ";
print $GAMS->Configuration->{$key};
print "\n";
}
To change the value of a configuration (also changing its value in the GAMS-X initialization file), use the Configure method. For example:
$GAMS->Configure( -Logo => "mylogo.gif", -LogoHeight => 100, -LogoWidth => 150 );
Two basic model summaries for models installed on a GAMS-X site are available in GAMS-Tk: The model index and the model summary.
To view the model index (figure ), select the View.Model Index menu option. This will present a list of the installed models together with their descriptions.
To view the model summary (see figure ), select the Tools.Model.Summary menu option.
A list of the installed models together with the number of solved cases, the number of cases which have generated GAMS errors, and the number of cases which have not yet been submitted to GAMS will be provided.
From the model summary, you may click on the name of any of the models to be provided with more detail regarding the model cases (see figure ).
When viewing the resulting window with the list of model cases, you may click on any of the case tags to view more detail on that particular case or edit the case (see figure ).
More detailed model information can be obtained through GAMS-X scripting with the Models and ModelState methods.
The Models method returns a pointer to an associative array with the keys ID, Installed, Description, File, Base, Root, GXFile, and Documentation.
The ID key provides the internal GAMS-X ID number of the model.
The Installed key returns the time and date of the model installation.
The Description key returns the description of the model.
The File key returns the full filename of the GAMS file associated with the model. The Base and Root keys return the file name (without the full path) of the File key, and the Root key returns the path (without the file name) of the File key.
The GXFile key returns the full filename of the GAMS-X datafile associated with the model, whereas the GXBase key returns only the filename of the GXFile key.
The Documentation key returns the file name of the HTML file associated with the model.
Example:
print "Here is the information associated with the model Ramsey:\n\n";
print "The GAMS-X model ID: ", $GAMS->Models->{ID}->{"Ramsey"}, "\n";
print "The installation date and time: ", $GAMS->Models->{Installed}->{"Ramsey"}, "\n";
print "The model description: ", $GAMS->Models->{Description}->{"Ramsey"}, "\n";
print "The GAMS file associated with the model: ", $GAMS->Models->{File}->{"Ramsey"}, "\n";
Thus, to obtain a list of the models currently installed on the site, you may simply check which models have been issued an ID:
print "The following models are installed:\n\n";
for $Model (sort keys %{$GAMS->Models->{ID}}) {
print $Model, "\n";
}
ModelState method takes a model name as an argument (provided a model has not been set with the Set method) and returns a reference to a ModelState data structure containing information on all of the cases, including those that have been submitted to GAMS and those pending submission, associated with the model. This data structure is described in full detail in section , and so will not be described here.
To install a model from GAMS-Tk, use the Tools.Model.Install menu option. You will be queried for model installation information by the model installation window (see ).
To install a model from a GAMS-X script, use the Install method, which takes as arguments the model name, a description, the file name (with a full absolute path) of the GAMS file, and, optionally, the file name (with full absolute path) of the model documentation and the file name (with full absolute path) of a GAMS-X data file to associate with the model. Example:
$GAMS->Install( 'Ramsey', 'Ramsey Model of Optimal Economic Growth', 'C:\gams-x\working\Ramsey\Ramsey.gms', 'C:\gams-x\working\Ramsey\X.gmx' 'C:\gams-x\working\Ramsey\Ramsey.html' );
To uninstall a model from GAMS-Tk, select the Tools.Model.Uninstall menu option. For help, click on the Help button at the bottom of the model uninstall window (see figure ).
To uninstall a model using a GAMS-X script, use the Uninstall method with the model name as the argument. For example:
$GAMS->Uninstall( 'Ramsey' );
The GAMS-X data file is the means by which models can be easily transferred between GAMS-X sites. The GAMS-X data file preserves the configuration of casebooks and cases for a particular user, allowing the same casebooks and cases to be installed at another site.
Thus, if you send someone who is running GAMS-X your GAMS code and a GAMS-X data file, they can install your model with the precise configuration of casebooks and cases that are currently associated with a user.
Note that when you install a model with a GAMS-X data file, GAMS-X resolves all of the model cases. Thus, a case might solve normally on the computer that generated the GAMS-X data file, but generate a GAMS error on your computer if, for example, you are supporting a different set of GAMS solvers.
To generate a GAMS-X data file in GAMS-Tk, select the File.Save.Model As.GAMS-X Data File menu option. The configuration of cases and casebooks affiliated with the user and model that is currently loaded will be saved.
To generate a GAMS-X data file from a GAMS-X script, use the GAMS-Tools method WriteData using a file name, user name, and model name as arguments. For example:
$GAMS->WriteData( 'C:\gams-x\temp\Ramsey.gmx', 'Grog', 'Ramsey' );
or, equivalently,
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' ); $GAMS->WriteData( 'C:\gams-x\temp\Ramsey.gmx' );
For example, if you are running GAMS-Tk, and you select File.Save.Model As.GAMS-X Data File, then send your model code and the GAMS-X data file to your friend in Copenhagen, when they install your model with the GAMS-X data file, they will find themselves looking at the same assortment of cases and casebooks that you were when you saved the file. Think of it as taking a snapshot of the user's account for that model.
In GAMS-Tk, user information can be obtained through the Tools.User.Summary menu option (see figure ). If need more user information, you can click on the user name in the user summary, and a window will be opened containing all of the user's profile information, including the user's ID, email address, affiliation, etc.
A list of users can similarly be obtained as the keys to the ID key of the reference to the associative array returned by the Users method, similarly to obtaining a list of models.
print "The following users have accounts on this site:\n\n";
for $User (sort keys %{$GAMS->Users->{ID}}) {
print $User, "\n";
}
Information on an individual user can be obtained through the UserProfile method, which returns a reference to an associative array containing the keys Name, Affiliation, Created, Email, Home, ID, LastLogin, and Password.
The Name key returns the user's name.
The Affiliation key returns the user's affiliation, as specified by the user when the user's account was created.
The Created key returns the date and time of the creation of the user's account.
The Email key returns the user's email address.
The Home key returns the user's remote host (typically the user's IP address) at the time that the user account was created. If the user account was created through GAMS-Tk or a GAMS-X script, Home returns ``Local Host.''
The ID key returns the internal user ID used by GAMS-X.
The LastLogin key returns the last login host of the user, typically the user's IP address.
The Password key returns the encrypted password of the user. Note that the actual (i.e., non-encrypted) password of the user is not stored internally, and is thus not accessible by the GAMS-X site owner.
User accounts can be created through three sources: Remotely through GAMS-CGI or locally through GAMS-Tk or a GAMS-X script.
Creating a user through GAMS-CGI is discussed in section .
To create a user through GAMS-Tk, use the Tools.User.Create menu option (see figure ).
To create a user within a GAMS-X script, use the AddUser method with the user's name, password, password confirmation, affiliation, and email address as arguments. Example:
$GAMS->Set(
-User => "Grog",
-Password => "grog!",
-PasswordConfirmation => "grog!",
-Affiliation => "University of Grog",
-Email => 'grog@spot',
-UserHome => "Local Host"
);
$GAMS->AddUser;
or, equivalently,
$GAMS->AddUser(
"Grog",
"grog!",
"grog!",
"University of Grog",
'grog@spot',
"Local Host"
);
Note that the user's email address should be enclosed in single quotes, or, if it is enclosed in double-quotes, should have the @ escaped.
User accounts can be removed from the GAMS-X system through three sources: Remotely through GAMS-CGI or locally through GAMS-Tk or a GAMS-X script.
A user can eliminate their own user account through the GAMS-CGI Edit Account Information button on the GAMS-CGI login.
In GAMS-Tk, user accounts can be eliminated through the Tools.User.Kill menu option (see figure ).
In a GAMS-X script, a user account can be killed through the Kill method, taking the user name as an argument. Example:
$GAMS->Kill( 'Grog' );
or, equivalently,
$GAMS->Set( -User => 'Grog' ); $GAMS->Kill;
A user's profile information can be edited through three sources: Remotely through GAMS-CGI or locally through GAMS-Tk or a GAMS-X script.
In GAMS-CGI, a user can edit their account through the Edit Account Information button on the GAMS-CGI login page.
To edit a user through GAMS-Tk, the Tools.User.Edit menu option (see figure ) may be selected. A list of the users will be presented from which a user may be selected.
Upon selecting a user through the User Editing window, you will be provided with a window that allows you to change all of the user's profile information, including the user's password (see figure ).
To change a user's profile information through a GAMS-X script, use the UserProfile option in conjunction with the Set method. The UserProfile option should point at a reference to an associative array whose keys are users' names and whose values are references to associative arrays whose keys are user profile keys and whose values are the values you are setting.
For example:
$GAMS->Set( -UserProfile => {
'Grog' => { 'Password' => 'grog!' },
'Wonk' => { 'Email' => 'wonk@spot'}
}
);
GAMS-X configuration variables are defined in a file called gams-x.ini located in the directory listed by the environment variables HOME in Unix and WINDIR in Windows. To check what your WINDIR is in Windows, you can type
echo %WINDIR%
at a DOS prompt.
The file consists of name=value pairs and comment lines, the latter of which start with a pound sign (#). For example, a gams-x.ini file may look something like the following:
# The GAMS-X Initialization File # The directory structure Shebang=#!C:/Perl/bin/perl.exe GXHome=http://economics.colorado.edu/gams-x GXRoot=c:/gams-x GXDir=c:/zbs/html/gams-x CGIRoot=c:/zbs/cgi CGILoc=/cgi . . . etc . . .
If you would like a value to be available to the GAMS-X system, you can edit this file to add a name=value pair.
Note that to change the values of items in the configuration file, you can use the Tools.Site.Configuration menu option in GAMS-Tk.
See also the Configure and Configuration methods.
Included in the GAMS-X root directory is a log file called gams-x.log that contains a log of all of the various comings and goings of GAMS-X users. If there is a great deal of activity on the system over a long period of time, the file can become quite large. Thus, on a particularly busy site, the GAMS-X administrator may want to manually edit the file every few months to eliminate old entries.
Chapter 7
The GAMS-CGI User's Guide
GAMS-CGI (General Algebraic Modeling System Common Gateway Interface) is a user interface designed to allow users operate remote models over the web by specifying model inputs and to present users with a compact and convenient presentation of model results.
Users should note that the GAMS-CGI environment is fully customizable, so while the figures included in this user's guide represent the default GAMS-CGI environment, depending on the creative flair of the webmaster, users may be presented with pages that look more or less like the ones seen here.
Central to understanding the GAMS-CGI system are the concepts of casebook and case. When a user selects a set of inputs to a GAMS model, she is creating a case. Casebooks are simply sets of cases. Thus, a user may create as many cases as she likes, which represent solutions of a model with various sets of inputs, and bundle them in casebooks to represent different sets of scenarios as she sees fit.
The central pages of the GAMS-CGI environment are as follows:
If a user is interested in viewing the documentation associated with a model or viewing the GAMS code associated with a model, this can be accomplished through the Casebook Index or Casebook page.
When a user first encounters the GAMS-CGI environment, she will be presented with the GAMS-CGI login page (figure ). If the user has already established an account, then the user fills in her user name and password and is taken to an index of the installed models. If not, the user may provide a user name and password and click on the new user button, in which case she will be brought to the New Account Creation page (figure ).
The login page is also the page which allows a user to either edit his or her account profile (the information such as email address associated with a user) or remove her account from the GAMS-X system. This can be accomplished by entering a user name and password and clicking on the Edit Account Information button (see figure ).
Note that users may view the documentation associated with any model on the site from the login page by clicking on any of the buttons displaying a model name.
Upon logging in, a user will be presented with an index of the models installed on a site (figure ). The model index not only provides a user with a description of each model, but provides a button (sporting the model name) which will take the user to the casebook index for that model.
Upon choosing a model from the Model Index page, a user will be brought to the Casebook Index page (figure ). From the Casebook Index page, a user may create new casebooks, access an existing casebook, and delete any empty casebooks or unused cases.
A user can create a new casebook for the model by entering a name in the New Casebook text box, and then clicking the "Create" button. Optional inputs for defining a new case include a description (type in the text area). It is also possible to include one of the existing cases in a new casebook. After generating the new casebook, GAMS-CGI will Update the casebook index to include the new casebook.
To access a casebook, simply click on the button containing the casebook name, located under the Casebook header. GAMS-CGI will then generate the casebook.
To delete a casebook, remove all of the existing cases from the casebook. This can be accomplished from the casebook page. Upon returning to the casebook index, a Delete button will appear by the casebook description. By clicking on the button, the casebook will be deleted and the casebook index will be rebuilt.
Upon choosing a casebook from the Casebook Index page, a user will be presented the Casebook page (figure ). The GAMS-CGI Casebook page allows the user to create new cases, access the GAMS output for any case, and remove cases from the casebook. Additionally, links are available to the GAMS source code for the model, the online model documentation, the library of available models, and the casebook index.
To create a new case, choose the parameter values that you would like from the dropdown menus. Enter a name for the case under the Create button, then press Create. Note that if the case has not been previously solved, it will appear as an solving case in the casebook.
If GAMS-CGI has previously solved a case, the results will appear immediately. Otherwise, the case will appear under the header "Solving." This simply means that GAMS-CGI has called on GAMS to solve the case. After allowing GAMS sufficient time to solve the case, you can press the Update Casebook button, located at the top of the casebook, to regenerate the casebook with the results from the newly solved case.
While ideally, the modeler has generated a model robust to a wide range of inputs, realistically, a modeler may not be able to anticipate the results of all of the possible input combinations. If an error occurs while GAMS is solving a case, the case will be listed under the header "GAMS Error" and a link will be provided to the GAMS listing, which can then be examined to determine the origin of the error.
To import an existing case into a casebook, choose a case from among the cases contained in the drop-down menu below the Import button in the casebook. Then click on the Import button. It's just that easy!
The results from a case will automatically be graphed with the results from the other cases in your casebook. If you would like to view the GAMS output for any case, simply click on the button containing the case name, located with the Outputs from the case.
To remove a case from a casebook, indicate which case is to be removed by clicking on the radio button to the right of the Remove button. Then click on the Remove button. GAMS-CGI will update the casebook with the case removed. Note that the case will not be removed from the workspace. If you would like to permanantly remove the case, reference deleting a case below.
To delete a case, delete the case from all of the casebooks in which it appears. Any references will be listed in the casebook index under the heading Referenced In Casebook. Upon returning to the casebook index, a Delete button will appear to the right of the case name. By clicking on the button, the case will be deleted and the casebook index will be rebuilt.
To change a casebook description, go to the bottom of the Casebook page. Put the new description in the ``Revise Description'' text box and click on the Submit button.
GAMS-CGI (General Algebraic Modeling System Common Gateway Interface) is a system for administering GAMS models online. It is designed to be portable both to Unix and Windows systems and offers an array of modeling and webmastering tools as well as easy customization of HTML input and output documents for those with a rudimentary knowledge of HTML forms.
It provides browser-interface to mathematical programming models coded in GAMS. The GAMS-CGI program permits remote operation of a GAMS model by one or more users via the Internet. The program is intended to provide modelers with a simple procedure for sharing model insights with non-modelers. Three objectives guided the system design:
Familiarity with internet programming is helpful but not required to install the GAMS-CGI system on a Windows 95/98/NT PC. The distribution materials contain a set of utilities to make site administration as trouble-free as possible.
Using GAMS-CGI, a remote user can specify some model inputs, solve the model on the host machine and then view the resulting model outputs. Limited graphical tools are provided for displaying model output as line graphs, and the remote user can view the GAMS source code, and listing files. A user can define a number of cases and then generate a "case book" to provide a cross-comparison of results.
A remote user accesses models via a user account which may be freely allocated or assigned to a limited number of individuals. A user workspace contains one or more models. A model workspace is then based on two concepts: (i) the case and (ii) the casebook. A case is simply an instance of a model based upon a particular set of parameters. GAMS-CGI allows the user to select from a set of values for each model parameter to generate an instance of the model. Once the case has been solved, the user can view the GAMS output in both graphical form (where applicable) or through "casebooks" which provide a tabular and/or graphical comparison of results from multiple cases. Once a case is solved, the user can import it into any of her other casebooks. Casebooks provide the user with flexibility in both the organization and presentation of results.
To understand how GAMS-CGI interacts with the web, it is necessary to understand a bit about what exactly web pages consist of and how applications in general interact with web pages. While to those unfamiliar with the web, the internet can seem somewhat overwhelming. it has been designed to be easily understandable and accessible by the teeming billions. After all, twelve-year-olds around the world regularly post their own homepages.
This section will attempt only to give the broadest of conceptual brushstrokes. There are about a million books and documents about the internet you may choose from if you are inclined to learn a little bit more.
A web page is simply a file on a computer somewhere. It consists of text which includes certain symbols, known as Hypertext Markup Language (HTML), which lets browsers such as Netscape or Internet Explorer know how to format and display the file. Markup is becoming increasingly sophisticated, and can now include templates, objects, and bits of programming code such as PerlScript or JavaScript. The basics, however, are quite simple.
For example, to create a web page that will display the message ``Hello World!'' to anyone who looks at it, one needs simply create a file which looks like this:
<HTML> <BODY> Hello World! </BODY> </HTML>
Once you have created a file consisting of HTML that you would like the world to be able to see, you need only put it in a special directory on a computer which is running a web server, such as Apache, Microsoft Internet Information Server, OMNI, or ZBServer, for people to be able to see it from a web browser.
For example, if I put the ``Hello World!'' text above in a file called hello.html in a directory called /apache/htdocs on a computer called nash.colorado.edu, then people who look for the site http://nash.colorado.edu/hello.html will receive my little greeting.
CGI stands for Common Gateway Interface, and is the standard means by which web pages can interact with computer programs. The process is generally as follows:
The process is really not much different than clicking a button in Microsoft Word, for example, except for the fact that the computer running the program may be half a world away.
For the remainder of this chapter, it will be assumed that you have perused the Perl Primer (section 5.3).
Forms are an HTML markup that is used to transfer data between a user's web browser and the CGI program. The idea behind forms is simple: Some parameters are specified in the form, either as hidden values or as user-defined input coming from radio buttons, check boxes, text fields, and other constructs commonly seen on the web. When a user hits a button, the parameters (in the case of GAMS-CGI, the user's name, the model name, etc.) are given to the CGI program, which then uses the parameters to decide what to do.
For example, suppose you want to run a Perl CGI program called hello.pl which gives a user a personalized ``Hello'' message. The CGI program will be activated by pressing a button on a page named hello.html. Then hello.html might consist of the following HTML:
<HTML> <BODY> <P> Please fill in your name in the text field below and click on the submit button. <P> <FORM ACTION="/cgi-bin/hello.pl" METHOD="POST"> <INPUT TYPE="text" NAME="UserName"> <INPUT TYPE="submit" VALUE="Submit"> </FORM> </BODY> </HTML>
Notice that the form starts with the <FORM markup and ends with the /FORM> markup, and that any information included in text boxes, radio buttons, check boxes, etc. that appear in between the form markups is passed to the CGI program hello.pl.
Let's suppose the CGI program hello.pl consists of the following Perl code:
use CGI;
$CGI = new CGI;
$UserName = $CGI->param('UserName');
print $CGI->header;
print <<"eop";
<HTML>
<BODY>
<H1>Hello $UserName! Welcome to my CGI script!</H1>
</BODY>
</HTML>
eop
Notice the common link between the HTML form and the CGI script: The UserName parameter. The first two lines (use and new) tell the program that it is a CGI script, and that it should go and get the information generated by the HTML form. Then that information can be accessed using the CGI param statement. Finally, a HTML header is printer with the print $CGI->header; statement and an HTML page with a greeting is printed for the user to see. The HTML header is a necessary formality, and simply tells the browser to expect to see an HTML document next, as opposed to, say, an Adobe PDF document. For more information on the HTML header and other CGI methods, see section .
The syntax is very similar in GAMS-CGI, with the exception that the CGI object is only part of the GAMS-CGI object, and so has to be referenced with an additional ->{CGI} syntax. Thus, to do the same thing using GAMS-CGI, the program would look like:
use GAMS::CGI;
$GAMS = new GAMS::CGI;
$UserName = $GAMS->{CGI}->param('UserName');
print $GAMS->{CGI}->header;
print <<"eop";
<HTML>
<BODY>
<H1>Hello $UserName! Welcome to my CGI script!</H1>
</BODY>
</HTML>
eop
As you can see, using GAMS-CGI gives you all the power of traditional CGI programming, and, in fact, professional CGI programmers can use GAMS-CGI with only a minor syntactic adjustment.
One final note: GAMS-CGI also provides a shortcut for obtaining CGI parameters that do not interfere with the GAMS-CGI namespace. If there are no GAMS-CGI (and hence CGI, GAMS, and GAMS-Ini) methods with the same name as the CGI parameter, the ->CGI->param('·') statement may be omitted. Thus, if a user name is being passed through an HTML form with the parameter 'UserName,' the value of the parameter can be obtained with the statement
$GAMS->UserName
This shortcut syntax will be used extensively throughout the GAMS-CGI documentation.
While basic GAMS-CGI administration is a fairly straightforward task with the aid of the GAMS-Tk visual environment, it barely scratches the surface of the true power of GAMS-CGI: The GAMS-CGI programming environment. Before reading this section, make sure you are acquainted with section 5.2 which describes GAMS-X scripting, the basis for GAMS-CGI scripting.
The fundamental concept underlying the family of GAMS-X methods is that of state. The GAMS-X environment is defined in terms of Users, Models, Casebooks, and Cases. While the GAMS-X methods can be called with the User, Model, etc. explicitly defined, they methods assume that the state has been established in the form of passed CGI parameters or the Set method.
Thus, if the WriteCasebook method will be called, it must know who is the user the casebook is to be written for, which model the casebook is defined in, and what the name of the casebook to be written in. If any of these pieces of information are missing, an error will be returned.
All of these parameters can be passed in through a CGI form as parameters (see section 8.3.2 for more information on HTML forms); for example, in an HTML form like this:
<FORM ACTION="/cgi-bin/myprogram.pl" METHOD="post" > <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="hidden" NAME="Model" VALUE="Ramsey"> <INPUT TYPE="hidden" NAME="Casebook" VALUE="STUDY1"> <INPUT TYPE="submit" VALUE="I am the submit button"> </FORM>
Then if the file myprogram.pl consisted of the simple program
use GAMS::CGI; my $GAMS = new GAMS::CGI; $GAMS->WriteCasebook;
the WriteCasebook method would know to write the casebook called Study1 for the user Grog and the model Ramsey.
Alternatively, the state can be set explicitly on the server side with the Set method so that the simple HTML button
<FORM ACTION="/cgi-bin/myprogram.pl" METHOD="post" > <INPUT TYPE="submit" VALUE="I am the submit button"> </FORM>
Then if the file myprogram.pl consisted of
use GAMS::CGI;
my $GAMS = new GAMS::CGI;
$GAMS->Set(
-User => 'Grog',
-Model => 'Ramsey',
-Casebook => 'Study1'
);
$GAMS->WriteCasebook;
pressing the button would still result in the writing of the casebook Study1 for the user Grog and the model Ramsey.
You will notice, then, that the entire default GAMS-CGI environment is established with a script that is less than 40 lines long (see appendix for the full text) that makes no reference to which user or model or casebook is current. These parameters are automatically passed in by whichever HTML forms are calling the script; for example, the form that causes a user's model index to be written is only 6 lines long:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post" > <INPUT TYPE="hidden" NAME="Task" VALUE="WriteModelIndex"> <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="hidden" NAME="Time" VALUE="917886870"> <INPUT TYPE="submit" VALUE="Go to model index"> </FORM>
and in gams-cgi.pl, the model index is returned to the user with one line:
} elsif ($GAMS->Task eq "WriteModelIndex") {$GAMS->WriteModelIndex
A couple of simple examples will be provided to get you started. You should browse appendix , which lists all of the GAMS-CGI methods, and appendix , which describes the Set method and many other useful methods, for more information.
Note that the GAMS-CGI environment can be completely customized in any way you see fit, but more extensive customization requires more learning and effort, whereas the changes introduced in this section can be effected with a minimum of thought and effort.
To begin customizing GAMS-CGI, it would be a good idea to copy the file gams-cgi.pl, located in the CGI root directory (you can use the GAMS-Tk Tools.Site.Configuration menu option to find the location of this directory), to a file named mygams-cgi.pl. This way you won't have to worry about making any mistakes. You may also want to copy the file named index.html in your GAMS-X public HTML directory (the GXLoc configuration variable) to myindex.html, and change the link in myindex.html from gams-cgi.pl to mygams-cgi.pl.
Now you have a completely separate GAMS-CGI script to work with, and don't have to worry about corrupting your default GAMS-CGI script.
The first few lines of gams-cgi.pl look something like this:
use GAMS::CGI;
my $GAMS = new GAMS::CGI;
# $GAMS->Gripe("This site has been taken offline for software development.");
# Process the appropriate task:
if ($GAMS->Task eq "Greeting") {$GAMS->Greeting
} elsif ($GAMS->Task eq "Log In") {$GAMS->Login
etc . . .
Suppose you want to change message at the top of the login page. The message is kept in the GAMS-CGI variable called LoginGreeting. Thus, adding the following lines to the top of mygams-cgi.pl will change the message:
use GAMS::CGI;
my $GAMS = new GAMS::CGI;
# $GAMS->Gripe("This site has been taken offline for software development.");
$LoginGreeting = <<"EndOfGreeting";
<CENTER>
<H2>
Welcome to My GAMS-CGI Site!
</H2>
</CENTER>
EndOfGreeting
$GAMS->Set( -LoginGreeting => $LoginGreeting );
# Process the appropriate task:
if ($GAMS->Task eq "Greeting") {$GAMS->Greeting
} elsif ($GAMS->Task eq "Log In") {$GAMS->Login
etc . . .
Notice that you can use the Perl << operator to nest the HTML directly in the GAMS-CGI script. Now open myindex.html in your favorite browser and click on the GAMS-CGI logo. You should see your new message on the greeting page.
Another simple facility that can be used is Perl regular expressions, which are facilities used to manipulate text. Most of the default GAMS-CGI pages are generated with methods with the same name as the page, but ending in HTML. For example, the ModelIndex method returns an HTML document generated by the ModelIndexHTML page. Furthermore, within the default GAMS-CGI documents are comments that can be used to make replacements in the default text or insert more text.16
To continue with the default, Model Index page suppose you want to put a little message above the webmaster's email address (which appears at the bottom of all of the default GAMS-CGI pages) indicating that users who suspect bugs in the GAMS code should instead contact the modeler.
Then the following modification of the basic gams-cgi.pl file would do the trick:
. . .
} elsif ($GAMS->Task eq "WriteModelIndex") {
$HTML = $GAMS->WriteModelIndexHTML;
$Message = <<"EndOfMessage";
<P>
<FONT SIZE=-1>
You may contact
about any questions or comments regarding the GAMS code.
<P>
EndOfMessage
$HTML =~ s/<!-- Webmaster Email On --\>/$Message/;
$GAMS->Set( -WriteModelIndexHTML => $HTML );
$GAMS->WriteModelIndex;
} elsif ($GAMS->Task eq "WriteCasebookIndex") {$GAMS->WriteCasebookIndex
. . .
This takes the basic Model Index HTML page, substitutes the message that you would like just in front of the webmaster email message, and then writes out the Model Index page based on the new HTML page.
In order to add features to your GAMS-CGI site, you may want to be able to preserve pieces of information, such as a reference to your homepage or the number of times a user has accessed your site or the number of times a model has been viewed. The next three subsections will give you insight into how to do this with a minimum of effort.
In order to make information available to all of the GAMS-X facilities, you can edit the GAMS-X initialization file. See section 6.4.1 for more information.
In order to attach information to a model, you can simply add a field to the ModelState data structure. For example, if you want to record the number of times that users have accessed a model named 'Ramsey,' you can add the following lines to the top of your GAMS-CGI script:
if ($GAMS->Task eq "WriteCasebookIndex") {
$Model = $GAMS->Model;
$GAMS->ModelState($Model)->{"NumberOfHits"} =
$GAMS->ModelState($Model)->{"NumberOfHits"} + 1
$GAMS->Set( -PreserveModelState => $Model );
}
Note the use of the Set method to set the PreserveModelState parameter. This ensures that the model state information will be saved when GAMS-CGI finishes what it is doing.
Each user is associated with a profile, accessible through the UserProfile method, with various pieces of information associated with that user. Using the GAMS-X and/or GAMS-CGI scripting abilities, you are able to attach information to user accounts through the Set method, and then can access them through the UserProfile method.
For example, suppose you want to attach a piece of information to each user indicating the number of times that they have logged on to a GAMS-CGI site.
Then adding the following lines to the gams-cgi.pl file (see appendix ) will accomplish that task:
. . . the beginning of the gams-cgi.pl file . . .
# Process the appropriate task:
if ($GAMS->Task eq "Greeting") {$GAMS->Greeting
} elsif ($GAMS->Task eq "Log In") {
$User = $GAMS->User;
$NumberOfLogins = $GAMS->UserProfile($User)->{'NumberOfLogins'};
$GAMS->Set( -UserProfile =>
{
$User => { "NumberOfLogins" => $NumberOfLogins+1 }
}
);
$GAMS->Login;
} elsif ($GAMS->Task eq "New User") {$GAMS->NewUser
. . . the end of the gams-cgi.pl file . . .
Just about anything that you can do on the web, you can do with GAMS-CGI. In fact, the possibilities are so numerous, that trying to provide an overview of them all would fill this volume and many others to overflowing. Instead, this section will present a simple example of a fully customized GAMS-CGI environment, hopefully providing you with a guidebook to creating your own GAMS-CGI web pages.
For more information on CGI programming in general, see appendix , which includes a number of excellent examples by Lincoln Stein, the author of the Perl CGI module, or any of the many Perl/CGI programming books on the market.
To begin our example, suppose that you have a model named (you guessed it!) Ramsey for which you want to create a fully customized CGI environment.
Since this example is for demonstration purposes only, we will restrict the number of pages to two: The page that users see when they first access the site, and a page that can be accessed through GAMS-CGI from the first page. Although the example is so simple it is almost ridiculous, it will hopefully provide you with the insight you need to design a fully customized GAMS-CGI environment.
The first page will have a simple dropdown box allowing users to select the discount factor for the Ramsey model and a button that will take them to the second page.
The second page will then display a graph of the consumption (in trillion rupees per year) that results from their choice of the discount factor.
For the remainder of the example, it will be assumed that the default Ramsey model that comes with the basic GAMS-X installation has been installed.
We first want to create a greeting page that will provide users with a greeting and instructions. Just a few lines of HTML will suffice:
<HTML> <BODY> <P> <H1> Welcome </H1> <FORM ACTION="/cgi/mygams-cgi.pl" METHOD="POST"> <P> You may choose from among the following options for the discount value for the Ramsey model: <SELECT NAME="BET" SIZE="1"> <OPTION SELECTED>0.95</OPTION> <OPTION>0.90</OPTION> <OPTION>0.925</OPTION> <OPTION>0.975</OPTION> </SELECT> <P> After you have selected a value, click on the submit button, and you will be shown a graph of the results of your selection. <P> <INPUT TYPE="submit" VALUE="Submit"> </FORM> </BODY> </HTML>
The FORM markup indicates that we are going to running the GAMS-CGI program contained in the file mygams-cgi.pl. Note that this example assumes that the virtual name of your CGI executable directory is /cgi.17 Then the SELECT markup provides a dropdown listbox with a list of the options for the Ramsey discount factor input as defined by the $libinclude X INPUT GAMS statement in the Ramsey model18
Finally, we need to have a submit button, defined with the INPUT TYPE="SUBMIT" markup, which executes the GAMS-CGI program mygams-cgi.pl with the value of the discount factor chosen in the dropdown listbox when it is clicked.
As you can see, designing an interactive web page is really quite simple to do in its most basic incarnation.
Now suppose a user has clicked on the submit button. We need to present them with the graph that results from their submission.
For simplicity, we will ignore the possibility that they will choose a value for a case that hasn't yet solved by generating solutions for all of the cases beforehand with the following little GAMS-X script:
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
$Default = $GAMS->Inputs->{'BET'}->{Default};
$GAMS->Set(
-Case => "BET=$Default",
-CaseInputs => { 'BET' => $Default }
);
$GAMS->NewCase;
for $Option (@{$GAMS->Inputs->{'BET'}->{Option}}) {
$GAMS->Set(
-Case => "BET=$Option",
-CaseInputs => { 'BET' => $Option }
);
$GAMS->NewCase;
}
$GAMS->Solver;
# Now generate some plots with the MultiPlot function
$Default = $GAMS->Inputs->{'BET'}->{Default};
# Note that using the value of the GXDir method as the directory
# ensures that the plot goes in a public HTML directory viewable
# from outside browsers
$GAMS->MultiPlot(
$GAMS->GXDir . "\\plot.$Default.gif",
'Grog',
'Ramsey',
"BET=$Default",
'C.L'
);
for $Option (@{$GAMS->Inputs->{'BET'}->{Option}}) {
$GAMS->MultiPlot(
$GAMS->GXDir . "\\plot.$Option.gif",
'Grog',
'Ramsey',
"BET=$Option",
'C.L'
);
}
$GAMS->Quit;
Now that the GAMS-X script above has created our cases and graphs for us, we can create a GAMS-CGI script that will take users' input and return the appropriate output and graph. Simply save the following script in your CGI executable directory as the file mygams-cgi.pl:19
use GAMS::CGI;
$GAMS = new GAMS::CGI;
$BET = $GAMS->BET;
# Note that GXDir to you is GXLoc to users looking in from a
# web browser
$PlotURL = $GAMS->GXLoc . "/plot.$BET.gif";
print $GAMS->{CGI}->header;
print <<"EndOfHTML";
<HTML>
<BODY>
<P>
Thank you for selecting the value of $BET for the discount factor.
<P>
The resulting level of capital consumption is given by:
<P>
<IMG SRC="$PlotURL">
EndOfHTML
Although this is an admittedly simple example, you can see that the possibilities are really only limited by your imagination and you understanding of the GAMS, CGI, and GAMS-CGI methods.
If you find the GAMS-CGI scripting system useful, and create scripts that you think would be helpful to other GAMS-CGI users, please forward them to me at .
You could use the CGI method redirect to direct first-time GAMS-CGI users to a welcome page. For example:
. . . the beginning of the gams-cgi.pl file . . .
} elsif ($GAMS->Task eq "AddUser") {$GAMS->AddUser;
print $GAMS->{CGI}->redirect(
-uri => 'http://www.myurl.com/welcome.html',
-nph => $GAMS->nph
)
} elsif ($GAMS->Task eq "Edit Account Information") {$GAMS->EditAccountInformation
. . . the end of the gams-cgi.pl file . . .
The previous example is a bit limited because once a user is presented the welcome page, he or she has to log back in again to see the site. In this example, the greeting page will be nested directly in the gams-cgi.pl file, which enables you to allow users to continue from the welcome page directly into their GAMS-CGI account.
I have actually used this example to provide students who are using GAMS-CGI to work with GAMS models for their classroom projects with an introductory page.
Here is the idea: A subroutine called Introduction will be created. The greeting page (written in HTML) will be nested directly into the subroutine. Since the page is accessed from within the GAMS-CGI script, an HTML link can be defined that will allow the user to continue directly from the greeting page into their user account's model index.
The first step is to access the Introduction subroutine instead of the usual the WriteModelIndex method that follows the creation of a user account. Modify the file gams-cgi.pl as follows:
. . . the beginning of the gams-cgi.pl file . . .
} elsif ($GAMS->Task eq "New User") {$GAMS->NewUser
} elsif ($GAMS->Task eq "AddUser") {$GAMS->AddUser; &Introduction;
} elsif ($GAMS->Task eq "Edit Account Information") {$GAMS->EditAccountInformation
. . . the end of the gams-cgi.pl file . . .
Now, at the end of the gams-cgi.pl file create a subroutine like this:
. . . at the very end of the gams-cgi.pl file . . .
sub Introduction {
my $User = $GAMS->User;
my $Model = $GAMS->Model;
# $GAMS->Action returns the virtual name of the CGI file.
# In this case, it may be something like
#
# /scripts/gams-cgi.pl
#
# See the appendix named GAMS-Ini Methods for more detail.
my $link =
$GAMS->Action . "?User=$User&Model=$Model&Task=WriteModelIndex";
print $GAMS->{CGI}->header;
# Here is the HTML:
print <<"EndOfHTML";
<HTML>
<BODY>
<P>
Hello, $User! I give you greetings and salutations.
<P>
When you are ready to continue, click <A HREF="$link">here</A>.
<P>
Blah, blah, blah . . .
</BODY>
</HTML>
EndOfHTML
}
Many of the tasks that GAMS-CGI administrator are responsible for,
such as installing and uninstalling models and creating, killing, and
editing user accounts, are discussed in detail in chapter
6, and so will not be discussed
here. Rather, topics specific to GAMS-CGI administration will be
discussed.
Section 8.3.6 introduced some methods that allow
you to make simple changes to the default GAMS-CGI pages, such as
changing the the message at the top of the page.
Several GAMS-X configuration variables control other aspects of
appearance of the basic GAMS-CGI environment. The graphic that goes
in place of the GAMS-CGI logo on the login page, as well as its
height and width, are defined by the configuration variables Logo,
LogoHeight, and LogoWidth. The default background color is defined
by the variable BGColor, whereas if a tiled graphic is desired as the
default GAMS-CGI background, then the Background configuration
variable can be set. In order to change these configuration
variables, simply choose the Tools.Site.Configure menu option in
GAMS-Tk. It's easier than burning toast!
Often times, when performing routine administrative tasks such as
installing a model, it is necessary to pause the GAMS-CGI server.
This will prevent all of the GAMS-CGI users from accessing the
GAMS-CGI site.
To pause the GAMS-CGI server, select the Tools.Site.Pause GAMS-CGI
menu option in GAMS-Tk. You will be prompted for a message that you
would like presented to the GAMS-CGI users upon trying to access
GAMS-CGI.
To restart the server, select Tools.Site.Pause GAMS-CGI menu option
again, then click on the Unpause button.
Note that GAMS-CGI is automatically paused when GAMS-Tk is in
operation to prevent conflicts with actions by GAMS-CGI users. The
Tools.Site.Pause GAMS-CGI menu option simply ensures that GAMS-CGI
remains paused after GAMS-Tk has been exited.
Normally, users have to log in through the GAMS-CGI login
screen every time they access a GAMS-CGI site. If you would like to
bypass this step, you can change the value of the Bypass
configuration variable, accessible through the GAMS-Tk
Tools.Site.Configure menu option, to a nonzero value.
When the Bypass variable is set to a nonzero value, when a user first
accesses a GAMS-CGI site, GAMS-CGI will check the last login address
of all of the current GAMS-CGI users. If only one user's last login
was from the same IP address as the user trying to log in, it will
bypass the login screen and bring the user directly to the model index.
8.4 Basic GAMS-CGI Administration
8.4.1 Configuration Variables that Change the Appearance of the GAMS-CGI Site
8.4.2 Pausing the GAMS-CGI Server
8.4.3 Bypassing the GAMS-CGI Login Screen
8.4.4 Security
GAMS-CGI security is what is known in web jargon as ``basic.'' That is, none of the information that is sent ``over the wire'' is encrypted. GAMS-CGI is intended for the dissemination of information, and as such, does not use the most secure data transfer protocol available (currently Netscape's SSL), commonly used for such things as credit-card information transfer.
The user passwords are encrypted on the server side, however, ensuring that not even the webmaster can access a user's password, though a webmaster may change a user's password at his or her discretion.
Login authentication is accomplished through cookies, which upon validation of a user's password, maintain a valid login for the user's current browser for 3 hours following submittal of the password.
If you are interested in creating a site with more than basic authentication, you may want to read appendix section or consult any of the various Perl CGI books on the market for more information.
The default GAMS-CGI installation contains a firewall to all of the basic GAMS-CGI methods to gaurd against potential incursions. With fully customized GAMS-CGI environments, however, it is up to the web programmer to ensure that there are no potential security risks in the CGI code. There are, however, some simple rules I recommend be followed when programming a fully customized GAMS-CGI environment:
Many aspects of this software are new, so I have not
had the opportunity to address many of the common questions that will
certainly arise. However, this chapter is an attempt to address the
kinds of questions that I anticipate will arise. If you have a
question that you would like included in future versions of this
document, please feel free to contact me at
collin.starkweather@colorado.edu.
Question 1
GAMS-X keeps showing me file names with the wrong kind of directory
divider, a / instead of a \! What is going on?
Answer 1
Perl, the language in which GAMS-X is written, is intended to be as
platform independent as possible. This means that it recognizes both
Unix directory dividers / and DOS directory dividers \. So
you can enter a file name like
Question 2
I want to use Gnuplot with GAMS-X. Where do I get it and how to I
set up GAMS-X to use Gnuplot?
Answer 2
As of September, 1999, the Gnuplot homepage can be found at
http://www.cs.dartmouth.edu/gnuplot_info.html
You will also be able to find a link through the Gnu homepage at
To configure GAMS-X to use Gnuplot,
Question 1
When I try to use the Perl Package Manager with ActivePerl to install
the packages used by GAMS-X, it tells me it can't find a package.
Answer 1
The Perl Package Manager (PPM) retrieves packages over the web. You
should be connected to the web to use it. Sometimes the web site
hosting the Perl packages is temporarily offline due to the volume of
traffic or whatever. If you have trouble accessing parts of the
ActiveState website
through you web browser, this is probably the case. You might just
want to try back later.
If you are located behind a firewall or a proxy, then you might need
to follow the following procedures to obtain the Perl packages (taken
from the ActiveState documentation):
PPM can then be run by typing 'ppm' in a command prompt window.
On my Windows machine, setting the environment variable HTTP_
proxy
goes something like this:
If you are still having problems, here's how to install the
modules manually:
You can also get the packages on this web site, though I make no
promises that they are current20:
Question 2
When I try double-click on gams-xinst.pl from Windows
Explorer, a DOS window just pops up and then disappears. What do I do?
Answer 2
This means that gams-xinst.pl can't run due to some kind of
error.
Instead of double-clicking on gams-xinst.pl from Windows
Explorer, open a DOS prompt, go into the directory in which
gams-xinst.pl is located and type gams-xinst.pl (or
perl gams-xinst.pl if you are using Windows 95/98). The
DOS prompt will automatically minimize (this is just the way the install
program works).
Bring the DOS prompt back by Alt-Tabbing to it or selecting it on the
Taskbar. Check to see what message was printed. Chances are the
message corresponds to something discussed in another FAQ. If it
does not, send me some email at
with a copy of
the message.
Question 3
When I try to use gams-xinst.pl I receive this (cryptic) message:
Answer 3
This message indicates that one of the Perl modules necessary to run
gams-xinst.pl is missing.
If you are a Windows user, all of the modules should be installed
provided you followed step 2.3.3.1 as outlined in section
2.3.3.1. If you are still having problems,
read FAQ 9.2.1 or try downloading and installing the latest version of Perl if you do
not already have it. You should at least have version 5.005.
You can check which version of perl is installed by typing
at the command prompt.
Question 4
When I try to use GAMS-Tk, Uninstall GAMS-X, or Update GAMS-X from
the Windows Start menu, either nothing happens or a DOS prompt
appears and then quickly disappears. What do I do?
Answer 4
All of these utilities can be run at a DOS prompt from the GAMS-X
root directory. Simply open a DOS prompt, go into the GAMS-X root
directory, and type gams-tk.pl, update.pl, or
gams-xuninst.pl, or, if you are using Window 95/98,
perl gams-tk.pl, perl update.pl, or perl
gams-xuninst.pl. If you receive an error message, read the rest of
the FAQs.
You may also have discovered a bug I have noticed in Windows NT (and
which may or may not exist in Windows 95/98).
Sometimes when first installing on Windows NT, the Update GAMS-X
option doesn't work when it is selected. You can either run the
program from the command line as described above, or, if you find the
shortcut in Windows Explorer, you can right-click on it, select
Properties, then the Shortcut tab, then press OK, suddenly it works!
Even though you have made no changes to the shortcut!
Mysterious are the ways of Microsoft.
Typically the shortcut would be located in the directory
Question 5
When I try to use GAMS-X I receive this (cryptic) message:
Answer 5
This message indicates that one of the Perl modules necessary to run
GAMS-X is missing.
If you are a Windows user, all of the modules should be installed
provided you followed step 2.3.3.1 as outlined in section
2.3.3.1. If you are still having problems,
read FAQ 9.2.1 or try downloading and installing the latest version of Perl if you do
not already have it. You should at least have version 5.005.
You can check which version of perl is installed by typing
at the command prompt.
Question 6
When I try to update GAMS-X automatically over the web, it can't find
the update file. I am working behind a firewall.
Answer 6
The GAMS-X Update utility can retrieve updates over the web. You
should be connected to the web to use it. Sometimes the web site
hosting the update is temporarily offline due to the volume of
traffic or whatever. If you have trouble accessing parts of the
GAMS-X homepage
through you web browser, this is probably the case. You might just
want to try back later.
If you are located behind a firewall or a proxy, then you might need
to follow the following procedures to obtain the update over the web:
Update can then be run by typing update.pl at the command
prompt from within the GAMS-X root directory (typically C:\gams-x).
On my Windows machine, setting the environment variable HTTP_
proxy
goes something like this:
If this doesn't solve the problem, try downloading the file manually
as per the instructions on the GAMS-X Update Page.
Question 7
When I install a model in Windows, sometimes when GAMS is called,
the DOS window that GAMS runs in doesn't go away when it is done, and
I have to close it manually. The title of the DOS window is Finished
- xsolve. How do I get it to close automatically so that I don't
have to close it myself?
Answer 7
The batch file xsolve.bat, located in your GAMS root
directory, is used to solve cases of models in GAMS-X. Go into
Windows Explorer, then select xsolve.bat, then
File.Properties. Go to the Program tag and select the ``Close on
exit'' option. Now the DOS window will close automatically.
Likewise, if you don't want the window to close (for example, if you
want to see the GAMS output for each case as it is submitted to
GAMS), deselect the ``Close on exit'' option.
Alternatively, when the DOS window finishes the GAMS job (you will
know that it is finished because it has the word Finished in the
window title), right-click on the title bar, then select properties,
then the Program tag, then select the ``Close on exit'' option.
Question 8
In the installation guide, it says I need to install the GAMS-CGI
daemon as a Windows NT/2000 service. How do I do that?
Answer 8
You can find the answer in the Fall 1999 issue of The Perl Journal.
Old copies of The Perl Journal can be ordered online at
http://www.tpj.com
Question 9
All of my cases yield GAMS errors and GAMS-X can't locate the
listings files. What is wrong?
Answer 9
Both GAMS and Perl must be on your path; e.g., if you have
installed GAMS in C:\GAMS and perl.exe is located in
C:\Perl\bin, both those directories must be in the string
returned when you type PATH from the command line.
Question 10
None of my new cases will solve. What is wrong?
Answer 10
Both GAMS and Perl must be on your path; e.g., if you have
installed GAMS in C:\GAMS and perl.exe is located in
C:\Perl\bin, both those directories must be in the string
returned when you type PATH from the command line.
Question 11
What kind of systems has GAMS-X been successfully tested on?
Answer 11
GAMS-X has been successfully installed on Windows NT 4.00.1381
running Apache for Win32 version 1.3, Windows NT 4.00.1381 Service
Pack 3 running Microsoft Internet Information Server version 2.0, and
Windows 95 4.00.950B running ZBServer R17 (make sure you're not
running anything less than R17 or GAMS-CGI will not work properly!).
Question 12
GAMS-Tk runs slowly. What can I do?
Answer 12
GAMS-Tk can run slowly, especially when switching between users or
models that result in it having to redraw graphs, or when a model has
been installed with a large21 number of inputs or outputs.
This is perhaps GAMS-Tk's biggest Achilles heel.
There is good news and bad news on this front: The good news is that
there is a way to remedy the speed problem. The bad news is that
your humble programmer will not have time to implement it until
summer 1999. I never promised you a rose garden.
If things become unbearably slow in GAMS-Tk with very large models
with a very large number of inputs and outputs, you may find it
worthwhile to take up GAMS-X scripting, which allows for all of the
functionality of GAMS-Tk and then some, and suffers none of the
compromises in speed associated with the visual environment.
Question 13
I installed a new model, and now GAMS-Tk will not run.
Answer 13
Very occasionally, if you cause an error in a GAMS-X script that
GAMS-X does not have an error message for, it can pass unnoticed,
whereas it may cause GAMS-Tk to have a seizure.
Try the Microsoft Solution to What Ails You. That is,
uninstall the model and check over your GAMS-X script and its output
to make sure everything is working correctly, then reinstall it
again.
For more information on uninstalling models, see section 5.4.3.1.
Question 14
GAMS-Tk seems to have locked up on me. What is going on?
Answer 14
One of two things may be causing this problem:
(1) Sometimes when a window is created by GAMS-Tk (e.g., the Model
Installation dialog box), the main GAMS-Tk window will be frozen so
that there are no conflicts between the two. Check whether you have
any other GAMS-Tk windows open, and if so, close them.
(2) There may be a GAMS-Tk error message hiding behind another
window. When GAMS-Tk generates an error, it pops up an error message
and waits for you to hit the 'OK' button. It is possible that some
combination of events results in this message appearing in a window
hidden behind your other windows. You may not see the message, and
it seems as if GAMS-Tk has locked up.
Question 15
When I open a file (e.g., a text file), I get a dialog box that says
something like C:\gams-x\gams-tk.pl cannot find the file specified.
When I click on OK, the file opens up just fine
anyway. What's going on?
Answer 15
This is a bug with Microsoft Windows, not GAMS-Tk. You will notice
that a similar message occasionally appears when you type something
like myfile.html from the DOS prompt to open an HTML file.
I suggest you send Mr. Gates an email.
Question 16
GAMS-CGI runs slowly. What can I do?
Answer 16
GAMS-CGI runs pretty fast already on a dedicated website. However,
if you want still faster performance in Windows, get PerlEx from
ActiveState
. NT is pretty darn fast normally. It's blindingly fast with
PerlEx.
The ActiveState press release of Thu, 04 Feb 1999 is as follows:
PerlEx runs on all popular commercial Windows NT Web servers, including
O'Reilly and Associates' WebSite Professional, Microsoft Internet
Information Server 3.0 & 4.0, Microsoft Personal Web Server 4.0, and
Netscape FastTrack and Enterprise servers.
PerlEx can be purchased for $395 U.S at
http://www.ActiveState.com/plex
.
Trial versions are also available. An upgrade to PerlEx 1.1 is available
at no cost to PerlEx 1.0 license holders from the same web page.
If you are using Unix, you shouldn't have any problems with
performance. But if you are looking for still better performance,
use GAMS-CGI in conjunction with mod_perl in the Unix environment.
Question 17
I can't get Perl scripts to work with Microsoft Internet Information
Server (MIIS). How do I do that?
Answer 17
If you installed Perl before installing MIIS, get the latest build
and install it (or reinstall it if you are already running it).
There should be a checkbox at some point which says something like
``Associate the extension pl with my web server.'' Select that
checkbox and complete the installation
If you installed Perl after installing MIIS, then run a simple test
script rather than a complex system like GAMS-CGI to test that it is
working; for example, put the following script in your
Inetpub\scripts directory:
and try running it.
Question 18
I did what you said in the last FAQ, and I still can't get Perl
scripts to work. I am running MIIS. What do I do now?
Answer 18
Edit the registry. (If you don't know how to edit the registry, you
have no business running a web site!) Add a key to
There should already be a .idc key there. Simply add a
.pl key with a value like
Question 19
I am using the Apache server in Windows and can't get GAMS-CGI to
work. What do I do?
Answer 19
If you did not check the box ``I use the Apache web server'' when you
installed GAMS-X, then the shebang was not put at the top of the
gams-cgi.pl file and the configuration variable that indicates
non-parsed headers should NOT be used was not set properly.
(If you do not know what a shebang is, then you should not be
running a web site.)
To change the configuration variable, go into GAMS-Tk, then select
the Tools.Site.Configure menu option, then change the variable
nph (non-parsed headers) from 1 to 0.
Question 20
When I create a new case in GAMS-CGI, it is listed as solving.
However, I have been waiting and waiting and the case has not yet
solved.
Answer 20
Make sure that you have turned on the GAMS-CGI daemon. The daemon is a
program that solves new cases as they are submitted. For more
information, see section 2.4.
Question 21
GAMS-CGI seems to be working just fine with the exception of the
graphs, which either don't appear or tend to disappear.
Answer 21
The likely cause of this problem is incorrectly set file permissions.
The web server by default does not give write permission to every
program that appears in the CGI directory. This is a reasonable
precaution, as you don't want to give the unwashed billions access
to your computer without at least a little bit of forethought.
If you are a Unix user, you must run any GAMS-CGI scripts (such as
the file gams-cgi.pl that comes with the installation)
through a setuid wrapper.
If you are a Windows user, make sure that the permissions for your
web server service will allow you write permission on the
public HTML directories.
Unfortunately, setting file permissions for web servers is a subject
far beyond the scope of this humble FAQ. Please consult your web
server documentation.
Question 22
When I try to run GAMS-CGI, I get server errors.
Answer 22
Check two things:
Unfortunately, server configuration is a tricky subject, though it is
getting easier all the time as web technology becomes more mature.
Server configuration is beyond the scope of this humble FAQ; be
assured, however, that GAMS-CGI has been tested on Apache, MIIS, and
ZBServer, so your humble programmer knows from experience that it
works on a wide variety of servers.
Question 23
GAMS-CGI is giving my users a message informing them that my GAMS-CGI
site is paused while GAMS-Tk is active when I know for a fact that it
is not.
Answer 23
Sometimes, when GAMS-Tk dies unexpectedly, it does not have time to
reset the parameter that informs GAMS-CGI that it is currently being used.
Try restarting GAMS-Tk, and then exiting again. If that does not
work for some reason, you may as a last resort edit the GAMS-X
initialization file (see section ) to change the line that reads
to read
Question 24
I created a customized GAMS-CGI script, and now I am having problems.
Answer 24
In their flexibility, fully customized GAMS-CGI scripts also provide
programmers with enough of the proverbial rope to hang themselves if
they do not think carefully about what they are doing. Those
creating such scripts should read the rules for CGI programming I
have included in section 8.4.4, as well as familiarize
themselves with CGI programming security considerations as described
in any of the plethora of web programming books on the market.
Also, an excellent, albeit not the most accessible, reference on file
locking and security procedures for CGI scripts is the GAMS-CGI
module itself.
Question 25
Suddenly my cases aren't solving and/or returning funny values for my
outputs and/or giving me plotting errors.
Answer 25
If you made any changes to your model after installing it that is
likely the culprit.
Otherwise, make sure none of the sets over which your outputs or
plots are defined may change in size as a result of a user's choice
of inputs. This will cause GAMS-X to misread the case solution
files, returning the output values with the wrong outputs and/or
erroneous plot values.
Perl/Tk is a recent port to the Windows environment; thus, there are
still several minor glitches which crop up and will hopefully be
remedied as the ActivePerl/Tk distribution matures.
Bug 1
This is not actually a bug, but simply the way Perl/Tk works: The
DOS prompt is minimized when GAMS-Tk is run. I find it to be an
annoyance, but there is currently no workaround. Simply Alt-Tab or
navigate the task bar back to the DOS prompt if you want to see the
GAMS output from a model installation, for example.
Bug 2
GAMS-Tk takes a long time to load. This is also not a bug, but it
would be nice to have some notification that loading is in progress.
The Tk::WaitBox widget, which updates users on the status of a
process, has not yet been included with the standard ActivePerl
distribution, but should be in the future.
Bug 3
When opening a file, the file type (*.gms etc.) may appear incorrectly. This
is a bug with the Tk::getOpenFile method, and has been submitted to ActiveState.
Bug 4
When cancelling a file open or file save, very occasionally a runtime
exception arises and kills GAMS-Tk. This is a bug with the
Tk::getOpenFile and Tk::getSaveFile methods, and has been submitted
to ActiveState.
This bug generates the error message Error: Runtime exception.
Bug 5
No directory browsing. When a user needs to enter a directory, they
do not have a browsing tool available to do so. This is due to a bug
in the Tk::DirTree widget, which has been submitted to ActiveState.
Bug 6
Actions initiated by the menu options do not always return errors
when they occur. This make it seem as if the menu option will not
work. This is a bug due to the Tk::Menubar widget, which has been
submitted to ActiveState.
See also FAQ 9.2.4.
No doubt, as with any 20,000 lines of code first released on the
marketplace, there are still bugs to be discovered. Your humble
programmer is a graduate student, not a crack team of computer whiz
kids, so there will doubtless be some bugs (hopefully not too many)
in the initial release.22
New bugs will be added to this section as they are uncovered, and
updates will be posted to correct any bugs that are discovered. Keep
in touch.
You may also find it worthwhile to peruse section , which contains information on bugs native to
ActivePerl rather than GAMS-X.
Bug 1
GAMS-Tk can run slowly, especially when switching between users or
models that result in it having to redraw graphs, or when a model has
been installed with a large23 number of inputs or outputs.
This is perhaps GAMS-Tk's biggest Achilles heel.
There is good news and bad news on this front: The good news is that
there is a way to remedy the speed problem. The bad news is that
your humble programmer will not have time to implement it until
summer 1999. I never promised you a rose garden.
If things become unbearably slow in GAMS-Tk with very large models
with a very large number of inputs and outputs, you may find it
worthwhile to take up GAMS-X scripting, which allows for all of the
functionality of GAMS-Tk and then some, and suffers none of the
compromises in speed associated with the visual environment.
The ModelState data structure is an associative array with the
following keys:
As you can see, all of the keys are identical to
those returned by the Models method24 with the exception of the Case and Pending keys.
The Case key returns a reference to a list containing all of the
cases that have been submitted to GAMS, while the Pending key returns
a reference to a list containing all of the cases that are awaiting
submission to GAMS.
Each case in the Case and Pending lists consists of a reference to an
associative array containing User, UserID, Name, Created, Status, ID,
Tag, and Input keys.
The User key returns the name of the user that submitted the case.
The UserID key returns the ID of the user that submitted the case.
The Name key returns the name of the case as first specified by the
user that submitted it.
The Created key returns the date and time that the case was created.
The Status key returns the status of the case (either Solved,
Error, or Unsolved).
The ID key returns the unique identifier used by the user account of
the user that submitted the case.
The Tag key returns a unique identifier for the case, and is used
internally by GAMS-X.
The Input key returns a reference to an associative array whose keys
are the input names associated with the case and whose values are the
input values.
Example:
See also section .
There is a UserState data structure associated with every combination
of user and model. To obtain the UserState data structure, use the
UserState method (see section ).
The UserState data structure is an associative array with all of the
information regarding users' cases and casebooks and a model's
associated inputs, outputs, and plots.
The array keys are
and the values are lists of the data structures
outlined in the subsections below.
To see for yourself what the keys are, you can write a GAMS-X script
like the following:
Each case in the UserState list of cases is an associative array
consisting of the following keys:
Note that the cases in the UserState list of cases is used to generate
the data structure returned by the Cases method (see ).
To obtain the Case keys, you could write a GAMS-X script like:
The Created key has a value giving the time and date at which the
case was created.
The ID key has a value that is a case identifier unique to the user,
and is used internally by GAMS-X.
The Name key has a value of the name given to the case by the user.
The Status key has a value which returns 'Solved', 'Unsolved', or
'Error', whichever represents the status of the case. Solved means
that the case was submitted to GAMS and completed normally. Unsolved
means that the case has not yet been submitted to GAMS. Error means
that the case was submitted to GAMS but resulted in a GAMS error.
The Tag key has a value that is a case identifier unique to the
model, and is used internally by GAMS-X.
The User key has a value that is the name of the User who created the
case.
The UserID key has a value that is the unique identifier associated
with the user who created the case, and is used internally by GAMS-X.
The Input key has a value which is an associative array whose keys
are the input names for the case and whose values are the input
values for the case. This is the same type of data structure used
when setting CaseInputs (see for an example of
setting CaseInputs). Example:
The Output key is similar to the Input key, in that its value is an
associative array whose keys are the output names for the case and
whose values are the output values. Example:
Finally, the Plots key returns an associative array whose keys are
the names of the plots defined in the model's GAMS code and whose
values are lists of the values that go in the plots. Example:
NB: While GAMS syntax is case-insensitive, GAMS-X syntax,
consistent with that of Perl, is not. Therefore if you create a
GAMS-X input with a GAMS statement like
you can refer to the input later in your GAMS file
with a statement like
whereas in GAMS-X, you must use the
capitalization used in declaring the input in GAMS (i.e., BET rather
than bet). For example,
would print nothing whereas
would print the default value of the input
BET (i.e., 0.95).
See also the Cases method, section .
The Casebooks key has a value that is an list of associative arrays with the
following keys:
The Name key returns a value that is the name of the case. Example:
The Description key returns a value that is the casebook description.
The Stamp key returns a timestamp of the last plots generated, and is
used internally by GAMS-X.
The Case key returns a list of the cases that are in currently in the
casebook. Each value in the list is a pointer to a case in the
user's case list. Example:
The UserState Input key returns a list of the inputs defined in the
GAMS model via a $libinclude X input statement. The list
is in the order declared in the GAMS code, and each value
in the list is an associative array possessing the following keys:
The Name key has a value that is the name of the input.
The Description key has a value that is the description of the input.
The Default key has a value that is the default value of the input.
The Option key has a value that is a list, in the order specified in
the GAMS code, of the available options for that input.
Example:
Note that the inputs in the UserState list of inputs is used to generate
the data structure returned by the Inputs method (see ).
The UserState Output key returns a list of the outputs defined in the
GAMS model via a $libinclude X output statement. The list
is in the order declared in the GAMS code, and each value
in the list is an associative array possessing the following keys:
The Name key has a value that is the name of the output.
The Description key has a value that is the description of the output.
Example:
Note that the outputs in the UserState list of outputs is used to generate
the data structure returned by the Outputs method (see ).
The UserState Plot key returns a list of the plots defined in the
GAMS model via a $libinclude X plot statement. The list
is in the order declared in the GAMS code, and each value
in the list is an associative array possessing the following keys:
The Name key has a value that is the name of the plot (e.g., C.L if
the level value of the variable C is being plotted).
The Description key has a value that is the description of the plot.
The Domain key has a value that is a list of the set elements over which
the domain of the plot is defined.
The Abcissa key has a value that is a list of the set elements that are
used as labels on the X-axis of the plot.
The NumberOfObservations key has a value that is the number of
observations to be plotted, and corresponds to the size of the Domain
and Abcissa lists.
The Option key has a value that is an associative array with
key-value pairs corresponding to the plot options (e.g., type=bars,
height=500, etc.).
Example:
Note that the plots in the UserState list of plots is used to generate
the data structure returned by the Plots method (see ).
The shebang used by the Apache server and Unix-based platforms to
identify the location of the Perl executable
Chapter 9
Frequently Asked Questions
9.1 User FAQs
c:\mydir/working\mymodel.gms
and it will
recognize it as a valid filename.
9.2 Modeler/Administrator FAQs
9.2.1 Installing Perl
Before you run PPM, you should be connected to the Internet. If your Internet connection is via a
firewall or proxy, you should set the environment variable 'HTTP_
proxy' to the name of this proxy
server. If your proxy server requires a username and password, the environment variables
'HTTP_
proxy_
user' and 'HTTP_
proxy_
pass' should be set to these values.
C:\>set HTTP_proxy=MyProxy
C:\>echo %HTTP_proxy%
MyProxy
PPM install ?.ppd
where ? is the package name (e.g., Storable) from a command prompt.
9.2.2 Installing GAMS-X
Can't locate ?.pm in @INC (@INC contains: /usr/perl/lib /usr/perl/site/lib .).
BEGIN failed--compilation aborted.
perl -V
9.2.3 General
C:\Winnt\Profiles\YourUserName\Start Menu\Programs\GAMS-X
Can't locate ?.pm in @INC (@INC contains: /usr/perl/lib /usr/perl/site/lib .).
BEGIN failed--compilation aborted.
perl -V
Before you run update, you should be connected to the Internet. If your Internet connection is via a
firewall or proxy, you should set the environment variable 'HTTP_
proxy' to the name of this proxy
server. If your proxy server requires a username and password, the environment variables
'HTTP_
proxy_
user' and 'HTTP_
proxy_
pass' should be set to these values.
C:\>set HTTP_proxy=MyProxy
C:\>echo %HTTP_proxy%
MyProxy
9.2.4 GAMS-Tk
9.2.5 GAMS-CGI
PerlEx 1.1 dramatically improves performance by pre-compiling Perl scripts
and storing them in memory. Using a web server's native Application Program
Interface (API), ActiveState has seen typical performance increases of 2 to
30 times, compared to an ordinary Perl ISAPI Dynamic Link Library or
standalone Perl.
use CGI;
$cgi = new CGI;
print $cgi->header;
print "Hello World!\n";
HKEY_LOCAL_MACHINE
SYSTEM
CurrentControlSet
Services
W3SVC
Parameters
Script Map
"C:\Perl\bin\perl.exe %s %s"
TkOn=1
TkOn=0
9.3 Known ActivePerl/Tk Bugs
9.4 Known GAMS-X Bugs
Appendix A
Data Structures
A.1 ModelState
use GAMS::Script;
$GAMS = new GAMS::Script;
# Loop over the cases that have been submitted to GAMS . . .
for $Case (@{$GAMS->ModelState('Ramsey')->{Case}}) {
print "Case $Case->{Name} was created $Case->{Created}.\n";
if ($Case->{Status} eq 'Solved') {
print "The case solved normally.\n";
} else {
print "The case caused a GAMS error.\n";
}
for $Input (sort keys %{$Case->{Input}}) {
print "Input $Input has value $Case->{Input}->{$Input}\n";
}
print "\n";
}
# . . . and the cases that are pending submission to GAMS
for $Case (@{$GAMS->ModelState('Ramsey')->{Case}}) {
print "Case $Case->{Name} was created $Case->{Created}.\n";
print "The case has not yet been submitted to GAMS.\n";
for $Input (sort keys %{$Case->{Input}}) {
print "Input $Input has value $Case->{Input}->{$Input}\n";
}
print "\n";
}
A.2 UserState
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the UserState data structure keys and their data types:\n\n";
for $key (sort keys %{$GAMS->UserState}) {
print "$key is of type ", ref ($GAMS->UserState->{$key}), "\n"
}
A.2.1 Cases
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the Case data structure keys and their data types:\n\n";
for $key (sort keys %{$GAMS->UserState->{Case}->[0]}) {
print "$key is of type ";
print ( ref ($GAMS->UserState->{Case}->[0]->{$key}) || 'SCALAR' );
print "\n";
}
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the inputs for the first case in Grog's UserState case list:\n\n";
for $key (sort keys %{$GAMS->UserState->{Case}->[0]->{Input}}) {
print "$key: ", $GAMS->UserState->{Case}->[0]->{Input}->{$key}, "\n"
}
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the outputs for the first case in Grog's UserState case list:\n\n";
for $key (sort keys %{$GAMS->UserState->{Case}->[0]->{Output}}) {
print "$key: ", $GAMS->UserState->{Case}->[0]->{Output}->{$key}, "\n"
}
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the plots for the first case in Grog's UserState case list:\n\n";
for $key (sort keys %{$GAMS->UserState->{Case}->[0]->{Plot}}) { print "$key\n" }
print "\nThe values in the plot of C.L are:\n\n";
print "@{$GAMS->UserState->{Case}->[0]->{Plot}->{'C.L'}}\n";
$libinclude X INPUT BET 0.95 "Discount Factor" MAX 0.975 MIN 0.95
SCALARS BET DISCOUNT FACTOR /%bet%/
print $GAMS->Inputs('Grog','Ramsey')->{'bet'}->{Default};
print $GAMS->Inputs('Grog','Ramsey')->{'BET'}->{Default};
A.2.2 Casebooks
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the casebooks for Grog's UserState:\n\n";
for $Casebook (@{$GAMS->UserState->{Casebook}}) { print "$Casebook->{'Name'}\n" }
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the cases in their corresponding casebooks for Grog's UserState:\n\n";
for $Casebook (@{$GAMS->UserState->{Casebook}}) {
for $Case (@{$Casebook->{Case}}) {
print "$Casebook->{'Name'}: $Case->{'Name'}\n"
}
}
A.2.3 Inputs
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the inputs for Grog's UserState:\n\n";
for $Input (@{$GAMS->UserState->{Input}}) {
print "$Input->{Name}\n"
}
print "\nThe first input has name ";
print $GAMS->UserState->{Input}->[0]->{Name};
print ", default value ";
print $GAMS->UserState->{Input}->[0]->{Default};
print ", and options \n\n";
for $Option (@{$GAMS->UserState->{Input}->[0]->{Option}}) {
print "$Option\n"
}
A.2.4 Outputs
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the outputs for Grog's UserState:\n\n";
for $Output (@{$GAMS->UserState->{Output}}) {
print "$Output->{Name} has description '$Output->{Description}'.\n\n"
}
A.2.5 Plots
use GAMS::Script;
$GAMS = new GAMS::Script;
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "These are the plots for Grog's UserState:\n\n";
for $Plot (@{$GAMS->UserState->{Plot}}) {
print "$Plot->{Name} has description '$Plot->{Description}'.\n\n"
}
print "\nThe first plot is defined over the following domain:\n\n";
print "@{$GAMS->UserState->{Plot}->[0]->{Domain}}\n\n";
print "and will use the following labels on the x-axis:\n\n";
print "@{$GAMS->UserState->{Plot}->[0]->{Abcissa}}\n\n";
Appendix B
GAMS-Ini MethodsFrom the GAMS-X Initialization File
Shebang
GXRoot
The GAMS-X root directory
The GAMS-X public HTML directory
The root directory for CGI executable files
The virtual CGI directory
The Perl binary directory
The Perl library directory
The GAMS root directory
A web browser executable (used by GAMS-Tk)
A text editor executable (used by GAMS-Tk)
Indicates whether GAMS-Tk is currently in operation: 1 = On, 0 = Off
The number of rows of inputs and outputs in the GAMS-Tk casebook table allowed before rows are scrolled. Default = 20.
The number of columns of cases in the GAMS-Tk casebook table allowed before columns are scrolled. Default = 10.
Indicates whether GAMS-CGI is installed at this GAMS-X site. 0=No, 1=Yes.
The organization affiliated with this GAMS-X site. No default.
The email address of the GAMS-CGI webmaster. No default.
Indicates whether the GAMS-CGI site is currently paused. 1 = Paused, 0 = Not Paused. Default = 0.
Indicates whether the GAMS-CGI bypasses the user login for existing users. 1 = Bypass, 0 = No Bypass. Default = 0.
An image that can be displayed as the GAMS-CGI default background; e.g., MyImage.gif No default.
The default background color of GAMS-CGI pages. Default = #D7CBBB
The logo that appears on the GAMS-CGI login page. Default = gams-cgi.gif
The height of the logo that appears on the GAMS-CGI login page. Default = 95
The width of the logo that appears on the GAMS-CGI login page. Default = 126
Indicates whether CGI headers are nonparsed. Consult your server documentation to find out whether nonparsed headers are required. If this is set to the wrong value, you will probably receive an error message when using GAMS-CGI to the effect that you have "malformed headers."
Windows servers typically like nonparsed headers (i.e., nph=1) with the exception of Apache, which does not (i.e., nph=0).
The GAMS-X homepage from which the URLs of the GAMS-X manual are derived. Default = http://www.gams.com/gams-x.
Returns the current owner (only defined in the Unix environment).
Returns the Perl GAMS library containing the GAMS::CGI, GAMS::Ini, and GAMS::Tools modules.
Returns the GAMS-X virtual directory (e.g., http://economics.colorado.edu/gams-x).
Returns the users' root directory.
Returns the users' public HTML directory.
Returns the users' virtual directory.
Returns the Models' root directory.
Returns the Models' public HTML directory.
Returns the Models' virtual directory.
Returns the HTML form action for the current GAMS-CGI script.
Returns the GAMS-X HTML image directory.
Returns the file name of the GAMS-CGI daemon.
Returns the file name of the GAMS-Ini module.
Returns the file name of the GAMS-X log.
Returns the file containing the message returned to users when GAMS-CGI is paused.
Returns the name of the default GAMS-X data file.
The name of the append file containing the pending GAMS-X cases. Used by the Solver method and the GAMS-CGI daemon
The name of the batch file containing the pending GAMS-X cases. Used by the Solver method and the GAMS-CGI daemon
The name of the file that contains the data returned by the GAMS method Users.
The name of the file that contains the data returned by the GAMS method Models.
The name of the data file that holds a user's profile. Located in the user's subdirectory of the users directory of the GAMS-X root directory.
The name of the data file that holds a user's or model's state. Users' state files are located in the model subdirectory of the user's subdirectory of the users directory of the GAMS-X root directory. Model state files are located in the directory in which the model is installed.
The name of the GAMS-X configuration file, generated whenever a model is first installed in GAMS-X.
The web server CGI directory
The GAMS-X working directory. This is established as a subdirectory of any model installed in GAMS-X.
The GAMS-X case directory. This is established as a subdirectory of any model installed in GAMS-X. This holds all of the GAMS case files generated by GAMS-X.
The GAMS-X case listings directory. This is established as a subdirectory of any model installed in GAMS-X, and holds all of the listing files generated for GAMS-X cases.
The name of the GAMS-X working directory which can be used as a repository for models being installed on site.
The name of the GAMS-X temporary directory.
Returns an associative array whose keys are the names of the configuration variables given in the GAMS-X initialization file and whose values are their values. Example:
use GAMS::Ini;
$GAMS = new GAMS::Ini;
print "These are the GAMS-X configuration variables and their values:\n\n";
for $key (sort keys %{$GAMS->Configuration}) {
print "$key: ", $GAMS->Configuration->{$key}, "\n";
}
Configures a GAMS-X configuration variable located in the GAMS-X initialization file (see Configuration above). For example, when GAMS-Tk wants to inform GAMS-CGI that it is currently running, it sets the configuration variable TkOn with a statement like:
$GAMS->Configure( -TkOn => 1 );
Supports a set of methods for administering GAMS models. Inherited by the GAMS::CGI, GAMS::Tk, and GAMS::Tools packages.
Note that in all of the methods given below, brackets [] in the method argument descriptions indicate that those arguments are optional and may be specified by the current state. Thus the statement
$Inputs = { AC => 0.15, blah blah blah, K0 => 3.00 };
$GAMS->NewCase( 'Grog','Ramsey','CASE1', $Inputs );
and
$Inputs = { AC => 0.15, blah blah blah, K0 => 3.00 };
$GAMS->Set( 'User' => 'Grog', 'Model' => 'Ramsey', 'Case' => 'CASE1' );
$GAMS->NewCase( '','','', $Inputs );
are equivalent. For more information, see the Set method below.
Creates the GAMS object. Example:
use GAMS;
$GAMS = new GAMS;
Returns the value of the option ? set with the Set method. If one cannot be found, it returns an undefined value. Example:
$GAMS->Set( -MyOption => "Hello!\n" ); print $GAMS->MyOption;
Note for debugging that if a method name is spelled wrong, you will likely not receive an error message. Instead, an undefined value will simply be returned.
Places the string in the GAMS-X log. Example:
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$GAMS->Log("It is $hour o'clock and all's well!");
Sets a parameter that can later be retrieved with a method call of the same name. Example:
$GAMS->Set( -MyName => 'Grog' );
Then
print $GAMS->MyName;
would print Grog. Note that many of these parameters, notably User, Model, Case, and Casebook, are used by other methods in lieu of explicit specification in the method call; thus, you must take care not to use reserved words when setting parameters.
See also $GAMS- > Quit below.
Returns a hash of the user accounts on the GAMS-X site. Example:
print "The user Grog has ID ";
print $GAMS->Users->{ID}->{'Grog'};
To check if a user exists, use the exists function to check whether an ID has been issued for that user. Example:
if (exists $GAMS->Users->{ID}->{'Grog'}) {
print "Grog exists!";
} else {
print "Grog doesn't exist!";
}
Returns a hash containing the account information for the user with name User. If no user is specified, the profile of the currently set user is returned. Example:
$MyProfile = $GAMS->UserProfile( 'Grog' );
print "The user Grog has email address ";
print $MyProfile->{'Email'};
Alternatively,
$GAMS->Set( -User => 'Grog' );
print "The user Grog has email address ";
print $GAMS->UserProfile->{'Email'};
Returns the user ID of the user with name User. If no user is specified, the ID of the currently set user is returned. Example:
$MyUserID = $GAMS->UserID( 'Grog' ); print "The user Grog has ID "; print $MyUserID;
Alternatively,
$GAMS->Set( -User => 'Grog' ); print "The user Grog has ID "; print $GAMS->UserID;
Returns the user's state object associated with user User and model Model. If no user or model is specified, these values are taken from the User and/or Model methods. Example:
$MyState = $GAMS->UserState('Grog', 'Ramsey');
print "Grog has cases @{[@{$MyState->{Case}}]} in the model Ramsey\n";
Alternatively,
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' ); $MyState = $GAMS->UserState;
Returns
Returns a hash of the models currently installed on the site whose keys are the model names and whose values are the model descriptions. Example:
print "Model Ramsey has description ";
print $GAMS->Models->{Description}->{Ramsey};
To check if a model exists, use the exists function to check whether an ID has been issued for that model. Example:
if (exists $GAMS->Models->{ID}->{'Ramsey'}) {
print "Ramsey exists!";
} else {
print "Ramsey doesn't exist!";
}
Returns the model object of the currently specified model. Example:
$GAMS->Set( -Model => 'Ramsey' );
print "The model Ramsey has description ";
print $GAMS->ModelState->{Description}
Alternatively,
print "The model Frank has description ";
print $GAMS->ModelState('Frank')->{Description}
Returns a hash of the cases specified by the current user state (see the UserState method above) whose keys are the case names. Example:
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "Case MyCase, input KAPITAL has value ";
print $GAMS->Cases->{MyCase}->{Input}->{KAPITAL};
See also the Cases Data Strucure, section A.2.1.
Returns a hash of the casebooks specified by the current user state (see the UserState method above) whose keys are the casebook names. Example:
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "Casebook MyCasebook has description ";
print $GAMS->Casebooks->{MyCasebook}->{Description};
See also the Casebooks Data Strucure, section A.2.2
Returns a hash of the inputs specified by the current user state (see the UserState method above) whose keys are the input names. Example:
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "Input KAPITAL has default value ";
print $GAMS->Inputs->{KAPITAL}->{Default};
See also the Inputs Data Strucure, section A.2.3.
Returns a hash of the outputs specified by the current user state (see the UserState method above) whose keys are the output names. Example:
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "Output UTILITY has description ";
print $GAMS->Outputs->{UTILITY}->{Description};
See also the Outputs Data Strucure, section A.2.4.
Returns a hash of the plots (optionally specified by the current user state - see the UserState method above) whose keys are the plot names. Example:
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
print "The plot CONSUME has description ";
print $GAMS->Plots->{CONSUME}->{Description};
Returns the filename of the image (GIF or whatever) for plot Plot. Example:
use GAMS::Script;
$GAMS = new GAMS::Script;
$Plot = $GAMS->PlotURL('Grog','Ramsey','STUDY1','C.L');
print "The GIF file for the plot of C.L in user Grog's Ramsey model casebook STUDY1 is:\n\n";
print $Plot;
See also the Plots Data Strucure, section A.2.5.
Returns the URL of the image (GIF or whatever) for plot Plot. Example:
use GAMS::CGI;
$GAMS = new GAMS::CGI;
print $GAMS->{CGI}->header;
$Plot = $GAMS->PlotURL('Grog','Ramsey','STUDY1','C.L');
print <<"eop"; <HTML> <BODY> <H1>Howdy!</H1> <P> This is the plot for series C.L for the user Grog and the model Ramsey: <P> <IMG SRC="$Plot"> </BODY> </HTML> eop
$GAMS->Quit;
Revises the description for the currently set user, model, and casebook. Example:
$GAMS->Set ( -User => 'Grog', -Model => 'Ramsey', -Casebook => 'STUDY1' ); $GAMS->ReviseDescription( 'This is a new description for the casebook STUDY1.' );
Creates a new casebook with name Case and description Description for user User, model Model.
Deletes the casebook with name $Casebook from the model Model account for user User. Note that a casebook must be free of cases in order to be successfully deleted.
Creates a new case with name Case for user User, model Model. Inputs is a reference to an array whose keys are input names and values are input values.
Thus, one may define the inputs with a statement like:
$Inputs = {
AC => 0.15,
B => 0.30,
BET => 0.95,
G => 0.03,
I0 => 0.05,
K0 => 3.00
};
Imports the case with name Case into the casebook named Casebook.
Removes the case with name Case from the casebook with name Casebook from the model Model account for user User.
Deletes the case with name Case from the model Model account for user User. Note that a case must be removed from all casebooks using the RemoveCase method before it may be deleted.
Puts case $Case into casebook Casebook for user User, model Model.
Clears all of the user and model information from memory, so that the next Users, Models, ModelState, or UserState method call will retrieve the information from the appropriate state file. A rather esoteric method, but I have found it very useful in odd circumstances.
Preserves all of the user and model states that have been altered by methods such as NewCase or ReviseDescription or are explicitly set to be preserved via the Set method PreserveUserState or PreserveModelState options, committing whatever changes have been made.
In long scripts, it is a good idea to activate the PreserveStates method from time to time to make sure you don't lose information if an fatal error arises.
Example:
$GAMS->Set ( -PreserveUserState => { 'Grog' => 'Ramsey' } );
$GAMS->Set ( -PreserveModelState => 'Ramsey' );
$GAMS->PreserveStates;
This method is called by the Quit method (below) before exiting. More detailed examples are given with the Quit method.
Exits, committing whatever changes have been made. Example:
$GAMS->Set ( -User => 'Grog', -Model => 'Ramsey', -Casebook => 'STUDY1' ); $GAMS->ReviseDescription( 'This is a new description for the casebook STUDY1.' ); $GAMS->Quit;
Changes are automatically committed when a method is called which changes a user's or model's state. To force a change to a user's or model's state to be committed, set the parameters PreserveUserState or PreserveModelState; for example,
$GAMS->Set ( -PreserveModelState => 'Ramsey' ); $GAMS->Quit;
will preserve the model state of Ramsey provided it has been loaded into memory. User states are associated with both a user and a model, and so must include both in the call to preserve the user state:
$GAMS->Set ( -PreserveUserState => { 'Grog' => 'Ramsey' } );
$GAMS->Quit;
If more than one model state needs to be preserved, use a pointer to a list of model names; for example,
$GAMS->Set ( -PreserveModelState => ['Ramsey', 'Frank'] ); $GAMS->Quit;
will preserve both Ramsey and Frank.
Similarly, to preserve more than one user and/or model state,
$GAMS->Set (
-PreserveUserState => {
'Grog' => 'Ramsey',
'Wonk' => ['Ramsey','Frank']
}
);
$GAMS->Quit;
would preserve the user state for Grog associated with the model Ramsey and for Wonk assiciated with the models Ramsey and Frank.
Note that the user and/or model states are automatically preserved following which change the user and/or model states.
Kills user User, removing that account from GAMS-X. Example:
$GAMS->Kill( 'Grog' );
Returns the index in the user state (cf. UserState) of casebook Casebook. Example:
$index = $GAMS->CasebookIndex( 'MyCasebook' );
$description = $GAMS->UserState->{Casebook}->[$index]->{'Description'};
print "Casebook MyCasebook has description $description";
Returns the index in user User's model Model casebook Casebook list of cases for case Case. Example:
$index = $GAMS->CasebookCaseIndex( 'Grog','Ramsey','MyCasebook','MyCase' ); print "MyCase is case number $index in casebook MyCasebook.\n";
Returns the index in user User's case list of case Case. Example:
$index = $GAMS->CaseIndex( 'Grog','Ramsey','MyCase' );
print "MyCase is case number $index in my case list.\n";
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
$description = $GAMS->UserState->{Case}->[$index]->{Description};
print "MyCase has description $description\n";
Returns the index in user User's plot list of plot Plot. Example:
$index = $GAMS->CaseIndex( 'Grog','Ramsey','MyCase' );
print "MyCase is case number $index in my case list.\n";
$GAMS->Set( -User => 'Grog', -Model => 'Ramsey' );
$description = $GAMS->UserState->{Case}->[$index]->{Description};
print "MyCase has description $description\n";
Returns the number of solved cases in user User's casebook Casebook in model Model. Example:
$solved = $GAMS->Solved( 'Grog','Ramsey','MyCasebook' ); print "There are $solved solved cases in casebook MyCasebook\n";
Returns the number of unsolved cases in user User's casebook Casebook in model Model. Example:
$unsolved = $GAMS->Unsolved( 'Grog','Ramsey','MyCasebook' ); print "There are $unsolved unsolved cases in casebook MyCasebook\n";
Returns the number of cases in user User's casebook Casebook in model Model that have generated a GAMS error. Example:
$error = $GAMS->Error( 'Grog','Ramsey','MyCasebook' ); print "$error cases resulted in GAMS errors in casebook MyCasebook\n";
Returns the total number of solved cases in model Model. Example:
$solved = $GAMS->TotalSolved( 'Ramsey' ); print "There are $solved solved cases in the Ramsey model\n";
Note that if two users solve the same case (i.e., the same input values), that represents only one solved case in the model Ramsey; that is, once a case has been solved, it is not resolved the next time it is submitted by another user (or even the same user).
Returns the total number of unsolved cases in model Model. Example:
$unsolved = $GAMS->TotalUnsolved( 'Ramsey' ); print "There are $unsolved unsolved cases in the Ramsey model\n";
Returns the total number of cases in model Model that have generated a GAMS error. Example:
$error = $GAMS->TotalError( 'Ramsey' ); print "$error cases resulted in GAMS errors in the Ramsey model\n";
Plots many cases against one series or many series against one case. File is the name of the file the plot is saved to. Cases may either be the name of a single case or a reference to a list of case names. Likewise, Plots may either be the name of a single plot or a reference to a list of plot names. The PlotOptions is a reference to an associative array whose keys are the names of plot options and whose values are their values. Example:
$GAMS->MultiPlot(
'C:\temp\myplot.gif',
'Grog',
'Ramsey',
'HIGHB',
[ 'C.L', 'CC.M' ],
{ 'type' => 'bars', 'height' => 600, 'width' => 800 }
);
Or, to plot many cases against a single series,
$GAMS->MultiPlot(
'C:\temp\myplot.gif',
'Grog',
'Ramsey',
[ 'HIGHB', 'HIGHG' ],
'C.L',
{ 'type' => 'bars', 'height' => 600, 'width' => 800 }
);
Generates plots for user User's model Model casebook Casebook. Example:
print "I shall make some fresh graphs for my casebook . . .\n"; $GAMS->CasebookPlots( 'Grog','Ramsey','MyCasebook' );
Adds a user account to GAMS-X with name User, email address Email, password Password with confirmation PasswordConfirmation, and affiliation Affiliation. Example:
$GAMS->AddUser(
'Grog',
'grog@spot',
'grog!',
'grog!',
'University of Grog'
);
Equivalently, one could write
$GAMS->Set(
-User => 'Grog',
-Email => 'grog@spot',
-Password => 'grog!',
-PasswordConfirmation => 'grog!',
-Affiliation => 'University of Grog'
);
$GAMS->AddUser;
Encrypts a string that is passed to it. Example:
$string = "Hello World!"; $crypt = $GAMS->Encrypt( $string ); print "When '$string' is encrypted, it yields '$crypt'\n";
Used for encrypting passwords and such.
Opens the GAMS-X log file and prints a time stamp.
Closes the GAMS-X log file.
Reads the solution file generated by GAMS for user User, model Model, case Case. If, for example, a model is changed and a case is resolved, this method can be used to update the user accounts with the new solution.
Submits all of the pending cases (i.e., those whose status is 'Unsolved') to GAMS. The Solver method does not release control back to the script until all of cases have been processed.
Creates a new GAMS::Tools object. Example:
use GAMS::Tools; $GAMS = new GAMS::Tools;
Writes a GAMS-X data file for the current user and model to File. See the Install method below.
Starts a web browser process with URL as an argument. Example:
$GAMS->Browse( 'http://www.gams.com' );
Starts a text editor with File as an argument. Example:
$GAMS->TextEdit( 'C:\gams-x\working\Ramsey\Ramsey.gms' );
Returns an string consisting of an HTML table of the user User's casebook Casebook for the model Model. Example:
open(HTML, '>MyCasebook.html') || die "Can't open MyCasebook.html!"; print HTML $GAMS->CasebookHTML( 'Grog','Ramsey','STUDY1' ); close HTML; `netscape MyCasebook.html`;
Returns an string consisting of an LaTeX table of the user User's casebook Casebook for the model Model. Example:
open(LATEX, '>MyCasebook.tex') || die "Can't open MyCasebook.tex!"; print LATEX $GAMS->CasebookLaTeX( 'Grog','Ramsey','STUDY1' ); close LATEX; `latex MyCasebook.tex`; `yap MyCasebook.dvi`;
Returns the filename of the listing file for the case with tag Tag in model Model.
Example:
$Tag = $GAMS->Cases->{'MyCase'}->{'Tag'};
$CaseListing = $GAMS->CaseListing( $Tag );
$GAMS->TextEdit( $CaseListing );
Installs a model with name Model, description Description based on the GAMS file GAMSFile, with optional HTML documentation Documentation and GAMS-X data file DataFile. Example:
$GAMS->Install(
'Ramsey',
'Ramsey Model of Optimal Economic Growth',
'C:\gams-x\working\Ramsey\Ramsey.gms',
'C:\gams-x\working\Ramsey\Ramsey.html',
'C:\gams-x\working\Ramsey\Ramsey.gmx'
);
new is the only GAMS-Script method available. It both creates a new GAMS::Script object which inherits all of the methods of GAMS-Ini, GAMS, and GAMS-Tools and verifies that GAMS-Tk, the GAMS-CGI daemon, and other GAMS-X scripts will not conflict with the actions executed by the script. Example:
use GAMS::Script; $GAMS = new GAMS::Script;
Supports a visual environement for administering GAMS models.
For the vast majority of GAMS-Tk users, the only file that they will ever use is the gams-tk application located in the GAMS-X root directory which consists of the following meager snippet of code:
use GAMS::Tk;
$GAMS = new GAMS::Tk;
$GAMS->Start;
$GAMS->Quit;
Returns the GAMS::Tk object. Example:
$GAMS->new;
Initializes the GAMS-Tk GUI interface. If the User or Model are not specified and are not set parameters, the User or Model that appears first alphabetically are chosen provided there are user accounts and models installed. If the Casebook is not stipulated, the first casebook appearing in user User's model Model state list is chosen. Example:
$GAMS->Set( -User => 'Grog' ); # In this case, Grog's account will be opened with the first # model that appears in alphabetical order $GAMS->Start;
The GAMS::CGI module inherits the GAMS::Ini , GAMS , and CGI module objects and all of their methods. In addition, the following methods are available:
Supports a set of methods for administering web sites based on GAMS models.
The GAMS::CGI module inherits the GAMS::Ini , GAMS , and CGI module objects and all of their methods. In addition, the following methods are available:
Creates a new GAMS::CGI object. Example:
use GAMS::CGI; $GAMS = new GAMS::CGI;
The CGI object inherited by the GAMS::CGI object. Example:
print $GAMS->{CGI}->header;
print "<HTML><BODY>Hello World!</BODY></HTML>";
For more information refer to the CGI pods.
Returns the value of the CGI parameter ?. If a CGI parameter cannot be found, it returns the value of the option with the same name that has been set with the Set method. If no such option has been set, returns an undefined value. Example:
print $GAMS->User;
CGI programmers should note that this returns the equivalent of
print $GAMS->{CGI}->param('User');
Note for debugging that if a CGI parameter or method name is spelled wrong, you will likely not receive an error message. Instead, an undefined value will simply be returned.
Returns the error message string to the user's browser. Example:
$GAMS->Gripe( "Only Grog may use this site!" ) unless $GAMS->User eq 'Grog';
Returns the GAMS-CGI Login Page. Example:
$GAMS->Greeting;
Logs a user in and validates the user's account from his login browser for 3 hours. Example:
$GAMS->Login;
Prints a HTML document that allows a user to create an account at the GAMS-CGI site. Example:
$GAMS->NewUser;
Example of an HTML form used to call the NewUser method:
<FORM NAME="Login" ACTION="/cgi/gams-cgi.pl" METHOD="post"> <P> Username: <INPUT TYPE="text" NAME="User" SIZE="30" MAXLENGTH="100"> <P> Password: <INPUT TYPE="password" NAME="Password" SIZE="30" MAXLENGTH="30"> <P> <INPUT TYPE="submit" NAME="Task" VALUE="New User"> </FORM>
Returns a HTML document that allows a user to create an account at the GAMS-CGI site. For example, the NewUser method is composed solely of the following two lines:
print $GAMS->{CGI}->header;
print $GAMS->NewUserHTML;
Adds a user account to GAMS-X with the user name, password, affiliation, and email as provided by the HTML form returned by the $GAMS- > NewUser method. Example:
# Someone just clicked on the submit button on the NewUser page, # so I will create an account for them.
$GAMS->AddUser; $GAMS->WriteModelIndex
Example HTML form that could be used with the AddUser method:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post" > <INPUT TYPE="hidden" NAME="Task" VALUE="AddUser"> <P> Username: <INPUT TYPE="text" NAME="User" SIZE="30" MAXLENGTH="100"> <P> Password: <INPUT TYPE="password" NAME="Password" SIZE="30" MAXLENGTH="30"> <P> Password Confirmation: <INPUT TYPE="password" NAME="PasswordConfirmation" SIZE="30" MAXLENGTH="30"> <P> Affiliation: <INPUT TYPE="text" NAME="Affiliation" SIZE="30" MAXLENGTH="100"> <P> email: <INPUT TYPE="text" NAME="Email" SIZE="30" MAXLENGTH="100"> <INPUT TYPE="submit" VALUE="Submit"> <INPUT TYPE="reset" VALUE="Reset"> </FORM>
Prints the User Account Edit Page, which allows a user to edit the information in his or her profile, and validates the user's current login for 3 hours. Example:
$GAMS->EditAccountInformation;
Example of an HTML form used to call the EditAccountInformation method:
<FORM NAME="Login" ACTION="/cgi/gams-cgi.pl" METHOD="post"> <P> Username: <INPUT TYPE="text" NAME="User" SIZE="30" MAXLENGTH="100"> <P> Password: <INPUT TYPE="password" NAME="Password" SIZE="30" MAXLENGTH="30"> <P> <INPUT TYPE="submit" NAME="Task" VALUE="Edit Account Information"> </FORM>
Edits a user's profile based on information provided in the $GAMS- > EditAccountInformation document and prints a confirmation page for the user. Example:
$GAMS->EditUser;
Sample HTML form that could be used with the EditUser method:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post" >
<INPUT TYPE="hidden" NAME="Task" VALUE="EditUser">
<INPUT TYPE="hidden" NAME="User" VALUE="Grog">
<INPUT TYPE="hidden" NAME="Time" VALUE="918942225">
<P>
Password: <INPUT TYPE="Password" NAME="NewPassword" SIZE="30" MAXLENGTH="100">
<P>
Password Confirmation: <INPUT TYPE="Password" NAME="PasswordConfirmation" SIZE="30" MAXLENGTH="100">
<P>
Affiliation: <INPUT TYPE="text"
NAME="Affiliation"
VALUE=""
SIZE="30"
MAXLENGTH="100">
<P>
email Address: <INPUT TYPE="text"
NAME="Email"
VALUE=""
SIZE="30"
MAXLENGTH="100">
<P>
<INPUT TYPE="submit" VALUE="Submit">
<INPUT TYPE="reset" VALUE="Reset">
</FORM>
Removes a user's account from the GAMS-X system. This option is provided on the page returned by $GAMS- > EditAccountInformation. Example:
$GAMS->RemoveAccount;
Sample HTML form that could be used with the RemoveAccount method:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post" > <INPUT TYPE="hidden" NAME="Task" VALUE="RemoveAccount"> <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="submit" VALUE="Remove Grog's account from GAMS-CGI database"> </FORM>
Prints a user's Model Index Page. Example:
$GAMS->WriteModelIndex;
Sample HTML form that could be used with the WriteModelIndex method:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post" > <INPUT TYPE="hidden" NAME="Task" VALUE="WriteModelIndex"> <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="submit" VALUE="Go to model index for user Grog"> </FORM>
Returns the HTML for the Model Index. This example is a little more advanced than most, using Perl's pattern matching capabilities. It takes advantage of the fact that all of the pages returned by GAMS-CGI have convenient markers to enable webmasters to easily customize the standard pages returned by GAMS-CGI:
# This example demonstrates how to write a customized Model Index
if ($GAMS->User eq 'Grog') {
$HTML = $GAMS->WriteModelIndexHTML;
# You have to put a slash \ before the > when
# pattern matching HTML markups
$On = '<!-- ModelIndexGreeting On--\\>';
$Off = '<!-- ModelIndexGreeting Off --\\>';
$HTML =~ s/$On.*?$Off/<CENTER><H1>Hello Grog!</H1><CENTER>/;
print $GAMS->{CGI}->header;
print $HTML;
} else {
$GAMS->WriteModelIndex;
}
Returns the HTML that makes up the model index; i.e., the listing of models that appears on the WriteModelIndexHTML document. Example:
$GAMS->ModelIndexHTML;
Prints a user's Casebook Index Page. Example:
$GAMS->WriteCasebookIndex;
Sample HTML form that could be used with the WriteCasebookIndex method:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post"> <INPUT TYPE="hidden" NAME="Task" VALUE="WriteCasebookIndex"> <INPUT TYPE="hidden" NAME="Model" VALUE="Ramsey"> <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="submit" VALUE="Go to Grog's Ramsey Casebook Index"> </FORM>
Returns the HTML text that is printed when the WriteCasebookIndex method is called. Example:
$GAMS->WriteCasebookIndexHTML;
Returns the HTML that forms the menu at the top of the casebook index page. Example:
print "Here is the HTML that makes up the casebook index menu:\n\n"; print $GAMS->CasebookIndexMenuHTML;
Prints a user's Casebook Page. Example:
$GAMS->WriteCasebook;
Sample HTML form that could be used with the WriteCasebookIndex method:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post"> <INPUT TYPE="hidden" NAME="Task" VALUE="WriteCasebook"> <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="hidden" NAME="Model" VALUE="Ramsey"> <INPUT TYPE="hidden" NAME="Casebook" VALUE="STUDY1"> <INPUT TYPE="submit" VALUE="Go to Grog's Ramsey casebook STUDY1"> </FORM>
$GAMS->WriteCasebookHTML;
Prints either the model documentation or the GAMS-CGI help file. Example:
$GAMS->CopyHTML;
Sample HTML forms that could be used with the CopyHTML method:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post" > <INPUT TYPE="hidden" NAME="Task" VALUE="CopyHTML"> <INPUT TYPE="hidden" NAME="FileType" VALUE="Model"> <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="hidden" NAME="Model" VALUE="Ramsey"> <INPUT TYPE="submit" VALUE="View documentation for model Ramsey"> </FORM>
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post" > <INPUT TYPE="hidden" NAME="Task" VALUE="CopyHTML"> <INPUT TYPE="hidden" NAME="FileType" VALUE="Help"> <INPUT TYPE="submit" VALUE="Help"> </FORM>
Prints either a listing file or model source code. Example:
$GAMS->CopyText;
Sample HTML forms that could be used with the CopyText method:
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post" > <INPUT TYPE="hidden" NAME="Task" VALUE="CopyText"> <INPUT TYPE="hidden" NAME="FileType" VALUE="Model"> <INPUT TYPE="hidden" NAME="Model" VALUE="Ramsey"> <INPUT TYPE="submit" VALUE="View GAMS source code"> </FORM>
<FORM ACTION="/cgi/gams-cgi.pl" METHOD="post"> <INPUT TYPE="hidden" NAME="Task" VALUE="CopyText"> <INPUT TYPE="hidden" NAME="FileType" VALUE="Listing"> <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="hidden" NAME="Model" VALUE="Ramsey"> <INPUT TYPE="hidden" NAME="Casebook" VALUE="STUDY1"> <INPUT TYPE="hidden" NAME="Case" VALUE="HIGHB"> <INPUT TYPE="submit" VALUE="HIGHB"> </FORM>
Creates a new case and, if it has not previously been solved, submits it to GAMS. It looks for CGI parameters that match the model inputs, builds an inputs hash, then submits the new case with the GAMS NewCase method. Example:
$GAMS->AddCase; $GAMS->WriteCasebook;
Sample HTML form that could be used with the AddCase method:
<FORM NAME="Create" ACTION="/cgi/gams-cgi.pl" ONSUBMIT="return checkCreate()" METHOD="post"> <INPUT TYPE="hidden" NAME="Task" VALUE="AddCase"> <INPUT TYPE="hidden" NAME="User" VALUE="Grog"> <INPUT TYPE="hidden" NAME="Model" VALUE="Ramsey"> <INPUT TYPE="hidden" NAME="Casebook" VALUE="STUDY1"> <P>Discount factor <SELECT NAME="BET" SIZE="1"> <OPTION SELECTED>0.95</OPTION> <OPTION>0.90</OPTION> <OPTION>0.925</OPTION> <OPTION>0.975</OPTION> </SELECT> <P>Capital value share <SELECT NAME="B" SIZE="1"> <OPTION SELECTED>0.25</OPTION> <OPTION>0.20</OPTION> <OPTION>0.30</OPTION> <OPTION>0.40</OPTION> <OPTION>0.50</OPTION> </SELECT> <INPUT TYPE="submit" VALUE="Create a New Case"> </FORM>
Returns a java script used to check user entry when a casebook is created.
$GAMS->CreateCasebookJava;
Returns the HTML for a button/dropdown list pair that can be used to import a case into the current casebook.
$GAMS->ImportHTML;
Returns a java script used to check user entry when using the ImportHTML case import.
$GAMS->ImportJava;
Returns the HTML for a button that takes a user to the GAMS-X help files.
$GAMS->HelpButton;
Returns the HTML for a button that takes a user to the GAMS documentation for the current model.
$GAMS->ViewDocumentationButton;
Returns a button that can be used to remove the current user's account.
$GAMS->RemoveAccountButton;
Returns the HTML for a button that presents a user with the GAMS code for the current model.
$GAMS->ViewGAMSCodeButton;
Returns the HTML for a button that gives the current user the casebook index for the current model.
$GAMS->CasebookIndexButton;
Returns the HTML for a button that gives the current user the current casebook for the current model.
$GAMS->WriteCasebookButton;
Returns the HTML for a button that gives the current user the listing for the specified case in the current casebook for the current model.
$GAMS->CaseListingButton( 'HIGHB' );
Returns the HTML for a button that gives the current user the model index.
$GAMS->ModelIndexButton;
Returns the menu of buttons that appears at the top of the Casebook Index page for the current user, casebook, and model.
$GAMS->CasebookIndexMenuHTML;
Returns the menu of buttons that appears at the top of the Casebook page for the current user, casebook, and model.
$GAMS->CasebookMenuHTML;
Returns HTML that can be used to revise the description of the current user's current casebook in the current model.
$GAMS->ReviseDescriptionHTML;
Returns the Java error-checking script used in conjunction with the ReviseDescriptionHTML.
$GAMS->ReviseDescriptionJava;
Returns the Java error-checking script used in conjunction with case creation.
$GAMS->CreateCaseJava;
$GAMS->ReturnButton;
Presents the user with a confirmation consisting of the passed string.
$GAMS->Confirm;
$GAMS->EditProfile;
Returns the HTML that makes up the model library; i.e., the listing of models that appears at the bottom of the GAMS-CGI greeting page. Example:
$GAMS->modelibraryHTML;
Returns the GAMS-CGI greeting page from which users may log in, create an account, or edit their current account information.
$GAMS->Greeting;
Returns the Java error-checking script used in conjunction with the GAMS-CGI greeting page. Example:
$GAMS->GreetingJava;
Returns the HTML that makes up the GAMS-CGI greeting page. Example:
$GAMS->GreetingHTML;
Returns the HTML used in the BODY markup associated with GAMS-CGI pages. Example:
print "This is the old body HTML: ", $GAMS->BodyHTML, "\n"; # Scary colors! $GAMS->Set( -BodyHTML => "<BODY BGCOLOR='#000000'>\n" ); # Now all of my GAMS-CGI pages will have the background color 000000!
Returns the HTML used to present the GAMS-CGI logo at the head of the GAMS-CGI greeting page. Example:
$GAMS->LogoHTML;
Returns the HTML for the message at the top of the GAMS-CGI Model Index page. Example:
$GAMS->Set(
-ModelIndexGreeting =>
"<CENTER>Look Ma! A New Model Index Greeting!</CENTER>"
);
Returns the HTML for the message at the top of the GAMS-CGI Casebook Index page. Example:
$GAMS->Set(
-CasebookIndexGreeting =>
"<CENTER>Look Ma! A New Casebook Index Greeting!</CENTER>"
);
Returns the HTML for the message at the top of the GAMS-CGI Casebook page. Example:
print "The old casebook greeting was \n\n", $GAMS->CasebookGreeting, "\n\n";
$User = $GAMS->User;
$GAMS->Set(
-CasebookGreeting =>
"<CENTER>Look $User! A New Casebook Greeting!</CENTER>"
);
Returns the HTML used to identify the webmaster at the bottom of GAMS-CGI pages. Example:
print "The old webmaster HTML is \n\n", $GAMS->WebmasterHTML, "\n\n"; # Now nobody will know who the webmaster is! $GAMS->Set( -WebmasterHTML => '' );
The following documentation is taken from the Perl CGI Pod (Plain Old Documentation) and is current as of 1/99. For the most recent documentation of the Perl CGI module, please refer to the documentation included with your installation of Perl. Translating from basic Perl CGI scripting to GAMS-CGI scripting is extremely simple and straightforward. One need only recognize that the CGI object is inherited by GAMS-CGI through the CGI key; thus, the equivalent GAMS-CGI formulation of the CGI script
use CGI; # load CGI routines
$q = new CGI; # create new CGI object
print $q->header, # create the HTTP header
$q->start_html('hello world'), # start the HTML
$q->h1('hello world'), # level 1 header
$q->end_html; # end the HTML
would be
use GAMS::CGI; # load CGI routines
$q = new GAMS::CGI; # create new CGI object
print $q->{CGI}->header, # create the HTTP header
$q->{CGI}->start_html('hello world'), # start the HTML
$q->{CGI}->h1('hello world'), # level 1 header
$q->{CGI}->end_html; # end the HTML
Note that in the above example, the object-oriented programming style mentioned in the following documentation is used. The function-oriented programming style is not supported by GAMS-CGI.
Many thanks to Lincoln Stein, who is responsible for the authorship and maintenance of the Perl CGI module.
# CGI script that creates a fill-out form # and echoes back its values.
use CGI qw/:standard/;
print header,
start_html('A Simple Example'),
h1('A Simple Example'),
start_form,
"What's your name? ",textfield('name'),p,
"What's the combination?", p,
checkbox_group(-name=>'words',
-values=>['eenie','meenie','minie','moe'],
-defaults=>['eenie','minie']), p,
"What's your favorite color? ",
popup_menu(-name=>'color',
-values=>['red','green','blue','chartreuse']),p,
submit,
end_form,
hr;
if (param()) {
print "Your name is",em(param('name')),p,
"The keywords are: ",em(join(", ",param('words'))),p,
"Your favorite color is ",em(param('color')),
hr;
}
This perl library uses perl5 objects to make it easy to create Web fill-out forms and parse their contents. This package defines CGI objects, entities that contain the values of the current query string and other state variables. Using a CGI object's methods, you can examine keywords and parameters passed to your script, and create forms whose initial values are taken from the current query (thereby preserving state information). The module provides shortcut functions that produce boilerplate HTML, reducing typing and coding errors. It also provides functionality for some of the more advanced features of CGI scripting, including support for file uploads, cookies, cascading style sheets, server push, and frames.
CGI.pm also provides a simple function-oriented programming style for those who don't need its object-oriented features.
The current version of CGI.pm is available at
http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html ftp://ftp-genome.wi.mit.edu/pub/software/WWW/
There are two styles of programming with CGI.pm, an object-oriented style and a function-oriented style. In the object-oriented style you create one or more CGI objects and then use object methods to create the various elements of the page. Each CGI object starts out with the list of named parameters that were passed to your CGI script by the server. You can modify the objects, save them to a file or database and recreate them. Because each object corresponds to the ßtate" of the CGI script, and because each object's parameter list is independent of the others, this allows you to save the state of the script and restore it later.
For example, using the object oriented style, here is now you create a simple "Hello World" HTML page:
#!/usr/local/bin/perl
use CGI; # load CGI routines
$q = new CGI; # create new CGI object
print $q->header, # create the HTTP header
$q->start_html('hello world'), # start the HTML
$q->h1('hello world'), # level 1 header
$q->end_html; # end the HTML
In the function-oriented style, there is one default CGI object that you rarely deal with directly. Instead you just call functions to retrieve CGI parameters, create HTML tags, manage cookies, and so on. This provides you with a cleaner programming interface, but limits you to using one CGI object at a time. The following example prints the same page, but uses the function-oriented interface. The main differences are that we now need to import a set of functions into our name space (usually the ßtandard" functions), and we don't need to create the CGI object.
#!/usr/local/bin/pelr
use CGI qw/:standard/; # load standard CGI routines
print header, # create the HTTP header
start_html('hello world'), # start the HTML
h1('hello world'), # level 1 header
end_html; # end the HTML
The examples in this document mainly use the object-oriented style. See HOW TO IMPORT FUNCTIONS for important information on function-oriented programming in CGI.pm
Most CGI.pm routines accept several arguments, sometimes as many as 20 optional ones! To simplify this interface, all routines use a named argument calling style that looks like this:
print $q->header(-type=>'image/gif',-expires=>'+3d');
Each argument name is preceded by a dash. Neither case nor order matters in the argument list. -type, -Type, and -TYPE are all acceptable. In fact, only the first argument needs to begin with a dash. If a dash is present in the first argument, CGI.pm assumes dashes for the subsequent ones.
You don't have to use the hyphen at allif you don't want to. After creating a CGI object, call the use_ named_ parameters() method with a nonzero value. This will tell CGI.pm that you intend to use named parameters exclusively:
$query = new CGI;
$query->use_named_parameters(1);
$field = $query->radio_group('name'=>'OS',
'values'=>['Unix','Windows','Macintosh'],
'default'=>'Unix');
Several routines are commonly called with just one argument. In the case of these routines you can provide the single argument without an argument name. header() happens to be one of these routines. In this case, the single argument is the document type.
print $q->header('text/html');
Other such routines are documented below.
Sometimes named arguments expect a scalar, sometimes a reference to an array, and sometimes a reference to a hash. Often, you can pass any type of argument and the routine will do whatever is most appropriate. For example, the param() routine is used to set a CGI parameter to a single or a multi-valued value. The two cases are shown below:
$q->param(-name=>'veggie',-value=>'tomato'); $q->param(-name=>'veggie',-value=>'[tomato','tomahto','potato','potahto']);
A large number of routines in CGI.pm actually aren't specifically defined in the module, but are generated automatically as needed. These are the "HTML shortcuts," routines that generate HTML tags for use in dynamically-generated pages. HTML tags have both attributes (the attribute="value" pairs within the tag itself) and contents (the part between the opening and closing pairs.) To distinguish between attributes and contents, CGI.pm uses the convention of passing HTML attributes as a hash reference as the first argument, and the contents, if any, as any subsequent arguments. It works out like this:
Code Generated HTML
---- --------------
h1() <H1>
h1('some','contents'); <H1>some contents</H1>
h1({-align=>left}); <H1 ALIGN="LEFT">
h1({-align=>left},'contents'); <H1 ALIGN="LEFT">contents</H1>
HTML tags are described in more detail later.
Many newcomers to CGI.pm are puzzled by the difference between the calling conventions for the HTML shortcuts, which require curly braces around the HTML tag attributes, and the calling conventions for other routines, which manage to generate attributes without the curly brackets. Don't be confused. As a convenience the curly braces are optional in all but the HTML shortcuts. If you like, you can use curly braces when calling any routine that takes named arguments. For example:
print $q->header( {-type=>'image/gif',-expires=>'+3d'} );
If you use the -w switch, you will be warned that some CGI.pm argument names conflict with built-in Perl functions. The most frequent of these is the -values argument, used to create multi-valued menus, radio button clusters and the like. To get around this warning, you have several choices:
print $q->header(-type => 'text/html',
-cost => 'Three smackers',
-annoyance_level => 'high',
-complaints_to => 'bit bucket');
This will produce the following nonstandard HTTP header:
HTTP/1.0 200 OK Cost: Three smackers Annoyance-level: high Complaints-to: bit bucket Content-type: text/html
Notice the way that underscores are translated automatically into hyphens. HTML-generating routines perform a different type of translation.
This feature allows you to keep up with the rapidly changing HTTP and HTML ßtandards".
$query = new CGI;
This will parse the input (from both POST and GET methods) and store it into a perl5 object called $query.
$query = new CGI(INPUTFILE);
If you provide a file handle to the new() method, it will read parameters from the file (or STDIN, or whatever). The file can be in any of the forms describing below under debugging (i.e. a series of newline delimited TAG=VALUE pairs will work). Conveniently, this type of file is created by the save() method (see below). Multiple records can be saved and restored.
Perl purists will be pleased to know that this syntax accepts references to file handles, or even references to filehandle globs, which is the öfficial" way to pass a filehandle:
$query = new CGI(\*STDIN);
You can also initialize the CGI object with a FileHandle or IO::File object.
If you are using the function-oriented interface and want to initialize CGI state from a file handle, the way to do this is with restore_ parameters(). This will (re)initialize the default CGI object from the indicated file handle.
open (IN,"test.in") || die;
restore_parameters(IN);
close IN;
You can also initialize the query object from an associative array reference:
$query = new CGI( {'dinosaur'=>'barney',
'song'=>'I love you',
'friends'=>[qw/Jessica George Nancy/]}
);
or from a properly formatted, URL-escaped query string:
$query = new CGI('dinosaur=barney&color=purple');
or from a previously existing CGI object (currently this clones the parameter list, but none of the other object-specific fields, such as autoescaping):
$old_query = new CGI;
$new_query = new CGI($old_query);
To create an empty query, initialize it from an empty string or hash:
$empty_query = new CGI("");
-or-
$empty_query = new CGI({});
@keywords = $query->keywords
If the script was invoked as the result of an < ISINDEX > search, the parsed keywords can be obtained as an array using the keywords() method.
@names = $query->param
If the script was invoked with a parameter list (e.g. "name1=value1&name2=value2&name3=value3"), the param() method will return the parameter names as a list. If the script was invoked as an < ISINDEX > script, there will be a single parameter named 'keywords'.
NOTE: As of version 1.5, the array of parameter names returned will be in the same order as they were submitted by the browser. Usually this order is the same as the order in which the parameters are defined in the form (however, this isn't part of the spec, and so isn't guaranteed).
@values = $query->param('foo');
-or-
$value = $query->param('foo');
Pass the param() method a single argument to fetch the value of the named parameter. If the parameter is multivalued (e.g. from multiple selections in a scrolling list), you can ask to receive an array. Otherwise the method will return a single value.
$query->param('foo','an','array','of','values');
This sets the value for the named parameter 'foo' to an array of values. This is one way to change the value of a field AFTER the script has been invoked once before. (Another way is with the -override parameter accepted by all methods that generate form elements.)
param() also recognizes a named parameter style of calling described in more detail later:
$query->param(-name=>'foo',-values=>['an','array','of','values']);
-or-
$query->param(-name=>'foo',-value=>'the value');
$query->append(-name=>'foo',-values=>['yet','more','values']);
This adds a value or list of values to the named parameter. The values are appended to the end of the parameter if it already exists. Otherwise the parameter is created. Note that this method only recognizes the named argument calling syntax.
$query->import_names('R');
This creates a series of variables in the 'R' namespace. For example, $R::foo, @R:foo. For keyword lists, a variable @R::keywords will appear. If no namespace is given, this method will assume 'Q'. WARNING: don't import anything into 'main'; this is a major security risk!!!!
In older versions, this method was called import(). As of version 2.20, this name has been removed completely to avoid conflict with the built-in Perl module import operator.
$query->delete('foo');
This completely clears a parameter. It sometimes useful for resetting parameters that you don't want passed down between script invocations.
If you are using the function call interface, use "Delete() " instead to avoid conflicts with Perl's built-in delete operator.
$query->delete_all();
This clears the CGI object completely. It might be useful to ensure that all the defaults are taken when you create a fill-out form.
Use Delete_ all() instead if you are using the function call interface.
$q->param_fetch('address')->[1] = '1313 Mockingbird Lane';
unshift @{$q->param_fetch(-name=>'address')},'George Munster';
If you need access to the parameter list in a way that isn't covered by the methods above, you can obtain a direct reference to it by calling the param_ fetch() method with the name of the . This will return an array reference to the named parameters, which you then can manipulate in any way you like.
You can also use a named argument style using the -name argument.
$query->save(FILEHANDLE)
This will write the current state of the form to the provided filehandle. You can read it back in by providing a filehandle to the new() method. Note that the filehandle can be a file, a pipe, or whatever!
The format of the saved file is:
NAME1=VALUE1
NAME1=VALUE1'
NAME2=VALUE2
NAME3=VALUE3
=
Both name and value are URL escaped. Multi-valued CGI parameters are represented as repeated names. A session record is delimited by a single = symbol. You can write out multiple records and read them back in with several calls to new. You can do this across several sessions by opening the file in append mode, allowing you to create primitive guest books, or to keep a history of users' queries. Here's a short example of creating multiple session records:
use CGI;
open (OUT,">>test.out") || die;
$records = 5;
foreach (0..$records) {
my $q = new CGI;
$q->param(-name=>'counter',-value=>$_);
$q->save(OUT);
}
close OUT;
# reopen for reading
open (IN,"test.out") || die;
while (!eof(IN)) {
my $q = new CGI(IN);
print $q->param('counter'),"\n";
}
The file format used for save/restore is identical to that used by the Whitehead Genome Center's data exchange format "Boulderio", and can be manipulated and even databased using Boulderio utilities. See
http://www.genome.wi.mit.edu/genome_ software/other/boulder.html
for further details.
If you wish to use this method from the function-oriented (non-OO) interface, the exported name for this method is save_ parameters().
To use the function-oriented interface, you must specify which CGI.pm routines or sets of routines to import into your script's namespace. There is a small overhead associated with this importation, but it isn't much.
use CGI <list of methods>;
The listed methods will be imported into the current package; you can call them directly without creating a CGI object first. This example shows how to import the param() and header() methods, and then use them directly:
use CGI 'param','header';
print header('text/plain');
$zipcode = param('zipcode');
More frequently, you'll import common sets of functions by referring to the gropus by name. All function sets are preceded with a ":" character as in ":html3" (for tags defined in the HTML 3 standard).
Here is a list of the function sets you can import:
Import all CGI-handling methods, such as param(), path_ info() and the like.
Import all fill-out form generating methods, such as textfield().
Import all methods that generate HTML 2.0 standard elements.
Import all methods that generate HTML 3.0 proposed elements (such as < table > , < super > and < sub > ).
Import all methods that generate Netscape-specific HTML extensions.
Import all HTML-generating shortcuts (i.e. 'html2' + 'html3' + 'netscape')...
Import ßtandard" features, 'html2', 'html3', 'form' and 'cgi'.
Import all the available methods. For the full list, see the CGI.pm code, where the variable %TAGS is defined.
use CGI qw/:standard :html3 gradient/;
print gradient({-start=>'red',-end=>'blue'});
Note that in the interests of execution speed CGI.pm does not use the standard the Exporter manpage syntax for specifying load symbols. This may change in the future.
If you import any of the state-maintaining CGI or form-generating methods, a default CGI object will be created and initialized automatically the first time you use any of the methods that require one to be present. This includes param(), textfield(), submit() and the like. (If you need direct access to the CGI object, you can find it in the global variable $CGI::Q). By importing CGI.pm methods, you can create visually elegant scripts:
use CGI qw/:standard/;
print
header,
start_html('Simple Script'),
h1('Simple Script'),
start_form,
"What's your name? ",textfield('name'),p,
"What's the combination?",
checkbox_group(-name=>'words',
-values=>['eenie','meenie','minie','moe'],
-defaults=>['eenie','moe']),p,
"What's your favorite color?",
popup_menu(-name=>'color',
-values=>['red','green','blue','chartreuse']),p,
submit,
end_form,
hr,"\n";
if (param) {
print
"Your name is ",em(param('name')),p,
"The keywords are: ",em(join(", ",param('words'))),p,
"Your favorite color is ",em(param('color')),".\n";
}
print end_html;
In addition to the function sets, there are a number of pragmas that you can import. Pragmas, which are always preceded by a hyphen, change the way that CGI.pm functions in various ways. Pragmas, function sets, and individual functions can all be imported in the same use() line. For example, the following use statement imports the standard set of functions and disables debugging mode (pragma -no_ debug):
use CGI qw/:standard -no_debug/;
The current list of pragmas is as follows:
When you use CGI -any , then any method that the query object doesn't recognize will be interpreted as a new HTML tag. This allows you to support the next ad hoc Netscape or Microsoft HTML extension. This lets you go wild with new and unsupported tags:
use CGI qw(-any);
$q=new CGI;
print $q->gradient({speed=>'fast',start=>'red',end=>'blue'});
Since using < cite > any < /cite > causes any mistyped method name to be interpreted as an HTML tag, use it with care or not at all.
This causes the indicated autoloaded methods to be compiled up front, rather than deferred to later. This is useful for scripts that run for an extended period of time under FastCGI or mod_ perl, and for those destined to be crunched by Malcom Beattie's Perl compiler. Use it in conjunction with the methods or method familes you plan to use.
use CGI qw(-compile :standard :html3);
or even
use CGI qw(-compile :all);
Note that using the -compile pragma in this way will always have the effect of importing the compiled functions into the current namespace. If you want to compile without importing use the compile() method instead (see below).
This makes CGI.pm produce a header appropriate for an NPH (no parsed header) script. You may need to do other things as well to tell the server that the script is NPH. See the discussion of NPH scripts below.
This overrides the autoloader so that any function in your program that is not recognized is referred to CGI.pm for possible evaluation. This allows you to use all the CGI.pm functions without adding them to your symbol table, which is of concern for mod_ perl users who are worried about memory consumption. Warning: when -autoload is in effect, you cannot use "poetry mode" (functions without the parenthesis). Use hr() rather than hr , or add something like use subs qw/hr p header/ to the top of your script.
This turns off the command-line processing features. If you want to run a CGI.pm script from the command line to produce HTML, and you don't want it pausing to request CGI parameters from standard input or the command line, then use this pragma:
use CGI qw(-no_debug :standard);
If you'd like to process the command-line parameters but not standard input, this should work:
use CGI qw(-no_debug :standard);
restore_parameters(join('&',@ARGV));
See the section on debugging for more details.
CGI.pm can process uploaded file. Ordinarily it spools the uploaded file to a temporary directory, then deletes the file when done. However, this opens the risk of eavesdropping as described in the file upload section. Another CGI script author could peek at this data during the upload, even if it is confidential information. On Unix systems, the -private_ tempfiles pragma will cause the temporary file to be unlinked as soon as it is opened and before any data is written into it, eliminating the risk of eavesdropping. n =back
Most of CGI.pm's functions deal with creating documents on the fly. Generally you will produce the HTTP header first, followed by the document itself. CGI.pm provides functions for generating HTTP headers of various types as well as for generating HTML. For creating GIF images, see the GD.pm module.
Each of these functions produces a fragment of HTML or HTTP which you can print out directly so that it displays in the browser window, append to a string, or save to a file for later use.
Normally the first thing you will do in any CGI script is print out an HTTP header. This tells the browser what type of document to expect, and gives other optional information, such as the language, expiration date, and whether to cache the document. The header can also be manipulated for special purposes, such as server push and pay per view pages.
print $query->header;
-or-
print $query->header('image/gif');
-or-
print $query->header('text/html','204 No response');
-or-
print $query->header(-type=>'image/gif',
-nph=>1,
-status=>'402 Payment required',
-expires=>'+3d',
-cookie=>$cookie,
-Cost=>'$2.00');
header() returns the Content-type: header. You can provide your own MIME type if you choose, otherwise it defaults to text/html. An optional second parameter specifies the status code and a human-readable message. For example, you can specify 204, "No response" to create a script that tells the browser to do nothing at all.
The last example shows the named argument style for passing arguments to the CGI methods using named parameters. Recognized parameters are -type, -status, -expires, and -cookie. Any other named parameters will be stripped of their initial hyphens and turned into header fields, allowing you to specify any HTTP header you desire. Internal underscores will be turned into hyphens:
print $query->header(-Content_length=>3002);
Most browsers will not cache the output from CGI scripts. Every time the browser reloads the page, the script is invoked anew. You can change this behavior with the -expires parameter. When you specify an absolute or relative expiration interval with this parameter, some browsers and proxy servers will cache the script's output until the indicated expiration date. The following forms are all valid for the -expires field:
+30s 30 seconds from now
+10m ten minutes from now
+1h one hour from now
-1d yesterday (i.e. "ASAP!")
now immediately
+3M in three months
+10y in ten years time
Thursday, 25-Apr-1999 00:40:33 GMT at the indicated time & date
The -cookie parameter generates a header that tells the browser to provide a "magic cookie" during all subsequent transactions with your script. Netscape cookies have a special format that includes interesting attributes such as expiration time. Use the cookie() method to create and retrieve session cookies.
The -nph parameter, if set to a true value, will issue the correct headers to work with a NPH (no-parse-header) script. This is important to use with certain servers, such as Microsoft Internet Explorer, which expect all their scripts to be NPH.
print $query->redirect('http://somewhere.else/in/movie/land');
Sometimes you don't want to produce a document yourself, but simply redirect the browser elsewhere, perhaps choosing a URL based on the time of day or the identity of the user.
The redirect() function redirects the browser to a different URL. If you use redirection like this, you should not print out a header as well. As of version 2.0, we produce both the unofficial Location: header and the official URI: header. This should satisfy most servers and browsers.
One hint I can offer is that relative links may not work correctly when you generate a redirection to another document on your site. This is due to a well-intentioned optimization that some servers use. The solution to this is to use the full URL (including the http: part) of the document you are redirecting to.
You can also use named arguments:
print $query->redirect(-uri=>'http://somewhere.else/in/movie/land',
-nph=>1);
The -nph parameter, if set to a true value, will issue the correct headers to work with a NPH (no-parse-header) script. This is important to use with certain servers, such as Microsoft Internet Explorer, which expect all their scripts to be NPH.
print $query->start_html(-title=>'Secrets of the Pyramids',
-author=>'fred@capricorn.org',
-base=>'true',
-target=>'_blank',
-meta=>{'keywords'=>'pharaoh secret mummy',
'copyright'=>'copyright 1996 King Tut'},
-style=>{'src'=>'/styles/style1.css'},
-BGCOLOR=>'blue');
After creating the HTTP header, most CGI scripts will start writing out an HTML document. The start_ html() routine creates the top of the page, along with a lot of optional information that controls the page's appearance and behavior.
This method returns a canned HTML header and the opening < BODY > tag. All parameters are optional. In the named parameter form, recognized parameters are -title, -author, -base, -xbase and -target (see below for the explanation). Any additional parameters you provide, such as the Netscape unofficial BGCOLOR attribute, are added to the < BODY > tag. Additional parameters must be proceeded by a hyphen.
The argument -xbase allows you to provide an HREF for the < BASE > tag different from the current location, as in
-xbase=>"http://home.mcom.com/"
All relative links will be interpreted relative to this tag.
The argument -target allows you to provide a default target frame for all the links and fill-out forms on the page. See the Netscape documentation on frames for details of how to manipulate this.
-target=>"answer_window"
All relative links will be interpreted relative to this tag. You add arbitrary meta information to the header with the -meta argument. This argument expects a reference to an associative array containing name/value pairs of meta information. These will be turned into a series of header < META > tags that look something like this:
<META NAME="keywords" CONTENT="pharaoh secret mummy">
<META NAME="description" CONTENT="copyright 1996 King Tut">
There is no support for the HTTP-EQUIV type of < META > tag. This is because you can modify the HTTP header directly with the header() method. For example, if you want to send the Refresh: header, do it in the header() method:
print $q->header(-Refresh=>'10; URL=http://www.capricorn.com');
The -style tag is used to incorporate cascading stylesheets into your code. See the section on CASCADING STYLESHEETS for more information.
You can place other arbitrary HTML elements to the < HEAD > section with the -head tag. For example, to place the rarely-used < LINK > element in the head section, use this:
print $q->start_html(-head=>Link({-rel=>'next',
-href=>'http://www.capricorn.com/s2.html'}));
To incorporate multiple HTML elements into the < HEAD > section, just pass an array reference:
print $q->start_html(-head=>[
Link({-rel=>'next',
-href=>'http://www.capricorn.com/s2.html'}),
Link({-rel=>'previous',
-href=>'http://www.capricorn.com/s1.html'})
]
);
JAVASCRIPTING: The -script, -noScript, -onLoad, -onMouseOver, -onMouseOut and -onUnload parameters are used to add Netscape JavaScript calls to your pages. -script should point to a block of text containing JavaScript function definitions. This block will be placed within a < SCRIPT > block inside the HTML (not HTTP) header. The block is placed in the header in order to give your page a fighting chance of having all its JavaScript functions in place even if the user presses the stop button before the page has loaded completely. CGI.pm attempts to format the script in such a way that JavaScript-naive browsers will not choke on the code: unfortunately there are some browsers, such as Chimera for Unix, that get confused by it nevertheless.
The -onLoad and -onUnload parameters point to fragments of JavaScript code to execute when the page is respectively opened and closed by the browser. Usually these parameters are calls to functions defined in the -script field:
$query = new CGI;
print $query->header;
$JSCRIPT=<<END;
// Ask a silly question
function riddle_me_this() {
var r = prompt("What walks on four legs in the morning, " +
"two legs in the afternoon, " +
"and three legs in the evening?");
response(r);
}
// Get a silly answer
function response(answer) {
if (answer == "man")
alert("Right you are!");
else
alert("Wrong! Guess again.");
}
END
print $query->start_html(-title=>'The Riddle of the Sphinx',
-script=>$JSCRIPT);
Use the -noScript parameter to pass some HTML text that will be displayed on browsers that do not have JavaScript (or browsers where JavaScript is turned off).
Netscape 3.0 recognizes several attributes of the < SCRIPT > tag, including LANGUAGE and SRC. The latter is particularly interesting, as it allows you to keep the JavaScript code in a file or CGI script rather than cluttering up each page with the source. To use these attributes pass a HASH reference in the -script parameter containing one or more of -language, -src, or -code:
print $q->start_html(-title=>'The Riddle of the Sphinx',
-script=>{-language=>'JAVASCRIPT',
-src=>'/javascript/sphinx.js'}
);
print $q->(-title=>'The Riddle of the Sphinx',
-script=>{-language=>'PERLSCRIPT'},
-code=>'print "hello world!\n;"'
);
A final feature allows you to incorporate multiple < SCRIPT > sections into the header. Just pass the list of script sections as an array reference. this allows you to specify different source files for different dialects of JavaScript. Example:
print $q->start_html(-title=>'The Riddle of the Sphinx',
-script=>[
{ -language => 'JavaScript1.0',
-src => '/javascript/utilities10.js'
},
{ -language => 'JavaScript1.1',
-src => '/javascript/utilities11.js'
},
{ -language => 'JavaScript1.2',
-src => '/javascript/utilities12.js'
},
{ -language => 'JavaScript28.2',
-src => '/javascript/utilities219.js'
}
]
);
</pre>
If this looks a bit extreme, take my advice and stick with straight CGI scripting.
See
http://home.netscape.com/eng/mozilla/2.0/handbook/javascript/
for more information about JavaScript.
The old-style positional parameters are as follows:
print $query->end_html
This ends an HTML document by printing the < /BODY > < /HTML > tags.
$myself = $query->self_url;
print "<A HREF=$myself>I'm talking to myself.</A>";
self_ url() will return a URL, that, when selected, will reinvoke this script with all its state information intact. This is most useful when you want to jump around within the document using internal anchors but you don't want to disrupt the current contents of the form (s). Something like this will do the trick.
$myself = $query->self_url;
print "<A HREF=$myself#table1>See table 1</A>";
print "<A HREF=$myself#table2>See table 2</A>";
print "<A HREF=$myself#yourself>See for yourself</A>";
If you want more control over what's returned, using the url() method instead.
You can also retrieve the unprocessed query string with query_ string() :
$the_string = $query->query_string;
$full_url = $query->url();
$full_url = $query->url(-full=>1); #alternative syntax
$relative_url = $query->url(-relative=>1);
$absolute_url = $query->url(-absolute=>1);
$url_with_path = $query->url(-path_info=>1);
$url_with_path_and_query = $query->url(-path_info=>1,-query=>1);
url() returns the script's URL in a variety of formats. Called without any arguments, it returns the full form of the URL, including host name and port number
http://your.host.com/path/to/script.cgi
You can modify this format with the following named arguments:
If true, produce an absolute URL, e.g.
/path/to/script.cgi
Produce a relative URL. This is useful if you want to reinvoke your script with different parameters. For example:
script.cgi
Produce the full URL, exactly as if called without any arguments. This overrides the -relative and -absolute arguments.
Append the additional path information to the URL. This can be combined with -full, -absolute or -relative. -path_ info is provided as a synonym.
Append the query string to the URL. This can be combined with -full, -absolute or -relative. -query_ string is provided as a synonym.
CGI.pm defines general HTML shortcut methods for most, if not all of the HTML 3 and HTML 4 tags. HTML shortcuts are named after a single HTML element and return a fragment of HTML text that you can then print or manipulate as you like. Each shortcut returns a fragment of HTML code that you can append to a string, save to a file, or, most commonly, print out so that it displays in the browser window.
This example shows how to use the HTML methods:
$q = new CGI;
print $q->blockquote(
"Many years ago on the island of",
$q->a({href=>"http://crete.org/"},"Crete"),
"there lived a minotaur named",
$q->strong("Fred."),
),
$q->hr;
This results in the following HTML code (extra newlines have been added for readability):
<blockquote> Many years ago on the island of <a HREF="http://crete.org/">Crete</a> there lived a minotaur named <strong>Fred.</strong> </blockquote> <hr>
If you find the syntax for calling the HTML shortcuts awkward, you can import them into your namespace and dispense with the object syntax completely (see the next section for more details):
use CGI ':standard';
print blockquote(
"Many years ago on the island of",
a({href=>"http://crete.org/"},"Crete"),
"there lived a minotaur named",
strong("Fred."),
),
hr;
The HTML methods will accept zero, one or multiple arguments. If you provide no arguments, you get a single tag:
print hr; # <HR>
If you provide one or more string arguments, they are concatenated together with spaces and placed between opening and closing tags:
print h1("Chapter","1"); # <H1>Chapter 1</H1>"
If the first argument is an associative array reference, then the keys and values of the associative array become the HTML tag's attributes:
print a({-href=>'fred.html',-target=>'_new'},
"Open a new frame");
<A HREF="fred.html",TARGET="_new">Open a new frame</A>
You may dispense with the dashes in front of the attribute names if
you prefer:
print img {src=>'fred.gif',align=>'LEFT'};
<IMG ALIGN="LEFT" SRC="fred.gif">
Sometimes an HTML tag attribute has no argument. For example, ordered lists can be marked as COMPACT. The syntax for this is an argument that that points to an undef string:
print ol({compact=>undef},li('one'),li('two'),li('three'));
Prior to CGI.pm version 2.41, providing an empty ('') string as an attribute argument was the same as providing undef. However, this has changed in order to accomodate those who want to create tags of the form < IMG ALT="" > . The difference is shown in these two pieces of code:
CODE RESULT img ({alt= > undef}) < IMG ALT > img ({alt= > ''}) < IMT ALT="" >
One of the cool features of the HTML shortcuts is that they are distributive. If you give them an argument consisting of a reference to a list, the tag will be distributed across each element of the list. For example, here's one way to make an ordered list:
print ul(
li({-type=>'disc'},['Sneezy','Doc','Sleepy','Happy']);
);
This example will result in HTML output that looks like this:
<UL>
<LI TYPE="disc">Sneezy</LI>
<LI TYPE="disc">Doc</LI>
<LI TYPE="disc">Sleepy</LI>
<LI TYPE="disc">Happy</LI>
</UL>
This is extremely useful for creating tables. For example:
print table({-border=>undef},
caption('When Should You Eat Your Vegetables?'),
Tr({-align=>CENTER,-valign=>TOP},
[
th(['Vegetable', 'Breakfast','Lunch','Dinner']),
td(['Tomatoes' , 'no', 'yes', 'yes']),
td(['Broccoli' , 'no', 'no', 'yes']),
td(['Onions' , 'yes','yes', 'yes'])
]
)
);
Consider this bit of code:
print blockquote(em('Hi'),'mom!'));
It will ordinarily return the string that you probably expect, namely:
<BLOCKQUOTE><EM>Hi</EM> mom!</BLOCKQUOTE>
Note the space between the element "Hi" and the element "mom!". CGI.pm puts the extra space there using array interpolation, which is controlled by the magic $" variable. Sometimes this extra space is not what you want, for example, when you are trying to align a series of images. In this case, you can simply change the value of $" to an empty string.
{
local($") = '';
print blockquote(em('Hi'),'mom!'));
}
I suggest you put the code in a block as shown here. Otherwise the change to $" will affect all subsequent code until you explicitly reset it.
A few HTML tags don't follow the standard pattern for various reasons.
comment() generates an HTML comment ( < !- comment - > ). Call it like
print comment('here is my comment');
Because of conflicts with built-in Perl functions, the following functions begin with initial caps:
Select
Tr
Link
Delete
In addition, start_ html() , end_ html() , start_ form() , end_ form() , start_ multipart_ form() and all the fill-out form tags are special. See their respective sections.
General note The various form-creating methods all return strings to the caller, containing the tag or tags that will create the requested form element. You are responsible for actually printing out these strings. It's set up this way so that you can place formatting tags around the form elements.
Another note The default values that you specify for the forms are only used the first time the script is invoked (when there is no query string). On subsequent invocations of the script (when there is a query string), the former values are used even if they are blank.
If you want to change the value of a field from its previous value, you have two choices:
(1) call the param() method to set it.
(2) use the -override (alias -force) parameter (a new feature in version 2.15). This forces the default value to be used, regardless of the previous value:
print $query->textfield(-name=>'field_name',
-default=>'starting value',
-override=>1,
-size=>50,
-maxlength=>80);
Yet another note By default, the text and labels of form elements are escaped according to HTML rules. This means that you can safely use " < CLICK ME > " as the label for a button. However, it also interferes with your ability to incorporate special HTML character sequences, such as Á, into your fields. If you wish to turn off automatic escaping, call the autoEscape() method with a false value immediately after creating the CGI object:
$query = new CGI;
$query->autoEscape(undef);
print $query->isindex(-action=>$action);
-or-
print $query->isindex($action);
Prints out an < ISINDEX > tag. Not very exciting. The parameter -action specifies the URL of the script to process the query. The default is to process the query with the current script.
print $query->startform(-method=>$method,
-action=>$action,
-encoding=>$encoding);
<... various form stuff ...>
print $query->endform;
-or-
print $query->startform($method,$action,$encoding);
<... various form stuff ...>
print $query->endform;
startform() will return a < FORM > tag with the optional method, action and form encoding that you specify. The defaults are:
method: POST action: this script encoding: application/x-www-form-urlencoded
endform() returns the closing < /FORM > tag.
Startform() 's encoding method tells the browser how to package the various fields of the form before sending the form to the server. Two values are possible:
This is the older type of encoding used by all browsers prior to Netscape 2.0. It is compatible with many CGI scripts and is suitable for short fields containing text data. For your convenience, CGI.pm stores the name of this encoding type in $CGI::URL_ ENCODED.
This is the newer type of encoding introduced by Netscape 2.0. It is suitable for forms that contain very large fields or that are intended for transferring binary data. Most importantly, it enables the "file upload" feature of Netscape 2.0 forms. For your convenience, CGI.pm stores the name of this encoding type in &CGI::MULTIPART
Forms that use this type of encoding are not easily interpreted by CGI scripts unless they use CGI.pm or another library designed to handle them.
JAVASCRIPTING: The -name and -onSubmit parameters are provided for use with JavaScript. The -name parameter gives the form a name so that it can be identified and manipulated by JavaScript functions. -onSubmit should point to a JavaScript function that will be executed just before the form is submitted to your server. You can use this opportunity to check the contents of the form for consistency and completeness. If you find something wrong, you can put up an alert box or maybe fix things up yourself. You can abort the submission by returning false from this function.
Usually the bulk of JavaScript functions are defined in a < SCRIPT > block in the HTML header and -onSubmit points to one of these function call. See start_ html() for details.
print $query->textfield(-name=>'field_name',
-default=>'starting value',
-size=>50,
-maxlength=>80);
-or-
print $query->textfield('field_name','starting value',50,80);
textfield() will return a text input field.
$value = $query->param('foo');
If you want to reset it from its initial value after the script has been called once, you can do so like this:
$query->param('foo',"I'm taking over this value!");
NEW AS OF VERSION 2.15: If you don't want the field to take on its previous value, you can force its current value by using the -override (alias -force) parameter:
print $query->textfield(-name=>'field_name',
-default=>'starting value',
-override=>1,
-size=>50,
-maxlength=>80);
JAVASCRIPTING: You can also provide -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut and -onSelect parameters to register JavaScript event handlers. The onChange handler will be called whenever the user changes the contents of the text field. You can do text validation if you like. onFocus and onBlur are called respectively when the insertion point moves into and out of the text field. onSelect is called when the user changes the portion of the text that is selected.
print $query->textarea(-name=>'foo',
-default=>'starting value',
-rows=>10,
-columns=>50);
-or
print $query->textarea('foo','starting value',10,50);
textarea() is just like textfield, but it allows you to specify rows and columns for a multiline text entry box. You can provide a starting value for the field, which can be long and contain multiple lines.
JAVASCRIPTING: The -onChange, -onFocus, -onBlur , -onMouseOver, -onMouseOut, and -onSelect parameters are recognized. See textfield() .
print $query->password_field(-name=>'secret',
-value=>'starting value',
-size=>50,
-maxlength=>80);
-or-
print $query->password_field('secret','starting value',50,80);
password_ field() is identical to textfield() , except that its contents will be starred out on the web page.
JAVASCRIPTING: The -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut and -onSelect parameters are recognized. See textfield() .
print $query->filefield(-name=>'uploaded_file',
-default=>'starting value',
-size=>50,
-maxlength=>80);
-or-
print $query->filefield('uploaded_file','starting value',50,80);
filefield() will return a file upload field for Netscape 2.0 browsers. In order to take full advantage of this you must use the new multipart encoding scheme for the form. You can do this either by calling startform() with an encoding type of $CGI::MULTIPART, or by calling the new method start_ multipart_ form() instead of vanilla startform().
The beta2 version of Netscape 2.0 currently doesn't pay any attention to this field, and so the starting value will always be blank. Worse, the field loses its ßticky" behavior and forgets its previous contents. The starting value field is called for in the HTML specification, however, and possibly later versions of Netscape will honor it.
$filename = $query->param('uploaded_file');
In Netscape Navigator 2.0, the filename that gets returned is the full local filename on the remote user's machine. If the remote user is on a Unix machine, the filename will follow Unix conventions:
/path/to/the/file
On an MS-DOS/Windows and OS/2 machines, the filename will follow DOS conventions:
C:\PATH\TO\THE\FILE.MSW
On a Macintosh machine, the filename will follow Mac conventions:
HD 40:Desktop Folder:Sort Through:Reminders
The filename returned is also a file handle. You can read the contents of the file using standard Perl file reading calls:
# Read a text file and print it out
while (<$filename>) {
print;
}
# Copy a binary file to somewhere safe
open (OUTFILE,">>/usr/local/web/users/feedback");
while ($bytesread=read($filename,$buffer,1024)) {
print OUTFILE $buffer;
}
When a file is uploaded the browser usually sends along some information along with it in the format of headers. The information usually includes the MIME content type. Future browsers may send other information as well (such as modification date and size). To retrieve this information, call uploadInfo() . It returns a reference to an associative array containing all the document headers.
$filename = $query->param('uploaded_file');
$type = $query->uploadInfo($filename)->{'Content-Type'};
unless ($type eq 'text/html') {
die "HTML FILES ONLY!";
}
If you are using a machine that recognizes "text" and "binary" data modes, be sure to understand when and how to use them (see the Camel book). Otherwise you may find that binary files are corrupted during file uploads.
JAVASCRIPTING: The -onChange, -onFocus, -onBlur, -onMouseOver, -onMouseOut and -onSelect parameters are recognized. See textfield() for details.
print $query->popup_menu('menu_name',
['eenie','meenie','minie'],
'meenie');
-or-
%labels = ('eenie'=>'your first choice',
'meenie'=>'your second choice',
'minie'=>'your third choice');
print $query->popup_menu('menu_name',
['eenie','meenie','minie'],
'meenie',\%labels);
-or (named parameter style)-
print $query->popup_menu(-name=>'menu_name',
-values=>['eenie','meenie','minie'],
-default=>'meenie',
-labels=>\%labels);
popup_ menu() creates a menu.
$popup_menu_value = $query->param('menu_name');
JAVASCRIPTING: popup_ menu() recognizes the following event handlers: -onChange, -onFocus, -onMouseOver, -onMouseOut, and -onBlur. See the textfield() section for details on when these handlers are called.
print $query->scrolling_list('list_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],5,'true');
-or-
print $query->scrolling_list('list_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],5,'true',
\%labels);
-or-
print $query->scrolling_list(-name=>'list_name',
-values=>['eenie','meenie','minie','moe'],
-default=>['eenie','moe'],
-size=>5,
-multiple=>'true',
-labels=>\%labels);
scrolling_ list() creates a scrolling list.
When this form is processed, all selected list items will be returned as a list under the parameter name 'list_ name'. The values of the selected items can be retrieved with:
@selected = $query->param('list_name');
print $query->checkbox_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-default=>['eenie','moe'],
-linebreak=>'true',
-labels=>\%labels);
print $query->checkbox_group('group_name',
['eenie','meenie','minie','moe'],
['eenie','moe'],'true',\%labels);
HTML3-COMPATIBLE BROWSERS ONLY:
print $query->checkbox_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-rows=2,-columns=>2);
checkbox_ group() creates a list of checkboxes that are related by the same name.
To include row and column headings in the returned table, you can use the -rowheaders and -colheaders parameters. Both of these accept a pointer to an array of headings to use. The headings are just decorative. They don't reorganize the interpretation of the checkboxes - they're still a single named unit.
@turned_on = $query->param('group_name');
The value returned by checkbox_ group() is actually an array of button elements. You can capture them and use them within tables, lists, or in other creative ways:
@h = $query->checkbox_group(-name=>'group_name',-values=>\@values);
&use_in_creative_way(@h);
JAVASCRIPTING: checkbox_ group() recognizes the -onClick parameter. This specifies a JavaScript code fragment or function call to be executed every time the user clicks on any of the buttons in the group. You can retrieve the identity of the particular button clicked on using the "this" variable.
print $query->checkbox(-name=>'checkbox_name',
-checked=>'checked',
-value=>'ON',
-label=>'CLICK ME');
-or-
print $query->checkbox('checkbox_name','checked','ON','CLICK ME');
checkbox() is used to create an isolated checkbox that isn't logically related to any others.
$turned_on = $query->param('checkbox_name');
JAVASCRIPTING: checkbox() recognizes the -onClick parameter. See checkbox_ group() for further details.
print $query->radio_group(-name=>'group_name',
-values=>['eenie','meenie','minie'],
-default=>'meenie',
-linebreak=>'true',
-labels=>\%labels);
-or-
print $query->radio_group('group_name',['eenie','meenie','minie'],
'meenie','true',\%labels);
HTML3-COMPATIBLE BROWSERS ONLY:
print $query->radio_group(-name=>'group_name',
-values=>['eenie','meenie','minie','moe'],
-rows=2,-columns=>2);
radio_ group() creates a set of logically-related radio buttons (turning one member of the group on turns the others off)
To include row and column headings in the returned table, you can use the -rowheader and -colheader parameters. Both of these accept a pointer to an array of headings to use. The headings are just decorative. They don't reorganize the interpetation of the radio buttons - they're still a single named unit.
$which_radio_button = $query->param('group_name');
The value returned by radio_ group() is actually an array of button elements. You can capture them and use them within tables, lists, or in other creative ways:
@h = $query->radio_group(-name=>'group_name',-values=>\@values);
&use_in_creative_way(@h);
print $query->submit(-name=>'button_name',
-value=>'value');
-or-
print $query->submit('button_name','value');
submit() will create the query submission button. Every form should have one of these.
$which_one = $query->param('button_name');
JAVASCRIPTING: radio_ group() recognizes the -onClick parameter. See checkbox_ group() for further details.
print $query->reset
reset() creates the "reset" button. Note that it restores the form to its value from the last time the script was called, NOT necessarily to the defaults.
print $query->defaults('button_label')
defaults() creates a button that, when invoked, will cause the form to be completely reset to its defaults, wiping out all the changes the user ever made.
print $query->hidden(-name=>'hidden_name',
-default=>['value1','value2'...]);
-or-
print $query->hidden('hidden_name','value1','value2'...);
hidden() produces a text field that can't be seen by the user. It is useful for passing state variable information from one invocation of the script to the next.
$hidden_value = $query->param('hidden_name');
Note, that just like all the other form elements, the value of a hidden field is ßticky". If you want to replace a hidden field with some other values after the script has been called once you'll have to do it manually:
$query->param('hidden_name','new','values','here');
print $query->image_button(-name=>'button_name',
-src=>'/source/URL',
-align=>'MIDDLE');
-or-
print $query->image_button('button_name','/source/URL','MIDDLE');
image_ button() produces a clickable image. When it's clicked on the position of the click is returned to your script as "button_ name.x" and "button_ name.y", where "button_ name" is the name you've assigned to it.
JAVASCRIPTING: image_ button() recognizes the -onClick parameter. See checkbox_ group() for further details.
print $query->button(-name=>'button_name',
-value=>'user visible label',
-onClick=>"do_something()");
-or-
print $query->button('button_name',"do_something()");
button() produces a button that is compatible with Netscape 2.0's JavaScript. When it's pressed the fragment of JavaScript code pointed to by the -onClick parameter will be executed. On non-Netscape browsers this form element will probably not even display.
Netscape browsers versions 1.1 and higher support a so-called "cookie" designed to help maintain state within a browser session. CGI.pm has several methods that support cookies.
A cookie is a name=value pair much like the named parameters in a CGI query string. CGI scripts create one or more cookies and send them to the browser in the HTTP header. The browser maintains a list of cookies that belong to a particular Web server, and returns them to the CGI script during subsequent interactions.
In addition to the required name=value pair, each cookie has several optional attributes:
This is a time/date string (in a special GMT format) that indicates when a cookie expires. The cookie will be saved and returned to your script until this expiration date is reached if the user exits Netscape and restarts it. If an expiration date isn't specified, the cookie will remain active until the user quits Netscape.
This is a partial or complete domain name for which the cookie is valid. The browser will return the cookie to any host that matches the partial domain name. For example, if you specify a domain name of ".capricorn.com", then Netscape will return the cookie to Web servers running on any of the machines "www.capricorn.com", "www2.capricorn.com", "feckless.capricorn.com", etc. Domain names must contain at least two periods to prevent attempts to match on top level domains like ".edu". If no domain is specified, then the browser will only return the cookie to servers on the host the cookie originated from.
If you provide a cookie path attribute, the browser will check it against your script's URL before returning the cookie. For example, if you specify the path "/cgi-bin", then the cookie will be returned to each of the scripts "/cgi-bin/tally.pl", "/cgi-bin/order.pl", and "/cgi-bin/customer_ service/complain.pl", but not to the script "/cgi-private/site_ admin.pl". By default, path is set to "/", which causes the cookie to be sent to any CGI script on your site.
If the ßecure" attribute is set, the cookie will only be sent to your script if the CGI request is occurring on a secure channel, such as SSL.
$cookie = $query->cookie(-name=>'sessionID',
-value=>'xyzzy',
-expires=>'+1h',
-path=>'/cgi-bin/database',
-domain=>'.capricorn.org',
-secure=>1);
print $query->header(-cookie=>$cookie);
cookie() creates a new cookie. Its parameters include:
The name of the cookie (required). This can be any string at all. Although Netscape limits its cookie names to non-whitespace alphanumeric characters, CGI.pm removes this restriction by escaping and unescaping cookies behind the scenes.
The value of the cookie. This can be any scalar value, array reference, or even associative array reference. For example, you can store an entire associative array into a cookie this way:
$cookie=$query->cookie(-name=>'family information',
-value=>\%childrens_ages);
The optional partial path for which this cookie will be valid, as described above.
The optional partial domain for which this cookie will be valid, as described above.
The optional expiration date for this cookie. The format is as described in the section on the header() method:
"+1h" one hour from now
If set to true, this cookie will only be used within a secure SSL session.
print $query->header(-cookie=>$my_cookie);
To create multiple cookies, give header() an array reference:
$cookie1 = $query->cookie(-name=>'riddle_name',
-value=>"The Sphynx's Question");
$cookie2 = $query->cookie(-name=>'answers',
-value=>\%answers);
print $query->header(-cookie=>[$cookie1,$cookie2]);
To retrieve a cookie, request it by name by calling cookie() method without the -value parameter:
use CGI;
$query = new CGI;
%answers = $query->cookie(-name=>'answers');
# $query->cookie('answers') will work too!
The cookie and CGI namespaces are separate. If you have a parameter named 'answers' and a cookie named 'answers', the values retrieved by param() and cookie() are independent of each other. However, it's simple to turn a CGI parameter into a cookie, and vice-versa:
# turn a CGI parameter into a cookie
$c=$q->cookie(-name=>'answers',-value=>[$q->param('answers')]);
# vice-versa
$q->param(-name=>'answers',-value=>[$q->cookie('answers')]);
See the cookie.cgi example script for some ideas on how to use cookies effectively.
NOTE: There appear to be some (undocumented) restrictions on Netscape cookies. In Netscape 2.01, at least, I haven't been able to set more than three cookies at a time. There may also be limits on the length of cookies. If you need to store a lot of information, it's probably better to create a unique session ID, store it in a cookie, and use the session ID to locate an external file/database saved on the server's side of the connection.
It's possible for CGI.pm scripts to write into several browser panels and windows using Netscape's frame mechanism. There are three techniques for defining new frames programmatically:
After writing out the HTTP header, instead of creating a standard HTML document using the start_ html() call, create a < FRAMESET > document that defines the frames on the page. Specify your script (s) (with appropriate parameters) as the SRC for each of the frames.
There is no specific support for creating < FRAMESET > sections in CGI.pm, but the HTML is very simple to write. See the frame documentation in Netscape's home pages for details
http://home.netscape.com/assist/net_sites/frames.html
You may provide a -target parameter to the header() method:
print $q- > header (-target= > 'ResultsWindow');
This will tell Netscape to load the output of your script into the frame named "ResultsWindow". If a frame of that name doesn't already exist, Netscape will pop up a new window and load your script's document into that. There are a number of magic names that you can use for targets. See the frame documents on Netscape's home pages for details.
You can specify the frame to load in the FORM tag itself. With CGI.pm it looks like this:
print $q->startform(-target=>'ResultsWindow');
When your script is reinvoked by the form, its output will be loaded into the frame named "ResultsWindow". If one doesn't already exist a new window will be created.
CGI.pm has limited support for HTML3's cascading style sheets (css). To incorporate a stylesheet into your document, pass the start_ html() method a -style parameter. The value of this parameter may be a scalar, in which case it is incorporated directly into a < STYLE > section, or it may be a hash reference. In the latter case you should provide the hash with one or more of -src or -code. -src points to a URL where an externally-defined stylesheet can be found. -code points to a scalar value to be incorporated into a < STYLE > section. Style definitions in -code override similarly-named ones in -src, hence the name "cascading."
You may also specify the type of the stylesheet by adding the optional -type parameter to the hash pointed to by -style. If not specified, the style defaults to 'text/css'.
To refer to a style within the body of your document, add the -class parameter to any HTML element:
print h1({-class=>'Fancy'},'Welcome to the Party');
Or define styles on the fly with the -style parameter:
print h1({-style=>'Color: red;'},'Welcome to Hell');
You may also use the new span() element to apply a style to a section of text:
print span({-style=>'Color: red;'},
h1('Welcome to Hell'),
"Where did that handbasket get to?"
);
Note that you must import the ":html3" definitions to have the span() method available. Here's a quick and dirty example of using CSS's. See the CSS specification at http://www.w3.org/pub/WWW/TR/Wd-css-1.html for more information.
use CGI qw/:standard :html3/;
#here's a stylesheet incorporated directly into the page
$newStyle=<<END;
<!--
P.Tip {
margin-right: 50pt;
margin-left: 50pt;
color: red;
}
P.Alert {
font-size: 30pt;
font-family: sans-serif;
color: red;
}
-->
END
print header();
print start_html( -title=>'CGI with Style',
-style=>{-src=>'http://www.capricorn.com/style/st1.css',
-code=>$newStyle}
);
print h1('CGI with Style'),
p({-class=>'Tip'},
"Better read the cascading style sheet spec before playing with this!"),
span({-style=>'color: magenta'},
"Look Mom, no hands!",
p(),
"Whooo wee!"
);
print end_html;
If you are running the script from the command line or in the perl debugger, you can pass the script a list of keywords or parameter=value pairs on the command line or from standard input (you don't have to worry about tricking your script into reading from environment variables). You can pass keywords like this:
your_script.pl keyword1 keyword2 keyword3
or this:
your_script.pl keyword1+keyword2+keyword3
or this:
your_script.pl name1=value1 name2=value2
or this:
your_script.pl name1=value1&name2=value2
or even as newline-delimited parameters on standard input.
When debugging, you can use quotes and backslashes to escape characters in the familiar shell manner, letting you place spaces and other funny characters in your parameter=value pairs:
your_script.pl "name1='I am a long value'" "name2=two\ words"
The dump() method produces a string consisting of all the query's name/value pairs formatted nicely as a nested list. This is useful for debugging purposes:
print $query->dump
Produces something that looks like:
<UL>
<LI>name1
<UL>
<LI>value1
<LI>value2
</UL>
<LI>name2
<UL>
<LI>value1
</UL>
</UL>
You can pass a value of 'true' to dump() in order to get it to print the results out as plain text, suitable for incorporating into a < PRE > section.
As a shortcut, as of version 1.56 you can interpolate the entire CGI object into a string and it will be replaced with the a nice HTML dump shown above:
$query=new CGI;
print "<H2>Current Values</H2> $query\n";
Some of the more useful environment variables can be fetched through this interface. The methods are as follows:
Return a list of MIME types that the remote browser accepts. If you give this method a single argument corresponding to a MIME type, as in $query- > accept ('text/html'), it will return a floating point value corresponding to the browser's preference for this type from 0.0 (don't want) to 1.0. Glob types (e.g. text/*) in the browser's accept list are handled correctly.
Returns the HTTP_ COOKIE variable, an HTTP extension implemented by Netscape browsers version 1.1 and higher. Cookies have a special format, and this method call just returns the raw form (?cookie dough). See cookie() for ways of setting and retrieving cooked cookies.
Called with no parameters, raw_ cookie() returns the packed cookie structure. You can separate it into individual cookies by splitting on the character sequence "; ". Called with the name of a cookie, retrieves the unescaped form of the cookie. You can use the regular cookie() method to get the names, or use the raw_ fetch() method from the CGI::Cookie module.
Returns the HTTP_ USER_ AGENT variable. If you give this method a single argument, it will attempt to pattern match on it, allowing you to do something like $query- > user_ agent (netscape);
Returns additional path information from the script URL. E.G. fetching /cgi-bin/your_ script/additional/stuff will result in $query- > path_ info() returning ädditional/stuff".
NOTE: The Microsoft Internet Information Server is broken with respect to additional path information. If you use the Perl DLL library, the IIS server will attempt to execute the additional path information as a Perl script. If you use the ordinary file associations mapping, the path information will be present in the environment, but incorrect. The best thing to do is to avoid using additional path information in CGI scripts destined for use with IIS.
As per path_ info() but returns the additional path information translated into a physical path, e.g. "/usr/local/etc/httpd/htdocs/additional/stuff".
The Microsoft IIS is broken with respect to the translated path as well.
Returns either the remote host name or IP address. if the former is unavailable.
Return the URL of the page the browser was viewing prior to fetching your script. Not available for all browsers.
Return the authorization/verification method in use for this script, if any.
Returns the name of the server, usually the machine's host name.
When using virtual hosts, returns the name of the host that the browser attempted to contact
Returns the server software and version number.
Return the authorization/verification name used for user verification, if this script is protected.
Attempt to obtain the remote user's name, using a variety of different techniques. This only works with older browsers such as Mosaic. Netscape does not reliably report the user name!
Returns the method used to access your script, usually one of 'POST', 'GET' or 'HEAD'.
NPH, or "no-parsed-header", scripts bypass the server completely by sending the complete HTTP header directly to the browser. This has slight performance benefits, but is of most use for taking advantage of HTTP extensions that are not directly supported by your server, such as server push and PICS headers.
Servers use a variety of conventions for designating CGI scripts as NPH. Many Unix servers look at the beginning of the script's name for the prefix "nph-". The Macintosh WebSTAR server and Microsoft's Internet Information Server, in contrast, try to decide whether a program is an NPH script by examining the first line of script output.
CGI.pm supports NPH scripts with a special NPH mode. When in this mode, CGI.pm will output the necessary extra header information when the header() and redirect() methods are called.
The Microsoft Internet Information Server requires NPH mode. As of version 2.30, CGI.pm will automatically detect when the script is running under IIS and put itself into this mode. You do not need to do this manually, although it won't hurt anything if you do.
There are a number of ways to put CGI.pm into NPH mode:
Simply add the "-nph" pragmato the list of symbols to be imported into your script:
use CGI qw(:standard -nph)
Call nph() with a non-zero parameter at any point after using CGI.pm in your program.
CGI->nph(1)
print $q->header(-nph=>1);
CGI.pm provides three simple functions for producing multipart documents of the type needed to implement server push. These functions were graciously provided by Ed Jordan < ed@fidalgo.net > . To import these into your namespace, you must import the ":push" set. You are also advised to put the script into NPH mode and to set $| to 1 to avoid buffering problems.
Here is a simple script that demonstrates server push:
#!/usr/local/bin/perl
use CGI qw/:push -nph/;
$| = 1;
print multipart_init(-boundary=>'----------------here we go!');
while (1) {
print multipart_start(-type=>'text/plain'),
"The current time is ",scalar(localtime),"\n",
multipart_end;
sleep 1;
}
This script initializes server push by calling multipart_ init(). It then enters an infinite loop in which it begins a new multipart section by calling multipart_ start(), prints the current local time, and ends a multipart section with multipart_ end(). It then sleeps a second, and begins again.
Initialize the multipart system. The -boundary argument specifies what MIME boundary string to use to separate parts of the document. If not provided, CGI.pm chooses a reasonable boundary for you.
multipart_start(-type=>$type)
Start a new part of the multipart document using the specified MIME type. If not specified, text/html is assumed.
multipart_end()
End a part. You must remember to call multipart_ end() once for each multipart_ start() .
A potential problem with CGI.pm is that, by default, it attempts to process form POSTings no matter how large they are. A wily hacker could attack your site by sending a CGI script a huge POST of many megabytes. CGI.pm will attempt to read the entire POST into a variable, growing hugely in size until it runs out of memory. While the script attempts to allocate the memory the system may slow down dramatically. This is a form of denial of service attack.
Another possible attack is for the remote user to force CGI.pm to accept a huge file upload. CGI.pm will accept the upload and store it in a temporary directory even if your script doesn't expect to receive an uploaded file. CGI.pm will delete the file automatically when it terminates, but in the meantime the remote user may have filled up the server's disk space, causing problems for other programs.
The best way to avoid denial of service attacks is to limit the amount of memory, CPU time and disk space that CGI scripts can use. Some Web servers come with built-in facilities to accomplish this. In other cases, you can use the shell limit or ulimit commands to put ceilings on CGI resource usage.
CGI.pm also has some simple built-in protections against denial of service attacks, but you must activate them before you can use them. These take the form of two global variables in the CGI name space:
If set to a non-negative integer, this variable puts a ceiling on the size of POSTings, in bytes. If CGI.pm detects a POST that is greater than the ceiling, it will immediately exit with an error message. This value will affect both ordinary POSTs and multipart POSTs, meaning that it limits the maximum size of file uploads as well. You should set this to a reasonably high value, such as 1 megabyte.
If set to a non-zero value, this will disable file uploads completely. Other fill-out form values will work as usual.
Set the variable at the top of the script, right after the üse" statement:
use CGI qw/:standard/;
use CGI::Carp 'fatalsToBrowser';
$CGI::POST_MAX=1024 * 100; # max 100K posts
$CGI::DISABLE_UPLOADS = 1; # no uploads
Open up CGI.pm, find the definitions for $POST_ MAX and $DISABLE_ UPLOADS, and set them to the desired values. You'll find them towards the top of the file in a subroutine named initialize_ globals() .
To make it easier to port existing programs that use cgi-lib.pl the compatibility routine "ReadParse" is provided. Porting is simple:
OLD VERSION require "cgi-lib.pl"; &ReadParse; print "The value of the antique is $in{antique}.\n";
NEW VERSION use CGI; CGI::ReadParse print "The value of the antique is $in{antique}.\n";
CGI.pm's ReadParse() routine creates a tied variable named %in, which can be accessed to obtain the query variables. Like ReadParse, you can also provide your own variable. Infrequently used features of ReadParse, such as the creation of @in and $in variables, are not supported.
Once you use ReadParse, you can retrieve the query object itself this way:
$q = $in{CGI};
print $q->textfield(-name=>'wow',
-value=>'does this really work?');
This allows you to start using the more interesting features of CGI.pm without rewriting your old scripts from scratch.
Address bug reports and comments to: lstein@genome.wi.mit.edu
Thanks very much to:
for suggestions and bug fixes.
#!/usr/local/bin/perl
use CGI;
$query = new CGI;
print $query->header;
print $query->start_html("Example CGI.pm Form");
print "<H1> Example CGI.pm Form</H1>\n";
&print_prompt($query);
&do_work($query);
&print_tail;
print $query->end_html;
sub print_prompt {
my($query) = @_;
print $query->startform;
print "<EM>What's your name?</EM><BR>";
print $query->textfield('name');
print $query->checkbox('Not my real name');
print "<P><EM>Where can you find English Sparrows?</EM><BR>";
print $query->checkbox_group(
-name=>'Sparrow locations',
-values=>[England,France,Spain,Asia,Hoboken],
-linebreak=>'yes',
-defaults=>[England,Asia]);
print "<P><EM>How far can they fly?</EM><BR>",
$query->radio_group(
-name=>'how far',
-values=>['10 ft','1 mile','10 miles','real far'],
-default=>'1 mile');
print "<P><EM>What's your favorite color?</EM> ";
print $query->popup_menu(-name=>'Color',
-values=>['black','brown','red','yellow'],
-default=>'red');
print $query->hidden('Reference','Monty Python and the Holy Grail');
print "<P><EM>What have you got there?</EM><BR>";
print $query->scrolling_list(
-name=>'possessions',
-values=>['A Coconut','A Grail','An Icon',
'A Sword','A Ticket'],
-size=>5,
-multiple=>'true');
print "<P><EM>Any parting comments?</EM><BR>";
print $query->textarea(-name=>'Comments',
-rows=>10,
-columns=>50);
print "<P>",$query->reset;
print $query->submit('Action','Shout');
print $query->submit('Action','Scream');
print $query->endform;
print "<HR>\n";
}
sub do_work {
my($query) = @_;
my(@values,$key);
print "<H2>Here are the current settings in this form</H2>";
foreach $key ($query->param) {
print "<STRONG>$key</STRONG> -> ";
@values = $query->param($key);
print join(", ",@values),"<BR>\n";
}
}
sub print_tail {
print <<END;
<HR>
<ADDRESS>Lincoln D. Stein</ADDRESS><BR>
<A HREF="/">Home Page</A>
END
}
Note that the code is truly contorted in order to avoid spurious warnings when programs are run with the -w switch.
GAMS-X plots currently come in 2 flavors called 'packages': GIFgraph and Gnuplot.
The default GAMS-X package is GIFgraph, authored by Martien Verbruggen.
The Gnuplot package uses the trusy Gnu Software Foundation's plotting package in much the same way as Tom Rutherfords GAMS Gnuplot library.25
GAMS-X plotting options can be set either within a GAMS-X script, when customized plots are being generated (through the GAMS-Tk custom plotting facilities or by the GAMS module MultiPlot method, for example) or within a model's GAMS code when a plot is defined with the $libinclude X plot statement.
In the latter case, a set of plot options can be defined, and then communicated to GAMS-X via a $setglobal statement. For example, if you want to create a set called plotopts to define your plotting options, you can do so as follows:
SET plotopts / package GIFgraph logo "D:/Inetpub/wwwroot/gams-x/gams-x.gif" logo_position UR height 400 width 550 transparent 0 bgcolor white /; $SETGLOBAL plot_opts plotopts $SETGLOBAL XTITLE "Welfare" $LIBINCLUDE X PLOT WELFARE T
If you prefer Gnuplot, the same series can be graphed with Gnuplot instead:
SET plotopts / package Gnuplot size "0.8,0.8" /; $SETGLOBAL plot_opts plotopts $SETGLOBAL XTITLE "Welfare" $LIBINCLUDE X PLOT WELFARE T
Create a line chart.
Create a bar chart.
Create a graph, representing the data as areas under a line.
Create a pie chart.
The height of the graph. Default: 300.
The width of the graph. Default: 400.
Top, bottom, left and right margin of the GIF. These margins will be left blank. Default: 0 for all.
Name of a logo file. This should be a GIF file. Default: no logo.
Factor to resize the logo by, and the position on the canvas of the logo. Possible values for logo_ position are 'LL', 'LR', 'UL', and 'UR'. (lower and upper left and right). Default: 'LR'.
If set to a true value, the produced GIF will have the background colour marked as transparent (see also option bgclr ). Default: 1.
If set to a true value, the produced GIF will be interlaced. Default: 1.
Background, foreground, text, label, axis label and accent colours.
options for bars , lines , and area charts.
If long_ ticks is a true value, ticks will be drawn the same length as the axes. Otherwise ticks will be drawn with length tick_ length . if tick_ length is negative, the ticks will be drawn outside the axes. Default: long_ ticks = 0, tick_ length = 4.
If x_ ticks is a true value, ticks will be drawm for the x axis. These ticks are subject to the values of long_ ticks and tick_ length . Default: 1.
Number of ticks to print for the Y axis. Use this, together with y_ label_ skip to control the look of ticks on the y axis. Default: 5.
This can be either a string, or a reference to a subroutine. If it is a string, it will be taken to be the first argument to an sprintf, with the value as the second argument:
$label = sprintf( $s->{y_number_format, $value );
If it is a code reference, it will be executed with the value as the argument:
$label = &{$s->{y_number_format}}($value);
This can be useful, for example, if you want to reformat your values in currency, with the - sign in the right spot. Something like:
sub y_format
{
my $value = shift;
my $ret;
if ($value >= 0)
{
$ret = sprintf("\$%d", $value * $refit);
}
else
{
$ret = sprintf("-\$%d", abs($value) * $refit);
}
return $ret;
}
$my_graph->set( 'y_number_format' => \&y_format );
(Yes, I know this can be much shorter and more concise)
Default: undef.
Print every x_ label_ skip th number under the tick on the x axis, and every y_ label_ skip th number next to the tick on the y axis. Default: 1 for both.
Force a print of all the x ticks, even if x_ label_ skip is set to a value Default: 0.
Controls the position of the X axis label (title). The value for this should be between 0 and 1, where 0 means aligned to the left, 1 means aligned to the right, and 1/2 means centered. Default: 3/4
Controls the position of both Y axis labels (titles). The value for this should be between 0 and 1, where 0 means aligned to the bottom, 1 means aligned to the top, and 1/2 means centered. Default: 1/2
If set to a true value, the X axis labels will be printed vertically. This can be handy in case these labels get very long. Default: 0.
If set to a true value, the values of the ticks on the x or y axes will be plotted next to the tick. Also see x_ label_ skip, y_ label_ skip . Default: 1 for both.
Draw the axes as a box, if true. Default: 1.
Use two separate axes for the first and second data set. The first data set will be set against the left axis, the second against the right axis. If this is set to a true value, trying to use anything else than 2 datasets will generate an error. Default: 0.
If set to a true value, the axis for y values of 0 will always be drawn. This might be useful in case your graph contains negative values, but you want it to be clear where the zero value is. (see also zero_ axis_ only and box_ axes ). Default: 0.
If set to a true value, the zero axis will be drawn (see zero_ axis ), and no axis at the bottom of the graph will be drawn. The labels for X values will be placed on the zero exis. Default: 0.
Maximum and minimum value displayed on the y axis. If two_ axes is a true value, then y1_ min_ value, y1_ max_ value (for the left axis), and y2_ min_ value, y2_ max_ value (for the right axis) take precedence over these.
The range (y_ min_ value..y_ max_ value) has to include all the values of the data points, or GIFgraph will die with a message.
For bar and area graphs, the range (y_ min_ value..y_ max_ value) has to include 0. If it doesn't, the values will be adapted before attempting to draw the graph.
Default: Computed from data sets.
This space will be left blank between the axes and the text. Default: 4.
If set to 0, bars of different data sets will be drawn next to each other. If set to 1, they will be drawn in front of each other. If set to 2 they will be drawn on top of each other. Default: 0.
If you have negative values in your data sets, setting overwrite to 2 might produce odd results. Of course, the graph itself would be quite meaningless, because overwrite = 2 is meant to show some cumulative effect.
First of all: GIFgraph does not support numerical x axis the way it should. Data for X axes should be equally spaced. That understood: There is some support to make the printing of graphs with numerical X axis values a bit better, thanks to Scott Prahl. If the option x_tick_number is set to a defined value, GIFgraph will attempt to treat the X data as numerical.
Extra options are:
If set to 'auto' , GIFgraph will attempt to format the X axis in a nice way, based on the actual X values. If set to a number, that's the number of ticks you will get. If set to undef, GIFgraph will treat X data as labels. Default: undef.
The minimum and maximum value to use for the X axis. Default: computed.
See y_ number_ format
See y_ label_ skip
Number of pixels to leave open between bars. This works well in most cases, but on some platforms, a value of 1 will be rounded off to 0. Default: 0
Which line types to use for lines and linespoints graphs. This should be a reference to an array of numbers:
$graph->set( line_types => [3, 2, 4] );
Available line types are 1: solid, 2: dashed, 3: dotted, 4: dot-dashed.
Default: [1] (always use solid)
Controls the length of the dashes in the line types. default: 6.
The width of the line used in lines and linespoints graphs, in pixels. Default: 1.
This controls the order of markers in points and linespoints graphs. This should be a reference to an array of numbers:
$graph->set( markers => [3, 5, 6] );
Available markers are: 1: filled square, 2: open square, 3: horizontal cross, 4: diagonal cross, 5: filled diamond, 6: open diamond, 7: filled circle, 8: open circle.
Default: [1,2,3,4,5,6,7,8]
The size of the markers used in points and linespoints graphs, in pixels. Default: 4.
At the moment legend support is minimal.
Options
Where to put the legend. This should be a two letter key of the form: 'B[LCR]|R[TCB]'. The first letter sigifies the placement (B ottom or R ight), and the second letter signifies the alignment (L eft, R ight, C enter, T op, or B ottom). Default: 'BC'
If the legend is placed at the bottom, some calculations will be made to ensure that there is some 'intelligent' wrapping going on. if the legend is placed at the right, all entries will be placed below each other.
The number of pixels to place around a legend item, and between a legend 'marker' and the text. Default: 4
The width and height of a legend 'marker' in pixels. Defaults: 12, 8
If you, for some reason, need to force the legend at the bottom to have a specific number of columns, you can use this. Default: computed
If set to a true value, the pie chart will be drawn with a 3d look. Default: 1.
The thickness of the pie when 3d is true. Default: 0.1 x GIF y size.
The angle at which the first data slice will be displayed, with 0 degrees being "6 o'clock". Default: 0.
Wherever a colour is required, a colour name should be used from the package the GIFgraph::colour manpage. perldoc GIFgraph::colour should give you the documentation for that module, containing all valid colour names. I will probably change this to read the systems rgb.txt file if it is available.
Wherever a font name is required, a font from the GD manpage should be used.
email: mgjv@comdyn.com.au
Copyright (C) 1995-1998 Martien Verbruggen. All rights reserved. This package is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Gnuplot comes with a fully documented set of options in the gnuplot installation. Simply type wgnuplot from within the Gnuplot directory or double-click on wgnuplot.exe to activate the Gnuplot interface, then type help at the Gnuplot prompt.
For more information, visit http://www.cs.dartmouth.edu/gnuplot_info.html .
Following installation of GAMS-X, you should have the following files and directories where /gams-x is the GAMS-X root directory, /perl/lib is the Perl library, /cgi-bin is the CGI directory included with your web server (it may exist under a different moniker such as cgi or Scripts), /public_ html is your public HTML directory (again, it may be called something like htdocs or Public), /gams is your GAMS root directory, and /gams/inclib is your GAMS include library (for more information about the GAMS include library, reference the LIBINCDIR GAMS call parameter in your GAMS User's Manual):
/gams-x/gams-tk.pl
/gams-cgid.pl
/update.pl
/gams-x.log
/pause.txt
/gams-xuninst.pl
/xpost.bat
/models/models.gx
/users/users.gx
/scripts/example.pl
/example.vbs
/install.bat
/uninstall.bat
/case.bat
/book.bat
/solveall.bat
/view.bat
/writedata.bat
/writehtml.bat
/users.bat
/models.bat
/working/Ramsey/Ramsey.gms
/Ramsey.gmx
/M1C/M1C.gms
/M1C.gmx
/html/gams-cgi.casebook.JPG
/gams-cgi.casebookindex.JPG
/gams-cgi.demo.JPG
/gams-cgi.login.JPG
/gams-cgi.modelindex.JPG
/gams-cgi.newuser.JPG
/gams-cgi.useredit.JPG
/gams-tk.casebook.JPG
/gams-tk.casebookindex.JPG
/gams-tk.caseprofile.JPG
/gams-tk.casesummary.JPG
/gams-tk.demo.JPG
/gams-tk.modelindex.JPG
/gams-tk.modelinstall.JPG
/gams-tk.modelsummary.JPG
/gams-tk.modeluninstall.JPG
/gams-tk.newcase.JPG
/gams-tk.newcasebook.JPG
/gams-tk.newuser.JPG
/gams-tk.plots.JPG
/gams-tk.revisedescription.JPG
/gams-tk.siteconfig.JPG
/gams-tk.useredit.JPG
/gams-tk.usereditchild.JPG
/gams-tk.userkill.JPG
/gams-tk.usersummary.JPG
/gams-x.html
/gams-x.plot.JPG
/perl/lib/GAMS.pm
/GAMS/CGI.pm
/GAMS/Ini.pm
/GAMS/Tools.pm
/GAMS/Pods.pm
/GAMS/Script.pm
/GAMS/Tk/Casebook.pm
/GAMS/Tk/CustomPlotting.pm
/GAMS/Tk/EditDialog.pm
/GAMS/Tk/EntryListbox.pm
/GAMS/Tk/ErrorDialog.pm
/GAMS/Tk/HitherYon.pm
/GAMS/Tk/MenuBar.pm
/GAMS/Tk/ModelInstall.pm
/GAMS/Tk/NewCase.pm
/GAMS/Tk/NewCasebook.pm
/GAMS/Tk/NewUser.pm
/GAMS/Tk/Pane.pm
/GAMS/Tk/Plots.pm
/GAMS/Tk/ProgressBar.pm
/GAMS/Tk/WaitBox.pm
/cgi-bin/gams-cgi.pl
/public_html/gams-x/index.htm
/images/gams-tk.gif
/gams-cgi.gif
/gams-x.gif
/users
/models
/gams/inclib/X.gms
The following is the full text of the GAMS code for the sample Ramsey model included with the default GAMS-X installation:
$TITLE Ramsey Model of Optimal Economic Growth
$OFFUPPER
$libinclude X INPUT BET 0.95 "Discount factor" 0.90 0.925 0.975
$libinclude X INPUT B 0.25 "Capital value share" 0.20 0.30 0.40 0.50
$libinclude X INPUT G 0.03 "Labor growth rate" 0.01 0.02 0.04 0.06 0.08
$libinclude X INPUT AC 0.15 "Absorptive capacity rate" 0.10 0.20 0.25
$libinclude X INPUT K0 3.00 "Initial capital" 2.0 4.0 5.0
$libinclude X INPUT I0 0.05 "Initial investment" 0.025 0.075 0.10 0.15 0.20
$libinclude X INPUT TEST 0.0 "Test input" -0.1 0.1
*
* This formulation is described in 'GAMS/MINOS: Three examples'
* by Alan S. Manne, Department of Operations Research, Stanford
* University, May 1986.
*
* The optimal objective value is 2.4875
*
* References:
* F P Ramsey: A Mathematical Theory of Saving, Economics Journal,
* December 1928.
* B Murtagh and M Saunders: A Projected Lagrangian Algorithm
* and its Implementation for Sparse Nonlinear Constraints,
* Mathematical Programming Study 16, pp 84-117, 1982,
* Section 5.12 Economic Growth Model
*---------------------------------------------------------------------
* The planning horizon covers the years from 1990 (TFIRST) to 2050
* (TLAST). The intervening asterisk indicates that this set includes
* all the integers between these two values. This first statement is
* the only one that needs to be changed if one wishes to examine a
* different planning horizon.
*---------------------------------------------------------------------
SETS T TIME PERIODS /1990*2050/
TFIRST(T) FIRST PERIOD
TLAST(T) LAST PERIOD
*---------------------------------------------------------------------
* Data may also be entered in the form of SCALAR(S), as illustrated
* below.
*---------------------------------------------------------------------
SCALARS BET DISCOUNT FACTOR /%BET%/
B CAPITAL'S VALUE SHARE /%B%/
G LABOR GROWTH RATE /%G%/
AC ABSORPTIVE CAPACITY RATE /%AC%/
K0 INITIAL CAPITAL /%K0%/
I0 INITIAL INVESTMENT /%I0%/
C0 INITIAL CONSUMPTION
A OUTPUT SCALING FACTOR;
C0 = 1 - I0;
PARAMETERS BETA(T) DISCOUNT FACTOR
AL(T) OUTPUT-LABOR SCALING VECTOR;
*-----------------------------------------------------------------------
* The following statements show how we may avoid entering information
* about the planning horizon in more than one place. Here the symbol
* "$" means "such that"; "ORD" defines the ordinal position in a set;
* "CARD" defines the cardinality of the set. Thus, TFIRST is
* determined by the first member included in the set; and TLAST by the
* cardinality (the last member) of the set.
* This seems like a roundabout way to do things, but is useful if we
* want to be able to change the length of the planning horizon by
* altering a single entry in the input data. The same programming style
* is employed when we calculate the present-value factor BETA(T) and the
* output-labor vector AL(T).
*-----------------------------------------------------------------------
TFIRST(T) = YES$(ORD(T) EQ 1);
TLAST(T) = YES$(ORD(T) EQ CARD(T));
DISPLAY TFIRST, TLAST;
BETA(T) = BET**ORD(T);
BETA(TLAST) = BETA(TLAST)/(1-BET);
*-----------------------------------------------------------------------
* BETA(TLAST), the last period's utility discount factor, is calculated
* by summing the infinite geometric series from the horizon date onward.
* Because of the logarithmic form of the utility function, the
* post-horizon consumption growth term may be dropped from the maximand.
*-----------------------------------------------------------------------
A = (C0+I0)/K0**B;
AL(T) = A*(1+G)**((1-B)*(ORD(T)-1));
DISPLAY BETA, AL;
VARIABLES K(T) CAPITAL STOCK (TRILLION RUPEES)
C(T) CONSUMPTION (TRILLION RUPEES PER YEAR)
I(T) INVESTMENT (TRILLION RUPEES PER YEAR)
UTILITY
*---------------------------------------------------------------------*
* Note that variables and equations cannot be identified by the same
* name. That is why the capital stock variables are called K(T), and
* the capital balance equations are KK(T).
*---------------------------------------------------------------------*
EQUATIONS CC(T) CAPACITY CONSTRAINT (TRILLION RUPEES PER YEAR)
KK(T) CAPITAL BALANCE (TRILLION RUPEES)
TC(T) TERMINAL CONDITION (PROVIDES FOR POST-TERMINAL GROWTH)
UTIL DISCOUNTED LOG OF CONSUMPTION: OBJECTIVE FUNCTION ;
*---------------------------------------------------------------------*
CC(T).. C(T) + I(T) =E= AL(T)*K(T)**B;
KK(T+1).. K(T+1) =E= K(T) + I(T);
TC(TLAST).. G*K(TLAST) =L= I(TLAST);
UTIL.. UTILITY =E= SUM(T, BETA(T)*LOG(C(T)));
*-----------------------------------------------------------------------
* Instead of requiring that "ALL" of these constraints are to be
* included, we specify that the RAMSEY model consists of each of the
* four individual constraint types. If, for example, we omit TC, we can
* check the sensitivity of the solution to this terminal condition.
*-----------------------------------------------------------------------
MODEL RAMSEY /CC, KK, TC, UTIL/;
*-----------------------------------------------------------------------
* The following statements represent lower bounds on the individual
* variables K(T), C(T) and I(T); a fixed value for the initial period's
* capital stock, K(TFIRST); and upper bounds (absorptive capacity
* constraints) on I(T). Bounds are required for K and C because
* LOG(C(T)) and K(T)**B are defined only for positive values of C and K
*-----------------------------------------------------------------------
K.LO(T) = K0; C.LO(T) = C0; I.LO(T) = I0;
K.FX(TFIRST) = K.LO(TFIRST);
I.UP(T) = I0*((1+AC)**(ORD(T)-1));
*-----------------------------------------------------------------------
SOLVE RAMSEY MAXIMIZING UTILITY USING NLP;
SET TL(T) /1990,2000,2010,2020,2030,2040,2050/;
$setglobal xsol_nd 4
$setglobal xtitle "Intertemporal utility"
$libinclude X OUTPUT UTILITY.L
* When you define an output parameter, the title is
* taken from the parameter declaration:
PARAMETER CONSUM Consumption (trillion rupees per year);
CONSUM(TL) = C.L(TL);
$libinclude X OUTPUT CONSUM TL
set plotopts /
package GIFgraph
type bars
height 300
width 400
/;
$ontext
For Gnuplot graphs, the set plotopts would be defined as something like
set plotopts /
package gnuplot
size "0.8,0.8"
/;
$offtext
* When you pass a level value or marginal through as an
* output, you must declare a title first:
$setglobal plot_opts plotopts
$setglobal xtitle "Consumption (trillion rupees per year)"
$libinclude X PLOT C.L T TL
$setglobal xtitle "Capital stock (trillion rupees)"
$libinclude X PLOT K.L T TL
$setglobal xtitle "Investment (trillion rupees per year)"
$libinclude X PLOT I.L T TL
$setglobal xtitle "Present value of consumption"
$libinclude X PLOT CC.M T TL
KK.M(TFIRST) = K.M(TFIRST);
$setglobal xtitle "Present value of capital"
$libinclude X PLOT KK.M T TL
use GAMS::Script;
$GAMS = new GAMS::Script;
# Anything that follows a # is a comment, and ignored by Perl
print <<"eop";
GAMS-X Example Script
---------------------
A full description of this example GAMS-X script can be found in the
chapter of the GAMS-X User's Guide and Owner's Manual titled 'GAMS-X
Scripting Guide.'
This script creates a user account for a user named Grog, installs
the model Ramsey (included with the GAMS-X distribution), creates a
set of cases and casebooks, and prints formatted output based on the
solutions to the cases.
It is strongly recommended that you exit GAMS-Tk before running this
or any other GAMS-X script.
eop
print "Continue? [y/n] ";
chomp ($answer = <STDIN>);
if ($answer !~ /y/) { die "\nGoodbye!\n" }
# Check whether the user Grog exists, and if so, remove his account
if (exists $GAMS->Users->{'ID'}->{'Grog'}) {
print "\nAn account for the user 'Grog' already exists. Delete 'Grog'? [y/n] ";
chomp ($answer = <STDIN>);
if ($answer =~ /^y/i) {
print "\nKilling Grog's user account . . .\n";
$GAMS->Kill( 'Grog' );
} else {
die "\nAborting . . .\n";
}
}
# Check whether the model Ramsey exists, and if so, uninstall it
if (exists $GAMS->Models->{'ID'}->{'Ramsey'}) {
print "\nThe model 'Ramsey' is already installed. Uninstall 'Ramsey'? [y/n] ";
chomp ($answer = <STDIN>);
if ($answer =~ /^y/i) {
print "\nUninstalling Ramsey . . .\n";
$GAMS->Uninstall( 'Ramsey' );
} else {
die "\nAborting . . .\n";
}
}
print "\nCreating a user account with name 'Grog' and password 'grog!' . . .\n";
$GAMS->Set(
-User => "Grog",
-Password => "grog!",
-PasswordConfirmation => "grog!",
-Affiliation => "University of Grog",
-Email => 'grog@spot',
-UserHome => "Local Host"
);
$GAMS->AddUser;
# Use print statements to let yourself know what you are doing . . .
print "\nInstalling the Ramsey model . . .\n";
# Note that \n in Perl is the newline character
# Give ourselves three seconds to read this message before
# the GAMS output runs all of our nicely printed messages
# off the screen . . .
sleep 3;
# You must adjust all of the filenames below to match those of your
# GAMS-X installation
$GAMS->Install(
'Ramsey',
'Ramsey Model of Optimal Economic Growth',
$GAMS->GXRoot . '\working\Ramsey\Ramsey.gms'
);
print "Creating the casebook STUDY1 . . .\n";
$GAMS->Set(
-User => "Grog",
-Model => "Ramsey",
-Casebook => "STUDY1",
-Description => "Comparing a high capital value share and high labor growth rate"
);
$GAMS->NewCasebook;
print "Creating the casebook STUDY2 . . .\n";
$GAMS->Set(
-Casebook => "STUDY2",
-Description => "Comparing a high labor growth rate and low discount factor"
);
$GAMS->NewCasebook;
print "Creating case HIGHB . . .\n";
$GAMS->Set(
-Case => "HIGHB",
-CaseInputs => { "B" => 0.30 }
);
$GAMS->NewCase;
print "Creating case HIGHG . . .\n";
$GAMS->Set(
-Case => "HIGHG",
-CaseInputs => { "G" => 0.06 }
);
$GAMS->NewCase;
print "Creating case LOWBET . . .\n";
$GAMS->Set(
-Case => "LOWBET",
-CaseInputs => { "BET" => 0.90 }
);
$GAMS->NewCase;
print "Solving the new cases . . .\n";
sleep 3;
# . . . and call the solver
$GAMS->Solver;
print "Putting the case HIGHB in the casebook STUDY1 . . .\n";
$GAMS->Set(
-Case => "HIGHB",
-Casebook => "STUDY1"
);
$GAMS->Book;
print "Putting the case HIGHG in the casebook STUDY1 . . .\n";
$GAMS->Set(
-Case => "HIGHG"
);
$GAMS->Book;
# The Book method does not generate the casebook plots, so it
# is important if you have plots to be seen, that when you
# finish putting cases into a casebook, you create new plots
# for the casebook with the CasebookPlot method
$GAMS->CasebookPlot;
print "Putting the case HIGHG in the casebook STUDY2 . . .\n";
$GAMS->Set(
-Case => "HIGHG",
-Casebook => "STUDY2"
);
$GAMS->Book;
print "Putting the case LOWBET in the casebook STUDY2 . . .\n";
$GAMS->Set(
-Case => "LOWBET"
);
$GAMS->Book;
$GAMS->CasebookPlot;
@MySortedCases =
grep $_->{'Status'} eq 'Solved',
grep $_->{'Input'}->{'B'} > 0.25,
grep $_->{'Output'}->{'UTILITY.L'} > 1,
grep $_->{'Name'} =~ /H/i, @{$GAMS->UserState->{'Case'}};
if (@MySortedCases) {
# . . . that is, if there are any cases in the @MySortedCases list
foreach $Case (@MySortedCases) {
print "The case $Case->{'Name'} meets my sorting criteria.\n";
}
} else {
print "No cases meet my sorting criteria!\n";
}
$MyDataFile = $GAMS->GXRoot . '\temp\Ramsey.gmx';
print "Writing GAMS-X data file to $MyDataFile . . .\n";
$GAMS->WriteData( $MyDataFile );
$GIFFile = $GAMS->GXRoot . '\temp\Ramsey.gif';
$Plots = [ "C.L", "I.L", "CC.M" ];
$PlotOptions = {
"height" => 400,
"width" => 500,
"type" => "bars"
};
print "Generating customized plot in file $GIFFile . . .\n";
$GAMS->MultiPlot(
$GIFFile,
"Grog",
"Ramsey",
"HIGHB",
$Plots,
$PlotOptions
);
print <<"eop";
Here is a listing of the cases I have just generated as well as the
value of the output UTILITY.L, all nicely formatted for my viewing
pleasure:
Case UTILITY.L CONSUM(1990) CONSUM(2050) KK(1990) KK(2050)
---- --------- ------------ ------------ -------- --------
eop
format MYFORMAT =
@|||||||||||||| @###.#### @###.#### @###.#### @##.#### @##.####
$Name, $UTILITY, $CONSUM1990, $CONSUM2050, $KK1990, $KK2050
.
$~ = MYFORMAT;
for $Case (@{$GAMS->UserState("Grog","Ramsey")->{'Case'}}) {
$Name = $Case->{'Name'};
$UTILITY = $Case->{'Output'}->{'UTILITY.L'};
$CONSUM1990 = $Case->{'Output'}->{'CONSUM(1990)'};
$CONSUM2050 = $Case->{'Output'}->{'CONSUM(2050)'};
$KK1990 = $Case->{'Plot'}->{'KK.M'}->[0];
$KK2050 = $Case->{'Plot'}->{'KK.M'}->[60];
write;
}
print "\nUTILITY.L for the case HIGHB formatted with the printf statement: ";
printf "%1.2f", $GAMS->Cases("Grog","Ramsey")->{'HIGHB'}->{'Output'}->{'UTILITY.L'};
print "\n\n";
print "Quitting . . .\n";
$GAMS->Quit;
use GAMS::CGI;
my $GAMS = new GAMS::CGI;
# $GAMS->Gripe("This site has been taken offline for maintenance.");
# Process the appropriate task:
if ($GAMS->Task eq "Greeting") {$GAMS->Greeting
} elsif ($GAMS->Task eq "Log In") {$GAMS->Login
} elsif ($GAMS->Task eq "New User") {$GAMS->NewUser
} elsif ($GAMS->Task eq "AddUser") {$GAMS->AddUser; $GAMS->WriteModelIndex
} elsif ($GAMS->Task eq "Edit Account Information") {$GAMS->EditAccountInformation
} elsif ($GAMS->Task eq "EditUser") {$GAMS->EditUser
} elsif ($GAMS->Task eq "RemoveAccount") {$GAMS->RemoveAccount
} elsif ($GAMS->Task eq "WriteModelIndex") {$GAMS->WriteModelIndex
} elsif ($GAMS->Task eq "WriteCasebookIndex") {$GAMS->WriteCasebookIndex
} elsif ($GAMS->Task eq "WriteCasebook") {$GAMS->WriteCasebook
} elsif ($GAMS->Task eq "CopyHTML") {$GAMS->CopyHTML
} elsif ($GAMS->Task eq "CopyText") {$GAMS->CopyText
} elsif ($GAMS->Task eq "AddCasebook") {$GAMS->NewCasebook; $GAMS->WriteCasebookIndex
} elsif ($GAMS->Task eq "DeleteCase") {$GAMS->DeleteCase; $GAMS->WriteCasebookIndex
} elsif ($GAMS->Task eq "DeleteCasebook") {$GAMS->DeleteCasebook; $GAMS->WriteCasebookIndex
} elsif ($GAMS->Task eq "ImportCase") {$GAMS->ImportCase; $GAMS->WriteCasebook
} elsif ($GAMS->Task eq "RemoveCase") {$GAMS->RemoveCase; $GAMS->WriteCasebook
} elsif ($GAMS->Task eq "AddCase") {$GAMS->AddCase; $GAMS->WriteCasebook
} elsif ($GAMS->Task eq "ReviseDescription") {$GAMS->ReviseDescription; $GAMS->WriteCasebook
} else {$GAMS->Greeting
}
$GAMS->Quit
A necessary, but in my opinion, silly, part of issuing freeware:
There is no warranty for this program. Except when otherwise stated in writing the program is provided äs is" without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction.
In no event unless required by applicable law or agreed to in writing will any party who may modify and/or distribute the program as permitted above, be liable to you for damages, including any general, special, incidental or consequential damages arising out of the use or inability to use the program (including but not limited to loss of data or data being rendered inaccurate or losses sustained by you or third parties or a failure of the program to operate with any other programs), even if such party has been advised of the possibility of such damages.
This software is freely distributable under the terms and conditions of Perl itself and the GNU General Public License.
1 GAMS, Perl, and a web server
2 GAMS, Perl, Java, HTML, and DOS
3 The ActivePerl 5.005+ distribution is highly recommended. So highly, in fact, that it is recommended that if you are using an earlier version of Perl, you should uninstall it and reinstall the new version. It's for your own good.
4 If you are a model developer or want to post your model online, you should download GAMS-X rather than GAMS-Xi.
5 This is not strictly true. You must be connected to the web in order for PPM to work this easily. If you are not connected to the web, or are connected to the web via a firewall or proxy, and the Perl Package Manager can't find the requisite modules, read FAQ for a solution.
6 Your humble author freely admits that he is not a Windows administrator. If there are any kind soulds out there who know of an easier way to install a service, he would be grateful for their advice in this regard.
7 Fans of the late artist will have to excuse the implicit commentary on Mr. Pollock's work.
8 If the command doesn't disappear after solving each case, and you would like it to, see FAQ .
9 Object Linking and Embedding, which provides easy access to Microsoft Excel spreadsheets, for example.
10 Which sounds suspiciously like an oxymoron!
11 Associative arrays are also known as hash tables, or simply hashes.
12 The \@list1 in this example creates a pointer to @list1.
13 Note that this snippet of code assumes that the BET input is continuously-valued, which it is not in the Ramsey model provided with the default installation. Consider it to be for demonstration purposes only.
14 In programming jargon, the pointer is dereferenced.
15 You can also plot many cases across a single series in a similar fashion.
16 To view the comments, you can select the View.Document Source menu option in Netscape. Comments are given by HTML markups that look like <!- * ->.
17 You should consult your web server documentation for more information on the virtual location of your CGI executable directory. If you are using Apache, it may be something like /cgi-bin. With Microsoft Internet Information Server (MIIS), it may be something like /scripts.
18 For a full text of the Ramsey model, see appendix .
19 You should consult your web server documentation for more information on the location of your CGI executable directory. If you are using Apache, it may be something like C:\apache\cgi-bin. With Microsoft Internet Information Server (MIIS), it may be something like C:\Inetpub\scripts.
20 They are currently current as of February 20, 1999.
21 By large, I mean more than 30 inputs and outputs, though we have run models through GAMS-Tk with up to 353 inputs and outputs.
22 The GAMS-CGI release is perhaps the oldest arm of the GAMS-X module family, and you should rest assured that it is also the most secure and bug-free.
23 By large, I mean more than 30 inputs and outputs, though we have run models through GAMS-Tk with up to 353 inputs and outputs.
24 This duplication of information is a convenience for the programmer more than anything else.
25 For more information, see http://nash.colorado.edu/tomruth/gnuplot/gnuplot.htm.
_File translated from TEX by TTH, version 2.25.
On 04 Dec 1999, 00:46.