GAMS-X: User's Guide and Owner's Manual

by Collin Starkweather

Dec 04, 1999

++

Chapter 1
Introduction

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.

Figure
Figure 1.1: GAMS-Tk

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.

Figure
Figure 1.2: GAMS-CGI

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.

Chapter 2
GAMS-X: The GAMS Model Interface

2.1  Overview

2.1.1  In Layman's Terms

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.

2.1.2  Technobabble

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.

2.2  How to Read This Document

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.

2.3  Downloading and Installation

2.3.1  The GAMS-X Homepage

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:

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

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 .

2.3.2  Windows

2.3.3  System Requirements

Installation Options

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.

Installing GAMS-X

Links to all of the files mentioned are included in the HTML version of this document.

  1. Download the ActivePerl installation file from http://www.activestate.com and double-click on it from Windows Explorer. The most recent build as of 9/99 is version 5.00503 build 519 with filename APi519e.exe located at http://www.activestate.com/ActivePerl/download.htm .
  2. You must now install several Perl packages. To do this,

    1. Open a DOS prompt
    2. Type
      PPM
      at the prompt (PPM stands for Perl Package Manager)
    3. Install the Storable, GD, GIFgraph, and Tk packages by typing
      install Storable GD GIFgraph Tk
      from the PPM prompt.

    You must be connected to the web to use the Perl Package Manager.5

  3. Get the GAMS-X installation file gams-xinst.pl and zip file gams-xinst.zip and put them in a temporary directory. If you do not have unzip (WinZip does not count), download unzip.exe and put it in the temporary directory as well. Double-click on gams-xinst.pl from Windows Explorer.
  4. Let me know who you are. Send me some email at . This way, I can let you know about any bug fixes or new releases.

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.

Installing GAMS-Xi

  1. Download the GAMS-X Lite installation file setup.exe and pack gams-xi.zip from the GAMS-X homepage and put them in a temporary directory. Double-click on setup.exe from Windows Explorer. If you do not have unzip (WinZip does not count), download unzip.exe and put it in the temporary directory as well.

2.3.4  Unix

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.

2.3.5  Upgrading from GAMS-X Version 2.x

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.

Do I need an update?

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.

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 .

How to Upgrade

Before updating your version of GAMS-X:

  1. Download the new update utility update.pl and put it in your GAMS-X root directory (typically C:\gams-x), replacing the existing update.pl.
  2. If you do not have unzip.exe either in your path or in your GAMS-X root directory, put it in your GAMS-X root directory.

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.

2.3.6  Upgrading from GAMS-CGI Version 1.x

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.

2.4  Starting the GAMS-CGI Daemon

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.

2.4.1  Windows 95/98

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.

2.4.2  Windows NT

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

2.4.3  Unix

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 [].

2.5  Uninstalling GAMS-X

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 .

2.6  Comments/Suggestions/Bug Reports

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.

Chapter 3
The GAMS-X Model Builder's Guide

3.1  Using GAMS-X with GAMS Models

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.

3.1.1  Design Philosophy

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:

  1. What are to be the inputs to the model that the user is allowed to choose from?
  2. What are the outputs that you would like the user to see after a model has been solved?
  3. What kinds of plots would you like generated by the output from your model?

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.

3.1.2  Defining Inputs

A model file defines a GAMS-X input with a statement like:

$libinclude X INPUT BET 0.95 "Discount factor" 0.90  0.925 0.975

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:

SCALAR  BET    Discount factor           /%BET%/;

It is also possible to employ non-numeric inputs. For example:

$libinclude X INPUT FTA_USC NO "FTA includes USA and Canada" YES

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:

SET  FTA(R)     Regions entering a free trade agreement;     
FTA("USC") = %FTA_USC%;

Finally, if a continuously variable input is desired, the input may be declared with a maximum and minimum value with a statement such as:

$libinclude X INPUT BET 0.95 "Discount Factor" MAX 0.975 MIN 0.95

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:

$libinclude X INPUT symbol default "description" alt1 [alt2 ..alt4 ]

The symbol name must be valid GAMS name. Some form of description and at least one alternative value must be provided.

3.1.3  Defining Outputs

A GAMS program defines a GAMS-X output with statements like:

$setglobal xsol_nd 4
$setglobal xtitle "Intertemporal utility"
$libinclude X OUTPUT UTILITY.L

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:

parameter CONSUM  Consumption (trillion rupees per year);   
CONSUM(TL) = C.L(TL);
$libinclude X OUTPUT CONSUM TL

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:

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

Formally, an X output statement must be entered on a single line with at least three arguments:

$LIBINCLUDE X OUTPUT item [first_set [second_set]]

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.

3.1.4  Defining Plots

GAMS-X provides some rudimentary tools for graphical reporting. A typical plotting statement would be:

$setglobal xtitle "Consumption (trillion rupees per year)" 
$libinclude X PLOT C.L  T TL

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:

$libinclude X PLOT item domain_set [label_set]

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:

SET     T       Annual time periods     /1990*2050/,
        TL(T)   Label periods (decades) /1990,2000,2010,2020,2030,2040,2050/;

Then the resulting plot appears as in figure

Figure
Figure 3.1: A GAMS-X Plot

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.

Chapter 4
The GAMS-Tk User's Guide

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.

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.

Figure
Figure 4.1: Creating a User

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.

Figure
Figure 4.2: Installing a Model

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.

Figure
Figure 4.3: Creating a Case

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!

4.2  The Casebook Window

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.

Figure
Figure 4.4: The GAMS-Tk Menu

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.

4.3  The File Menu

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.

4.4  The Goto 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.

4.5  The Edit Menu

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 ).

Figure
Figure 4.5: Creating a Case

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 ).

Figure
Figure 4.6: Creating a Casebook

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 ).

Figure
Figure 4.7: Changing a Casebook Description

4.6  The View Menu

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 .

Figure
Figure 4.8: The Casebook Index

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.

4.7  The Tools Menu

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 ).

Figure
Figure 4.9: A GAMS-X Plot

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

4.8  The Help Menu

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.

4.9  The Plots Window

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).

Figure
Figure 4.10: GAMS-Tk Plots

Chapter 5
The GAMS-X Scripting Guide

5.1  Overview of the GAMS-X Environment

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:

  1. Run GAMS-Tk and select Grog as the user and Ramsey as the model
  2. Log on to GAMS-CGI as the user Grog and select the model Ramsey
  3. Compose a simple and intuitive snippet of GAMS-X script:

    print $GAMS->Cases('Grog','Ramsey')->{'MyCase'}->{Output}->{'UTILITY.L'};
    

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.

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.

5.3  A Perl Primer

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.

5.4  A Brief GAMS-X Scripting Tutorial

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.

5.4.1  Getting Started

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.

5.4.2  Creating a New User

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.

5.4.3  Installing a Model

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.

Uninstalling a Model

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');"

5.4.4  Creating a New Casebook for the Model

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.

5.4.5  Creating Some New Cases for the Model

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.

5.4.6  Solving the Cases

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;

5.4.7  Putting the Cases in the Casebooks

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.

5.4.8  Sorting the Cases

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.

5.4.9  Saving a GAMS-X Data File

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.

5.4.10  Creating Some Customized Plots for Your Model

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
);

5.4.11  Printing Formatted Output

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.

5.4.12  Exiting GAMS-X

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.

5.5  Send Me Your Code!

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 .

Chapter 6
The GAMS-X Administrator's Guide

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.

6.1  Your GAMS-X Site Configuration

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.

Figure
Figure 6.1: Configuring Your GAMS-Tk Site

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
);

6.2  Administering Models

6.2.1  Obtaining Model Information

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.

Figure
Figure 6.2: The GAMS-Tk Model Index

To view the model summary (see figure ), select the Tools.Model.Summary menu option.

Figure
Figure 6.3: The Model Summary

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 ).

Figure
Figure 6.4: The Model Case Summary

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 ).

Figure
Figure 6.5: The Case Profile

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.

6.2.2  Installing Models

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 ).

Figure
Figure 6.6: Installing a Model

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'
);

6.2.3  Uninstalling Models

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 ).

Figure
Figure 6.7: Uninstalling a Model

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' );

6.2.4  The GAMS-X Data File

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.

6.3  Administering Users

6.3.1  Obtaining User Information

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.

Figure
Figure 6.8: The User Summary

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.

6.3.2  Creating a User

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 ).

Figure
Figure 6.9: Creating a User

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.

6.3.3  Killing a User

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 ).

Figure
Figure 6.10: Killing a User

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;

6.3.4  Editing a User

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.

Figure

Figure 6.11: Editing a User Profile

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 ).

Figure
Figure 6.12: The User Profile Editing Box

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'}
                            }
);

6.4  Some Important GAMS-X Files

6.4.1  The GAMS-X Initialization File

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.

6.4.2  The GAMS-X Log File

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

7.1  Overview

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.

7.2  Logging In

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.

Figure
Figure 7.1: The User Login

Figure
Figure 7.2: The User Account Creation Page

Figure
Figure 7.3: The User Profile Editing Page

7.3  Choosing a Model

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.

Figure
Figure 7.4: The Model Index

7.4  Choosing a Casebook

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.

Figure
Figure 7.5: The Casebook Index

7.4.1  Creating a New Casebook

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.

7.4.2  Accessing a 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.

7.4.3  Deleting a 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.

7.5  Working with Cases

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.

Figure
Figure 7.6: The Casebook

7.5.1  Creating a New Case

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.

7.5.2  Why is my case listed under the heading "Solving"?

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.

7.5.3  Why did my case yield a GAMS error?

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.

7.5.4  Importing an existing case into a casebook

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!

7.5.5  Viewing the GAMS Output for a Case

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.

7.5.6  Removing a Case from the Casebook

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.

7.5.7  Deleting a Case

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.

7.5.8  Changing a Casebook Description

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.

Chapter 8
The GAMS-CGI Administrator's and Web Developer's Guide

8.1  Overview

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:

  1. All that a model-user should need to know in order to use GAMS-CGI is how to operate an internet browser,
  2. All that a model-developer should need to know in order to use GAMS-CGI is how to program in GAMS,
  3. GAMS-CGI and associated software should be easy to install on any computer running GAMS and connected to the internet.

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.

8.2  Web Basics

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.

8.2.1  What Exactly is a Web Page?

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>

8.2.2  How is a Web Page Posted on the Web?

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.

8.3  CGI Basics

8.3.1  What is CGI?

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:

  1. You click a button on a web page
  2. Your browser sends some information to the computer that keeps the web page (the web server) with details about which button you pushed and whatnot
  3. The server runs a program, such as GAMS-CGI, which processes the information and spits out a web page that is returned to your browser.
  4. You see the new web page

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).

8.3.2  HTML Forms

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.

8.3.3  CGI Parameters

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.

8.3.4  Programming in GAMS-CGI

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.

8.3.5  The Basic GAMS-CGI Environment

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

8.3.6  Some Simple Examples

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.

8.3.7  Making Information Available to the Site

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.

8.3.8  Attaching Information to a Model

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.

8.3.9  Attaching Information to a User Account

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 . . .

8.3.10  Creating a Fully Customized GAMS-CGI Environment

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.

Getting Started

The Welcome Page

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.

The GAMS-CGI Program

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 .

8.3.11  Example: Presenting First-Time Users with a Greeting Page

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 . . .

8.3.12  Example: Presenting First-Time Users with a More Sophisticated Greeting Page

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

}

8.4  Basic GAMS-CGI Administration

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.

8.4.1  Configuration Variables that Change the Appearance of the GAMS-CGI Site

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!

8.4.2  Pausing the GAMS-CGI Server

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.

8.4.3  Bypassing the GAMS-CGI Login Screen

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.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:

  1. Don't ever ever ever use user input in a system call or as a filename or part of a filename.
  2. Never put a file that you don't want exposed to the world in your public HTML directory.
  3. Always check each form input that your script expects for logical consistency with your code; e.g., make sure a user or model exists before trying to do something with it.
  4. Guard against several users trying to access the same file at the same time with flock (not available on Windows 95/98).
  5. Don't ever put a dll or executable in the CGI directory that does anything other than process a CGI form.
  6. Don't transfer sensitive information, such as users' passwords, through CGI parameters. Use cookies instead and encrypt the information.
  7. All run-time evals should be done in a safe compartment. For more information, see the documentation accompanying the Safe module.

Chapter 9
Frequently Asked Questions

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.

9.1  User FAQs

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

c:\mydir/working\mymodel.gms
and it will recognize it as a valid filename.

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

http://www.gnu.org

To configure GAMS-X to use Gnuplot,

9.2  Modeler/Administrator FAQs

9.2.1  Installing Perl

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):

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.

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:

C:\>set HTTP_proxy=MyProxy

C:\>echo %HTTP_proxy%
MyProxy

If you are still having problems, here's how to install the modules manually:

  1. Go to the ActiveState Package Repository at http://www.ActiveState.com/packages/
  2. Get the appropriate zip files (e.g., Storable.zip, GD.zip, etc.) and put them in a temporary directory.
  3. Unzip them. You can unzip them with the unzip utility provided with the GAMS-X distribution. You should see files with the extension ppd.
  4. Type
    PPM install ?.ppd
    
    where ? is the package name (e.g., Storable) from a command prompt.

You can also get the packages on this web site, though I make no promises that they are current20:

  1. Storable.zip
  2. GD.zip
  3. GIFgraph.zip
  4. Tk.zip

9.2.2  Installing GAMS-X

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:

Can't locate ?.pm in @INC (@INC contains: /usr/perl/lib /usr/perl/site/lib .).
BEGIN failed--compilation aborted.

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

perl -V

at the command prompt.

9.2.3  General

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

C:\Winnt\Profiles\YourUserName\Start Menu\Programs\GAMS-X

Question 5 When I try to use GAMS-X I receive this (cryptic) message:

Can't locate ?.pm in @INC (@INC contains: /usr/perl/lib /usr/perl/site/lib .).
BEGIN failed--compilation aborted.

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

perl -V

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:

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.

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:

C:\>set HTTP_proxy=MyProxy

C:\>echo %HTTP_proxy%
MyProxy

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!).

9.2.4  GAMS-Tk

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.

9.2.5  GAMS-CGI

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 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.

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:

use CGI;

$cgi = new CGI;

print $cgi->header;
print "Hello World!\n";

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

HKEY_LOCAL_MACHINE
	SYSTEM
		CurrentControlSet
			Services
				W3SVC
					Parameters
						Script Map

There should already be a .idc key there. Simply add a .pl key with a value like

"C:\Perl\bin\perl.exe %s %s"

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:

  1. Your server is configured to recognize *.pl files as Perl files. With Apache, this is accomplished through the shebang (#) at the top of gams-cgi.pl, and Microsoft IIS should automatically recognize Perl files if ActiveState Perl is installed.
  2. The header is of the correct form. Some servers require nonparsed headers while others do not. If you are using the wrong type of header, you may receive a message saying something to the effect of ``malformed header.'' Change the configuration variable nph (see section 6.4.1) from a 0 (false) to a 1 (true) or vice versa if you think this may be the problem.

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

TkOn=1

to read

TkOn=0

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.

9.3  Known ActivePerl/Tk Bugs

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.

9.4  Known GAMS-X Bugs

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.

Appendix A
Data Structures

A.1  ModelState

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:

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";

}

See also section .

A.2  UserState

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:

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

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:

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"; 
}

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:

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" 
}

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:

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" 
}

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:

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";

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).

See also the Cases method, section .

A.2.2  Casebooks

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:

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" }

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:

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

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:

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" 
}

Note that the inputs in the UserState list of inputs is used to generate the data structure returned by the Inputs method (see ).

A.2.4  Outputs

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:

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" 
}

Note that the outputs in the UserState list of outputs is used to generate the data structure returned by the Outputs method (see ).

A.2.5  Plots

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:

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";

Note that the plots in the UserState list of plots is used to generate the data structure returned by the Plots method (see ).

Appendix B
GAMS-Ini Methods

From the GAMS-X Initialization File

Shebang

The shebang used by the Apache server and Unix-based platforms to identify the location of the Perl executable

GXRoot

The GAMS-X root directory

GXDir

The GAMS-X public HTML directory

CGIDir

The root directory for CGI executable files

CGILoc

The virtual CGI directory

PBin

The Perl binary directory

PLib

The Perl library directory

GDir

The GAMS root directory

Browser

A web browser executable (used by GAMS-Tk)

TextEditor

A text editor executable (used by GAMS-Tk)

TkOn

Indicates whether GAMS-Tk is currently in operation: 1 = On, 0 = Off

TkRows

The number of rows of inputs and outputs in the GAMS-Tk casebook table allowed before rows are scrolled. Default = 20.

TkColumns

The number of columns of cases in the GAMS-Tk casebook table allowed before columns are scrolled. Default = 10.

CGIEnabled

Indicates whether GAMS-CGI is installed at this GAMS-X site. 0=No, 1=Yes.

Organization

The organization affiliated with this GAMS-X site. No default.

WebmasterEmail

The email address of the GAMS-CGI webmaster. No default.

Pause

Indicates whether the GAMS-CGI site is currently paused. 1 = Paused, 0 = Not Paused. Default = 0.

Bypass

Indicates whether the GAMS-CGI bypasses the user login for existing users. 1 = Bypass, 0 = No Bypass. Default = 0.

Background

An image that can be displayed as the GAMS-CGI default background; e.g., MyImage.gif No default.

BGColor

The default background color of GAMS-CGI pages. Default = #D7CBBB

Logo

The logo that appears on the GAMS-CGI login page. Default = gams-cgi.gif

LogoHeight

The height of the logo that appears on the GAMS-CGI login page. Default = 95

LogoWidth

The width of the logo that appears on the GAMS-CGI login page. Default = 126

nph

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).

GXHome

The GAMS-X homepage from which the URLs of the GAMS-X manual are derived. Default = http://www.gams.com/gams-x.

From the GAMS-Ini Module Directly

Owner

Returns the current owner (only defined in the Unix environment).

GPLib

Returns the Perl GAMS library containing the GAMS::CGI, GAMS::Ini, and GAMS::Tools modules.

GXLoc

Returns the GAMS-X virtual directory (e.g., http://economics.colorado.edu/gams-x).

UserRoot

Returns the users' root directory.

UserDir

Returns the users' public HTML directory.

UserLoc

Returns the users' virtual directory.

ModelRoot

Returns the Models' root directory.

ModelDir

Returns the Models' public HTML directory.

modeloc

Returns the Models' virtual directory.

Action

Returns the HTML form action for the current GAMS-CGI script.

ImageLoc

Returns the GAMS-X HTML image directory.

Daemon

Returns the file name of the GAMS-CGI daemon.

IniFile

Returns the file name of the GAMS-Ini module.

LogFile

Returns the file name of the GAMS-X log.

PauseFile

Returns the file containing the message returned to users when GAMS-CGI is paused.

XDat

Returns the name of the default GAMS-X data file.

Job

The name of the append file containing the pending GAMS-X cases. Used by the Solver method and the GAMS-CGI daemon

JobFile

The name of the batch file containing the pending GAMS-X cases. Used by the Solver method and the GAMS-CGI daemon

UserHash

The name of the file that contains the data returned by the GAMS method Users.

ModelHash

The name of the file that contains the data returned by the GAMS method Models.

Profile

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.

StateFile

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.

XCfg

The name of the GAMS-X configuration file, generated whenever a model is first installed in GAMS-X.

XConfig

CGIRoot

The web server CGI directory

XDir

The GAMS-X working directory. This is established as a subdirectory of any model installed in GAMS-X.

CaseDir

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.

ListingsDir

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.

WorkingDir

The name of the GAMS-X working directory which can be used as a repository for models being installed on site.

TemporaryDir

The name of the GAMS-X temporary directory.

Configuration

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";
  }

Configure

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 );

Appendix C
GAMS Methods

The GAMS Base Class

NAME

GAMS The GAMS-X Base Class

SYNOPSIS

GAMS - General Algebraic Modeling System Base Class

Supports a set of methods for administering GAMS models. Inherited by the GAMS::CGI, GAMS::Tk, and GAMS::Tools packages.

GAMS METHODS

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.

new

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.

Log( string );

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!");

Set( Key1 = > Value1, Key2 = > Value2, ... )

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.

Users

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!";
  }

UserProfile( [User] )

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'};

UserID( [User] )

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;

UserState( [User, Model] )

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

Models

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!";
  }

ModelState( [Model] )

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}

Cases( [User, Model] )

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.

Casebooks( [User, Model] )

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

Inputs( [User, Model] )

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.

Outputs( [User, Model] )

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.

Plots( [User,Model] )

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};

PlotFile( [User,Model,Casebook,Plot] )

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.

PlotURL( [User,Model,Casebook,Plot] )

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;

ReviseDescription( Description )

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.' );

NewCasebook( [User,Model,Casebook,Description] )

Creates a new casebook with name Case and description Description for user User, model Model.

DeleteCasebook( [User,Model,Casebook] )

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.

NewCase( [User,Model,Case,CaseInputs] )

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
             };

ImportCase( [User,Model,Casebook,Case] )

Imports the case with name Case into the casebook named Casebook.

RemoveCase( [User,Model,Casebook,Case] )

Removes the case with name Case from the casebook with name Casebook from the model Model account for user User.

DeleteCase( [User,Model,Case] )

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.

Book( [User,Model,Casebook,Case] )

Puts case $Case into casebook Casebook for user User, model Model.

Clear

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.

PreserveStates

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.

Quit

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.

Kill( [User] )

Kills user User, removing that account from GAMS-X. Example:

  $GAMS->Kill( 'Grog' );

CasebookIndex( [User,Model,Casebook] )

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";

CasebookCaseIndex( [User,Model,Casebook,Case] )

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";

CaseIndex( [User,Model,Casebook,Case] );

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";

PlotIndex( [User,Model,Casebook,Plot] );

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";

Solved

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";

Unsolved

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";

Error

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";

TotalSolved

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).

TotalUnsolved

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";

TotalError

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";

MultiPlot( [File,User,Model,Cases,Plots,PlotOptions] )

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 }
   );

CasebookPlots( [User,Model,Casebook] )

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' );

AddUser( [User,Password,PasswordConfirmation,Affiliation,Email] )

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;

Encrypt( String )

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.

OpenLog

Opens the GAMS-X log file and prints a time stamp.

CloseLog

Closes the GAMS-X log file.

ReadSolution( [User,Model,Case] )

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.

Solver

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.

Appendix D
GAMS-Tools Methods

NAME

GAMS-Tools

SYNOPSIS

GAMS::Tools - Additional tools for installing and uninstalling models and other administrative tasks

new

Creates a new GAMS::Tools object. Example:

  use GAMS::Tools;
  $GAMS = new GAMS::Tools;

WriteData( File[,User,Model] )

Writes a GAMS-X data file for the current user and model to File. See the Install method below.

Browse( URL )

Starts a web browser process with URL as an argument. Example:

  $GAMS->Browse( 'http://www.gams.com' );

TextEdit( File )

Starts a text editor with File as an argument. Example:

  $GAMS->TextEdit( 'C:\gams-x\working\Ramsey\Ramsey.gms' );

CasebookHTML( [User,Model,Casebook] )

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`;

CasebookLaTeX( [User,Model,Casebook] )

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`;

CaseListing( Tag[,Model] )

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 );

Install( Model,Description,GAMSFile[,Documentation,DataFile] )

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'
   );

Appendix E
GAMS-Script Methods

NAME

GAMS-Script

SYNOPSIS

GAMS::Script - Used for creating GAMS-X scripts - Combines all of the major GAMS-X modules and verifies before execution that there are no conflicts with currently running processes

new

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;

Appendix F
GAMS-Tk Methods

NAME

GAMS::Tk The GAMS-Tk Base Class

SYNOPSIS

GAMS::Tk - General Algebraic Modeling System Tcl/Tk Interface

Supports a visual environement for administering GAMS models.

GAMS-Tk METHODS

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;

new

Returns the GAMS::Tk object. Example:

   $GAMS->new;

Start( [User,Model,Casebook] )

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;

Appendix G
GAMS-CGI Methods

Base Class Methods

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:

NAME

GAMS::CGI The GAMS-CGI Base Class

SYNOPSIS

GAMS::CGI - General Algebraic Modeling System Common Gateway Interface

Supports a set of methods for administering web sites based on GAMS models.

GAMS-CGI METHODS

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:

new

Creates a new GAMS::CGI object. Example:

  use GAMS::CGI;
  $GAMS = new GAMS::CGI;

{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.

Gripe( string )

Returns the error message string to the user's browser. Example:

  $GAMS->Gripe( "Only Grog may use this site!" ) unless $GAMS->User eq 'Grog';

Greeting

Returns the GAMS-CGI Login Page. Example:

   $GAMS->Greeting;

Login

Logs a user in and validates the user's account from his login browser for 3 hours. Example:

   $GAMS->Login;

NewUser

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>

NewUserHTML

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;

AddUser

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>

EditAccountInformation

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>

EditUser

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>

RemoveAccount

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>

WriteModelIndex

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>

WriteModelIndexHTML

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;
   }

ModelIndexHTML

Returns the HTML that makes up the model index; i.e., the listing of models that appears on the WriteModelIndexHTML document. Example:

   $GAMS->ModelIndexHTML;

WriteCasebookIndex

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>

WriteCasebookIndexHTML

Returns the HTML text that is printed when the WriteCasebookIndex method is called. Example:

   $GAMS->WriteCasebookIndexHTML;

CasebookIndexMenuHTML

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;

WriteCasebook

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>

WriteCasebookHTML

   $GAMS->WriteCasebookHTML;

CopyHTML

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>

CopyText

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>

AddCase

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>

CreateCasebookJava

Returns a java script used to check user entry when a casebook is created.

   $GAMS->CreateCasebookJava;

ImportHTML

Returns the HTML for a button/dropdown list pair that can be used to import a case into the current casebook.

   $GAMS->ImportHTML;

ImportJava

Returns a java script used to check user entry when using the ImportHTML case import.

   $GAMS->ImportJava;

HelpButton

Returns the HTML for a button that takes a user to the GAMS-X help files.

   $GAMS->HelpButton;

ViewDocumentationButton

Returns the HTML for a button that takes a user to the GAMS documentation for the current model.

   $GAMS->ViewDocumentationButton;

RemoveAccountButton

Returns a button that can be used to remove the current user's account.

   $GAMS->RemoveAccountButton;

ViewGAMSCodeButton

ViewDocumentationButton

Returns the HTML for a button that presents a user with the GAMS code for the current model.

   $GAMS->ViewGAMSCodeButton;

CasebookIndexButton

Returns the HTML for a button that gives the current user the casebook index for the current model.

   $GAMS->CasebookIndexButton;

WriteCasebookButton

Returns the HTML for a button that gives the current user the current casebook for the current model.

   $GAMS->WriteCasebookButton;

CaseListingButton( Case )

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' );

ModelIndexButton

Returns the HTML for a button that gives the current user the model index.

   $GAMS->ModelIndexButton;

CasebookIndexMenuHTML

Returns the menu of buttons that appears at the top of the Casebook Index page for the current user, casebook, and model.

   $GAMS->CasebookIndexMenuHTML;

CasebookMenuHTML

Returns the menu of buttons that appears at the top of the Casebook page for the current user, casebook, and model.

   $GAMS->CasebookMenuHTML;

ReviseDescriptionHTML

Returns HTML that can be used to revise the description of the current user's current casebook in the current model.

   $GAMS->ReviseDescriptionHTML;

ReviseDescriptionJava

Returns the Java error-checking script used in conjunction with the ReviseDescriptionHTML.

   $GAMS->ReviseDescriptionJava;

CreateCaseJava

Returns the Java error-checking script used in conjunction with case creation.

   $GAMS->CreateCaseJava;

ReturnButton

   $GAMS->ReturnButton;

Confirm( string )

Presents the user with a confirmation consisting of the passed string.

   $GAMS->Confirm;

EditProfile

   $GAMS->EditProfile;

modelibraryHTML

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;

Greeting

Returns the GAMS-CGI greeting page from which users may log in, create an account, or edit their current account information.

   $GAMS->Greeting;

GreetingJava

Returns the Java error-checking script used in conjunction with the GAMS-CGI greeting page. Example:

   $GAMS->GreetingJava;

GreetingHTML

Returns the HTML that makes up the GAMS-CGI greeting page. Example:

   $GAMS->GreetingHTML;

BodyHTML

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!

LogoHTML

Returns the HTML used to present the GAMS-CGI logo at the head of the GAMS-CGI greeting page. Example:

   $GAMS->LogoHTML;

ModelIndexGreeting

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>" 
   );

CasebookIndexGreeting

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>" 
   );

CasebookGreeting

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>" 
   );

WebmasterHTML

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 => '' );

CGI Methods

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.

NAME

CGI - Simple Common Gateway Interface Class

SYNOPSIS

  # 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;
   }

ABSTRACT

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/

DESCRIPTION

PROGRAMMING STYLE

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

CALLING CGI.PM ROUTINES

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:

  1. Use another name for the argument, if one is available. For example, -value is an alias for -values.

  2. Change the capitalization, e.g. -Values

  3. Put quotes around the argument name, e.g. '-values'

Many routines will do something useful with a named argument that it doesn't recognize. For example, you can produce non-standard HTTP header fields by providing them as named arguments:
  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".

CREATING A NEW QUERY OBJECT (OBJECT-ORIENTED STYLE):

     $query = new CGI;

This will parse the input (from both POST and GET methods) and store it into a perl5 object called $query.

CREATING A NEW QUERY OBJECT FROM AN INPUT FILE

     $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({});

FETCHING A LIST OF KEYWORDS FROM THE QUERY:

     @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.

FETCHING THE NAMES OF ALL THE PARAMETERS PASSED TO YOUR SCRIPT:

     @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).

FETCHING THE VALUE OR VALUES OF A SINGLE NAMED PARAMETER:

    @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.

SETTING THE VALUE (S) OF A NAMED PARAMETER:

    $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');

APPENDING ADDITIONAL VALUES TO A NAMED PARAMETER:

   $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.

IMPORTING ALL PARAMETERS INTO A NAMESPACE:

   $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.

DELETING A PARAMETER COMPLETELY:

    $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.

DELETING ALL PARAMETERS:

   $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.

DIRECT ACCESS TO THE PARAMETER LIST:

   $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.

SAVING THE STATE OF THE SCRIPT TO A FILE:

    $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().

USING THE FUNCTION-ORIENTED INTERFACE

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:

:cgi

Import all CGI-handling methods, such as param(), path_ info() and the like.

:form

Import all fill-out form generating methods, such as textfield().

:html2

Import all methods that generate HTML 2.0 standard elements.

:html3

Import all methods that generate HTML 3.0 proposed elements (such as < table > , < super > and < sub > ).

:netscape

Import all methods that generate Netscape-specific HTML extensions.

:html

Import all HTML-generating shortcuts (i.e. 'html2' + 'html3' + 'netscape')...

:standard

Import ßtandard" features, 'html2', 'html3', 'form' and 'cgi'.

:all

Import all the available methods. For the full list, see the CGI.pm code, where the variable %TAGS is defined.

If you import a function name that is not part of CGI.pm, the module will treat it as a new HTML tag and generate the appropriate subroutine. You can then use it like any other HTML tag. This is to provide for the rapidly-evolving HTML ßtandard." For example, say Microsoft comes out with a new tag called < GRADIENT > (which causes the user's desktop to be flooded with a rotating gradient fill until his machine reboots). You don't need to wait for a new version of CGI.pm to start using it immeidately:
   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;

PRAGMAS

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:

-any

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.

-compile

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).

-nph

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.

-autoload

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.

-no_ debug

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.

-private_ tempfiles

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

GENERATING DYNAMIC DOCUMENTS

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.

CREATING A STANDARD HTTP HEADER:

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.

GENERATING A REDIRECTION HEADER

   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.

CREATING THE HTML DOCUMENT HEADER

   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:

Parameters:

1.
The title

2.
The author's e-mail address (will create a < LINK REV="MADE" > tag if present

3.
A 'true' flag if you want to include a < BASE > tag in the header. This helps resolve relative addresses to absolute ones when the document is moved, but makes the document hierarchy non-portable. Use with care!

4, 5, 6...

Any other parameters you want to include in the < BODY > tag. This is a good place to put Netscape extensions, such as colors and wallpaper patterns.

ENDING THE HTML DOCUMENT:

        print $query->end_html

This ends an HTML document by printing the < /BODY > < /HTML > tags.

CREATING A SELF-REFERENCING URL THAT PRESERVES STATE INFORMATION:

    $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;

OBTAINING THE SCRIPT'S URL

    $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:

-absolute

If true, produce an absolute URL, e.g.

    /path/to/script.cgi

-relative

Produce a relative URL. This is useful if you want to reinvoke your script with different parameters. For example:

    script.cgi

-full

Produce the full URL, exactly as if called without any arguments. This overrides the -relative and -absolute arguments.

-path (-path_ info)

Append the additional path information to the URL. This can be combined with -full, -absolute or -relative. -path_ info is provided as a synonym.

-query (-query_ string)

Append the query string to the URL. This can be combined with -full, -absolute or -relative. -query_ string is provided as a synonym.

CREATING STANDARD HTML ELEMENTS:

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;

PROVIDING ARGUMENTS TO HTML SHORTCUTS

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="" >

THE DISTRIBUTIVE PROPERTY OF HTML SHORTCUTS

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'])
           ]
           )
        );

HTML SHORTCUTS AND LIST INTERPOLATION

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.

NON-STANDARD HTML SHORTCUTS

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.

CREATING FILL-OUT FORMS:

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 &Aacute;, 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);
                             

CREATING AN ISINDEX TAG

   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.

STARTING AND ENDING A FORM

    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:

application/x-www-form-urlencoded

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.

multipart/form-data

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.

For compatibility, the startform() method uses the older form of encoding by default. If you want to use the newer form of encoding by default, you can call start_ multipart_ form() instead of startform().

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.

CREATING A TEXT FIELD

    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.

Parameters

1.
The first parameter is the required name for the field (-name).

2.
The optional second parameter is the default starting value for the field contents (-default).

3.
The optional third parameter is the size of the field in characters (-size).

4.
The optional fourth parameter is the maximum number of characters the field will accept (-maxlength).

As with all these methods, the field will be initialized with its previous contents from earlier invocations of the script. When the form is processed, the value of the text field can be retrieved with:
       $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.

CREATING A BIG TEXT FIELD

   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() .

CREATING A PASSWORD FIELD

   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() .

CREATING A FILE UPLOAD FIELD

    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().

Parameters

1.
The first parameter is the required name for the field (-name).

2.
The optional second parameter is the starting value for the field contents to be used as the default file name (-default).

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.

3.
The optional third parameter is the size of the field in characters (-size).

4.
The optional fourth parameter is the maximum number of characters the field will accept (-maxlength).

When the form is processed, you can retrieve the entered filename by calling param() .
       $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.

CREATING A POPUP MENU

   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.

  1. The required first argument is the menu's name (-name).

  2. The required second argument (-values) is an array reference containing the list of menu items in the menu. You can pass the method an anonymous array, as shown in the example, or a reference to a named array, such as "\@foo".

  3. The optional third parameter (-default) is the name of the default menu choice. If not specified, the first item will be the default. The values of the previous choice will be maintained across queries.

  4. The optional fourth parameter (-labels) is provided for people who want to use different values for the user-visible label inside the popup menu nd the value returned to your script. It's a pointer to an associative array relating menu values to user-visible labels. If you leave this parameter blank, the menu values will be displayed by default. (You can also leave a label undefined if you want to).

When the form is processed, the selected value of the popup menu can be retrieved using:
      $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.

CREATING A SCROLLING LIST

   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.

Parameters:

1.
The first and second arguments are the list name (-name) and values (-values). As in the popup menu, the second argument should be an array reference.

2.
The optional third argument (-default) can be either a reference to a list containing the values to be selected by default, or can be a single value to select. If this argument is missing or undefined, then nothing is selected when the list first appears. In the named parameter version, you can use the synonym "-defaults" for this parameter.

3.
The optional fourth argument is the size of the list (-size).

4.
The optional fifth argument can be set to true to allow multiple simultaneous selections (-multiple). Otherwise only one selection will be allowed at a time.

5.
The optional sixth argument is a pointer to an associative array containing long user-visible labels for the list items (-labels). If not provided, the values will be displayed.

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');

JAVASCRIPTING: scrolling_ list() recognizes the following event handlers: -onChange, -onFocus, -onMouseOver, -onMouseOut and -onBlur. See textfield() for the description of when these handlers are called.

CREATING A GROUP OF RELATED CHECKBOXES

   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.

Parameters:

1.
The first and second arguments are the checkbox name and values, respectively (-name and -values). As in the popup menu, the second argument should be an array reference. These values are used for the user-readable labels printed next to the checkboxes as well as for the values passed to your script in the query string.

2.
The optional third argument (-default) can be either a reference to a list containing the values to be checked by default, or can be a single value to checked. If this argument is missing or undefined, then nothing is selected when the list first appears.

3.
The optional fourth argument (-linebreak) can be set to true to place line breaks between the checkboxes so that they appear as a vertical list. Otherwise, they will be strung together on a horizontal line.

4.
The optional fifth argument is a pointer to an associative array relating the checkbox values to the user-visible labels that will be printed next to them (-labels). If not provided, the values will be used as the default.

5.
HTML3-compatible browsers (such as Netscape) can take advantage of the optional parameters -rows, and -columns. These parameters cause checkbox_ group() to return an HTML3 compatible table containing the checkbox group formatted with the specified number of rows and columns. You can provide just the -columns parameter if you wish; checkbox_ group will calculate the correct number of rows for you.

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.

When the form is processed, all checked boxes will be returned as a list under the parameter name 'group_ name'. The values of the ön" checkboxes can be retrieved with:
      @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.

CREATING A STANDALONE CHECKBOX

    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.

Parameters:

1.
The first parameter is the required name for the checkbox (-name). It will also be used for the user-readable label printed next to the checkbox.

2.
The optional second parameter (-checked) specifies that the checkbox is turned on by default. Synonyms are -selected and -on.

3.
The optional third parameter (-value) specifies the value of the checkbox when it is checked. If not provided, the word ön" is assumed.

4.
The optional fourth parameter (-label) is the user-readable label to be attached to the checkbox. If not provided, the checkbox name is used.

The value of the checkbox can be retrieved using:
    $turned_on = $query->param('checkbox_name');

JAVASCRIPTING: checkbox() recognizes the -onClick parameter. See checkbox_ group() for further details.

CREATING A RADIO BUTTON GROUP

   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)

Parameters:

1.
The first argument is the name of the group and is required (-name).

2.
The second argument (-values) is the list of values for the radio buttons. The values and the labels that appear on the page are identical. Pass an array reference in the second argument, either using an anonymous array, as shown, or by referencing a named array as in "\@foo".

3.
The optional third parameter (-default) is the name of the default button to turn on. If not specified, the first item will be the default. You can provide a nonexistent button name, such as "-" to start up with no buttons selected.

4.
The optional fourth parameter (-linebreak) can be set to 'true' to put line breaks between the buttons, creating a vertical list.

5.
The optional fifth parameter (-labels) is a pointer to an associative array relating the radio button values to user-visible labels to be used in the display. If not provided, the values themselves are displayed.

6.
HTML3-compatible browsers (such as Netscape) can take advantage of the optional parameters -rows, and -columns. These parameters cause radio_ group() to return an HTML3 compatible table containing the radio group formatted with the specified number of rows and columns. You can provide just the -columns parameter if you wish; radio_ group will calculate the correct number of rows for you.

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.

When the form is processed, the selected radio button can be retrieved using:
      $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);

CREATING A SUBMIT BUTTON

   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.

Parameters:

1.
The first argument (-name) is optional. You can give the button a name if you have several submission buttons in your form and you want to distinguish between them. The name will also be used as the user-visible label. Be aware that a few older browsers don't deal with this correctly and never send back a value from a button.

2.
The second argument (-value) is also optional. This gives the button a value that will be passed to your script in the query string.

You can figure out which button was pressed by using different values for each one:
     $which_one = $query->param('button_name');

JAVASCRIPTING: radio_ group() recognizes the -onClick parameter. See checkbox_ group() for further details.

CREATING A RESET BUTTON

   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.

CREATING A DEFAULT BUTTON

   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.

CREATING A HIDDEN FIELD

        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.

Parameters:

1.
The first argument is required and specifies the name of this field (-name).

2.
The second argument is also required and specifies its value (-default). In the named parameter style of calling, you can provide a single value here or a reference to a whole list

Fetch the value of a hidden field this way:
     $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');

CREATING A CLICKABLE IMAGE BUTTON

     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.

Parameters:

1.
The first argument (-name) is required and specifies the name of this field.

2.
The second argument (-src) is also required and specifies the URL

3. The third option (-align, optional) is an alignment type, and may be TOP, BOTTOM or MIDDLE

Fetch the value of the button this way: $x = $query- > param ('button_ name.x'); $y = $query- > param ('button_ name.y');

CREATING A JAVASCRIPT ACTION BUTTON

     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 COOKIES

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:

  1. an expiration time

    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.

  2. a domain

    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.

  3. a path

    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.

  4. a ßecure" flag

    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.

The interface to Netscape cookies is the cookie() method:
    $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:

-name

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.

-value

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);

-path

The optional partial path for which this cookie will be valid, as described above.

-domain

The optional partial domain for which this cookie will be valid, as described above.

-expires

The optional expiration date for this cookie. The format is as described in the section on the header() method:

        "+1h"  one hour from now

-secure

If set to true, this cookie will only be used within a secure SSL session.

The cookie created by cookie() must be incorporated into the HTTP header within the string returned by the header() method:
        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.

WORKING WITH NETSCAPE FRAMES

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:

  1. Create a < Frameset > document

    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
    

  2. Specify the destination for the document in the HTTP header

    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.

  3. Specify the destination for the document in the < FORM > tag

    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.

The script "frameset.cgi" in the examples directory shows one way to create pages in which the fill-out form and the response live in side-by-side frames.

LIMITED SUPPORT FOR CASCADING STYLE SHEETS

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;

DEBUGGING

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"

DUMPING OUT ALL THE NAME/VALUE PAIRS

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";

FETCHING ENVIRONMENT VARIABLES

Some of the more useful environment variables can be fetched through this interface. The methods are as follows:

accept()

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.

raw_ cookie()

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.

user_ agent()

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);

path_ info()

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.

path_ translated()

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.

remote_ host()

Returns either the remote host name or IP address. if the former is unavailable.

script_ name() Return the script name as a partial URL, for self-refering scripts.

referer()

Return the URL of the page the browser was viewing prior to fetching your script. Not available for all browsers.

auth_ type ()

Return the authorization/verification method in use for this script, if any.

server_ name ()

Returns the name of the server, usually the machine's host name.

virtual_ host ()

When using virtual hosts, returns the name of the host that the browser attempted to contact

server_ software ()

Returns the server software and version number.

remote_ user ()

Return the authorization/verification name used for user verification, if this script is protected.

user_ name ()

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!

request_ method()

Returns the method used to access your script, usually one of 'POST', 'GET' or 'HEAD'.

USING NPH SCRIPTS

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:

In the use statement

Simply add the "-nph" pragmato the list of symbols to be imported into your script:

      use CGI qw(:standard -nph)

By calling the nph() method:

Call nph() with a non-zero parameter at any point after using CGI.pm in your program.

      CGI->nph(1)

By using -nph parameters in the header() and redirect() statements:
      print $q->header(-nph=>1);

SERVER PUSH

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.

multipart_ init() multipart_ init(-boundary= > $boundary);

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()
  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()
  multipart_end()

End a part. You must remember to call multipart_ end() once for each multipart_ start() .

Users interested in server push applications should also have a look at the CGI::Push module.

AVOIDING DENIAL OF SERVICE ATTACKS

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:

$CGI::POST_ MAX

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.

$CGI::DISABLE_ UPLOADS

If set to a non-zero value, this will disable file uploads completely. Other fill-out form values will work as usual.

You can use these variables in either of two ways.

1. On a script-by-script basis

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

2. Globally for all scripts

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() .

Since an attempt to send a POST larger than $POST_ MAX bytes will cause a fatal error, you might want to use CGI::Carp to echo the fatal error message to the browser window as shown in the example above. Otherwise the remote user will see only a generic Ïnternal Server" error message. See the the CGI::Carp manpage manual page for more details.

COMPATIBILITY WITH CGI-LIB.PL

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.

AUTHOR INFORMATION

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

Address bug reports and comments to: lstein@genome.wi.mit.edu

CREDITS

Thanks very much to:

Matt Heffron (heffron@falstaff.css.beckman.com)

James Taylor (james.taylor@srs.gov)

Scott Anguish < sanguish@digifix.com >

Mike Jewell (mlj3u@virginia.edu)

Timothy Shimmin (tes@kbs.citri.edu.au)

Joergen Haegg (jh@axis.se)

Laurent Delfosse (delfosse@csgrad1.cs.wvu.edu)

Richard Resnick (applepi1@aol.com)

Craig Bishop (csb@barwonwater.vic.gov.au)

Tony Curtis (tc@vcpc.univie.ac.at)

Tim Bunce (Tim.Bunce@ig.co.uk)

Tom Christiansen (tchrist@convex.com)

Andreas Koenig (k@franz.ww.TU-Berlin.DE)

Tim MacKenzie (Tim.MacKenzie@fulcrum.com.au)

Kevin B. Hendricks (kbhend@dogwood.tyler.wm.edu)

Stephen Dahmen (joyfire@inxpress.net)

Ed Jordan (ed@fidalgo.net)

David Alan Pisoni (david@cnation.com)

Doug MacEachern (dougm@opengroup.org)

Robin Houston (robin@oneworld.org)

...and many many more...

for suggestions and bug fixes.

A COMPLETE EXAMPLE OF A SIMPLE FORM-BASED SCRIPT

        #!/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
        }

BUGS

This module has grown large and monolithic. Furthermore it's doing many things, such as handling URLs, parsing CGI input, writing HTML, etc., that are also done in the LWP modules. It should be discarded in favor of the CGI::* modules, but somehow I continue to work on it.

Note that the code is truly contorted in order to avoid spurious warnings when programs are run with the -w switch.

SEE ALSO

the CGI::Carp manpage, the URI::URL manpage, the CGI::Request manpage, the CGI::MiniSvr manpage, the CGI::Base manpage, the CGI::Form manpage, the CGI::Apache manpage, the CGI::Switch manpage, the CGI::Push manpage, the CGI::Fast manpage

Appendix H
Plotting Options

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
 

H.1  GIFgraph

NAME

GIFgraph - Graph Plotting Module for Perl 5

DESCRIPTION

The following graph types with axes are defined:

lines

Create a line chart.

bars

Create a bar chart.

area

Create a graph, representing the data as areas under a line.

Additional types:

pie

Create a pie chart.

OPTIONS

Options for all graphs

height

The height of the graph. Default: 300.

width

The width of the graph. Default: 400.

t_ margin, b_ margin, l_ margin, r_ margin

Top, bottom, left and right margin of the GIF. These margins will be left blank. Default: 0 for all.

logo

Name of a logo file. This should be a GIF file. Default: no logo.

logo_ resize, logo_ position

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'.

transparent

If set to a true value, the produced GIF will have the background colour marked as transparent (see also option bgclr ). Default: 1.

interlaced

If set to a true value, the produced GIF will be interlaced. Default: 1.

bgclr, fgclr, textclr, labelclr, axislabelclr, accentclr

Background, foreground, text, label, axis label and accent colours.

Options for graphs with axes.

options for bars , lines , and area charts.

long_ ticks, tick_ length

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.

x_ ticks

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.

y_ tick_ number

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.

y_ number_ format

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.

x_ label_ skip, y_ label_ skip

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.

x_ all_ ticks

Force a print of all the x ticks, even if x_ label_ skip is set to a value Default: 0.

x_ label_ position

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

y_ label_ position

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

x_ labels_ vertical

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.

x_ plot_ values, y_ plot_ values

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.

box_ axis

Draw the axes as a box, if true. Default: 1.

two_ axes

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.

zero_ axis

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.

zero_ axis_ only

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.

y_ max_ value, y_ min_ value

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.

axis_ space

This space will be left blank between the axes and the text. Default: 4.

overwrite

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.

Options for graphs with a numerical X axis

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:

x_ tick_ number

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.

x_ min_ value, x_ max_ value

The minimum and maximum value to use for the X axis. Default: computed.

x_ number_ format

See y_ number_ format

x_ label_ skip

See y_ label_ skip

Options for graphs with bars

bar_ spacing

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

Options for graphs with lines

line_ types

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)

line_ type_ scale

Controls the length of the dashes in the line types. default: 6.

line_ width

The width of the line used in lines and linespoints graphs, in pixels. Default: 1.

Options for graphs with points

markers

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]

marker_ size

The size of the markers used in points and linespoints graphs, in pixels. Default: 4.

Graph legends (axestype graphs only)

At the moment legend support is minimal.

Options

legend_ placement

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.

legend_ spacing

The number of pixels to place around a legend item, and between a legend 'marker' and the text. Default: 4

legend_ marker_ width, legend_ marker_ height

The width and height of a legend 'marker' in pixels. Defaults: 12, 8

lg_ cols

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

Options for pie graphs

  1. d

    If set to a true value, the pie chart will be drawn with a 3d look. Default: 1.

  2. pie_ height

    The thickness of the pie when 3d is true. Default: 0.1 x GIF y size.

  3. start_ angle

    The angle at which the first data slice will be displayed, with 0 degrees being "6 o'clock". Default: 0.

NOTES

All references to colours in the options for this module have been shortened to clr. The main reason for this was that I didn't want to support two spellings for the same word ('colour' and 'color')

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.

AUTHOR

Martien Verbruggen

Contact info

email: mgjv@comdyn.com.au

Copyright

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.

H.2  Gnuplot

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 .

Appendix I
The GAMS-X Packing List

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

Appendix J
The Ramsey Model

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

Appendix K
example.pl

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;

Appendix L
gams-cgi.pl

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

Appendix M
The Disclaimer

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.

Appendix N
Terms and Conditions

This software is freely distributable under the terms and conditions of Perl itself and the GNU General Public License.

Bibliography

[]
Till, David, Teach Yourself Perl 5 in 21 Days, SAMS Publishing (1996).

[]
Schwartz, Randal L., and Tom Christiansen, Learning Perl, O'Reilly & Associates (1997).

[]
Wall, Larry, Tom Christiansen, and Randal L. Schwartz, Programming Perl, O'Reilly & Associates (1997).

[]
Nemeth, Evi, Garth Snyder, Scott Seebass, and Trent R. Hein, Unix System Administration Handbook, Prentice Hall (1995).

[]
Microsoft Windows NT Server Resource Kit: For Windows NT Server Version 4.0, Microsoft Press (1996).

Index (showing section)

_

Footnotes:

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.