Interchange Documentation (Full)
================================

icfull.1.2

This is the documentation for Interchange, all in one large file.

Interchange Advanced Topics
Interchange Catalog-Building Tutorial
Interchange Configuration
Interchange Database
Interchange Ecommerce Functions
Interchange Foundation Store
Interchange I18N Features
Interchange Templates
Interchange Tags Reference
Interchange Frequently Asked Questions
Interchange Upgrade Guide

line:

Interchange Ecommerce Functions
===============================

1. THE ORDER PROCESS
====================

Interchange has a completely flexible order basket and checkout
scheme. The foundation demo presents a common use of this process, in
the directory pages/ord -- the files are:

    basket.html      The order basket displayed by default
    checkout.html    The form where the customer enters their billing
                     and shipping info

               and in the directory etc:

    receipt.html     The receipt displayed to the customer
    report           The order report mailed to you
    mail_receipt     The customer's email copy (if requested)

It is not strictly necessary to display an order basket when an item
is ordered. If you specify a different page to be displayed that is
fine, but most customers will be confused if you don't give them an
indication that the order operation has succeeded.

Any order basket is an HTML FORM. It will have a number of variables
on it. At the minimum it must have an [item-list] to loop through the
items, and the quantity of each item must be set in some place on that
form. Any valid Interchange tags may be used on the page, and you may
use multiple item lists if necessary.

1.1. How to order an item
-------------------------

Interchange can either use a form-based order or a link-based order to
place an item in the shopping cart. The link-based order uses the
special [order item-code] tag:

[order code]

     named attributes:

             [order code="sku" quantity="n"* href="page"* cart="cartname"* base="table"*]
             * = optional parameters

     Expands into a hypertext link which will include the specified
     code in the list of products to order and display the order page.
     code should be a product SKU listed in one of the "products"
     tables, and is the only required parameter. quantity may be
     specified if more than one (the default) of the item should be
     placed in the cart. href allows some page other than the default
     order page to be displayed once the item has been added to the
     cart. cart selects the shopping cart the item will be placed in.
     The optional argument base constrains the order to a particular
     products file -- if not specified, all tables defined as products
     files will be searched in sequence for the item.



     Example:

       Order a [order TK112]Toaster</a> today.

     Note that this is the same as:

       Order a [page order TK112]Toaster</A> today.

     You can change frames for the order with:

       Order a <A HREF="[area order TK112]" TARGET=newframe>Toaster</A> today.

[/order]

     Expands into </a>. May be used to give the order tag the
     appearance of being a container tag, but neither necessary nor
     recommended.

To order with a form, you set the form variable mv_order_item to the
item-code/SKU and use the refresh action:

  <FORM ACTION="[process-target]" METHOD=POST>
  <INPUT TYPE=hidden  NAME="mv_todo"        VALUE="refresh">
  <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="TK112">

  Order <INPUT NAME="mv_order_quantity" SIZE=3 VALUE=1> toaster

  <INPUT TYPE=submit VALUE="Order!">
  </FORM>

You may batch select whole groups of items:

  <FORM ACTION="[process-target]" METHOD=POST>
  <INPUT TYPE=hidden  NAME="mv_todo"        VALUE="refresh">

  <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="TK112">
  <INPUT NAME="mv_order_quantity" SIZE=3> Standard Toaster

  <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="TK200">
  <INPUT NAME="mv_order_quantity" SIZE=3> Super Toaster

  <INPUT TYPE=submit VALUE="Order!">
  </FORM>

Items that have a quantity of zero (or blank) will be skipped, and
only items with a positive quantity will be placed in the basket.

You may also specify attributes like size or color at time of order
(see How to set up an order button).

1.2. How to set up an order link
--------------------------------

On a product display page, use:

    [order 00-0011]Order the Mona Lisa</a>

If coming from a search results or on-the-fly page, you may use the
generated [item-code] thusly:

    [order [item-code]]Order [item-field name]</a>

Bear in mind that if you have not reached the page via a search or
on-the-fly operation, [item-code] means nothing and will cause an
error.

1.3. How to set up an order button
----------------------------------

Interchange can order via form submission as well. This allows you to
order a product (or group of products) via a form button. In its
simplest form, it is:

    <FORM ACTION="[process-target]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
    <INPUT TYPE=submit VALUE="Order the Mona Lisa">
    </FORM>

The default quantity is one.  An initial quantity may be set by the
user by adding an mv_order_quantity variable:

     Number to order:<INPUT TYPE=text NAME=mv_order_quantity VALUE="1">

You can order multiple items by stacking the variables:

    <FORM ACTION="[process-target]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
    <INPUT TYPE=submit VALUE="Order the Mona Lisa with frame">
    </FORM>

Initial size or color may be set as well, provided UseModifier is set
up properly:

    <INPUT TYPE=hidden NAME=mv_order_size VALUE="L">

If the order is coming from a generated flypage, loop list, or search
results page, you can get a canned select box from the
[item-accessories size] or [item-accessories size] tag. See Item
Attributes.

1.4. How to set up an on-the-fly item
-------------------------------------

If you enable the catalog directive OnFly, setting it to the name of a
subroutine (or possibly a UserTag) that can handle its calls, then
Interchange will add items to the basket that are not in the product
database. Interchange supplies an internal onfly subroutine, which
will work according to the examples given below.

In catalog.cfg:

    OnFly  onfly

If your item code is not to be named mv_order_item then you must
perform a rename in the Autoload routine.

A basic link can be generated like:

    <a href="[area form="
            mv_todo=refresh
            mv_order_item=000101
            mv_order_fly=description=An on-the-fly item|price=100.01
    "]">Order item 000101</a>

The form parameter value mv_order_fly can contain any number of fields
which will set corresponding parameters in the item attributes. The
fields are separated by the pipe (|) character and contain
value-parameter pairs separated by an = sign. (These are URL-encoded
by the [area ...] or [page ...] tag, of course.) You can set a size,
color, or any other parameter.

The special attribute mv_price can be used in conjunction with the
CommonAdjust atom $ to set the price for checkout and display.

The [item-list] sub-tag [item-description], when used with an
item-list, will use the item attribute description to display in the
basket. Note that [item-field description] or [item-data products
description] will NOT work, as both of these tags reference an actual
field value for a record in the products table - not applicable for
on-the-fly items. Similarly, an attempt to generate a flypage for an
on-the-fly item ([page 000101], for example) will fail, resulting in
the display of the SpecialPage missing.

If you wish to set up a UserTag to process on-the-fly items, it should
accept a call of

    usertag(mv_item_code, mv_item_quantity, mv_order_fly)

The mv_item_code and mv_order_fly parameters are required to trigger
Interchange's add_item routine (along with mv_todo=refresh to set the
action).

The item will always act as if SeparateItems or mv_separate_items is
set.

Multiple items can be ordered at once by stacking the variables. If
there is only one mv_order_item instance, however, you can stack the
mv_order_fly variable so that all are concatenated together as with
the | symbol. So the above example could be done as:

    [area form="
            mv_todo=refresh
            mv_order_item=000101
            mv_order_fly=description=An on-the-fly item
            mv_order_fly=price=100.00
    "]

Multiple items would need multiple instances of mv_order_item with a
corresponding mv_order_fly for each mv_order_item. You can order both
000101 and 000101 as follows:

    [area form="
        mv_todo=refresh

        mv_order_item=000101
        mv_order_fly=description=An on-the-fly item|price=100.00

        mv_order_item=000102
        mv_order_fly=description=Another on-the-fly item|price=200.00
    "]

The following two forms correspond to the above two examples, in
order, with the slight refinement of adding a quantity:

  <FORM ACTION="[area process]" METHOD=POST>
        <INPUT TYPE=hidden NAME=mv_todo VALUE="refresh">
        <INPUT TYPE=hidden NAME=mv_order_item VALUE="000101">
        Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1">
        <INPUT TYPE=hidden NAME=mv_order_fly
                VALUE="description=An on-the-fly item|price=100.00">
        <INPUT TYPE=submit VALUE="Order button">
    </FORM>

   <FORM ACTION="[area process]" METHOD=POST>
        <INPUT TYPE=hidden NAME=mv_todo VALUE="refresh">
        <INPUT TYPE=hidden NAME=mv_order_item VALUE="000101">
        Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"><BR>
        <INPUT TYPE=hidden NAME=mv_order_fly
            VALUE="description=An on-the-fly item|price=100.00">
        <INPUT TYPE=hidden NAME=mv_order_item VALUE="000102">
        Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"><BR>
        <INPUT TYPE=hidden NAME=mv_order_fly
            VALUE="description=Another on-the-fly item|price=200.00">
        <INPUT TYPE=submit VALUE="Order two different with a button">
    </FORM>

1.5. Order Groups
-----------------

Interchange allows you to group items together, making a master item
and sub-items. This can be used to delete accessories or options when
the master item is deleted. In its simplest form, you order just one
master item and all subsequent items are sub-items.

    <FORM ACTION="[process-target]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
    <INPUT TYPE=submit VALUE="Order the Mona Lisa with frame">
    </FORM>

If you wish to stack more than one master item, then you must define
mv_order_group for all items, with either a 1 value (master) or 0
value (sub-item). A master owns all subsequent sub-items until the
next master is defined.

    <FORM ACTION="[process-target]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_todo VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011">
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="0">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a">
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="1">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="19-202">
    <INPUT TYPE=hidden NAME=mv_order_group VALUE="0">
    <INPUT TYPE=hidden NAME=mv_order_item VALUE="99-102">
    <INPUT TYPE=submit VALUE="Order items">
    </FORM>

When the master item 00-0011 is deleted from the basket, 00-0011a will
be deleted as well. And when 19-202 is deleted, then 99-102 will be
deleted from the basket.

     NOTE: Use of checkboxes for this type of thing can be hazardous,
     as they do not pass a value when unchecked.  It is preferable to
     use radio groups or select/drop-down widgets. If you must use
     checkboxes, be sure to explicitly clear mv_order_group and
     mv_order_item somewhere on the page which contains the form:

    [value name=mv_order_group set='']
    [value name=mv_order_item set='']

The attributes mv_mi and mv_si are set to the group and sub-item
status of each item.  The group, contained in the attribute mv_mi, is
a meaningless yet unique integer. All items in a group will have the
same value of mv_mi. The attribute mv_si is set to 0 if the item is a
master item, and 1 if it is a sub-item.

1.6. Basket display
-------------------

The basket page(s) are where the items are tracked and adjusted by the
customer. It is possible to have an unlimited number of basket pages.
It is also possible to have multiple shopping carts, as in buy or
sell. This allows a basket/checkout type of ordering scheme, with
custom order pages for items which have many accessories.

The name of the page to display can be configured in several ways:

1.   Set the SpecialPage order to the page to display when an item is
     ordered.

2.   Use the [order code=item page=page_name] Order it! </a> form of
     order tag to specify an arbitrary order page for an item.

3.   If already on an order page, set the mv_orderpage, mv_nextpage,
     mv_successpage, or mv_failpage variables.

The following variables can be used to control cart selection and page
display:

mv_cartname

     The shopping cart (default is main) to be used for this order
     operation.

mv_failpage

     Page to be displayed on a failed order check (see Advanced
     Multi-level Order Pages)

mv_nextpage

     Page to display on a return operation.

mv_orderpage

     Page to be displayed on a refresh.

mv_successpage

     Page to be displayed on a successful order check (see Advanced
     Multi-level Order Pages).

mv_order_profile

     Order profile to be used if the form action is submit (see
     Advanced Multi-level Order Pages).

1.7. Multiple Shopping Carts
----------------------------

Interchange allows you to define and maintain multiple shopping carts.
One shopping cart -- main, by name -- is defined when the user session
starts. If the user orders item M1212 with the following tag:

    [order code=M1212 cart=layaway] Order this item! </a>

the order will be placed in the cart named layaway. However, by
default you won't see the just-ordered item on the basket page.  That
is because the default shopping basket displays the contents of the
'main' cart only. So copy the default basket page
(pages/ord/basket.html in the demo) to a new file, insert a [cart
layaway] tag, and specify it as the target page in your [order] tag:

    [order code=M1212 cart=layaway page=ord/lay_basket] Order this item! </a>

Now the contents of the layaway cart will be displayed. Most of the
ITL tags that are fundamental to cart display accept a 'cartname'
option, allowing you to specify which cart to be used:

[cart cartname]

     A 'sticky' setting of the default cart name to use for all
     subsequent cart-related tags.  Convenient, but you must remember
     to use [cart main] to get back to the primary cart!  As an
     alternative, you can specify the desired cart as a parameter of
     the other tags.  These are not sticky, referencing the specified
     cart only for the instance in which they are called:

[item-list cartname]...[/item-list]

     Iterates over the items in the specified cart - tags like
     [item-quantity] and [item-price] will be evaluated accordingly;

[nitems cartname]

     Returns the total number of items in the specified cart;

[subtotal cartname]

     Returns the monetary subtotal for the contents of specified cart;

[shipping cartname], [handling cartname], [salestax cartname],
[total-cost cartname]

     You get the idea. It is worth noting that tags which summarize
     cart contents do not need to be in used concert, or in
     conjunction with an [item-list]. For instance, you can display
     just the grand total for a cart on the sidebar or bottom of each
     page, using [total-cost] by itself, if you wish.

You can also order items from a form, using the mv_order_item,
mv_cartname, and optional mv_order_quantity variables.

 <FORM METHOD=POST ACTION="[process]">
 <input type=checkbox name="mv_order_item" value="M3243"> Item M3243
 <input name="mv_order_quantity" value="1"> Quantity
 <input type=hidden name="mv_cartname" value="layaway">
 <input type=hidden name="mv_doit" value="refresh">
 <input type=submit name="mv_junk" value="Place on Layaway Now!">
 </FORM>

If you need to utilize an alternative item price in conjunction with
the use of a custom cart, see the section on PRODUCT PRICING for
pricing methods and strategies.

2. PRODUCT PRICING
==================

Interchange maintains a price in its database for every product. The
price field is the one required field in the product database -- it is
necessary to build the price routines.

For speed, Interchange builds the code that is used to determine a
product's price at catalog configuration time. If you choose to change
a directive that affects product pricing you must reconfigure the
catalog.

2.1. Simple pricing
-------------------

The simplest method is flat pricing based on a fixed value in the
products database. If you put that price in a field named price, you
don't need to do more. If you want to change pricing based on
quantity, size, color or other factors read on.

2.2. Price Maintenance with CommonAdjust
----------------------------------------

A flexible chained pricing scheme is available when the CommonAdjust
directive is set.

We talk below about a CommonAdjust string; it will be defined in due
time.

A few rules about CommonAdjust, all assuming the PriceField directive
is set to price:

1

If CommonAdjust is set to any value, a valid CommonAdjust string or
not, extended price adjustments are enabled. It may also hold the
default pricing scheme.

2

The price field may also hold a CommonAdjust string. It takes
precedence over the default.

3

If the value of the CommonAdjust directive is set to a CommonAdjust
string, and the price field is empty or specifically 0, then it will
be used to set the price of the items.

4

If no CommonAdjust strings are found, then the price will be 0,
subject to any later application of discounts.

5

If another CommonAdjust string is found as the result of an operation,
it will be re-parsed and the result applied. Chaining is retained; a
fallback may be passed and will take effect.

Prices may be adjusted in several ways, and the individual actions are
referred to below as atoms. Price atoms may be final, chained, or
fallback. A final price atom is always applied if it does not evaluate
to zero. A chained price atom is subject to further adjustment. A
fallback price atom is skipped if a previous chained price was not
zero.

Atoms are separated by whitespace, and may be quoted (although there
should not normally be whitespace in a setting). A chained item ends
with a comma.  A fallback item has a leading semi-colon.  Final atoms
have no comma appended or semi-colon prepended.

A settor is the means by which the price is set. There are eight
different types of price settors. All settors can then yield another
CommonAdjust string.

It is quite possible to create endless loops, so the maximum number of
initial CommonAdjust strings is set to 16, and there may be only 32
iterations by default before the price will return zero on an error.
(The maximum iterations is specified with the Limit directive.)

NOTE:  Common needs are easily shown but not so easily explained; skip
to the examples if the reference below if your vision starts to blur
when reading the next section. 8-)

USAGE: Optional items below have asterisks appended. The asterisk
should not be used in the actual string. Optional base or table always
defaults to the active products database table.  The optional key
defaults to the item code except in a special case for the
attribute-based lookup. The field name is not optional except in the
case of an attribute lookup.

N.NN or -N.NN

     where N is a digit.  A number which is applied directly; for
     instance 10 will yield a price of 10. May be a positive or
     negative number.

N.NN%

     where N is a digit.  A number which is applied as a percentage of
     the current price value. May be a positive or negative number.
     For example, if the price is 10 and -8% is applied, the next
     price value will be 9.20.

table*:column:key*

     Causes a straight lookup in a database table. The optional table
     defaults to the main products database table for the item
     (subject of course to multiple product files). The column must
     always be present. The optional key defaults to the item code
     except in a special case for the attribute-based lookup. The
     return value is then re-parsed as another price settor.

table*:col1..col5,col10:key*

     Causes a quantity lookup in database table table (which defaults
     to the products database), with a set of comma-separated fields,
     looked up by the optional key. (Key defaults to the item code, of
     course). If ranges are specified with .., each column in the
     sequence will be used; Therefore

         pricing:p1,p2,p3,p4,p5,p10:

     is the same as

         pricing:p1..p5,p10:

     Leading non-digits are stripped, and the item quantity is
     compared with the numerical portion of the column name. The price
     is set to the value of the database column (numeric portion) that
     is at least equal to it but doesn't yet reach the next break.

     WARNING: If the field at the appropriate quantity level is blank,
     a zero cost will be returned from the atom. It is important to
     have all columns populated.

==attribute:table*:column*:key*

     Does an attribute-based adjustment. The attribute is looked up in
     the database table, with the optional column defaulting to the
     same name as the value of the attribute. If the column is not
     left blank, the key is set to the value of the attribute if
     blank.

& CODE

     The leading & sign is stripped and the code is passed to the
     equivalent of a [calc] tag. No Interchange tags can be used, but
     the &tag_data routine is available, the current value of the
     price and quantity are available as $s, and the current item
     (code, quantity, price, and any attributes) are available as
     $item, all forced to the package Vend::Interpolate. That means
     that in a UserTag:

       $Vend::Interpolate::item          is the current item
       $Vend::Interpolate::item->{code}  gives key for current item
       $Vend::Interpolate::item->{size}  gives size for current item (if there)
       $Vend::Interpolate::item->{mv_ib} gives database ordered from

[valid Interchange tags]

     If the settor begins with a square bracket ([) or underscore, it
     is parsed for Interchange tags with variable substitution (but no
     Locale substitution). You may define a price in a Variable in
     this fashion. The string is re-submitted as an atom, so it may
     yield yet another settor.

$

     Tells Interchange to look in the mv_price attribute of the
     shopping cart, and apply that price as the final price, if it
     exists. The attribute must be a numerical value.

>>word

     Tells the routine to return word directly as the result. This is
     not useful in pricing, as it will evaluate to zero. But when
     CommonAdjust is used for shipping, it is a way of re-directing
     shipping modes.

word

     The value of word, which must not match any of the other settors,
     is available as a key for the next lookup (only). If the next
     settor is a database lookup, and it contains a dollar sign ($)
     the word will be substituted; i.e. table:column:$ becomes
     table:column:word.

( settor )

     The value returned by settor will be used as a key for the next
     lookup, as above.

2.3. CommonAdjust Examples
--------------------------

Most examples below use an outboard database table named pricing, but
any valid table including the products table can be used. We will
refer to this pricing table:

  code    common  q1     q5     q10    XL    S      red
  99-102          10     9      8      1     -0.50  0.75
  00-343                               2
  red      0.75

The simplest case is a straight lookup on an attribute; size in this
case.

  10.00, ==size:pricing

With this value in the price field, a base price of 10.00 will be
adjusted with the value of the size attribute. If size for the item
99-102 is set to XL then 1.00 will be added for a total price of
11.00; if it is S then .50 will be subtracted for a total price of
9.50; for any other value of size no further adjustment would be made.
00-343 would be adjusted up 2.00 only for XL.

  10.00, ==size:pricing, ==color:pricing

This is the same as above, except both size and color are adjusted
for. A color value of red for item code 99-102 would add 0.75 to the
price. For 00-343 it would have no effect.

  10.00, ==size:pricing, ==color:pricing:common

Here price is set based on a common column, keyed by the value of the
color attribute. Any item with a color value of red would have 0.75
added to the base price.

  pricing:q1,q5,q10:, ;10.00, ==size:pricing, ==color:pricing:common

Here is a quantity price lookup, with a fallback price setting. If
there is a valid price found at the quantity of 1, 5, or 10, depending
on item quantity, then it will be used. The fallback of 10.00 only
applies if no non-zero/non-blank price was found at the quantity
lookup. In either case, size/color adjustment is applied.

  pricing:q1,q5,q10:, ;10.00 ==size:pricing, ==color:pricing:common

Removing the comma from the end of the fallback string stops
color/size lookup if it reaches that point. If a quantity price was
found, then size and color are chained.

  pricing:q1,q5,q10:, ;products:list_price, ==size:pricing, ==color:pricing

The value of the database column list_price is used as a fallback
instead of the fixed 10.00 value. The above value might be a nice one
to use as the default for a typical retail catalog that has items with
colors and sizes.

2.4. PriceBreaks, discounts, and PriceAdjustment
------------------------------------------------

There are several ways that Interchange can modify the price of a
product during normal catalog operation. Several of them require that
the pricing.asc file be present, and that you define a pricing
database. You do that by placing the following directive in
catalog.cfg:

  Database  pricing pricing.asc 1

     NOTE: PriceAdjustment is slightly deprecated by CommonAdjust, but
     will remain in use at least through the end of Version 3 of
     Interchange.

Configurable directives and tags with regard to pricing:

o    Quantity price breaks are configured by means of the PriceBreaks
     and MixMatch directives. They require a field named specifically
     price in the pricing database. The price field contains a
     space-separated list of prices that correspond to the quantity
     levels defined in the PriceBreaks directive. If quantity is to be
     applied to all items in the shopping cart (as opposed to quantity
     of just that item) then the MixMatch directive should be set to
     Yes.

o    Individual line-item prices can be adjusted according to the
     value of their attributes. See PriceAdjustment and CommonAdjust.
     The pricing database must be defined unless you define the
     CommonAdjust behavior.

o    Product discounts for individual products, specific product
     codes, all products, or the entire order can be configured with
     the [discount ...] tag. Discounts are applied on a per-user basis
     -- you can gate the discount based on membership in a club or
     other arbitrary means. See Product Discounts.

For example, if you decided to adjust the price of T-shirt part number
99-102 up 1.00 when the size is extra large and down 1.00 when the
size is small, you would have the following directives defined in
<catalog.cfg>:

  Database          pricing pricing.asc 1
  UseModifier       size
  PriceAdjustment   size

To enable automatic modifier handling, you define a size field in
products.txt:

  code    description   price    size
  99-102  T-Shirt       10.00    S=Small, M=Medium, L=Large*, XL=Extra Large

You would place the proper tag within your [item-list] on the
shopping-basket or order page:

    [item-accessories size]

In the pricing.asc database source, you would need:

  code      S       XL
  99-102    -1.00   1.00

If you want to assign a price based on the option, precede the number
with an equals sign:

  code    S       M       L       XL
  99-102  =9.00   =10     =10     =11

IMPORTANT NOTE: Price adjustments occur AFTER quantity price breaks,
so the above would negate anything set with the PriceBreaks
directive/option.

Numbers that begin with an equals sign (=) are used as absolute prices
and are interpolated for Interchange tags first, so you can use
subroutines to set the price. To facilitate coordination with the
subroutine, the session variables item_code and item_quantity are set
to the code and quantity of the item being evaluated. They would be
accessed in a global subroutine with $Vend::Session->{item_code} and
$Vend::Session->{item_quantity}.

The pricing information must always come from a database because of
security.

2.5. Item Attributes
--------------------

Interchange allows item attributes to be set for each ordered item.
This allows a size, color, or other modifier to be attached to a
common part number. If multiple attributes are set, then they should
be separated by commas. Previous attribute values can be saved by
means of a hidden field on a form, and multiple attributes for each
item can be stacked on top of each other.

The configuration file directive UseModifier is used to set the name
of the modifier or modifiers. For example

    UseModifier        size,color

will attach both a size and color attribute to each item code that is
ordered.

IMPORTANT NOTE: You may not use the following names for attributes:

    item  group  quantity  code  mv_ib  mv_mi  mv_si

You can also set it in scratch with the mv_UseModifier scratch
variable -- [set mv_UseModifier]size color[/set] has the same effect
as above. This allows multiple options to be set for products.
Whichever one is in effect at order time will be used. Be careful, you
cannot set it more than once on the same page. Setting the
mv_separate_items or global directive SeparateItems places each
ordered item on a separate line, simplifying attribute handling. The
scratch setting for mv_separate_items has the same effect.

The modifier value is accessed in the [item-list] loop with the
[item-modifier attribute] tag, and form input fields are placed with
the [modifier-name attribute] tag. This is similar to the way that
quantity is handled, except that attributes can be "stacked" by
setting multiple values in an input form.

You cannot define a modifier name of code or quantity, as they are
already used. You must be sure that no fields in your forms have
digits appended to their names if the variable is the same name as the
attribute name you select, as the [modifier-name size] variables will
be placed in the user session as the form variables size0, size1,
size2, etc.

You can use the [loop arg="item item item"] list to reference multiple
display or selection fields for modifiers, or you can use the built-in
[PREFIX-accessories ...] tags available in most Interchange list
operations. The modifier value can then be used to select data from an
arbitrary database for attribute selection and display.

Below is a fragment from a shopping basket display form which shows a
selectable size with "sticky" setting. Note that this would always be
contained within the [item_list] [/item-list] pair.

    <SELECT NAME="[modifier-name size]">
    <OPTION  [selected [modifier-name size] S]> S
    <OPTION  [selected [modifier-name size] M]> M
    <OPTION  [selected [modifier-name size] L]> L
    <OPTION [selected [modifier-name size] XL]> XL
    </SELECT>

It could just as easily be done with a radio button group combined
with the [checked ...] tag.

Interchange will automatically generate the above select box when the
[accessories <code size]> or [item-accessories size] tags are called.
They have the syntax:

   [item_accessories attribute*, type*, field*, database*, name*, outboard*]

   [accessories code attribute*, type*, field*, database*, name*, outboard*]

code

     Not needed for item-accessories, this is the product code of the
     item to reference.

attribute

     The item attribute as specified in the UseModifier configuration
     directive. Typical are size or color.

type

     The action to be taken. One of:

       select          Builds a dropdown <SELECT> menu for the attribute.
                       NOTE: This is the default.
     
       multiple        Builds a multiple dropdown <SELECT> menu for the
                       attribute.  The size is equal to the number of
                       option choices.
     
       display         Shows the label text for *only the selected option*.
     
       show            Shows the option choices (no labels) for the option.
     
       radio           Builds a radio box group for the item, with spaces
                       separating the elements.
     
       radio nbsp      Builds a radio box group for the item, with &nbsp;
                       separating the elements.
     
       radio left n    Builds a radio box group for the item, inside a
                       table, with the checkbox on the left side. If "n"
                       is present and is a digit from 2 to 9, it will align
                       the options in that many columns.
     
       radio right n   Builds a radio box group for the item, inside a
                       table, with the checkbox on the right side. If "n"
                       is present and is a digit from 2 to 9, it will align
                       the options in that many columns.
     
       check           Builds a checkbox group for the item, with spaces
                       separating the elements.
     
       check nbsp      Builds a checkbox group for the item, with &nbsp;
                       separating the elements.
     
       check left n    Builds a checkbox group for the item, inside a
                       table, with the checkbox on the left side. If "n"
                       is present and is a digit from 2 to 9, it will align
                       the options in that many columns.
     
       check right n   Builds a checkbox group for the item, inside a
                       table, with the checkbox on the right side. If "n"
                       is present and is a digit from 2 to 9, it will align
                       the options in that many columns.

     The default is 'select', which builds an HTML select form entry
     for the attribute.  Also recognized is 'multiple', which
     generates a multiple-selection drop down list, 'show', which
     shows the list of possible attributes, and 'display', which shows
     the label text for the selected option only.

field

     The database field name to be used to build the entry (usually a
     field in the products database).  Defaults to a field named the
     same as the attribute.

database

     The database to find field in, defaults to the first products
     file where the item code is found.

name

     Name of the form variable to use if a form is being built.
     Defaults to mv_order_attribute -- i.e.  if the attribute is size,
     the form variable will be named mv_order_size.

outboard

     If calling the item-accessories tag, and you wish to select from
     an outboard database, you can pass the key to use to find the
     accessory data.

When called with an attribute, the database is consulted and looks for
a comma-separated list of attribute options. They take the form:

    name=Label Text, name=Label Text*

The label text is optional -- if none is given, the name will be used.

If an asterisk is the last character of the label text, the item is
the default selection. If no default is specified, the first will be
the default. An example:

    [item_accessories color]

This will search the product database for a field named "color". If an
entry "beige=Almond, gold=Harvest Gold, White*, green=Avocado" is
found, a select box like this will be built:

    <SELECT NAME="mv_order_color">
    <OPTION VALUE="beige">Almond
    <OPTION VALUE="gold">Harvest Gold
    <OPTION SELECTED>White
    <OPTION VALUE="green">Avocado
    </SELECT>

In combination with the mv_order_item and mv_order_quantity variables
this can be used to allow entry of an attribute at time of order.

If used in an item list, and the user has changed the value, the
generated select box will automatically retain the current value the
user has selected.

The value can then be displayed with [item-modifier size] on the order
report, order receipt, or any other page containing an [item-list].

2.6. Product Discounts
----------------------

Product discounts can be set upon display of any page. The discounts
apply only to the customer receiving them, and are of one of three
types:

    1. A discount for one particular item code (key is the item-code)
    2. A discount applying to all item codes (key is ALL_ITEMS)
    3. A discount for an individual line item (set the mv_discount attribute
       with embedded Perl)
    4. A discount applied after all items are totaled
       (key is ENTIRE_ORDER)

The discounts are specified via a formula. The formula is scanned for
the variables $q and $s, which are substituted for with the item
quantity and subtotal respectively. The variable $s is saved between
iterations, so the discounts are cumulative. In the case of the item
and all items discount, the formula must evaluate to a new subtotal
for all items of that code that are ordered. The discount for the
entire order is applied to the entire order, and would normally be a
monetary amount to subtract or a flat percentage discount.

Discounts are applied to the effective price of the product, including
any quantity discounts or price adjustments.

To apply a straight 20% discount to all items:

    [discount ALL_ITEMS] $s * .8 [/discount]

or with named attributes:

    [discount code=ALL_ITEMS] $s * .8 [/discount]

To take 25% off of only item 00-342:

    [discount 00-342] $s * .75 [/discount]

To subtract $5.00 from the customer's order:

    [discount ENTIRE_ORDER] $s - 5 [/discount]

To reset a discount, set it to the empty string:

    [discount ALL_ITEMS][/discount]

Perl code can be used to apply the discounts, and variables are saved
between items and are shared with the [calc] tag. This example gives
10% off if two items are ordered, with 5% more for each additional up
to a maximum of 30% discount:

    [calc]
        [item-list]
            $totalq{"[item-code]"} += [item-quantity];
        [/item-list]
            return '';
    [/calc]

    [item-list]
        [discount code="[item-code]"]
            return ($s)       if $totalq{"[item-code]"} == 1;
            return ($s * .70) if $totalq{"[item-code]"} > 6;
            return ($s * ( 1 - 0.05 * $totalq{"[item-code]"} ));
        [/discount]
    [/item-list]

Here is an example of a special discount for item code 00-343 which
prices the second one ordered at 1 cent:

    [discount 00-343]
    return $s if $q == 1;
    my $p = $s/$q;
    my $t = ($q - 1) * $p;
    $t .= 0.01;
    return $t;
    [/discount]

If you want to display the discount amount, use the [item-discount]
tag.

    [item-list]
    Discount for [item-code]: [item-discount]
    [/item-list]

Finally, if you want to display the discounted subtotal, you need to
use the [calc] capability:

    [item-list]
    Discounted subtotal for [item-code]: [currency][calc]
                                            [item-price] * [item-quantity]
                                            [/calc][/currency]
    [/item-list]

3. Taxing
=========

Interchange allows taxing in a number of ways.

Simple salestax.asc table

The SalesTax directive is set to a form field or fields for user
input, and those form fields are used look up the tax rate in
salestax.asc.

Fly tax

Another simple tax method. A series of Interchange Variable settings
are read to develop a salestax rate for one or a few localities,
usually a state in the US.

Salestax multi -- VAT taxing

The country and state tables are used to develop complex VAT or
salestax rate calculations based on country and state, possibly with
different rates based on product type.

Levies -- multiple levels of tax

Using the Levies setting and the Levy structure, any or all of the
above methods is used to implement one or more taxes.

3.1. Sales Tax -- simple salestax.asc table
-------------------------------------------

Interchange allows calculation of sales tax on a straight percentage
basis, with certain items allowed to be tax-exempt. To enable this
feature, the directive SalesTax is initialized with the name of a
field (or fields) on the order form. Commonly, this is zipcode and/or
state:

    SalesTax    zip,state

This being done, Interchange assumes the presence of a file
salestax.asc, which contains a database with the percentages. Each
line of salestax.asc should be a code (again, usually a five-digit zip
or a two letter state) followed by a tab, then a percentage. Example:

        DEFAULT 0.0
    45056   .0525
    61821   .0725
    61801   .075
    IL      .0625
    OH      .0525
    VAT     .15
    WA      .08

Based on the user's entry of information in the order form,
Interchange will look up (for our example SalesTax directive) first
the zip, then the state, and apply the percentage to the SUBTOTAL of
the order. The subtotal will include any taxable items, and will also
include the shipping cost if the state/zip is included in the
TaxShipping directive. It will add the percentage, then make that
available with the [salestax] tag for display on the order form. If no
match is found, the entry DEFAULT is applied -- it is normally zero.

If business is being done on a national basis, it is now common to
have to collect sales tax for multiple states. If you are doing so, it
is possible to subscribe to a service which issues regular updates of
the sales tax percentages -- usually by quarterly or monthly
subscription. Such a database should be easily converted to
Interchange format -- but some systems are rather convoluted, and it
will be well to check and see if the program can export to a flat
ASCII file format based on zip code.

If some items are not taxable, then you must set up a field in your
database which indicates that. You then place the name of that field
in the NonTaxableField directive. If the field for that item evaluates
true on a yes-no basis (i.e. is set to yes, y, 1, or the like), sales
tax will not be applied to the item. If it evaluates false, it will be
taxed.

If your state taxes shipping, use the TaxShipping directive. Utah and
Nevada are known to tax shipping -- there may be others.

If you want to set a fixed tax for all orders, as might occur for VAT
in some countries, just set the SalesTax directive to a value like
tax_code, and define a variable in the user session to reflect the
proper entry in the salestax.asc file.  To set it to 15% with the
above salestax.asc file, you would put in a form:

    <INPUT TYPE=hidden NAME=tax_code VALUE="VAT">

or to do it without submitting a form:

    [perl] $Values->{tax_code} = 'VAT'; return; [/perl]

3.2. Fly tax
------------

The [fly-tax] tag is placed in the DEFAULT setting of salestax.asc,
and the variables TAXAREA, TAXRATE, and TAXSHIPPING are used to build
the rates.

TAXAREA

A space-separated or comma-seperated list of states to apply tax to.
Not needed for anything in the calculation, it is used to build the UI
list of states to tax.

TAXRATE

An Interchange accessory-list style of value, with the format

  XX=N.NN, XX=N.NN

where XX is the two-letter state code and N.NN is the tax rate in
percent. To apply a tax of 7.25% for Illinois and 5.5% for Nevada, you
would use:

IL=7.25, NV=5.5

TAXSHIPPING

A space- or comma-separated list of states where shipping is taxed.
For the above example, if Nevada taxed shipping and Illinois did not,
you would make TAXSHIPPING equal to "NV".

The Salestax Directive

To set the field that is used for the state code, you use the standard
Interchange SalesTax directive. It would almost always be set to
state.

3.3. Salestax "multi" -- VAT taxing
-----------------------------------

If the SalesTax directive is set to "multi", then the type of tax is
read from the country table. To see the tax type in force for the UK,
you can place in a page:

        [data table=country col=tax key="UK"].

     NOTE: We mention the "country" table above. In actual practice,
     most everything is configurable for variable name and field name
     via different Variable settings. They are:

  MV_COUNTRY_TABLE      Table for country info (default "country")
  MV_COUNTRY_FIELD      Form field determining country (default "country")
  MV_COUNTRY_TAX_FIELD  Table column for country-wide tax (default "tax")
  MV_STATE_TABLE        Table for state/province info (default "state")
  MV_STATE_FIELD        Form field determining state/province (default "state")
  MV_STATE_TAX_FIELD    Table column for state-wide tax (default "tax")
  MV_TAX_TYPE_FIELD     Table column enumerating tax types (default "tax_type")
  MV_TAX_CATEGORY_FIELD Table column for product type (default tax_category)

Below, we refer to the tables, columns, and fields by their default
names.

The first lookup is done in table country based on the user input of
country (i.e. [value country]). The tax field is read and one of the
following is done:

1. If no string is found, tax returns 0.

2. If string "simple:XX" is found, uses [fly-tax] with the area
specifed in XX.

3. If string "state" is found, does a re-lookup with

     select tax from state where country = country and state = state

and value is applied as below.

4. If just digits are found, rate applied directly -- i.e. "0.05"

5. If N.NN% is found, applied as percentage.

6. If category = N.NN%, default = N.NN% is found, the tax_category
field in the products table is used to determine tax basis. If no
tax_category is found for the product, default rate is used.

This product data

    sku      price     tax_category
    os28003  10.00     tools
    os28004  20.00     food

with this country and state data:

    code     name     tax
    US       U.S.A.   state
    JP       Japan    tools=10%, default=15%


    code   country   state   name      tax
    0001   US        IL      Illinois  6.5%
    0002   US        OH      Ohio      default = 5.5%, food = 1%
    0003   US        AZ      Arizona

Will yield tax for one each of os28003 and os28004 of:

    Japan   $4.00
    US/IL   $1.95
    US/OH   $0.75
    US/AZ   $0.00

4. THE CHECKOUT PROCESS
=======================

4.1. Advanced Multi-level Order Pages
-------------------------------------

An unlimited number of order checking profiles can be defined with the
OrderProfile directive, or by defining order profiles in scratch
variables. This allows a multi-level ordering process, with checking
for format and validity at every stage.

To custom-configure the error message, place it after the format check
requirement.

Specifications take the form of an order page variable (like name or
address), followed by an equals sign and one of five check types:

required

     A non-blank value is required

mandatory

     Must be non-blank, and must have been specified on this form, not
     a saved value from a previous form

phone

     The field must look like a phone number, by a very loose
     specification allowing numbers from all countries

phone_us

     Must have US phone number formatting, with area code

state

     Must be a US state, including DC and Puerto Rico.

province

     Must be a Canadian province or pre-1997 territory.

state_province

     Must be a US state or Canadian province.

zip

     Must have US postal code formatting, with optional ZIP+4. Also
     called by the alias us_postcode.

ca_postcode

     Must have Canadian postal code formatting. Checks for a valid
     first letter.

postcode

     Must have Canadian or US postal code formatting.

true

     Field begins with y, 1, or t (Yes, 1, or True) - not case
     sensitive

false

     Field begins with n, 0, or f (No, 0, or False) - not case
     sensitive

email

     Rudimentary email address check, must have an '@' sign, a name,
     and a minimal domain

regex

     One or more regular expressions (space-separated) to check
     against. To check that all submissions of the "foo" variable have
     "bar" at the beginning, do:

             foo=regex ^bar

     You can add an error message by putting it in quotes at the end:

        foo=regex ^bar "You must have bar at the beginning of this"

     You can require that the value not match the regex by preceding
     the regex with a ! character (and no space afterwards):

        foo=regex !^bar "You may not have bar at the beginning!"

length

     A range of lengths you want the input to be:

        foo=length 4-10

     That will require foo be from 4 to 10 characters long.

unique

     Tests to see that the value would be a unique key in a table:

        foo=unique userdb Sorry, that username is already taken

filter

     Runs the value through an Interchange filter and checks that the
     returned value is equal to the original value.

        foo=filter entities Sorry, no HTML allowed

     To check for all lower-case characters:

             foo=filter lower Sorry, no uppercase characters

Also, there are pragmas that can be used to change behavior:

&charge

     Perform a real-time charge operation. If set to any value but
     "custom", it will use Interchange's CyberCash routines. To set to
     something else, use the value "custom ROUTINE". The ROUTINE
     should be a GlobalSub which will cause the charge operation to
     occur -- if it returns non-blank, non-zero the profile will have
     succeeded. If it returns 0 or undef or blank, the profile will
     return failure.

&credit_card

     Checks the mv_credit_card_* variables for validity. If set to
     "standard", it will use Interchange's encrypt_standard_cc
     routines. This destroys the CGI value of mv_credit_card_number --
     if you don't want that to happen (perhaps to save it for sending
     to CyberCash) then add the word keep on the end.

     Example:

         # Checks credit card number and destroys number after encryption
         # The charge operation can never work
     
         &credit_card=standard
         &charge=custom authorizenet
     
         # Checks credit card number and keeps number after encryption
         # The charge operation can now work
     
         &credit_card=standard keep
         &charge=custom authorizenet

     You can supply your own check routine with a GlobalSub:

         &credit_card=check_cc

     The GlobalSub check_cc will be used to check and encrypt the
     credit card number, and its return value will be used to
     determine profile success.

&fail

     Sets the mv_failpage value.

         &fail=page4

     If the submit process succeeds, the user will be sent to the page
     page4.

&fatal

     Set to '&fatal=yes' if an error should generate the error page.

&final

     Set to '&final=yes' if a successful check should cause the order
     to be placed.

&update

     Set to '&update=yes' if a successful check should cause the
     variable to be copied from the CGI space to the Values space.
     This is like [update values] except only for that variable.

     This is typically used when using a mv_form_profile check so that
     a failing check will not cause all values to be reset to their
     former state upon returning to the form.

&return

     Causes profile processing to terminate with either a success or
     failure depending on what follows. If it is non-blank and
     non-zero, the profile succeeds.

         # Success :)
         &return 1
     
         # Failure :\
         &return 0

     Will ignore the &fatal pragma, but &final is still in effect if
     set.

&set

     Set a user session variable to a value, i.e. &set=mv_email [value
     email]. This will not cause failure if blank or zero.

&setcheck

     Set a user session variable to a value, i.e. &set=mv_email [value
     email].  This will cause failure if set to a blank or zero. It is
     usually placed at the end after a &fatal pragma would have caused
     the process to stop if there was an error -- can also be used to
     determine pass/fail based on a derived value, as it will cause
     failure if it evaluates to zero or a blank value.

&success

     Sets the mv_successpage value. Example:

         &success=page5

     If the submit process succeeds, the user will be sent to the page
     page5.

As an added measure of control, the specification is evaluated for the
special Interchange tags to provide conditional setting of order
parameters. With the [perl] [/perl] capability, quite complex checks
can be done. Also, the name of the page to be displayed on an error
can be set in the mv_failpage variable.

The following file specifies a simple check of formatted parameters:

 name=required You must give us your name.
 address=required Oops! No address.
 city=required
 state=required
 zip=required
 email=required
 phone_day=phone_us XXX-XXX-XXXX phone-number for US or Canada
 &fatal=yes
 email=email Email address missing the domain?
 &set=mv_email [value email]
 &set=mv_successpage ord/shipping

The profile above only performs the &set directives if all of the
previous checks have passed -- the &fatal=yes will stop processing
after the check of the email address if any of the previous checks
failed.

If you want to place multiple order profiles in the same file,
separate them with __END__, which must be on a line by itself.

User-defined check routines can be defined in a GlobalSub:

    GlobalSub <<EOF
    sub set_up_extra_check {
        BEGIN {
            package Vend::Order;
            sub _pt_postcode {
                # $ref is to Vend::Session->{'values'} hash
                # $var is the passed name of the variable
                # $val is current value of checked variable
                my($ref, $var, $val) = @_;

                if ($ref->{country} =~ /^(PT|portugal)$/i) {
                    return $val =~ /^\d\d\d\d$/ ?
                        (1, $var, '') : (undef, $var, "not a Portugese postal code");
                }
                else {
                    return (1, $var, '');
                }
            }
        }
    }
    EOF

Now you can specify in an order profile:

  postcode=pt_postcode

Very elaborate checks are possible. There must be an underscore
preceding the routine name. The return value of the subroutine should
be a three-element array, consisting of:

1.   the pass/fail ('1' or 'undef') status of the check;

2.   the name of the variable which was checked;

3.   a standard error message for the failure, in case a custom one
     has not been specified in the order profile.

The latter two elements are used by the [error] tag for on-screen
display of form errors. The checkout page of the Foundation demo
includes examples of this.

4.2. Simple Order Report File
-----------------------------

The simple order report file, "report", defines the layout of the
order report which gets mailed on the completion of the order. For
example,

              Order Date: $date

                    Name: $name
           Email address: $email

        Shipping address: $addr
        Town, State, Zip: $town, $state $zip
                 Country: $country

Any input field from the order page can be included using the dollar
sign notation.

Interchange defines some values for use in the search form -- they
begin with mv_ and are automatically ignored.

4.3. Fully-configurable Order Reports
-------------------------------------

You can specify a fully-configurable order report by setting the
hidden field "mv_order_report" to a legal Interchange page. This page
will be interpolated with all Interchange tags before sending by
email. The order number as set by backend ordering is in the variable
mv_order_number, and available for your use.

You could if you wish include HTML in the file, which will be
interpreted by many mailers, but you can choose to use standard ASCII
format. An example report is provided in the demo file
<pages/ord/report.html>.

4.4. Order Receipts
-------------------

The file can of course be configured with all Interchange tags, and
will be interpolated for the ordered items before they are deleted
from the user session. You can set the default receipt with the
receipt key in SpecialPage. If using order Routes, as in the
foundation demo, you set it with the receipt key to Route.

4.5. The Order Counter
----------------------

An order counter can be enabled if the OrderCounter directive is set
to a file name. An incrementing count of all orders will be kept and
assigned as orders are placed. By default, the number starts at 0, but
you can edit the file and change the default starting number at any
time.

This capability is made possible by the File::CounterFile module,
available (as a part of the fine libwww modules) at the same place you
got Interchange. It is included with the distribution.

4.6. Customer Input Fields
--------------------------

On the order (or shopping basket) page, by default order.html, you
will have a number of input fields allowing the customer to enter
information such as their name and address. You can add more fields
simply by putting more input elements on the order.html page, and the
information will automatically be included in the order report. Input
elements should be written in this way:

    <input type="text" name="town" value="[value town]" size=30>

Choose a name for this input field such as "email" for an email
address. Set the name attribute to the name you have chosen.

The value attribute specifies the default value to give the field when
the page is displayed. Because the customer may enter information on
the order page, return to browsing, and come back to the order page,
you want the default value to be what was entered the first time. This
is done with the [value var] element, which returns the last value of
an input field. Thus,

    value="[value name]"

will evaluate to the name entered on the previous order screen, such
as:

       value="Jane Smith"

which will be displayed by the browser.

The size attributes specifies how many characters wide the input field
should be on the browser. You do not need to set this to fit the
longest possible value since the browser will scroll the field, but
you should set it large enough to be comfortable for the customer.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Interchange + CVS HOWTO
=======================

5. Introduction
===============

5.1. Preamble
-------------

Copyright 2001,2002 Dan Browning <dan.browning@kavod.com>.  This
document is freely redistributable under terms of the GNU General
Public License.

5.2. Purpose
------------

The purpose of this document is to help others take advantage of CVS
and Interchange together to increase the quality of their programming,
whether they are sole developers or part of a large team of
programmers, graphic artists, and HTML design gurus.  Portions of it
apply to general CVS setup and use, but it is geared toward the
average developer using Interchange to implement an e-commerce
website.

5.3. Audience
-------------

I intend for this document to be useful to those who are not yet
familiar with CVS as well as those who are.  If you already know how
to setup a pserver then you might just skim chapter 2 ("Setup CVS"),
or skip it all together.

In addition, I have tried to write at a technical level that would be
on par with what I perceive to be the average Interchange user that
participates on the interchange-users mailing list.  It is assumed
that the reader can and already has setup Interchange and the template
catalog (e.g. Foundation) is working correctly.

5.4. Contact the author
-----------------------

If you find any spelling errors, technical slip-ups, mistakes,
subliminal messages, or if you wish to send feedback, critique,
remarks, comments, or if you wish to contribute examples, instructions
for alternative platforms, chapters, or other material, please do so.

The preferred method of submitting changes is in the form of a context
diff against the SDF source file (ic_cvs.sdf).  Please address your
correspondence to:

Dan Browning dan.browning@kavod.com

5.5. The advantages of using CVS
--------------------------------

CVS is a very useful tool and can help you in your development, no
matter if you are one developer or are part of a team of developers.

o    What is CVS all about?

o    What are its advantages?

The official CVS website (http://www.cvshome.org/new_users.html) has
more detailed answers to these questions, but here are some brief
points of interest.

o    Checkout "historic" points in time or milestones in a project,
     for example when an e-commerce site went "live" or before a major
     branch in the code.

o    Revert to older versions of a file, directory, or an entire
     website.

o    Branching releases.  Concurrently develop an unstable development
     version as well as fix bugs in the stable production version.

o    Multiple developers can work on the same catalog and even the
     same file at the same time.  (For more information about how
     multiple simultaneous writes are merged and conflicts resolved,
     see the CVS docs in the Resources Appendix).

o    CVS is better than ftp for file transfer, because it
     automatically downloads only changed files, and even then, only
     the portion of the file that has changed (using patches).

o    CVS can automatically merge two simultaneous writes to the same
     file by different developers.

o    Allows one to keep track of the changes that have been made over
     time (many release managers repackage CVS commit logs into
     WHATSNEW, HISTORY, and/or NEWS files).

5.6. How to use this document
-----------------------------

There are many potential uses of CVS as it applies to Interchange.  In
fact, there are as many unique ways to use CVS as there are unique
developers.  This document only covers some of the ways, including
basic and useful techniques to get started using CVS.  For the intents
of the average web developer using IC for a B2C e-commerce site, I've
identified a few of the possible uses:

Simple

o    One server

o    One catalog

o    One CVS module

o    One branch

Medium

o    One server

o    Two catalogs (e.g., one is live, one is development)

o    Two CVS modules

o    Separate development and live branches

Complex/Custom

o    Multiple servers (e.g., developers' servers, staging servers, and
     live servers)

o    Multiple catalogs

o    Multiple CVS modules

o    Multiple branches

o    Custom setup

This document attempts to cover the simple well, explain many aspects
of the medium, and hopefully give you the background you need if you
decide to setup your own complex development environment.

6. Setup CVS
============

6.1. Assumptions
----------------

Here are some of the assumptions that I make that apply to various
parts of the rest of this document:

o    Red Hat Linux 7.x

o    Interchange installed (RPM or tarball)

o    Default Interchange tarball installation directory paths (adjust
     for your environment)

o    Template catalog setup and working

Note: I will assume "foundation" for the catalog name and directory
paths, but it should be just as easy to use this document with your
own catalog by mentally transposing the names and paths.

There shouldn't be any reason why you could not do everything I
mention here on other Linux distributions, Unices or Windows (using
cygwin). However, my statements will reflect Red Hat Linux 7.x.
Additionally, Red Hat Linux 6.x is for the most part the same as 7.x,
except for the difference of using inetd instead of xinetd to setup
pserver.

6.2. Install CVS
----------------

This is the easy part.  For Red Hat Linux systems, download the CVS
rpms and install them.  You can search for rpms for your system using
http://www.rpmfind.net.

Create the user and group that will administrate the Interchange
repository. For this document, it will be the interch user, (which was
setup during the installation of Interchange).  But if you understand
the mechanics of Unix users/groups, then you can use whatever username
and group scheme you prefer. For example, some create a cvs user and
cvs group, then add the Interchange user and catalog owner to its
group or vice-versa.  The integration of Interchange and CVS in the
latter portion of this document will require that the CVS user can
write to the catalog directory.

6.3. Create the CVS repository directory
----------------------------------------

You will need to create a repository directory such as /rep, which is
used here and in the rest of the document, but it can be any directory
you desire, and must be owned by the cvs user.  Many use /var/rep or
/home/cvs/rep.

        su - root
        mkdir /rep
        chown interch.interch /rep

6.4. Setup environment variables
--------------------------------

The CVSROOT and EDITOR environment variables should be setup for all
users in /etc/profile.  Of course, EDITOR can be whatever Unix text
editor you prefer, such as vi, emacs, pico, or joe.

/etc/profile:

export CVSROOT=/rep
export EDITOR=vi

Note: You will need to logout/login for the profile changes to take
effect.

6.5. Initialize the repository
------------------------------

Initialize the repository as the CVS user, which is interch for this
document.

        su - interch
        cvs -d /rep init

6.6. CVS Authentication
-----------------------

6.6.1. Background
-----------------

Authentication is done in CVS through the $CVSROOT/CVSROOT/passwd
file. It can be easily manipulated through some of the CVS
administration tools that are available.

6.6.2. CVS administration tools
-------------------------------

o    http://freshmeat.net/projects/cvsadmin/

o    http://freshmeat.net/projects/cvspadm/

I recommend cvsadmin, but there are also a variety of manual methods
that can be used in the absence of such tools, one of which involves
copying the system shadow file and modifying it for use by CVS.  For
more information on this manual method, see the Red Hat CVS pserver
setup guide by Michael Amorose (http://www.michael-amorose.com/cvs/).

6.6.3. Setup authentication using the cvsadmin tool
---------------------------------------------------

You can find a tarball to install on your system using the above
address, but here is the address of a recent RPM package of the
version. This package is intended for Mandrake systems, but is
compatible with Red Hat Linux 7.1:

o    ftp://speakeasy.rpmfind.net/linux/Mandrake-devel/contrib/RPMS/cvsadmin-1.0.1-1mdk.i586.rpm

After installing, create a password file (touch
$CVSROOT/CVSROOT/passwd), and execute cvsadmin add <usernames>.

6.7. Setup CVS modules
----------------------

Note: From this point on, assume that all commands are executed as the
CVS user (e.g. interch), unless otherwise specified.

A module is CVS is like the concept of a "project", where each module
has its own branches, trees,  and other features.

6.7.1. Add your project to the modules configuration file
---------------------------------------------------------

The format of the modules file is explained in detail in the CVS
documentation, here is the simplest way to use it:

/rep/CVSROOT/modules:

<Module name><TAB><Module Directory>

The module name can be whatever you want, and the module directory is
what we will create later under /rep.  We'll want a module for the
template catalog (foundation).  For example:

foundation      foundation

6.7.2. Create the module directory
----------------------------------

This is the directory that is referred to in the CVSROOT/modules file
we just modified.

mkdir /rep/foundation

6.8. Setup binary file types
----------------------------

This isn't necessary if you aren't going to manage any binary files
(e.g. if you plan on excluding your /images/ directory).  But I
recommend including it. The following is an example including many
binary file types (by extension) used in web development.

/rep/CVSROOT/cvswrappers:

*.avi   -k 'b' -m 'COPY'
*.doc   -k 'b' -m 'COPY'
*.exe   -k 'b' -m 'COPY'
*.gif   -k 'b' -m 'COPY'
*.gz    -k 'b' -m 'COPY'
*.hqx   -k 'b' -m 'COPY'
*.jar   -k 'b' -m 'COPY'
*.jpeg  -k 'b' -m 'COPY'
*.jpg   -k 'b' -m 'COPY'
*.mov   -k 'b' -m 'COPY'
*.mpg   -k 'b' -m 'COPY'
*.pdf   -k 'b' -m 'COPY'
*.png   -k 'b' -m 'COPY'
*.ppt   -k 'b' -m 'COPY'
*.sit   -k 'b' -m 'COPY'
*.swf   -k 'b' -m 'COPY'
*.tar   -k 'b' -m 'COPY'
*.tgz   -k 'b' -m 'COPY'
*.tif   -k 'b' -m 'COPY'
*.tiff  -k 'b' -m 'COPY'
*.xbm   -k 'b' -m 'COPY'
*.xls   -k 'b' -m 'COPY'
*.zip   -k 'b' -m 'COPY'

6.9. Testing your repository
----------------------------

At this point, you should have a working (though empty) CVS
repository. Before we continue with setting up the pserver or
importing source code, try logging in as one of the CVS users listed
in your CVSROOT/passwd and test the checkout.

#test checkout in home directory of any cvs user
mkdir ~/src
cd ~/src
cvs co foundation

This should create foundation/ and foundation/CVS.

6.10. Setup the CVS pserver
---------------------------

You will likely need to be root to do this, and there are lots of
guides on the Internet for setting up a CVS pserver, hopefully you
wont have any trouble doing it on your particular operating system. 
See the Resources Appendix for more information.

6.10.1. Setup pserver in Red Hat Linux 7.1 using xinetd.
--------------------------------------------------------

For Red Hat Linux 7.x, edit /etc/xinetd.d/cvspserver (create a new one
if none exists).  The following works for me, but customization may be
required for your environment (see the next section below for an
inetd-based system example).  This also must be done as root.

su - root
/etc/xinetd.d/cvspserver:

# default: on
service cvspserver
{
        disable = no
        socket_type  = stream
        protocol  = tcp
        wait   = no
        user    = root
        server   = /usr/bin/cvs
        server_args  = -f --allow-root=/rep pserver
}

Also unset the HOME variable in xinetd.  This was required for my
repository to work correctly, but if anyone has a better suggestion, I
would appreciate a note.

/etc/xinetd.d/cvspserver:

unset HOME

Now, restart xinetd for the changes to take effect.

service xinetd restart

6.10.2. Setup pserver in inetd-based systems.
---------------------------------------------

For inetd-based systems such as Red Hat Linux 6.2, make sure that the
following files are setup accordingly.

/etc/services:

cvspserver      2401/tcp
N:/etc/inetd.conf:

cvspserver stream tcp nowait root /usr/sbin/tcpd /usr/bin/cvs --allow-root=/rep pserver

6.10.3. Testing your pserver
----------------------------

At this point, you should be able to use a CVS client to use your
pserver and execute all the same commands that you can locally (which
we tested before). You may wish to take advantage of a graphical CVS
client, which can be particularly helpful in leveling the learning
curve.

See the Resources Appendix for links to some graphical CVS tools.

7. Import your Interchange catalog into CVS
===========================================

7.1. Configuring your catalog
-----------------------------

Eventually, we will import your catalog into the CVS repository, but
first we need to do some work with a temporary copy of the catalog so
we can get it into shape for importing.

Note: From here on, assume the use of the Interchange user, such as
interch, unless otherwise noted.

su - interch

If you installed via RPM:

service interchange stop

If you installed via tarball (default path):

/usr/local/interchange/bin/interchange --stop

7.2. Remove old CVS folders
---------------------------

If, for any reason, you already have CVS/ directories in your catalog,
they must be removed because they might interfere with the new CVS
setup.  For example, maybe you moved servers and you are setting up
CVS again.  You might use the following find command, which will find
any folders named CVS in the current directory and remove them.  There
is probably a better way to deal with old CVS/ folders, but the
following works for me (again, suggestions welcome).

Note: You should make a backup of the catalog directory before you do
this.


#Become Interchange catalog user
su - interch

#backup catalog folder first
tar czf ~/foundation_backup.tgz /var/lib/interchange/foundation

#get rid of any old CVS folders -- (BE CAREFUL!)
cd /var/lib/interchange/foundation
find . -name CVS -exec rm -Rf {} \;

7.3. Create a working copy of your catalog
------------------------------------------

A working copy of your catalog is necessary to get it into shape for
use with CVS.  The following command creates a copy in the /tmp
directory.

cp -a /var/lib/interchange/foundation /tmp/import_foundation
cd /tmp/import_foundation

7.4. Streamline your catalog for CVS
------------------------------------

7.4.1. Considerations about what to import into CVS
---------------------------------------------------

From your working directory (/tmp/import_foundation), decide which
files will be in the CVS repository, and which will not.  While it is
entirely possible to import the entire catalog into the repository
unchanged, I usually prefer to doctor my directories up before letting
them into my repository because of several reasons:

o    Will the file be modified by another source?

For example, /etc/order.number is modified by Interchange when run.
But not everyone will use a local development model that includes
running Interchange on a directly checked-out copy of their source. 
Which means this specific issue is avoided if you upload every edit
before viewing your changes on a server.

o    The likelihood that you will modify the file.

For example, if I am certain that I wont every want to modify the
session/ files directly, then I probably wouldn't need to manage that
through CVS, but I do import the empty session/ directory to make it
easier when setting up new catalogs.

o    Speed.

Managing less files in the repository takes away from the amount of
time required for CVS checkout, update, branching, and other CVS
actions.  For most, this amount of time is small already, but it is a
consideration for some.

o    Ease of use.

Ease of use is one reason not to remove anything from your catalog
before importing it, because it creates the ability to have a
completely working catalog from just one checkout (much like the CVS
tree at cvs.icdevgroup.org).  Whereas if you leave out other
directories like etc/ session/ orders/, etc., then you must first
combine your checkout with the other working parts of a catalog before
the catalog is viable.  But this is slower and will bring up lots of
harmless notification and warning messages (about changed local
versions) if you run Interchange on your local source copy (because
Interchange will touch etc/ session/ orders/, etc. directly, and then
warn that your local copy has changed from the CVS copy).  You may be
able to manage some of these notifications and warnings with
CVSROOT/cvsignore or $CVSIGNORE, see the Resources appendix for more
details.

7.4.2. Remove files that aren't needed in CVS
---------------------------------------------

Here is an example of some directories to remove.  If you do move more
directories, be sure to move them to a directory that you can later
use to re-unite with a checked-out copy for a working catalog.  But
here I chose just to move files that are not needed for a template
"skeleton" catalog.

The images directory is typically symlinked to
/var/www/html/foundation/images, so I remove this symlink from the
working copy, and replace it with an exact copy which will go into the
CVS repository.

cd /tmp/import_foundation
mkdir /tmp/import_foundation_nonCVS

#Setup images directory
rm images
cp -a /var/www/html/foundation/images .

#Remove
mv error.log logs/* orders/* session/* tmp/* upload/*  \
        /tmp/import_foundation_nonCVS

7.5. Import the streamlined catalog
-----------------------------------

Import the remaining portion of the catalog using the cvs import
command, with "foundation" as the module name and repository directory
name. See the CVS documentation resources mentioned in Appendix
Resources for more information.

When you run the import command, it will launch $EDITOR (set to 'vi'
earlier), and ask for a message to go along with the import action. 
Whatever you see fit to write (e.g. "starting new CVS module with my
foundation catalog...") is fine.

This example import command includes renaming the foundation "working"
directory back to "foundation" for the import.

su - interch
cd /tmp/import_foundation
cvs import foundation foundation start

7.6. Testing the new CVS module
-------------------------------

Now you should be able to do another test checkout or update using any
CVS client, which should now download all the files that you have just
imported into CVS.  Additionally, you might test your newly imported
code by making a change to one of your checked-out source files,
saving it, then committing it.

index.html:
<!--this is a test comment at the top of index.html-->

Now commit the change

cvs commit index.html

Your changed version will now be resident in the repository.  There
are a lot of good CVS documentation and resources for discovering more
about the checkout/update/commit cycle and other CVS aspects in the
Resources Appendix

You'll also notice that even if you start your interchange server, the
change you made did not take effect.  The next section will detail the
process of tying CVS and Interchange together in a way that this will
happen automatically.

8. Integrate CVS and Interchange
================================

The next step is to allow CVS to update the directory that Interchange
uses to serve pages.

8.1. CVS checkout into the catalog directory
--------------------------------------------

Now it is the time to replace the directories in your catalog that
have counterparts in CVS with fresh checkouts from CVS (this is a
preliminary action to allow CVS to update your catalog directory when
a change is made to CVS).

Note: Make sure interchange daemon is stopped and you have a good
backup before continuing.

tar czf ~/foundation.backup2.tgz /var/lib/interchange/foundation

Checkout a copy from CVS into a different directory (such as
foundation_CVS).

cd /var/lib/interchange/
cvs co -d foundation_CVS foundation

This should create the foundation_CVS/ directory for you, so that it
wont conflict with your existing foundation/ directory.

8.1.1. Add any needed files to checked-out catalog
--------------------------------------------------

Note that empty directories are pruned, so they will need something in
them for them to show up with a -P checkout. Often a zero-byte file
called '.empty' is used.

If you removed any directories during the streamlining step, we must
first add those back so that the catalog is usable to Interchange.  In
this document, we only removed unneeded files and left empty
directories.

This can also be the time to copy any "data" files such as orders/
logs/, etc. that might be needed if it is a live catalog.

cd /var/lib/interchange/foundation
cp -a <NEEDED_FILES> \
        /var/lib/interchange/foundation_CVS

8.1.2. Install and test the new catalog
---------------------------------------

Now lets move the old foundation out of the way and put the new
foundation_CVS in its place.

cd /var/lib/interchange/
mv foundation foundation_old
mv foundation_CVS foundation

Now, link up the CVS images for use by Apache.

cd /var/www/html/foundation/
mv images images_old
ln -s /var/lib/interchange/foundation/images images

Now, you should have a working catalog again.  To make sure, start up
Interchange and test the site with your browser.

8.2. Testing manual CVS updates on Interchange catalogs
-------------------------------------------------------

Next, lets again update the checkout we made a while back before
importing our catalog.  (Alternatively, one could use a visual CVS
client detailed above).

cd ~/src
cvs -q up -d foundation # -q for quiet, -d for directory prune/update

Additionally, you might test making a change to one of your
checked-out source files, saving it, then committing it.

index.html:
<!--this is a test comment at the top of index.html-->

Now commit the change

cvs commit index.html

Your changed version will now be resident in the repository.  Again,
CVS documentation is in the Resources Appendix.

This time, we can allow the changes to take effect on the code being
used by Interchange to serve pages. To do so, one must run a cvs
update on the catalog directory:

cd /var/lib/interchange/foundation
cvs -q up -d    #up is the shortened version of "update"

That should notify you of the new version it downloaded with something
like:

U pages/index.html

You may also get something like the following:

M catalog.cfg
M etc/status.foundation
M ...
? orders/000001
? ...

The ? lines in the above example mean that the CVS server has never
heard of the listed directories or files (they are in your local
source dir but not in the CVS source dir).  It is harmless, but
sometimes annoying, and can be taken care of with CVSIGNORE.

The M means that the file has been modified on your local copy, and is
out of sync with the remote CVS version (e.g. when Interchange runs it
updates etc/status.foundation).  Normally this is corrected by
uploading your "modified" version to the server, but in this case, the
modification was done by Interchange instead of the programmer, and
wasn't meant to be committed back to the CVS repository.  These types
of messages can be handled with $CVSIGNORE and
$CVSROOT/CVSROOT/cvsignore.

Now, check to make sure that your change has taken effect by
refreshing the homepage on the site.  To see the comment, use
View->Page Source or whatever the relevant command for your browser
is.

At this point, its obvious that it would be time consuming to manually
run 'cvs up' every time you make a change to the source code, so the
next step is to setup CVS to automatically update the catalog whenever
you commit something to CVS.

8.3. Automatic updates on commit
--------------------------------

Start by modifying $CVSROOT/CVSROOT/loginfo

^foundation     (date; cat; (sleep 1; cd /var/lib/interchange/foundation; cvs -q update -d) &) >> $CVSROOT/CVSROOT/updatelog 2>&1

The first line tells CVS that for every commit on modules that start
with "foundation" (notice the regular expression "^foundation"), it
will run cvs update on the given catalog directory in the background. 
It is important that it is executed in a forked shell (notice the "&")
after sleep'ing for 1 second, because otherwise you may run into
contention issues that can cause file locking problems.  The 1 second
timing used above works fine for me, but a longer pause may be
necessary for slower computers (you'll know if you get errors about
"file locked by user").  See the CVS documentation in the Resources
Appendix for more details.

8.4. Automatic e-mail on commit
-------------------------------

Often it is very helpful to have a commit mailing list that keeps
developers up-to-date on every commit happening to the CVS.  To setup
automatic e-mails on every commit, put the following in

/rep/CVSROOT/loginfo:

ALL     /usr/bin/cvs-log     $CVSROOT/CVSROOT/commitlog $USER "%{sVv}"

This tells CVS to pipe the commit output to a shell script, which in
turn updates a log file and e-mails an update (typically to a mailing
list address). Create the shell script at /usr/bin/cvs-log that is
executable by the cvs user (using "chmod 755 /usr/bin/cvs-log").

/usr/bin/cvs-log:

#!/bin/sh
(echo "----------------------------------------------";
 echo -n $2"  ";
 date;
 echo;
 cat) | tee -a $1 | /usr/bin/Mail -s "[foundation-cvs] $3" foundation-cvs@example.com

Your commit logs will now be archived in the CVSROOT/commitlog file
and e-mailed to the  foundation-cvs@example.com address (which is
especially useful when you have a Mailserver for CVS updates).  Here
is what a sample e-mail looks like:

Subject: [foundation-cvs] 'directory/subdirectory filename.c,1.7,1.8'


----------------------------------------------
cvs Fri Mar 16 21:14:09 PST 2001
Update of directory/subdirectory
In directory cvs.foundationsomething.com:/tmp/cvs-serv7721
Modified Files:
filename.c
Log Message:
test

Now you have a working CVS development system.  At this point it may
be valuable to learn more about CVS the client tools that you are
using.

9. The two track model: development and live catalogs
=====================================================

It is often very valuable to have a two-track development model that
separates the classes of work into separate timing and decision
categories.  Some use "staging" and "production" terminology, others
prefer "unstable" and "stable", "beta" and "release", or "development"
and "live".

The easiest starting point for two-track development is to just use
two completely separate CVS modules and catalogs.  This can make a lot
of sense for many situations, for example when the next revision of
the site will be so different that it is for all practical purposes
starting from ground zero.

A slightly more complicated solution is to use the CVS branches
feature.  It is more difficult to set up, but can be rewarding when
used correctly.

9.1. When to branch
-------------------

The first decision is when to branch the source code.  For websites,
this can sometimes be an easy decision like "first went live", or
"site-wide overhaul", etc.

9.2. Which way to branch
------------------------

There are many different ways to branch source code.  What seems to be
the most common method is to use the "trunk", which is the HEAD tag to
CVS as the development version, and then make a branch when a stable
release is to be made.

That model doesn't fit my development style at the current time, so I
use the HEAD default branch as my stable live version, and use other
tags (like DEV1 and DEV_REALLY_UNSTABLE) for my development branch.

You may find that you are merging (or "folding") most or all of your
development ranch back into your stable branch frequently.  This is
because unlike traditional programming where products are launched
every two or three years with new features, web sites often have
little fixes and new features added every day or every few weeks, with
new "releases" happening more often than traditional software
development (though not all web sites follow that trend).  The
flexibility is there to branch the source for quite some time to work
on a very complex feature or complete redesign before bringing it to
the live site, as well as the flexibility for day-to-day updates.

9.3. Performing the branch
--------------------------

To perform the branch use the cvs tag -b <BRANCH NAME> command.  For
example:

cvs tag -b DEV1

Remember that this does not change your locally checked out working
directory to the new tag automatically, it only creates the branch
within the CVS repository.

9.4. Setup the development catalog
----------------------------------

Now we have a branch in CVS, but we need to tie it to something in the
real world, namely, an Interchange catalog.

9.4.1. Importing the catalog
----------------------------

Like we did in Integrating CVS with Interchange, you must make another
copy of your catalog for use as the development version.  Some would
like to keep the orders/, logs/, and other directories the same, but I
prefer to start with a clean slate, especially since I don't plan on
having any customers visit the development site.  (In fact, you can
restrict who can access the development URL using the Apache
<Directory> allow from... directive).

9.4.1.1. Checkout source code
-----------------------------

cd /var/lib/interchange
cvs co -d foundation_dev foundation

9.4.1.2. Copy any other needed directories to complete the catalog
------------------------------------------------------------------

Depending on how complete your catalog is in CVS, you may need to
create or copy directories/files.

cd /var/lib/interchange/foundation
cp -a catalog.cfg orders/*   \
        /var/lib/interchange/foundation_dev

Note: A lot of the following steps are performed by the
/usr/local/interchange/bin/makecat script, but here is how to do it
manually:

9.4.2. Setting up a separate database
-------------------------------------

Most often, I find it profitable to make use of a second database for
the development catalog, rather than having both catalogs reference
the same database (especially if the first catalog is live).

9.4.2.1. Create a second database
---------------------------------

Use the means of your database platform to create a separate database.
 For example, PostgreSQL users might do something like:

createdb foundation_dev

9.4.2.2. Populate the database
------------------------------

You can rely on the catalogs internal products/*.txt data to generate
the database tables and populate them, or you can export another
catalog's database and import it for the development catalog, like the
example below for PostgreSQL users.

pg_dump foundation  > ~/foundation.dump
psql foundation_dev < ~/foundation.dump

9.4.3. Copy the catalog support files
-------------------------------------

#Must be root
su - root

#Copy HTML
cd /var/www/html/
cp -a foundation foundation_dev

#Copy CGI
cd /var/www/cgi-bin
cp -a foundation foundation_dev

9.4.4. Configure the Interchange daemon
---------------------------------------

Perform the necessary modifications to interchange.cfg.  For example:

/usr/local/interchange/interchange.cfg:
Catalog foundation     /var/lib/interchange/foundation     /cgi-bin/foundation
Catalog foundation_dev /var/lib/interchange/foundation_dev /cgi-bin/foundation_dev

9.4.5. Configure the catalog specifics
--------------------------------------

The development catalog will differ at least a little bit from the
standard catalog, such as in the CGI_URL and database parameters.  You
can also modify/add the foundation_dev/variable.txt instead of the
following.

/var/lib/interchange/catalog.cfg:
Variable CGI_URL   /cgi-bin/foundation_dev
Variable IMAGE_DIR /foundation_dev/images
Variable SQLDSN    dbi:Pg:dbname=foundation_dev
Variable SQLDB     foundation_dev

Now you can restart Interchange to make your changes take effect.

9.5. Splitting updates on commit by tag
---------------------------------------

Setup CVS so that when you commit to the DEV1 branch, only the
development (foundation_dev) catalog will be updated.  And when you
commit with no tags (HEAD branch), the live (foundation) catalog will
be updated.  Here is an example loginfo.  The -r <tag> may be used
just in case your environment is such that the tags may be changed by
other sources.

$CVSROOT/CVSROOT/loginfo:
^foundation      (date; cat; (sleep 1; cd /var/lib/interchange/foundation_dev; cvs -q up -d; cd /var/lib/interchange/foundation; cvs -q up -d) &) >> $CVSROOT/CVSROOT/updatelog 2>&1
ALL     /usr/bin/cvs-log     $CVSROOT/CVSROOT/commitlog $USER "%{sVv}"

9.6. Using new branches
-----------------------

To use your new branch, checkout a working copy of the source with the
correct tag specified.  For example:

cvs co -P -r DEV1

Then make change to one of the files, and commit it.  The change
should show on your development catalog, but not your live catalog.

9.7. Merging
------------

When you want to merge a change that you have made on your development
branch into your stable branch, there are many ways that you can do
it.  One would be to :

     o    Make a change in the development branch (DEV1) and commit
          it.

     o    Copy the development-tagged file to a temporary name

     o    Update to the live version (HEAD)

     o    Overwrite the live (HEAD) version of the file with your
          temporary one

     o    Commit the result

     o    Update back to the development version (DEV1)

I do the above so often that I have written a Tcl script for WinCVS
that will automatically perform the above steps.  And similar shell
scripts can probably be easily written to match your development
environment.

The above seems to be the easiest way, to me.  However, there are
other alternatives detailed in the CVS manual in chapter 5, "Branching
and merging", that I highly recommend for reading.  One method
involves specifying the last version that has already been merged into
the live branch using a specific version number, date, relative time,
or special purpose tag.

10. Tools of the trade
======================

This is the productivity tips section, which will hopefully help you
to be able to get more done in less time.

10.1. Workstation Interchange installation
------------------------------------------

Not all developers work on Linux workstations, many use Apples
(graphics designers and HTML gurus tend to, I've found), and many use
Windows.  This means that many developers have the extra step of
uploading their changes to a Unix server where Interchange is running
in order to see their changes.

The remedy to that is to setup an Interchange server on your
workstation, or any location that has direct access to the CVS source
files.  I'll explain:

The Interchange server that runs where the CVS server is (that we
setup earlier) can be seen as the gathering point for all the
developers.  However, each developer may run as many Interchange
daemons as he/she requires in a local context for the purpose of
seeing the changes made before uploading them via CVS.

For example, Bob could setup another Interchange catalog on the same
server as the CVS, (e.g. foundation-bob).  To get direct access to
those files (rather than FTP), Bob could use NFS mounts (if Bob's
workstation is Linux) or SMB mounts using Samba if his workstation is
a Windows variant.  Any way that Bob can get direct access to the
files will save him some time (by cutting out the "upload" from the
"edit->upload->test" development cycle).  One could even use VMware to
run a Linux server on your Windows workstation.

Note: You can now use the cygwin compatibility confirmed in
Interchange versions 4.7.6 and above to run Interchange right on your
Windows workstation.

The result will be that you can modify the files with your favorite
text editor and see the results immediately through your local
catalog.  Setting up the catalog initially is quite easy.  Just follow
the same steps used to setup the CVS catalog.  Which is:

o    Stop Interchange.

o    bin/makecat a new catalog.

o    Checkout from CVS into a new CVS catalog directory and link the
     images/ directory.

o    Move any needed files back into the CVS catalog directory.

o    Make modifications to products/variable.txt and catalog.cfg (e.g.
     CGI_URL, HOSTNAME, DBI_USER, DBI_PASSWORD).

o    Restart Interchange.

One aspect of this local configuration is managing the differences
between the main Interchange daemon which runs on the CVS server and
the local Interchange daemon.  The differences are probably hostname,
database information, etc.  That will all need to be managed (usually
through catalog.cfg entries) and database exports & imports (i.e. the
postgres pg_dump command).

Another thing that you might have noticed at this point is all the
files that are modified locally by the Interchange daemon will report
? or M when you run an update.  This can be handled with
CVSROOT/cvsignore and $CVSIGNORE, which are beyond the scope of this
document.

10.2. Mailserver for CVS updates
--------------------------------

To setup a mailserver for CVS updates, first download and install
Mailman. For RPM-based systems, check on rpmfind.net for a precompiled
binary package.

After installing, read the following information about Mailman and
what needs to be done after installation (taken from the RPM meta
data):

"Mailman is software to help manage email discussion lists, much like
Majordomo and Smartmail. Unlike most similar products, Mailman gives
each mailing list a web page, and allows users to subscribe,
unsubscribe, etc. over the web. Even the list manager can administer
his or her list entirely from the web. Mailman also integrates most
things people want to do with mailing lists, including archiving, mail
<-> news gateways, and so on.

When the package has finished installing, you will need to:

o    Run /var/mailman/bin/mmsitepass to set the Mailman administrator
     password.

o    Edit /var/mailman/Mailman/mm_cfg.py to customize Mailman's
     configuration for your site.

o    Modify the sendmail configuration to ensure that it is running
     and accepting connections from the outside world (to ensure that
     it runs, set "DAEMON=yes" in /etc/sysconfig/sendmail, ensuring
     that it accepts connections from the outside world may require
     modifying /etc/mail/sendmail.mc and regenerating sendmail.cf),
     and

o    Add these lines:

  ScriptAlias /mailman/ /var/mailman/cgi-bin/
  Alias /pipermail/ /var/mailman/archives/public/
  <Directory /var/mailman/archives>
    Options +FollowSymlinks
  </Directory>

to /etc/httpd/conf/httpd.conf to configure your web server.

Users upgrading from previous releases of this package may need to
move their data or adjust the configuration files to point to the
locations where their data is."

Then run /var/mailman/bin/newlist and follow the directions from
there.

10.3. Locally mapped source code for a network IC server
--------------------------------------------------------

This is useful mostly to Windows users, since Linux users can just as
easily run IC daemons on their own workstation as they can a separate
server.

The idea is to have the IC server use its own files and directories
for things that won't be edited and modified locally, but reference a
Samba directory or NFS directory for things that will (such as pages/,
templates/, etc.).

10.3.1. Mount the Samba or NFS directory
----------------------------------------

smbmount <...> or mount -t nfsfs <...>

The following script uses two directories (source and destination) to
create symlinks for the commonly modified source directories of
Interchange.

export S=/mnt/nfs/foundation
export D=/var/lib/interchange/foundation
F=db; ln -s $S/$F $D/$F
F=dbconf; ln -s $S/$F $D/$F
F=etc; ln -s $S/$F $D/$F
F=images; ln -s $S/$F $D/$F
F=pages; ln -s $S/$F $D/$F
F=special_pages; ln -s $S/$F $D/$F
F=templates; ln -s $S/$F $D/$F

This will leave you with a working catalog that can be quickly
modified (since your editor can access the local copy), while
Interchange has to do the work of going over the SMB or NFS
connection.

10.4. jEdit - a good editor with Interchange/HTML/Perl colorization and CVS
---------------------------------------------------------------------------

I have been quite impressed with jEdit (http://www.jedit.org, and open
source editor that is written in Java and runs on most platforms.

I use the interchange.xml language definition written by Chris
Jesseman chris@sitemajic.net, which is available from
http://www.sitemajic.net/jedit/.  With this, jEdit automatically
colors HTML, Perl, AND many Interchange tags very intelligently.

Further, jEdit has a CVS plugin, written by Ben Sarsgard
bsarsgard@vmtllc.com, and available at:
http://www.vmtllc.com/~bsarsgard/jedit.html.  This plugin allows you
to diff, update, and commit right from the editor.

10.5. Separate servers for development and live catalogs
--------------------------------------------------------

If you have the luxury of separate server hardware for the development
and live catalogs, you might find the following utility helpful:

o    CVSviaFTP (http://www.cvshome.org/dev/addoncvsftp.html) - from
     the CVS Add-ons page (http://www.cvshome.org/dev/addons.html).

It allows one to have a given CVS module automatically publish each
update to an FTP server, which could serve as the live server.  Or one
could could use it if your CVS installation is only local and you
could use it to upload your changes to your production server.

A. Credits
==========

o    Jon Jensen: Thanks for helping me get going on the SDF format
     already used by the Interchange documentation, and fixing some
     SDF syntax errors.

o    Mike Heins & all who have contributed to the success of
     Interchange: Thanks for following the Way Of The Source, for
     quality programming, and for helping to making IC something to
     write about.

o    Thanks to the countless others who have written the CVS
     documentation that is available online, which was my only source
     for learning CVS.

B. Document history
===================

o    May 2001.  Conceived and written by Dan Browning.

o    July 19, 2001.  First draft complete, first public release.

o    April 12, 2002.  Minor typographical edit.

o    June 8, 2002.  Minor updates.

C. Resources
============

C.1. CVS Documentation
----------------------

Here are some resources for learning more about CVS.  I have ranked
them by the order of usefulness, which is of course, objective.

o    Karl Fogel's CVS book http://cvsbook.red-bean.com/

o    The official CVS manual http://www.cvshome.org/docs/manual/

o    The official CVS FAQ http://faq.cvshome.org/

o    The official CVS homepage http://www.cvshome.org

o    Info-CVS mailing list
     http://mail.gnu.org/mailman/listinfo/info-cvs

o    CVS FAQ 2 http://www.cs.utah.edu/dept/old/texinfo/cvs/FAQ.txt

o    Sean Dreilinger's CVS Version Control for Web Site Projects
     http://durak.org/cvswebsites/

o    Pascal Molli's CVS reference site
     http://www.loria.fr/~molli/cvs-index.html

o    CVS Tutorial
     http://cellworks.washington.edu/pub/docs/cvs/tutorial/cvs_tutorial_1.html

o    CVS Tutorial 2
     http://www.csc.calpoly.edu/~dbutler/tutorials/winter96/cvs/

o    Red Hat CVS pserver setup guide
     http://www.michael-amorose.com/cvs/

o    CVS Add-ons http://www.cvshome.org/dev/addons.html

C.2. CVS Server Software
------------------------

o    CVS RPM download (Red Hat Linux 7.1) 
     ftp://speakeasy.rpmfind.net/linux/redhat/7.1/en/os/i386/RedHat/RPMS/cvs-1.11-3.i386.rpm

o    Links to source tarball links can can be found at cvshome.org.

C.3. CVS Client Software
------------------------

There is a variety of client access methods for using CVS on your
development box.

o    CVSGUI is a great project that brings graphical clients to Linux,
     Windows, and Mac at http://www.cvsgui.org.  These also give you
     the same access to all the command line cvs commands.

o    jCVS is a great cross-platform graphical CVS client available at
     http://www.jcvs.org.

o    jEdit is a great cross-platform text editor written in java,
     which not only has a CVS module that allows you to commit
     (upload) files directly from the editor, but also has a
     Interchange Tag Language (and Perl language) colorizer/parser. 
     It is available from http://www.jedit.org.

______________________________________________________________________

Copyright 2001,2002 Dan Browning <dan.browning@kavod.com>.  Freely
redistributable under terms of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License.

line:

Interchange + Forum/Blog HOWTO
==============================

11. Introduction
================

11.1. Preamble
--------------

Copyright 2002 Mike Heins <mike.heins@perusion.net> and Michael Wilk
<mwilk@steppenwolf.com>. Freely redistributable under terms of the GNU
General Public License.

11.2. Purpose
-------------

The purpose of this document is to expose how to use Interchange 5.0's
forum and blog capability, enabled with the [forum ...] tag and a few
ancilliary files.

11.3. Audience
--------------

Anyone who is using an Interchange catalog. This is not rocket
science.

11.4. Contact the authors
-------------------------

If you find any spelling errors, technical slip-ups, mistakes,
subliminal messages, or if you wish to send feedback, critique,
remarks, comments, or if you wish to contribute examples, instructions
for alternative platforms, chapters, or other material, please do so.

The preferred method of submitting changes is in the form of a context
diff against the SDF source file (ic_howto_forum.sdf). Please address
your correspondence to:

Michael Wilk mwilk@steppenwolf.com

Mike Heins mike.heins@perusion.net

11.5. What it does
------------------

Interchange forums allow your customers to comment on your products,
or allow you to sponsor discussion threads on an interchange catalog.
They maintain their content in a single database table named forum.

12. Component files of the forums
=================================

There are two directories to add to your foundation catalog --
include/forum and pages/forum. You must add a database table
definition, as well as a database source file. You should add Variable
support to the variable.txt database, and supporting metadata with
help. Finally, you need to add the forum.tag file which contains the
forum code.

If you build a foundation catalog from the latest Interchange source,
all of these will be done already.

The files that are needed in the catalog directory:

        dbconf/default_db/forum.dbm
        dbconf/mysql/forum.mysql
        dbconf/pgsql/forum.pgsql
        include/forum/reply_form
        include/forum/submit_form
        pages/forum/reply.html
        pages/forum/display.html
        pages/forum/submit.html
        products/forum.txt

The files that are needed in the Interchange software directory:

        code/UserTag/forum.tag

Add the following lines to products/variable.txt (change | to TAB):

FORUM_ANON_NAME|Anonymous Coward|Forums
FORUM_PRODUCTS|1|Forums
FORUM_EMAIL_NOTIFY|sales@yourcompany.com|Forums

Add the following lines to products/mv_metadata.asc (change | to TAB):

variable::Variable::FORUM_EMAIL_NOTIFY|text|50||||||||Forum notify email|An email address to send copies of user comments on products.||||||||||
variable::Variable::FORUM_ANON_NAME|text|20||||||||Forum Anonymous Name|Name to use when a user posts anonymously to a forum||||||||||
variable::Variable::FORUM_PRODUCTS|yesno|||||||||Enable Product Forums|This enables user comments on products in the flypage. Only enabled by default if using MySQL or Postgres, as it will not work well on DBM and is not tested on Oracle.||||||||||

Add the following block to pages/flypage.html:

        [if variable FORUM_PRODUCTS]
          <tr>
                <td>
                        [forum top="[item-code]" display_page="forum/display" /]
                        <p>
                        [page href="forum/reply"
                                        form="
                                                product=1
                                                mv_arg=[item-code]
                                        "
                        ]Comment on this product.</A>
                        </p>
                </td>
          </tr>
        [/if]

This would normally go at the end of the table displaying the product,
but you can place and edit to suit.

Again, all of this is provided if you have installed from the latest
Interchange 4.9.4 or higher.

13. The [forum] ITL Tag
=======================

The [forum] tag is what provides the capability. It uses the forum
table and follows tree-like threads in that table.

It has one required parameter, top. That gives the id of the message
that is the top of the thread to display.

This is a complete forum display for a product:

        [forum top="[item-code]" /]

You will see something like that in the snip from pages/flypage.html
above.

You can pass many more parameters to the [forum] tag. Some of them
are:

display-page

By default, the [forum ...] tag uses the current page to link to to
re-display the forum at another level. Normally this works fine, but
on a product flypage it will not work. You must pass in a different
page.

        [forum top="[item-code]" display-page="forum/display" /]

show-level

By default, [forum] only displays the text of top-level replies to the
current thread. If you want to display more levels, set the show-level
parameter to 1 or higher:

        [forum top="[data session arg]" show-level=3 /]

The above will show the first four levels of replies, with links to
any further down the tree.

scrub-score

If you want to moderate certain comments so that their text won't be
shown, you can set the scrub-score parameter to -1 and then set the
score field in the message's database record to -1. By default, it is
linked to with a message:

  <A HREF="{DISPLAY_URL}">One message beneath your threshold</A>

If you want to totally disable the appearance of the link and message,
set the scrub-template to something:

        [forum top=THREAD scrub-score="-1" scrub-template="<!-- killed! -->" /]

show-score

By default, if a message has a score of two or higher, it's text will
be shown no matter what level of display it is on. You can set that
threshold with this paramter.

template

You can set the template that displays replies with this parameter.
You can also pass this as the container text for the [forum] tag,
i.e.:

        [forum top="[data session arg]"]
        <table cellspacing=0 cellpadding=2 width="65%">
                  <tr>
                        <td class=contentbar1>
                                <A HREF="{DISPLAY_URL}"><b>{SUBJECT}</b></A>
                                by <b>{USERINFO}</b>
                                on {DATE}
                        </td>
                        <td class=contentbar1 align=right>
                                &#91;
                                        <A HREF="{REPLY_URL}"><b>Reply</b></A>
                                &#93;
                        </td>
                  </tr>
                  <tr>
                        <td colspan=2>
                        {COMMENT}
                        </td>
                  </tr>
                </table>
        [/forum]

See pages/forum/display.html for an example.

header-template

You can set the header template that displays the top-level message
with this parameter. See pages/forum/display.html for an example.

link-template

You can set the template that displays the links to messages that are
not shown with this parameter. See pages/forum/display.html for an
example.

scrub-template

The template for a message that has a score lower than scrub-score.
See pages/forum/display.html for an example.

threshold-message

The message displayed in the default scrub-template when a message is
scrubbed. If you set the scrub-template yourself, it is ignored.

display-page

The page linked to with {DISPLAY_URL}. Default is the current page.
See Templating below.

reply-page

The page linked to with {REPLY_URL}.  Default is forum/reply.html. See
Templating below.

submit-page

The page linked to with {SUBMIT_URL}. Default is forum/submit.html.
See Templating below.

date-format

The format for the date provided with {DATE}. Default is %B %e, %Y
@%H:%M, which provides a date like October 5, 2002 @21:19.

14. Templating
==============

All of the [forum] display mechanisms are templated. You can pass four
templates -- template, header-template, link-template, and
scrub-template.

They use the substitution style found in Interchange's attr-list ITL
tag.

The following values are available for templating:

   ADDITIONAL    Additional text normally only used at the top level
   COMMENT       Text of the message
   CREATED       Created date in ISO format
   DATE          Date the comment was made
   DISPLAY_URL   URL to display the forum with a new starting point
   FORUM_APPEND  End indent </UL> tags for item (automatic, don't use)
   FORUM_PREPEND Begin indent <UL> tags for item (automatic, don't use)
   MOD_TIME      Modified date in ISO format
   PARENT_URL    URL to call the parent of the comment
   REASON        Text indicating reason for scoring
   REPLY_URL     URL to reply to the commetn
   SCORE         Score of the article
   SUBJECT       Subject of the message
   SUBMIT_URL    URL to submit a new top-level thread
   TOP_URL       URL to call the top level of the thread (if not at top)
   USERINFO      User information based on login status and anonymity

You can see how the above are used by examining the file
pages/forum/display.html and playing around with the provided
templates.

14.1. Templating rules
----------------------

14.1.1. {KEY}
-------------

Inserts the value of the KEY for the reference. In a database query,
this is the column name.

14.1.2. {KEY|fallback string}
-----------------------------

Displays the value of {KEY} or if it is zero or blank, the fallback
string (i.e., default).

14.1.3. {KEY true string}
-------------------------

Displays true string if the value of {KEY} is non-blank, non-zero, or
displays nothing if the key is false.

14.1.4. {KEY?} true text {/KEY?}
--------------------------------

Displays true text if the value of {KEY} is non-blank, non-zero, and
nothing otherwise.

14.1.5. {KEY:} false text {/KEY:}
---------------------------------

Displays false text if the value of {KEY} is blank or zero, and
nothing otherwise.

Copyright 2002 Mike Heins <mike.heins@perusion.net> and Michael Wilk
<mwilk@steppenwolf.com>. Freely redistributable under terms of the GNU
General Public License. line:

Interchange + QuickBooks HOWTO
==============================

15. Introduction
================

15.1. Summary Description
-------------------------

Interchange QuickBooks -- QuickBooks support for transactions and
items

15.2. Audience
--------------

Users who already have Quickbooks setup and are familiar with it, in
addition to having the foundation (or other) catalog correctly
working.

15.3. Contact the author
------------------------

If you find any spelling errors, technical slip-ups, mistakes,
subliminal messages, or if you wish to send feedback, critique,
remarks, comments, or if you wish to contribute examples, instructions
for alternative platforms, chapters, or other material, please do so.

The preferred method of submitting changes is in the form of a context
diff against the SDF source file (ic_howto_qb.sdf).  Please address
your correspondence to:

Volunteer Maintainer, Dan Browning dan.browning@kavod.com

or

Original Author, Mike Heins mike@perusion.com

15.4. Version
-------------

This document describes software based on Interchange 4.5 and later.

16. Description
===============

Interchange is a business-to-business and business-to-consumer
internet ordering and cataloguing product. It has the ability to take
orders via the World Wide Web, and store transaction data.

This document describes how to interface Interchange with QuickBooks,
the popular small-business accounting program from Intuit.

QuickBooks has an import/export format called IIF, a mnemonic for
Intuit Interchange Format. Fitting, eh?

The standard capabilities of Interchange allow production of IIF files
for transaction passing.  With some support from Interchange UserTags,
can even import and export item listings.

17. Contents
============

The extension files can be found in the Interchange tarball under the
'extensions/quickbooks' directory.  The following files are used with
this extension:

  usertag/import_quicken_items  UserTag for importing items
  usertag/export_quicken_items  UserTag for exporting items
  pages/admin/quickbooks/*      Menu support for Interchange UI
  etc/trans_quickbooks          Report file used with quickbooks route
  qb.catalog.cfg                Route for quickbooks transaction logging

18. Installation
================

To set up this extension, the basic steps are:

o    Create and copy directories and files.

o    Add additional database fields.

o    Modify catalog.cfg with additions.

o    Add "quickbooks" order route to checkout pages.

o    Restart Interchange.

o    Export your items from Interchange catalog (or import your
     existing QuickBooks items to Interchange).

o    Test.

18.1. Terms and locations
-------------------------

Several terms are used in the examples.

Catalog Directory

     This is the main directory for the catalog, where catalog.cfg
     resides. It will have a NAME, the name for the catalog. (Some
     common Interchange demo names are foundation, construct, barry,
     and simple.)

     Common locations:

     /var/lib/interchange/NAME /usr/local/interchange/catalogs/NAME
     $HOME/catalogs/NAME

     We will use the path /var/lib/interchange/foundation in these
     examples.

Interchange software directory

     This is the main directory for your Interchange server, where the
     file interchange.cfg resides. Common locations:

     /usr/lib/interchange /usr/local/interchange $HOME/ic

     We will use the path /usr/lib/interchange in these examples.

Interchange User

     The Interchange daemon runs as a user ID that cannot be root. It
     will require write permission on directories it must modify to do
     its work.

     We will use the user ID interch in these examples.

18.2. Create and copy directories and files
-------------------------------------------

This extension requires you to add some files to your catalog.

It is assumed you have tools and knowledge to create directories with
the proper permissions. Any directories that will contain varying
files like order transaction logs will require write permission for
the Interchange daemon user; pages and configuration only need have
read permission.

Make orders directory

     Create the directory orders in your Catalog Directory if it
     doesn't already exist. (It may be a symbolic link to another
     location.) It must have write permission on it.

     cd /var/lib/interchange/foundation mkdir orders

     If you are doing this as root, also do:

     chown interch orders

     This directory is used to store the QuickBooks IIF files produced
     for orders. The files are created with the form:

     qbYYYYMMDD.iif

     Each day will have a file, and when a day is complete you should
     download the orders. (There are other schemes possible.)

Copy pages

     You will want the Interchange UI support if you are using the UI.
     It provides links for importing/exporting items, downloading and
     viewing IIF files, and possibly other functions over time. At the
     UNIX command line:

     cp -r
     /usr/lib/interchange/extensions/quickbooks/pages/admin/quickbooks
     \ /var/lib/interchange/foundation/pages

Copy report generation file etc/trans_quickbooks

     This file is used to generate the IIF file(s) for transaction
     oimport into QuickBooks.

     cp
     /usr/lib/interchange/extensions/quickbooks/etc/trans_quickbooks \
     /var/lib/interchange/foundation/etc

Copy usertags

     If you want to use the UI item import/export, two usertags are
     required. The easiest thing is just to copy them to the
     Interchange software directory subdirectory lib/UI/usertag, which
     is #included as a part of the UI configuration file.

     cd /usr/lib/interchange cp -i extensions/quickbooks/usertag/*
     lib/UI/usertag

18.3. Additional database fields -- userdb
------------------------------------------

Quickbooks requires a couple more fields than Interchange has. If you
want the user to retain their customer number, add the following field
to the "userdb" table:

customer_number

It can be an integer number field if your database needs that
information. To add the field in MySQL, you can issue the following
queries at the mysql prompt:

alter table userdb add column customer_number int;

If you don't add it, it just means that a new customer number will be
assigned every time.

WARNING If you are using Interchange DBM files and have live data it
is not recommended you add this field unless you are positive you will
not overwrite your data. If you are not a developer, get one to help
you. In any case, back up your userdb.gdbm or userdb.db file first.

18.4. Additional database fields -- inventory
---------------------------------------------

Quicken also needs an account to debit for the split transactions it
uses to track item sales. If you don't create these fields to relate
to each SKU, the account "Other Income" will be used in the exports.

Add the following fields to the "inventory" table:

account cogs_account

To add the fields in MySQL, you can issue the following queries at the
mysql prompt:

alter table inventory add column account char(20); alter table
inventory add column cogs_account char(20);

Other SQL databases will have similar facilities.

If you are using Interchange DBM files, just export the inventory
database, stop the Interchange server (to prevent corruption), add the
fields on the first line by editing the inventory.txt file, then
restart Interchange.

18.5. Modify catalog.cfg with additions:
----------------------------------------

Add the entries in qb.catalog.cfg to catalog.cfg (you can use a
#include statement if you wish).

There are some Require directives to ensure that the needed UserTag
definitions are included in the catalog, as well as the Route which is
used

18.6. Add quickbooks order route
--------------------------------

In the Interchange UI, there is a Preferences area "ORDER_ROUTES". You
should add the quickbooks route. Place it after the transaction
logging step, i.e.

code     ORDER_ROUTES Variable log quickbooks main copy_user

ADVANCED, If you know Interchange Variable settings, you can add it
directly:

Variable ORDER_ROUTES  log quickbooks main copy_user

Also, you can use other methods to set order routes. See the
Interchange reference documentation.

18.7. Additional Variables
--------------------------

Optionally, you may specify some variables that modify the behavior of
the Quickbooks export feature.  Below is a command that will append
the empty variables to your variable.txt file.

cat >>/path/to/your/products/variable.txt  <<EOF
QB_DISABLE_DOCNUM               Quickbooks
QB_ITEM_PREFIX          Quickbooks
QB_ITEM_LENGTH          Quickbooks
QB_FILE_SUFFIX          Quickbooks
QB_SHIPPING_ACCOUNT             Quickbooks
QB_SHIPPING_ITEM                Quickbooks
QB_DEFAULT_ACCOUNT              Quickbooks
QB_SALES_TAX_ACCOUNT            Quickbooks
QB_SALES_TAX_AGENCY             Quickbooks
QB_SALES_TAX_ITEM               Quickbooks
EOF

Documentation for these variables is provided via item-specific meta
data, which can be added to your mv_metadata.asc file in a similar way
as above for automatic display by the Admin UI:

cat >>/path/to/your/products/mv_metadata.asc  <<EOF
variable::Variable::QB_DISABLE_DOCNUM   yesno                                                                           <b>Yes</b> will cause the invoice number (AKA DOCNUM & Document Number) to be blank.  No by default.  <b>No</b> will cause etc/trans_quickbooks the use of the Interchange order number as the Quickbooks invoice number.  Some prefer to have the number left blank so as not to cause Quickbooks to change its auto-count.
variable::Variable::QB_ITEM_PREFIX      text                                                                            A prefix applied to all product names (the unique identifier in Quickbooks).  Empty by default.  For example, some Quickbooks users may have a category for all the products sold on their website such as "E-Commerce Products:" (the colon is a category deliniator for Quickbooks).  Other Quickbooks users may use the same category scheme in in their Interchange store as they do in their Quickbooks item lists, in which case something to this effect would be applicable:  "[item-field category]:"
variable::Variable::QB_ITEM_LENGTH      text                                                                            The item name maximum length for product line items (any characters past this length will be truncated).  30 by default.  Quickbooks versions 6.0 and 99 may have a problem with item names that are longer than 30 characters; however, lengths of 45 and longer have been known to work on Quickbooks 2000 and later version.  Please report any compatibility problems/information to the interchange-users@icdevgroup.org mailing list.
variable::Variable::QB_FILE_SUFFIX      text                                                                            If left blank, the current date will be used and each order will be appended to the file.  <BR><BR>Another option is to use [value mv_order_number] to cause the creation of a separate file for each order.
variable::Variable::QB_SHIPPING_ACCOUNT text                                                                            The income account associated with shipping.  "Other Income" by default.
variable::Variable::QB_SHIPPING_ITEM    text                                                                            The item name given for the shipping.  "Shipping" by default.
variable::Variable::QB_DEFAULT_ACCOUNT  text                                                                            The income account associated with each product line item.  "Other Income" by default; however, the highest precence is 'account' field in the 'inventory' table.
variable::Variable::QB_SALES_TAX_ACCOUNT        text                                                                            The liability account associated with sales tax.  "Sales Tax Payable" by default.
variable::Variable::QB_SALES_TAX_AGENCY text                                                                            The name of the sales tax agency for your locality.  "State Board of Equalization" by default (the name given in the Quickbooks 2000 sample products based business).
variable::Variable::QB_SALES_TAX_ITEM   text                                                                            The item name (Quickbooks unique identifier) for the sales tax.  "Sales Tax Item" by default (from Quickbooks 2000 sample products based business).
EOF

18.8. Restart the catalog
-------------------------

This can be done by restarting the Interchange server or by clicking
Apply Changes in the UI.

18.9. Export the items
----------------------

You can access the Quickbooks UI index by making your URL:

http://YOURCATALOG_URL/admin/quickbooks/index

It will provide options for importing and exporting items. This is
necessary so QuickBooks will be able to take orders for your items.

QuickBooks uses the product "name" as an SKU, along with an integer
reference number. Either you need to make your SKUs match the integer
reference number, or you must ensure your product title is unique.

18.10. Test
-----------

Place a test order on your Interchange catalog once you have finished
installing. You should find a file in the orders directory with the
name qbYYYYMMDD.iif. (YYYY=year, MM=month, DD=day.) Transfer this file
to your QuickBooks machine and run File/Import and select that file as
the source. This should import the customer and order into the system.
If it doesn't work, it may be due to lack of sales tax or shipping
definitions, discussed below.

19. Discussion
==============

The interface provided works for the sample company data distributed
with QuickBooks. There are certain requirements to make sure it works
in your environment.

Also, you can change the configuration by editing the file
etc/trans_quickbooks to suit your IIF file needs.

19.1. Sales Tax
---------------

QuickBooks has a taxing system whereby tax rates are defined by
customer location. There is usually also a generic Sales Tax Item,
such as contained in the sample company data. This allows Interchange
to calculate the sales tax. If that item is not present then you will
need to create it, or specify your tax item using the
QB_SALES_TAX_ITEM variable.

19.2. Shipping
--------------

Interchange will add a generic item Shipping to each order that has a
shipping cost. Its MEMO field will contain the text description of the
mode. If that item is not in your QuickBooks item definitions, then
you must create it, or specify your shipping item using the
QB_SHIPPING_ITEM variable.

19.3. Customer Imports
----------------------

To generate a QuickBooks transtype of INVOICE, a CUSTOMER is required.
Interchange outputs a CUST IIF record for each sale with the customer
information. Since QuickBooks uses the customer name or company to
generate the unique listing, we place the Interchange username in
parentheses after the company or name.

D. Credits
==========

o    Mike Heins: This document was copied from the original POD
     documentation (extensions/quickbooks/ic_qb.pod) written by Mike
     Heins mike@perusion.com.

o    Dan Browning: Slightly modified by Dan Browning
     dan.browning@kavod.com.

E. Document history
===================

o    July 20, 2002.  Initial revision.

F. Resources
============

F.1. Documentation
------------------

o    What are the IIF File Headers?
     http://www.quickbooks.com/support/faqs/qbw2000/121756.html

o    See the Quickbooks Help item, "Reference guide to import files"

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Advanced Interchange Topics
===========================

20. Advanced Interchange Topics
===============================

o    Maintaining production Interchange servers

o    Interchange Administration Tool Development

o    Making catalog skeletons for use with makecat

o    Building custom link programs

o    Installation tips and troubleshooting

o    Usertracking

21. Maintaining Interchange
===========================

Some utilities are supplied in the VendRoot/bin directory:

 compile_link Compiles an Interchange vlink or tlink CGI link
 configdump   Dumps the configuration directives for a particular catalog
 dump         Dumps the session file for a particular catalog
 expire       Expires sessions for a particular catalog
 expireall    Expires all catalogs
 makecat      Make catalog

Some example scripts for other functions are in the eg/ directory of
the software distribution.

Some thought should be given to where the databases, error logs, and
session files should be located, especially on an ISP that might have
multiple users sharing an Interchange server. In particular, put all
of the session files and logs in a directory that is not writable by
the user. This eliminates the possibility that the catalog may crash
if the directory or file is corrupted.

To test the format of user catalog configuration files before
restarting the server, set (from VendRoot):

   bin/interchange -test

This will check all configuration files for syntax errors, which might
otherwise prevent a catalog from booting. Once a catalog configures
properly, user reconfiguration will not crash it. It will just cause
an error. But, it must come up when the server is started.

21.1. Starting, Stopping, and Re-starting the Servers
-----------------------------------------------------

The following commands need to have VENDROOT changed to the main
directory where Interchange is installed. If the Interchange base
directory is /home/interchange/, the start command would be
/home/interchange/bin/interchange.

Do a perldoc VENDROOT/bin/interchange for full documentation.

To start the server with default settings:

   VENDROOT/bin/interchange

Assuming the server starts correctly, the names of catalogs as they
are configured will be displayed, along with a message stating the
process ID it is running under.

It is usually best to issue a restart instead. It doesn't hurt to do a
restart if you're actually starting the first time. And, if a server
is already running (from this VENDROOT), a new start attempt will
fail. To restart the server:

   VENDROOT/bin/interchange -restart

The -r option is the same as -restart.

This is typically done to force Interchange to re-read its
configuration. A message will be displayed stating that a TERM signal
has been sent to the process ID the servers are running under. This
information is also sent to VENDROOT/error.log. Check the error.log
file for confirmation that the server has restarted properly.

To stop the server:

   VENDROOT/bin/interchange -stop

A message will be displayed stating that a TERM signal has been sent
to the process ID the server is running under. This information is
also sent to VENDROOT/error.log.

Because processes waiting for selection on some operating systems
block signals, they may have to wait for HouseKeeping seconds to stop.
The default is 60.

To terminate the Interchange server with prejudice, in the event it
will not stop:

   VENDROOT/bin/interchange -kill

21.2. UNIX and INET modes
-------------------------

Both UNIX-domain and INET-domain sockets can be used for
communication. INET domain sockets are useful when more than one web
server, connected via a local-area network (LAN), is used for
accessing an Interchange server.

Important note: When sending sensitive information like credit card
numbers over a network, always ensure that the data is secured by a
firewall, or that the Interchange server runs on the same machine as
any SSL-based server used for encryption.

Use the -i and -u flags if you only want to use one communication
method:

   # Start only in UNIX mode
   VENDROOT/bin/interchange -r -u

   # Start only in INET mode
   VENDROOT/bin/interchange -r -i

21.3. User Reconfiguration
--------------------------

The individual catalogs can be reconfigured by the user by running the
[reconfig] support tag. This should be protected by one of the several
forms of Interchange authentication, preferably by HTTP basic
authorization. See RemoteUser.

The command line can be reconfigured (as the Interchange user) with:

   VENDROOT/bin/interchange -reconfig <catalog>

It is easy for the administrator to manually reconfigure a catalog.
Interchange simply looks for a file etc/reconfig (based in the
Interchange software directory) at HouseKeeping time. If it finds a
script name that matches one of the catalogs, it will reconfigure that
catalog.

21.4. Expiring Sessions
-----------------------

If Interchange is using DBM capability to store the sessions,
periodically expire old sessions to keep the session database file
from growing too large.

   expire -c catalog

There is also an expireall script which reads all catalog entries in
interchange.cfg and runs expire on them. The expire script accepts a
-r option which tells it to recover lost disk space.

On a UNIX server, add a crontab entry such as the following:

   # once a day at 4:40 am
   40 4 * * *    perl /home/interchange/bin/expireall -r

Interchange will wait until the current transaction is finished before
expiring, so this can be done at any time without disabling web
access. Any search paging files for the affected session (kept in
ScratchDir) will be removed as well.

If not running DBM sessions, use a Perl script to delete all files not
modified in the last one or two days. The following will work if given
an argument of a session directory or session files:

   #!perl
   # expire_sessions.pl -- delete files 2 days old or older

   my @files;
   my $dir;
   foreach $dir (@ARGV) {
       # just push files on the list
       if (-f $dir) { push @files, $_; next; }

       next unless -d $dir;

       # get all the file names in the directory
       opendir DIR, $dir or die "opendir $dir: $!\n";
       push @files, ( map { "$dir/$_" } grep(! /^\.\.?$/, readdir DIR) ) ;
   }

   for (@files) {
       unless (-f $_) {
           warn "skipping $_, not a file.\n";
           next;
       }
       next unless -M $_ >= 2;
       unlink $_ or die "unlink $_: $!\n";
   }

It would be run with a command invocation like:

   perl expire_sessions.pl /home/you/catalogs/simple/session

Multiple directory names are acceptable, if there is more than one
catalog.

This script can be adjusted as necessary. Refinements might include
reading the file to "eval" the session reference and expire only
customers who are not members.

21.5. My session files change to owner root every day!
------------------------------------------------------

You have the expireall -r entry in the root crontab, and it should
either be in the Interchange user crontab or run as:

44 4 * * * su -c "/INTERCHANGE_ROOT/bin/expireall -r" INTERCHANGE_USERNAME

22. Interchange Components
==========================

Interchange components are merely portions of HTML/ITL that are
included into pages within the site depending on options set in the
Admin UI. The default component set includes the following:

best_horizontal
best_vertical
cart
cart_display
cart_tiny
category_vertical
cross_horizontal
cross_vertical
promo_horizontal
promo_vertical
random_horizontal
random_vertical
upsell_horizontal
upsell_vertical

22.1. Content -> Page Edit
--------------------------

The Interchange Admin UI offers a page editor function that allows
component definitions and options to be modified for each page within
the catalog.

22.1.1. Template
----------------

The choices for the Template drop-down are read from template
definition files located in the CATROOT/template directory. These
files store the name and description of the template, as well as
components and options for the particular template.

To create a new template for use in the admin, it is best to copy an
existing template definition to a new file name and edit it's contents
to suit. Once the catalog is reconfigured, the new choice will be
visible within the Content Page Editor admin function.

Each template option is looped through and a scratch is set using its
same name and value.

ITL is used near the bottom of this file to set each option to default
values before the page is displayed.

[set page_title][set]
[set page_banner][set]
[set members_only][set]
[set component_before][set]
[set component_after][set]
[set bgcolor]#FFFFFF[/set]

22.1.2. Page Title
------------------

Sets the title of the page which is synonymous with the html
<title></title> code.

The following code within the template definition file is used to
display this option within in the content editor:

page_title: description: Page title

This code dynamically adds the title to the page:

<title>[scratch page_title]</title>

22.1.3. Page Banner
-------------------

Sets a textual title for each page which is called by [either][scratch
page_banner][or][scratch page_title][/either] This results in the Page
Banner being displayed if defined. Otherwise, the Page Title is used.

22.1.4. Members Only
--------------------

The members only function is handled by the following code within each
template file:

[if scratch members_only]
    [set members_only][/set]
    [if !session logged_in]
    [set mv_successpage]@@MV_PAGE@@[/set]
    [bounce page=login]
    [/if]
[/if]

This code says if members only is set to yes and the visitor is logged
in, display the page. Otherwise, redirect the visitor to the login
page.

22.1.5. Break 1
---------------

This code causes a separation in the Content Editor between the next
set of options. (A blue line)

22.1.6. Horizontal Before Component
-----------------------------------

This allows the inclusion of a defined component to be displayed
before, or above, the page's content. It is called with the following
code within the LEFTRIGHT_TOP template:

[if scratch component_before]
[include file="templates/components/[scratch component_before]"]
[set component_before][/set]
[/if]

22.1.7. Horizontal After Component
----------------------------------

This function allows the inclusion of a defined component to be
displayed after or below the page's content. It's called with the
following code within the LEFTRIGHT_BOTTOM template:

[if scratch component_after]
[include file="templates/components/[scratch component_after]"]
[set component_after][/set]
[/if]

22.1.8. Horizontal Item Width
-----------------------------

This setting allows you to choose how many items the horizontal
components display. For example, the horizontal best sellers component
uses this setting to randomly select the best sellers. Notice the
default to 2 if nothing is defined.

random="[either][scratch component_hsize][or]2[/either]"

22.1.9. Special Tag
-------------------

This setting is only viable when a promotion is used for a horizontal
component. It tells the promotional component which rows to evaluate
in the merchandising table for display within the component. This
setting normally correlates to the featured column of the
merchandising table as follows:

        [query arrayref=main
                   sql="
                        SELECT sku,timed_promotion,start_date,finish_date
                        FROM merchandising
                        WHERE featured = '[scratch hpromo_type]'
                        "][/query]

22.1.10. Before/After Banner
----------------------------

Allows a title for the horizontal components to be defined to
displayed in a header above the component's items. It is called with
the [scratch hbanner] tag.

22.1.11. Break 2
----------------

This code causes a separation in the Content Editor between the next
set of options. (A blue line)

22.1.12. Vertical Component
---------------------------

Defines a component to be displayed along the right side of the
LEFTRIGHT_BOTTOM template. It is called from the template with the
following code:

[include file="templates/components/[scratch component_right]"]

22.1.13. Vertical Items Height
------------------------------

Sets the number of items to display within the vertical component.
Called with the following code:

random="[either][scratch component_vsize][or]3[/either]"

22.1.14. Right Banner
---------------------

Allows a title to be set for a vertical component which is displayed
as a header above the items in the vertical component. It's called
with the [scratch vbanner] tag.

22.1.15. Special Tag
--------------------

Essentially the same as the Special Tag setting described in item
number 9 above.

22.1.16. Background Color
-------------------------

Allows the background color of the page to be selected. The choices
are stored within the page or template definition as in:

bgcolor:
        options: #FFFFFF=White,pink=Pink
        widget: select
        description: Background color

22.1.17. Content
----------------

Allows the page code to be downloaded, uploaded and viewed/edited.
Only the code between <!-- BEGIN CONTENT --> and <!-- END CONTENT -->
is displayed or can be edited here.

22.1.18. Preview, Save, and Cancel buttons
------------------------------------------

Allows the changes to the edited page to be previewed in a pop-up
browser window, or saved. Cancel returns you to the page editor
selection page.

22.1.19. Save template in page
------------------------------

Template settings are stored in the template definitions by default.
This allows a common set of choices for template settings for all
pages. If specific setting options are desired for a page, the
template can be saved within the page so that it may have individual
options.

The in-page template definition must be surrounded by [comment] 
[/comment].

22.2. Custom Admin UI Options
-----------------------------

Other options may be added to the template by defining them in the
default definition file, or using in-page definitions.

When the following lines are added to the template definition, the new
option is added to the Admin UI.

option_name:
options: 1,2*,3
widget: select
description: Option Description
help: Other Details

Each time the template is used, an option_name scratch variable is
created. (Called with: [scratch option_name].) This scratch value will
be equal to what's selected here in the admin tool.

The possible widgets include:

break - produces the blue line separator.
radio - produces radio button type selections.
select - standard drop-down selector.
move_combo - select drop down with options and text input for new option.

23. Administrative Pages
========================

With Interchange's GlobalSub capability, very complex add-on schemes
can be implemented with Perl subroutines. And with the new writable
database, pages that modify the catalog data can be made. See
MasterHost, RemoteUser, and Password.

In addition, any Interchange page subdirectory can be protected from
access by anyone except the administrator if a file called '.access'
is present and non-zero in size.

23.1. Controlling Access to Certain Pages
-----------------------------------------

If the directory containing the page has a file .access and that
file's size is zero bytes, access can be gated in one of several ways.

1.   If the file .access_gate is present, it will be read and scanned
     for page-based access. The file has the form:

  page: condition
  *: condition

     The page is the file name of the file to be controlled (the .html
     extension is optional). The condition is either a literal Yes/No
     or Interchange tags which would produce a Yes or No (1/0 work
     just fine, as do true/false).

     The entry for * sets the default action if the page name is not
     found. If pages will be allowed by default, set it to 1 or Yes.
     If pages are to be denied by default in this directory, leave
     blank or set to No. Here is an example, for the directory
     controlled, having the following files:

 -rw-rw-r--   1 mike     mike            0 Jan  8 14:19 .access
 -rw-rw-r--   1 mike     mike          185 Jan  8 16:00 .access_gate
 -rw-rw-r--   1 mike     mike          121 Jan  8 14:59 any.html
 -rw-rw-r--   1 mike     mike          104 Jan  8 14:19 bar.html
 -rw-rw-r--   1 mike     mike          104 Jan  8 14:19 baz.html
 -rw-rw-r--   1 mike     mike          104 Jan  8 14:19 foo.html

     The contents of .access_gate:

   foo.html: [if session username eq 'flycat']
               Yes
             [/if]
   bar:      [if session username eq 'flycat']
             [or scratch allow_bar]
               Yes
             [/if]
   baz:      yes
   *:        [data session logged_in]

     The page controlled/foo is only allowed for the logged-in user
     flycat.

     The page controlled/bar is allowed for the logged-in user flycat,
     or if the scratch variable allow_bar is set to a non-blank,
     non-zero value.

     The page controlled/baz is always allowed for display.

     The page controlled/any (or any other page in the directory not
     named in .access_gate) will be allowed for any user logged in via
     UserDB.

2.   If the Variable MV_USERDB_REMOTE_USER is set (non-zero and
     non-blank), any user logged in via the UserDB feature will
     receive access to all pages in the directory. NOTE: If there is a
     .access_gate file, it overrides this.

3.   If the variables MV_USERDB_ACL_TABLE is set to a valid database
     identifier, the UserDB module can control access with simple ACL
     logic. See USER DATABASE. NOTE: If there is a .access_gate file,
     it overrides this. Also, if MV_USERDB_REMOTE_USER is set, this
     capability is not available.

23.2. display tag and mv_metadata
---------------------------------

Interchange can store meta information for selected columns of tables
in a site's database. This meta information is used when the user
interacts with the database. For example, the meta information for a
Hide Item field might specify that a checkbox be displayed when the
user edits that field, since the only reasonable values are on and
off. Or, the meta information might specify a filter on data entered
for a Filename field which makes sure that the characters entered are
safe for use in a filename.

Widget type specifies the HTML INPUT tag type to use when displaying
the field in, say, the item editor.

Width and Height only apply to some of the Widget type options, for
instance the Textarea widget.

Label is displayed instead of the internal column name. For example,
the category column of the products table might have a label of
Product Category.

Help is displayed below the column label, and helps describe the
purpose of the field to the user.

Help url can be used to link to a page giving more information on the
field.

Lookup can be used when a field is acting like a foreign key into
another table. In that case, use some sort of select box as the widget
type, and if referencing multiple rows in the destination table, use a
multi select box, with colons_to_null as the pre_filter, and :: as the
lookup_exclude.

Filter and pre_filter can be used to filter data destined for that
field or data read from that field, respectively.

Repeat?: The Interchange back office UI uses the mv_metadata table to
discover formatting information for field, table, and view display.
The information is kept in fields in the mv_metadata table, and is
used to select the display, the HTML input type, the size (height and
width where appropriate), label, help text, additional help URL, and
default value display.

It works in conjunction with the [display ...] usertag defined in the
Interchange UI as well as in specific pages in the UI. The [display]
tag has this syntax:

[display table=tablename column=fieldname key=key arbitrary=tag
filter=op ...]

In the simplest use, the formatting information for a table form field
is called with:

     [display table=products column=category key="os28007"]

The mv_metadata table is scanned for the following keys:

     products::category::os28007

     products::category

If a row is found with one of those keys, then the information in the
row is used to set the display widget. If no row is found, an INPUT
TYPE=TEXT widget is displayed. If the data is all digits, a size of 8
is used, otherwise the size is 60.

If the following row were found (not all fields shown, would be
tab-separated in the actual data):

  code                type   width height label     options
  products::category  text   20           Category

Then this would be output:

<INPUT TYPE=text SIZE=20 VALUE="*category*">

If the following row were found:

  code                type   width height label     options
  products::category  select              Category  =none, product=Hardware

Then the following would be output:

        <SELECT NAME=category>
        <OPTION VALUE="">none
        <OPTION VALUE="product">Hardware
        </SELECT>

The standard widget types are:

text

     The default. Uses the fields:

    width   size of input box

textarea

     Format a <TEXTAREA> </TEXTAREA> pair. Uses the fields:

        width   COLS for textarea
        height  ROWS for textarea

select

     Format a <SELECT> </SELECT> pair with appropriate options. Uses
     the fields:

  height          SIZE for select
  default         Default for SELECTED
  options         Options for a fixed list (or prepended to a lookup)
  lookup          signals a lookup (used as field name if "field" empty)
  field           field to look up possible values in
  db              table to look up in if not current table
  lookup_exclude  regular expression to exclude certain values from lookup

24. Usertag Reference
=====================

Admin Tool-specific usertags.

25. Admin Tool Database Tables
==============================

25.1. icmenu.txt
----------------

Used for back-office administration UI menus and wizards.

    code
                Arbitrary primary key
    mgroup
                Menu group (for grouping searches)
    msort
                Sort order within the group
    next_line
                Set to 1 if submenu
    indicator
    exclude_on
    depends_on
    page
    form
    name
    super
    inactive
    special
    help_name
        img_dn
        img_up
        img_sel
        img_icon
        url

25.2. mv_metadata.asc
---------------------

    code
        Table::Column to be operated on.
        Database table
    type
        Widget type (Select the basic display type for the field)
            textarea = Textarea
            text = Text Entry (default)
            select = Select Box
            yesno = Yes/No (Yes=1)
            noyes = No/Yes (No=1)
            multiple = Multiple Select
            combo = Combo Select
            reverse_combo = Reverse Combo
            move_combo = Combo move
            display = Text of option
            hidden_text = Hidden(show text)
            radio = Radio box
            radio_nbsp = Radio (nbsp)
            checkbox = Checkbox
            check_nbsp = Checkbox (nbsp)
            imagedir = Image listing
            imagehelper = Image upload
            date = Date selector
            value = Value
            option_format = Option formatter
            show = Show all options
    width
        Width (SIZE for TEXT, COLS for TEXTAREA, Label limit for SELECT)
    height
        Height (SIZE for SELECT, ROWS for TEXTAREA)
    field
        Field for lookup (can be two comma separated fields, in which case
        second is used as the label text.  Both must be in the same table.)
    db
    name
        Variable name (normally left empty, changes variable name to send in
        form)
    outboard
        Select directory for image listing widget
    options
        options in the format <blockquote>value=label*</blockquote>
    attribute
        Column name (Do not set this.)
    label
    help
        Help (displays at top of page)
    lookup
        Lookup select (Whether lookup is performed to get options for a select
        type.  If nothing is in the field, then used as the name of the field
        to lookup in.  Use lookup table if you want to look up in a different
        table.
    filter
        Filters (Filters which can transform or constrain your data.  Some
        widgets require filters.)
    help_url
        Help URL (links below help text)
        A URL which will provide more help
    pre_filter
    lookup_exclude
        ADVANCED: regular expression that excludes certain keys from the lookup
    prepend
    append
        Append HTML (HTML to be appended to the widget.  Will substitute in the
        macros _UI_TABLE_, _UI_COLUMN_, _UI_KEY_, and _UI_VALUE_, and will
        resolve relative links with absolute links.)
    display_filter

26. makecat - Set Up a Catalog from a Template
==============================================

After Interchange is installed, you need to set up at least one
catalog. Interchange will not function properly until a catalog is
created.

The supplied makecat script, which is in the Interchange program
directory bin, is designed to set up a catalog based on the user's
server configuration. It interrogates the user for parameters like
which directories to use, a URL to base the catalog in, HTTP server
definitions, and file ownership. It gives relevant examples of the
entries it expects to receive.

Note: A catalog can only be created once. All further configuration is
done by editing the files within the catalog directory.

The makecat script requires a catalog skeleton to work from. The
Foundation demo is distributed with Interchange. See the icfoundation
document for information on building the Foundation demo store. Other
demo catalogs are available at http://www.icdevgroup.org/.

It is not normally necessary for you to understand how to build
catalog skeletons for use with makecat, but the following information
will help you if you should ever need to.

26.1. Catalog Skeletons
-----------------------

A catalog skeleton contains an image of a configured catalog. The best
way to see what the makecat program does is to configure the simple
demo and then run a recursive diff on the template and configured
catalog directories:

    cd /usr/local/interchange
    diff -r construct catalogs/construct

The files are mostly identical, except that certain macro strings have
been replaced with the answers given to the script. For example, if
www.mydomain.com was answered at the prompt for a server name, this
difference would appear in the catalog.cfg file:

    # template
    Variable SERVER_NAME  __MVC_SERVERNAME__

    # configured catalog
    Variable SERVER_NAME  www.mydomain.com

The macro string __MVC_SERVERNAME__ was substituted with the answer to
the question about server name. In the same way, other variables are
substituted, and include:

    MVC_BASEDIR      MVC_IMAGEDIR
    MVC_CATROOT      MVC_IMAGEURL
    MVC_CATUSER      MVC_MAILORDERTO
    MVC_CGIBASE      MVC_MINIVENDGROUP
    MVC_CGIDIR       MVC_MINIVENDUSER
    MVC_CGIURL       MVC_SAMPLEHTML
    MVC_DEMOTYPE     MVC_SAMPLEURL
    MVC_DOCUMENTROOT MVC_VENDROOT
    MVC_ENCRYPTOR

Note: Not all of these variables are present in the "construct"
template, and more may be defined. In fact, any environment variable
that is set and begins with MVC_ will be substituted for by the
makecat script. For example, to set up a configurable parameter to
customize the COMPANY variable in catalog.cfg, run a pre-qualifying
script that set the environment variable MVC_COMPANY and then place in
the catalog.cfg file:

Variable   COMPANY   __MVC_COMPANY__

All files within a template directory are substituted for macros, not
just the catalog.cfg file. There are two special directories named
html and images. These will be recursively copied to the directories
defined as SampleHTML and ImageDir.

Note: The template directory is located in the Interchange software
directory, i.e., where interchange.cfg resides. Avoid editing files in
the template directory. To create a new template, it is recommended
that it should be named something besides 'construct' and a copy of
the construct demo directory be used as a starting point. Templates
are normally placed in the Interchange base directory, but can be
located anywhere. The script will prompt for the location if it cannot
find a template.

In addition to the standard parameters prompted for by Interchange,
and the standard catalog creation procedure, four other files in the
config directory of the template may be defined:

    additional_fields -- file with more parameters for macro substitution
    additional_help   -- extended description for the additional_fields
    precopy_commands  -- commands passed to the system prior to catalog copy
    postcopy_commands -- commands passed to the system after catalog copy

All files are paragraph-based. In other words, a blank line (with no
spaces) terminates the individual setting.

26.1.1. Additional fields
-------------------------

The additional_fields file contains:

    PARAM
    The prompt. Set PARAM to?
    The default value of PARAM^IAlternate value of PARAM

This would cause a question during makecat:

    The prompt. Set PARAM to?.....[The default value of PARAM]

The default value line can contain alternate values, separated by tabs
from the default value. (The default value may not contain a TAB
character.) This will allow command-line editing to cycle between the
different values -- usually with the UP and DOWN arrow keys.

If you wish to set the parameter to the default value in this file
without a prompt, precede the parameter with an exclamation point,
i.e.:

    !PARAM
    The prompt.  Set PARAM to?
    default value^Ialternate value

If you wish only to prompt for a value if a previous parameter was
set, put the previous parameter to set in curly brackets before the
actual parameter:

    {MYSQL}SQLDSN
    Data source name (DSN) for MySQL?
    dbi:mysql:test___MVC_CATALOGNAME__

The above will be ignored if the MYSQL parameter was not previously
set to a true value.

Note that information collected in the main makecat run (in this case,
the catalog name) can be inserted via macro substitution.

26.1.2. Additional help
-----------------------

If the additional_help file is present, additional instructions for
PARAM may be provided.

    PARAM

    These are additional instructions for PARAM, and they
    may span multiple lines up to the first blank line.

The prompt would now be:

    These are additional instructions for PARAM, and they
    may span multiple lines up to the first blank line.

    The prompt. Set PARAM to?.....[The default value of PARAM]

26.1.3. Command files
---------------------

If the file config/precopy_commands exists, it will be read as a
command followed by the prompt/help value.

    mysqladmin create __MVC_CATALOGNAME__
    We need to create an SQL database for your Interchange
    database tables.

This will cause the prompt:

    We need to create an SQL database for your Interchange
    database tables.

    Run command "mysqladmin create simple"?

If the response is "y" or "yes," the command will be run by passing it
through the Perl system() function. As with any of the additional
configuration files, MVC_PARAM macro substitution is performed on the
command and help. Proper permissions for the command are required.

The file config/postcopy_commands is exactly the same as
<precopy_commands>, except the prompt occurs after the catalog files
are copied and macro substitution is performed on all files.

There may also be SubCatalog directives:

    SubCatalog easy simple /home/catalogs/simple /cgi-bin/easy

easy

     The name of the subcatalog, which also controls the name of the
     subcatalog configuration file. In this case, it is easy.cfg.

simple

     The name of the base configuration that will be the basis for the
     catalog. Parameters in the easy.cfg file that are different will
     override those in the catalog.cfg file for the base
     configuration.

The remaining parameters are similar to the Catalog directive.

Additional interchange.cfg parameters set up administrative parameters
that are catalog wide. See the server configuration file for details
on each of these.

Each catalog can be completely independent with different databases,
or catalogs can share pages, databases, and session files. This means
that several catalogs can share the same information, allowing
"virtual malls."

26.2. Manual Installation of Catalogs
-------------------------------------

An Interchange installation is complex, and requires quite a few
distinct steps. Normally you will want to use the interactive catalog
builder, makecat, described above. It makes the process much easier.
Please see the iccattut document for a full tutorial on building a
catalog by hand.

27. Link Programs
=================

Interchange requires a web server that is already installed on a
system. It does have an internal server which can be used for
administration, testing, and maintenance, but this will not be useful
or desirable in a production environment.

As detailed previously, Interchange is always running in the
background as a daemon, or resident program. It monitors either a
UNIX-domain file-based socket or a series of INET-domain sockets. The
small CGI link program, called in the demo simple, is run to connect
to one of those sockets and provide the link to a browser.

Note: Since Apache is the most popular web server, these instructions
will focus on it. If using another type of web server, some
translation of terms may be necessary.

A ScriptAlias or other CGI execution capability is needed to use the
link program. (The default ScriptAlias for many web servers is
/cgi-bin.) If ExecCGI is set for all directories, then any program
ending in a particular file suffix (usually .cgi) will be seen as a
CGI program.

Interchange, by convention, names the link program the same name as
the catalog ID, though this is not required. In the distribution demo,
this would yield a program name or SCRIPT_PATH of /cgi-bin/simple or
/simple.cgi. This SCRIPT_PATH can be used to determine which
Interchange catalog will be used when the link program is accessed.

27.1. UNIX-Domain Sockets
-------------------------

This is a socket which is not reachable from the Internet directly,
but which must come from a request on the server. The link program
vlink is the provided facility for such communication with
Interchange. This is the most secure way to run a catalog, for there
is no way for systems on the Internet to interact with Interchange
except through its link program.

The most important issue with UNIX-domain sockets on Interchange is
the permissions with which the CGI program and the Interchange server
run. To improve security, Interchange normally runs with the socket
file having 0600 permissions (rw-------), which mandates that the CGI
program and the server run as the same user ID. This means that the
vlink program must be SUID to the same user ID as the server executes
under. (Or that CGIWRAP is used on a single catalog system).

With Interchange's multiple catalog capability, the permissions
situation gets a bit tricky. Interchange comes with a program,
makecat, which configures catalogs for a multiple catalog system. It
should properly set up ownership and permissions for multiple users if
run as the superuser.

27.2. INET-Domain Sockets
-------------------------

These are sockets which are reachable from the Internet directly. The
link program tlink is the provided facility for such communication
with Interchange. Other browsers can talk to the socket directly if
mapped to a catalog with the global TcpMap directive. To improve
security, Interchange usually checks that the request comes from one
of a limited number of systems, defined in the global TcpHost
directive. (This check is not made for the internal HTTP server.)

27.3. Internal HTTP Server
--------------------------

If the socket is contacted directly (only for INET-domain sockets),
Interchange will perform the HTTP server function itself, talking
directly to the browser. It can monitor any number of ports and map
them to a particular catalog. By default, it only maps the special
catalog mv_admin, which performs administrative functions. The default
port is 7786, which is the default compiled into the distribution
tlink program. This port can be changed via the TcpMap directive.

To prevent catalogs that do not wish access to be made in this way
from being served from the internal server, Interchange has a fixed
SCRIPT_PATH of /catalogname (/simple for the distribution demo) which
needs to be placed as an alias in the Catalog directive to enable
access. See TcpMap for more details.

27.4. Setting Up VLINK and TLINK
--------------------------------

The vlink and tlink programs, compiled from vlink.c and tlink.c, are
small C programs which contact and interface to a running Interchange
daemon. The VLINK executable is normally made setuid to the user
account which runs Interchange, so that the UNIX-domain socket file
can be set to secure permissions (user read-write only). It is
normally not necessary for the user to do anything. They will be
compiled by the configuration program. If the Interchange daemon is
not running, either of the programs will display a message indicating
that the server is not available. The following defines in the
produced config.h should be set:

LINK_FILE

     Set this to the name of the socket file that will be used for
     configuration, usually "/usr/local/lib/interchange/etc/socket" or
     the "etc/socket" under the directory chosen for the VendRoot.

LINK_HOST

     Set this to the IP number of the host which should be contacted.
     The default of 127.0.0.1 (the local machine) is probably best for
     many installations.

LINK_PORT

     Set this to the TCP port number that the Interchange server will
     monitor. The default is 7786 (the decimal ASCII codes for 'M' and
     'V') and does not normally need to be changed.

LINK_TIMEOUT

     Set this to the number of seconds vlink or tlink should wait
     before announcing that the Interchange server is not running. The
     default of 45 is probably a reasonable value.

27.5. Compiling VLINK and TLINK
-------------------------------

There is a compile_link program which will assist with this. Do:

   perldoc VENDROOT/bin/compile_link

for its documentation.

27.6. Manually Compiling VLINK and TLINK
----------------------------------------

Change directories to the src directory, then run the GNU configure
script:

   cd src
   ./configure

There will be some output displayed as the configure script checks the
system. Then, compile the programs:

   perl compile.pl

To compile manually:

   cc vlink.c -o vlink
   cc tlink.c -o tlink

On manual compiles, ensure that the C compiler will be invoked
properly with this little ditty:

   perl -e 'do "syscfg"; system("$CC $LIBS $CFLAGS $DEFS -o tlink tlink.c");'
   perl -e 'do "syscfg"; system("$CC $LIBS $CFLAGS $DEFS -o vlink vlink.c");'

On some systems, the executable can be made smaller with the strip
program, if available. It is not required.

   strip vlink
   strip tlink

If Interchange is to run under a different user account than the
individual configuring the program, make that user the owner of vlink.
Do not make vlink owned by root, because making vlink SETUID root is
an huge and unnecessary security risk. It should also not normally run
as the default Web user (often nobody or http)).

   chown interchange vlink

Move the vlink executable to the cgi-bin directory:

   mv vlink /the/cgi-bin/directory

Make vlink SETUID:

   chmod u+s /the/cgi-bin/directory/vlink

Most systems unset the SUID bit when moving the file, so change it
after moving.

The SCRIPT_NAME, as produced by the HTTP server, must match the name
of the program. (As usual, let the makecat program do the work.)

27.7. VLINK or TLINK Compile Problems
-------------------------------------

The latest version of vlink.c and tlink.c have been compiled on the
following systems:

   AIX 4.1
   BSD2.0 (Pentium/x86)
   Debian GNU/Linux
   Digital Unix (OSF/Alpha)
   FreeBSD 2.x, 3.x, 4.x
   IRIX 5.3, IRIX 6.1
   OpenBSD 2.7
   Red Hat Linux 6.2, 7.0, 7.1, 7.2, 7.3, 8.0
   SCO OpenServer 5.x
   Solaris 2.x (Sun compiler and GCC)
   Solaris 7 (Sun compiler and GCC)
   SunOS 4.1.4

Some problems may occur. In general, ignore warnings about pointers.

Make sure that you have run the configure program in the src
directory. If you use Interchange's makecat program, it will try to
compile an appropriate link at that time, and will substitute tlink.pl
if that doesn't work.

You can compile manually with the proper settings with this series of
commands:

   cd src
   ./configure
   perl -e 'do "syscfg"; system ("$CC $CFLAGS $DEFS $LIBS -o tlink tlink.c")'
   perl -e 'do "syscfg"; system ("$CC $CFLAGS $DEFS $LIBS -o vlink vlink.c")'

There is also a compile_link program which has documentation embedded
and which will compile an appropriate link. If you cannot compile, try
using the tlink.pl script, written in Perl instead of C, which should
work on most any system. Since vlink needs to have values set before
compilation, a pre-compiled version will not work unless it has the
exact values you need on your system. If you can use the defaults of
'localhost' and port 7786, you may be in luck.

28. Installing Perl Modules without Root Access
===============================================

Installing Interchange without root access is no problem. However,
installing Perl modules without root access is a little trickier.

You must build your makefile to work in your home dir. Something like:

PREFIX=~/usr/local \
INSTALLPRIVLIB=~/usr/local/lib/perl5 \
INSTALLSCRIPT=~/usr/local/bin \
INSTALLSITELIB=~/usr/local/lib/perl5/site_perl \
INSTALLBIN=~/usr/local/bin \
INSTALLMAN1DIR=~/usr/local/lib/perl5/man \
INSTALLMAN3DIR=~/usr/local/lib/perl5/man/man3

Put this in a file, say 'installopts', and use it for the Makefile.PL.

perl Makefile.PL `cat installopts`

Then, forget ./config. Just do:

make
make test
make install

Some of the tests may fail, but that's probably ok.

Also make sure to install Bundle::Interchange, which will need the
same config data as you put into 'installopts'.

29. Installation Troubleshooting
================================

Interchange uses the services of other complex programs, such as Perl,
Web servers, and relational databases, to work. Therefore, when there
is a problem, check these programs before checking Interchange. Many
more basic installation problems have to do with those than with
Interchange itself.

If an error message is received about not being able to find
libraries, or a core dump has occurred, or a segment fault message, it
is always an improperly built or configured Perl. Contact the system
administrator or install a new Perl.

The makecat program is intended to be used to create the starting
point for the catalog. If the demo does not work the first time, keep
trying. If it still does not work, try running in INET mode.

Check the two error log files: error.log in the Interchange home
directory (where interchange.cfg resides) and error.log in the catalog
directory (where catalog.cfg resides; there can be many of these).
Many problems can be diagnosed quickly if these error logs are
consulted.

Check the README file, the FAQ, and mail list archive at the official
Interchange web site for information:

       http://www.icdevgroup.org/

Double check the following items:

1.   Using UNIX sockets?

     o    Check that the vlink program is SUID, or the appropriate
          changes have been made in the SocketPerms directive. Unless
          the files are world-writable, the vlink program and the
          Interchange server must run as the same user ID! If running
          CGI-WRAP or SUEXEC, the vlink program must not be SUID.

     o    If having trouble with the vlink program (named construct in
          the demo configuration), try re-running makecat and using
          INET mode instead. (Or copy the tlink INET mode link program
          over vlink). This should work unchanged for many systems.

     o    If using an ISP or have a non-standard network
          configuration, some changes to interchange.cfg are
          necessary. For tlink to work, the proper host name(s) must
          be configured into the TcpHost directive in interchange.cfg.
          The program selects port 7786 by default (the ASCII codes
          for "M" and "V", for MiniVend). If another port is used, it
          must be set to the same number in both the tlink program (by
          running compile_link) and the interchange.cfg file. The
          tlink program does not need to be SUID.

2.   Proper file permissions?

     o    The Interchange server should not run as the user nobody!
          The program files can be owned by anyone, but any databases,
          ASCII database source files, error logs, and the directory
          that holds them must be writable by the proper user ID, that
          is the one that is executing the Interchange program.

     o    The best way to operate in multi-user, multiple catalog
          setups is to create a special interch user, then put that
          user in the group that contains each catalog user. If a
          group is defined for each individual user, this provides the
          best security. All associated files can be in 660 or 770
          mode. There should be no problems with permissions and no
          problems with security.

3.   Is the vlink program being executed on a machine that has the
     socket file etc/socket on a directly attached disk?

     o    UNIX-domain sockets will not work on NFS-mounted file
          systems! This means that the Interchange server and the CGI
          program vlink must be executing on the same machine.

     o    The tlink program does not have this problem, but it must
          have the proper host name(s) and TCP ports set in the
          TcpHost and TcpMap directives in interchange.cfg. Also, be
          careful of security if sensitive information, like customer
          credit card numbers, is being placed on a network wire.

30. Usertracking
================

Several actions from the user are recorded by Interchange's
usertracking facility. The usertracking data is logged at two
locations, depending on your setup.

The first location is the one specified by the TrackFile configuration
directive, e.g. logs/usertrack in the foundation demo.

The second location are the HTTP headers. You can configure Apache to
write this header into the access logs.

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %T %v \"%{X-Track}o\"" track
CustomLog /var/log/apache/access.log track

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Catalog-Building Tutorial
=========================

31. Purpose
===========

The purpose of this document is to guide you through constructing a
simple Interchange catalog from scratch. The demo catalog that ships
with Interchange is quite complex since it highlights some of the many
capabilities that Interchange offers. As a template for your own
catalog, the demo can either be an intimidating place to start.

The simple catalog you create using this tutorial should give you a
feel for the basic Interchange system. It should also be considered a
stepping stone to a more complete and functional e-commerce system
built with Interchange. The tutorial relies as much as possible on
default settings to accentuate how Interchange works. It will use as
few of Interchange's capabilities as possible, while still building a
usable store. The resulting site will be simple but usable. The value
of this tutorial is in the instruction that occurs along the way.

It is recommended that you create the files used in this tutorial
yourself. You will learn more by creating the directory structure and
using your favorite text editor to create files in the proper places
on your own system as they are discussed.

32. Before you begin
====================

This section explains the initial set up tasks that must be completed
before you can begin building your simple e-commerce site.

32.1. Install Interchange and the demo catalog
----------------------------------------------

The easiest way to get Interchange and the demo set up is through an
RPM install on the Red Hat Linux or Linux Mandrake operating systems.
You can also get Interchange by unpacking an Interchange tarball or
checking out a copy of the CVS repository and doing a manual
installation. These installations can be done either as a regular user
or as root, installing for a special Interchange user.

You must also know what type of installation you ran so you know where
to place the various files created. Before proceeding, verify that
Interchange is properly installed. Also, keep in mind which type of
installation you did:

o    RPM (RPM Package Manager) install

o    Manual install as root

o    Manual install as regular user

Note: After installation, makecat should be run to build your catalog.
For information on installing Interchange and building your catalog
using makecat, see the Interchange Getting Started Guide. Do not to
continue with this tutorial without a working demo catalog.

Installing the demo catalog set up the Interchange global
configuration file interchange.cfg, which resides in the Interchange
software directory. Also, it compiled the link program for your
specific server and placed the executable program in your cgi-bin
directory. This is necessary for your catalog to run properly.

32.2. The Interchange operating system user
-------------------------------------------

If Interchange was installed as a regular user, that will be the user
Interchange runs as. If Interchange was installed as root or from an
RPM, you need to know the name of the separate Interchange user. The
Interchange daemon will not run as root, and should not run as the web
server user (usually 'apache', 'www', 'httpd', or 'nobody'). If
Interchange was installed from the RPM, or with the default source
installation settings, the username is interch. If you selected a
different user name, you will need to know what it is.

32.3. Important directories
---------------------------

In order to complete this tutorial you will need to know the location
of each of the following directories and have write permissions on
them:

o    Interchange software directory

     o    RPM install: /usr/lib/interchange

     o    Manual install as root: /usr/local/interchange

     o    Manual install as regular user: /home/username/interchange

o    Catalogs directory

     o    RPM install: /var/lib/interchange

     o    Manual install as root: /usr/local/interchange/catalogs

     o    Manual install as regular user: /home/username/catalogs

o    cgi-bin directory

     o    RPM install or source install as root: /var/www/cgi-bin

     o    Manual install as root (locally installed web server):
          /usr/local/htdocs, /opt/www, ...

     o    Manual install as regular user: /home/username/public_html
          (with .cgi extension)

Note: The installation of Interchange is very flexible and the file
locations on your system may vary, depending on how your system was
set up. It is recommended that you not proceed until you are sure you
have this information and the necessary permissions to write to these
directories.

32.4. Your catalog URL
----------------------

Finally, you need to know the URL to access your store from a web
browser. Again, this can vary depending on how your web server has
been set up. But, assuming a common setup of the Apache web server,
your URL should be one of the following:

o    Root or RPM install: http://localhost/cgi-bin/tutorial/pagename

o    Manual install as user:
     http://localhost/~username/tutorial.cgi/pagename

If you aren't running your web browser on the server where Interchange
is running, you need to substitute your server's host name (for
example: machine.domain.com for localhost) where mentioned.

Note: It is recommended that you use the real machine name instead of
localhost. The standard for cookies specifies that they can only be
set when a domain name has at least two dots in it. If you use
localhost, you will lose session information if you leave catalog,
since the session ID is passed only as part of the URL.

32.5. Starting or restarting Interchange
----------------------------------------

When you make changes to the configuration files you need to restart
the Interchange server. How this is done depends on how you installed
Interchange:

o    RPM install as root: /usr/sbin/interchange -r

o    Manual install as Interchange user:
     /usr/local/interchange/bin/interchange -r

o    Manual install as root: su interch -c
     '/usr/local/interchange/bin/interchange -r'

o    Manual install as regular user: ~/interchange/bin/interchange -r

Find the right command for your system and remember it, since you will
need to restart Interchange a few times during the tutorial.

32.6. Tutorial assumptions
--------------------------

Because it is impossible to cover all scenarios, this tutorial assumes
that you installed Interchange on Red Hat Linux from the RPM packages.
This creates the following settings:

o    Interchange software directory: /usr/lib/interchange

o    Catalogs directory: /var/lib/interchange

o    cgi-bin directory: /var/www/cgi-bin

o    Interchange user: interch

o    Demo catalog name: foundation

o    Demo catalog URL base: http://localhost/cgi-bin/foundation

o    Tutorial catalog name: tutorial

o    Tutorial catalog URL base: http://localhost/cgi-bin/tutorial

o    Tutorial catalog directory: /var/lib/interchange/tutorial

If you did not install with these settings, substitute the correct
values for your system when these settings are mentioned in the
tutorial.

33. Building Your Catalog
=========================

This section describes the pages and directories that need to be
established to create a properly functioning catalog.

33.1. Create the link program
-----------------------------

You need to make a copy of the demo link program in your cgi-bin
directory and name it tutorial.

The demo link program has the same name as your demo catalog, usually
foundation. The link program links the Interchange daemon with your
web server. Make sure that it has the same owner and file permissions
as the one you copied from. The set-UID bit is especially (unless you
installed as a regular user). Normally you will need to be root to
have write permissions in the cgi-bin directory.

Type this command as root while in your cgi-bin directory:

  cp -p foundation tutorial

If everything is working correctly, typing ls -l should describe your
files roughly like this:

  -rwsr-xr-x    1 interch  interch      7708 Dec 16 22:47 foundation
  -rwsr-xr-x    1 interch  interch      7708 Dec 16 22:47 tutorial

33.2. Create the tutorial catalog directory
-------------------------------------------

As root, create a subdirectory named tutorial under your catalogs
directory (probably /var/lib/interchange/). This is where all of the
catalog-specific files will go. It needs to be readable, writable, and
executable by the Interchange user. This will be referred to as your
catalog directory. Type the following while in the catalogs directory
to create the tutorial subdirectory:

  mkdir tutorial
  chown interch.interch tutorial
  chmod 770 tutorial

33.3. Become the Interchange user
---------------------------------

You should be able to do everything you need to do as the 'interch'
user for the rest of this tutorial. So you can switch to that user now
(su - interch). If you installed Interchange from the RPM, the user
interch probably doesn't have a password. You'll have to set it with a
command such as passwd interch while root.

33.4. Go to the tutorial catalog directory
------------------------------------------

Change to the catalog directory with the 'cd' command. For the rest of
this tutorial, all file locations will be given relative to the
tutorial catalog directory. For example, pages/ord/basket.html would
actually be /var/lib/interchange/tutorial/pages/ord/basket.html or the
equivalent on your system. The only exception is interchange.cfg,
which is in the Interchange software directory.

Note: To improve clarity, we will append a trailing slash to directory
names to clearly distinguish them from file names. (Similar to the
output of the ls command with the -F option.)

33.5. Create the session directory
----------------------------------

You need to create the session directory where Interchange saves
information on each visitor's browsing session. If you do not have
this directory, your catalog will not work. This directory is called
session/ and goes under your catalog directory. Type mkdir session to
create this directory.

34. Configuration files
=======================

Interchange configuration is controlled by a number of directives,
which are specified in two files. Global configuration directives go
in interchange.cfg in the Interchange software directory.
Catalog-specific configuration directives go in catalog.cfg in the
catalog directory.

A complete directive consists of the directive name followed by
whitespace-separated parameters. Any number of spaces or tabs can be
between the directive and its options, but the directive and its
options must be on the same line. The directive is case-insensitive,
but it is recommended that you use it consistently for readability.

You can insert blank lines or comment lines (lines where the first
non-blank character is '#') throughout the configuration files to
improve readability. The order the lines appear in is significant, but
unimportant for the simple catalog you are creating.

For the next part, access your text editor (for example, vi, emacs,
pico, joe, gedit, or nedit) to start editing some files.

34.1. interchange.cfg
---------------------

The first directive we need to use is a global directive that tells
Interchange where the new catalog is, called Catalog. The Catalog
directive has the following format:

  Catalog   name   catalog_base_directory   link_url_path

Open interchange.cfg in the Interchange software directory. Go near
the top of the file, right below the other Catalog directives, and add
this line:

  Catalog  tutorial  /var/lib/interchange/tutorial  /cgi-bin/tutorial

Save the file.

34.2. catalog.cfg
-----------------

For the rest of the tutorial, most of the files mentioned do not exist
yet. You will create them yourself with initial text we give.

You need to create a catalog.cfg file for your tutorial store (in the
tutorial catalog directory). We'll start with a very simple products
database table with a few fields and a few products.

The Database directive describes a database table to the Interchange
system in this format:

  Database  name  filename  format

Interchange has several database options available. We will use the
simplest, which is the built-in default (specifically, some variant of
DBM). The default location for filename is in a subdirectory called
products under the catalog directory. Interchange recognizes a number
of file formats. We will use a tab-delimited text file. Enter the
following into catalog.cfg:

  Database  products  products.txt  TAB

This tells Interchange that you have a database table named 'products'
that is described in a tab-delimited file named products.txt. You can
describe an unlimited number of arbitrary database tables for the
system to use this way. Interchange keeps a list of default tables
called "Product Files," reflecting its e-commerce roots. You can
specify all of the database tables that contain products by using the
ProductFiles directive. There is no default for this, so you will have
to specify your products table's name by adding the following line to
catalog.cfg:

  ProductFiles  products

There are a few other directives that Interchange expects to see in
order to complete the minimum configuration. They are VendURL,
SecureURL, and MailOrderTo. They are, respectively, your catalog's
base URL, its secure URL, and the e-mail address to mail order notices
to. Add the following lines to catalog.cfg to establish these
directives:

  VendURL  http://localhost/cgi-bin/tutorial
  SecureURL  http://localhost/cgi-bin/tutorial
  MailOrderTo  your@email.address

The catalog.cfg file should look like this when you save it:

  Database  products  products.txt  TAB
  ProductFiles  products
  VendURL  http://localhost/cgi-bin/tutorial
  SecureURL  http://localhost/cgi-bin/tutorial
  MailOrderTo  your@email.address

35. The products database table
===============================

35.1. products/products.txt
---------------------------

Create the products/ directory in your tutorial catalog directory.

The products/products.txt file will serve two purposes. It will
provide Interchange with the layout of the products database table and
it will also provide the data. When Interchange parses the
products.txt file, it will expect the first line to contain the names
of the fields for the database table (for example, sku, description,
price). The first field in the list is expected to be a primary key
(unique identifier) for that row. In most cases you are going to use
the SKU (stock keeping unit) as the unique identifier for each
product.

The product database is handled as a special case since Interchange
expects at least the description, price, and product ID (sku) fields.
In other words, the products.txt file must at least contain fields
named sku, price, and description. You can have other fields too, if
you wish.

The simple store that we are going to build will sell tests. You can
choose another sample product line, but it is recommended that you
keep it simple. Create the file products/products.txt to look like
this, with a single tab separating each field:

  sku   description     price
  4595  Nice Bio Test   275.45
  2623  Stack of Econ Quizzes   1.24
  0198  Really Hard Physics Test        1589.34
  1299  Ubiquitous diff eq final        37.00

Note: When using tab-delimited files as we are, make sure you have
exactly one tab between each field. Some text editors will use spaces
to simulate tabs. Interchange expects actual ASCII tab characters;
extra spaces or other characters will corrupt your data.

You may notice that the columns don't line up in your text editor.
This is the nature of tab-delimited files. Do not try to fix these.

36. Page templates
==================

Since most sites have certain aspects of the site that remain the same
as the content of the pages changes, we are going to create a template
that we can use for all pages. We'll divide the page into four
sections:

   _____________________
  |                     |
  |         top         |
  |                     |
  |---------------------|
  |      |              |
  |      |              |
  | left |     main     |
  |      |              |
  |      |              |
  |---------------------|
  |                     |
  |        bottom       |
  |_____________________|

The "main" section holds the content that is different for each page.
The "top" section is for headers, banners, menus, and so on. The
"left" section can be used as a sidebar or navigation bar, and the
"bottom" section can contain the copyright and contact info. The top,
left, and bottom sections will remain constant throughout the site.
Making a change to information in one of these sections will make that
change to all pages in your site.

Now type the HTML for each template section in an individual plain
text file in the catalog directory, named 'top', 'left', and 'bottom',
respectively using the code displayed below. No '.html' suffixes are
used on these because they are not meant to be parsed directly by
Interchange as full pages.

36.1. top
---------

  <html>
  <head>
  <title>The Interchange Test Catalog</title>
  </head>
  <body>
  <div align=center>
  <table width="80%" border cellpadding=15>
  <tr><td colspan=2 align=center><h1>The Interchange Test Catalog</h1></td></tr>

36.2. left
----------

  <tr>
  <td align=center>(left)</td>
  <td align=center>

36.3. bottom
------------

  </td>
  </tr>
  <tr><td colspan=2 align=center>(bottom)</td></tr>
  </table>
  </div>
  </body>
  </html>

36.4. The Interchange Tag Language
----------------------------------

Now we need a way to pull the template pieces we just created into the
proper places to make a complete page. This is done using ITL, the
Interchange Tag Language.

ITL is at the heart of almost all Interchange catalog pages. It's how
you use Interchange's functionality. The ITL tags appear between
square brackets like [this]. Options appear after the tag, separated
by whitespace, like this: [tag option1 option2] and this: [tag
option1=value1 option2=value2]. They can span multiple lines. (That
can help readability when the tag has many options.) There are many
ITL tags, and for this tutorial very few will be addressed. For a
complete listing of the ITL tags, see the Interchange Tag Reference
Guide.

Your first tag will be [include], which reads the file mentioned
(relative to the catalog directory), parses any Interchange tags, and
puts the result in place of the tag. This is demonstrated on the next
page you need to create.

37. Creating a welcome page
===========================

37.1. pages/index.html
----------------------

Create a directory called pages/ in your tutorial catalog directory.

Type the following text and save it as pages/index.html. This will
create a page to test that everything works so far.

  [include top]
  [include left]
  This is where your content goes.
  [include bottom]

Restart Interchange so your changes take effect. Go to your web
browser and load the page. The URL should be similar to the following:
http://localhost/cgi-bin/tutorial/index.html.

Note: Interchange pages in the pages/ or other directories must have
the .html suffix on them. You can drop the suffix in your URL and in
other places, such as the [page] tag you'll learn about later, but the
file name on disk must have the suffix.

38. Troubleshooting
===================

Your first Interchange page should have displayed as described in your
browser. If it didn't, you need to figure out what went wrong. Most of
the time, overlooked details are the problem. Double-checking your
typing is a good habit to get into.

The following is a troubleshooting checklist to use when you run into
problems:

1.   Have you created directories with the proper names in the proper
     locations? (See Appendix A for a full directory and file
     structure of the tutorial catalog.)

2.   Have you misspelled any file names or put them in the wrong
     directories? Are the files and parent directories readable by the
     interch user? Double-check with the ls command.

3.   Did you type letters in the proper case? Remember that both Unix
     and Interchange are case-sensitive, and for the most part you may
     not switch upper- and lower-case letters.

4.   Did you type all punctuation, ITL tags, and HTML tags correctly?

5.   Did you use whitespace correctly in the cases where it mattered?
     Remember to use tabs when tabs are called for (in lists and
     database text files).

6.   Did you restart Interchange if you changed anything in
     interchange.cfg or catalog.cfg, or if you're in a high-traffic
     mode?

7.   Check your catalog error log, error.log in your tutorial catalog
     directory, to see if Interchange reported any errors.

8.   Check the Interchange server error log, error.log in the
     Interchange software directory, to see if it had problems loading
     the catalog at all.

9.   View the HTML source of any catalog pages that are loading
     incorrectly to check for a coding error. The problem may reveal
     itself when you see what HTML the browser is getting.

39. Displaying products
=======================

39.1. Listing all products
--------------------------

Now that your store is running, you need to display your products on
the welcome page. We will loop over all of the products in our
database and produce an entry for each one in a table. Replace the
line "This is where your content goes" in pages/index.html with the
following:

  <table cellpadding=5>
  <tr>
  <th>Test #</th>
  <th>Description</th>
  <th>Price</th>
  </tr>

  . . .

  </table>

Now we will use Interchange tags to fill in the rest of the table from
the products database you created. The [loop] [/loop] ITL tag pair
tells Interchange to iterate over each item in the parameter list. In
this case, the loop is over the result of an Interchange search. The
search parameter does a database search on the provided parameters. In
this case, we're doing a very simple search that returns all of the
fields for all of the entries in the products database. The parameters
passed to the search tell Interchange to return all ('ra') on the file
('fi') products respectively. The following should take the place of
the ellipsis in the code you placed in index.html:

  [loop search="ra=yes/fi=products"]

  . . .

  [/loop]

In the loop we just established, the individual elements of the entry
using the [loop-field] tag. The following code should replace the
above ellipsis in the code we placed in pages/index.html:

  <tr>
  <td>[loop-code]</td>
  <td>[loop-field description]</td>
  <td align=right>[loop-field price]</td>
  </tr>

The [loop-code] tag refers to the primary key (unique identifier) for
the current row of the database table in question. In this case, it
will produce the same output as the [loop-field sku] tag, because the
'sku' field is the primary key for products table. In each case the
tag is replaced by the appropriate element. When put together,
Interchange generates a page with your products table on it.

Your finished page should look like this:

  [include top]
  [include left]
  <table cellpadding=5>
  <tr>
  <th>Test #</th>
  <th>Description</th>
  <th>Price</th>
  </tr>
  [loop search="ra=yes/fi=products"]
  <tr>
  <td>[loop-code]</td>
  <td>[loop-field description]</td>
  <td align=right>[loop-field price]</td>
  </tr>
  [/loop]
  </table>
  [include bottom]

Test this page by refreshing the index.html page in your browser.

39.2. pages/flypage.html
------------------------

The next step is to create an individual page for each item. To do
this, you need to create a special generic page called
pages/flypage.html. When a page is requested that does not exist in
the pages/ directory, Interchange will check and see if the requested
page has the same name as a product ID from the product database table
(in this case a SKU). If it does, it will show the flypage for that
product. If there's no product with that ID, the special error page
special_pages/missing.html (described in the next section) will be
displayed.

For example, if the page 0198.html was requested, Interchange first
checks for a page with that name. If one is not found, it searches the
products database table for a product with that ID. Interchange then
creates a product page "on the fly" using pages/flypage.html. When
constructing the flypage, the entire product record for the requested
product is available through the [item-field] tag (similar to the
[loop-field] tag). To create a fly page, type the following code and
save it as pages/flypage.html.

  [include top]
  [include left]

  <h3>Test #[item-code]</h3>
  <p>[item-field description] . . . [item-field price]</p>

  [include bottom]

Then, to provide links to the product flypages from your home page,
modify pages/index.html slightly, so that:

  <td>[loop-field description]</td>

becomes:

  <td><a href="[loop-code].html">[loop-field description]</a></td>

39.3. special_pages/missing.html
--------------------------------

Create the special_pages/ directory in your tutorial catalog directory
(not in the pages/ directory).

As mentioned, it is a good idea to display an error page when
Interchange is asked for an unknown page. To create a missing page for
display, type the following and save it as special_pages/missing.html.

  [include top]
  [include left]
  <p>We're sorry, the page you requested has not been found.</p>

  <p>Try finding what you need on the [page index]welcome page</a>.</p>
  [include bottom]

The addition of this page ensures that users see your error message
instead of a mysterious server error if they mistype a URL.

40. The shopping basket
=======================

40.1. A link for ordering
-------------------------

Now that you have your products available, let's add a shopping cart
so customers can purchase them. This is created using the [order] tag.
These tags create an HTML link that causes the specified item to be
ordered and transfers the shopper to the basket page. This is a
built-in shortcut to the complete order process which uses an HTML
form submission process. The parameter for the [order] tag is the
product ID. To add these tags to the catalog, make the following
change to pages/index.html:

  <tr>
  <td>[loop-code]</td>
  <td>[loop-field description]</td>
  <td align=right>[loop-field price]</td>
+ <td>[order [loop-code]]Order Now</a></td>
  </tr>
  [/loop]

Note: The line you need to add is marked by a '+'. However, do not
include the '+' when adding this line. The surrounding lines are shown
to give you context. This style is called a "context diff" and is used
often in this tutorial.

40.2. pages/ord/basket.html
---------------------------

Create the directory pages/ord/ in the tutorial catalog directory. In
other words, ord/ should be inside the pages/ directory.

For the [order] tag, Interchange expects a default page called
pages/ord/basket.html. This page displays the contents of the shopping
basket and contains other shopping basket functionality.

The Foundation store has a full-featured shopping basket available for
use, but this tutorial teaches you to build your own simple one. The
shopping basket items can be accessed using a set of tags that have an
[item] prefix. Put the following code in the new file
pages/ord/basket.html. The section that follows explains the tags
used.

  [include top]
  [include left]

  <h2>This is your shopping cart!</h2>

  <table cellpadding=5>

  <tr>
  <th>Qty.</th>
  <th>Description</th>
  <th>Cost</th>
  <th>Subtotal</th>
  </tr>

  [item-list]
  <tr>
  <td align=right>[item-quantity]</td>
  <td>[item-field description]</td>
  <td align=right>[item-price]</td>
  <td align=right>[item-subtotal]</td>
  </tr>
  [/item-list]

  <tr><td colspan=4></td></tr>

  <tr>
  <td colspan=3 align=right><strong>Total:</strong></td>
  <td align=right>[subtotal]</td>
  </tr>

  </table>

  <hr>

  <p>
  [page checkout]Purchase now</a><br>
  [page index]Return to shopping</a>
  </p>

  [include bottom]

The basket items can be accessed one at a time by using the
[item-list] tag. So we will create a table by iterating through the
basket items. The text within the [item-list] [/item-list] tags is
created for each item in the list.

o    [item-quantity] shows the quantity of the item ordered. If the
     same item is ordered multiple times, the quantity increases.

o    [item-field description] shows the description from the product
     database table. Any field that is not special to Interchange can
     be accessed from the shopping cart this way.

o    [item-price] shows the per-item price that is defined in the
     product database table.

o    [item-subtotal] shows the total cost of this order line. This is
     normally the price multiplied by the quantity, but it can also
     take into account other considerations, such as various kinds of
     price discounts.

o    [subtotal] shows the calculated shopping basket subtotal.

o    [page index] creates the starting HTML <a href="..."> for a link
     to the catalog welcome page.

You also need to put a link in the index page so that shoppers can go
to their shopping cart without ordering something. Modify the end of
pages/index.html by adding the following lines.

  </table>
+ <hr>
+ <p align=center>[page order]View shopping cart</a></p>
  [include bottom]

Refresh the page and test the shopping basket in your browser.

41. Order checkout
==================

41.1. pages/checkout.html
-------------------------

The site can now be completed by adding the ability to check out with
the shopping cart and finalize the order. To do this the customer
needs to provide a shipping address (which, for the sake of this
tutorial, we will assume is the same as the billing address), and
payment information. We will process the order by verifying the
customer's payment information and sending an email to the merchant
(ourselves) detailing the order.

First you need to create a checkout page. The checkout page consists
of a form that receives order information from the customer and
performs a simple credit card number check. In this tutorial we will
use a built-in test that only checks to see if a given credit card
number could be valid. If the information is acceptable the customer
will move to the next phase of the order process. If it is not, an
error page will be displayed.

To create a checkout page, type the following code and save it as
pages/checkout.html. The section that follows explains the code.

  [include top]
  [include left]
  <h1>Checkout Page</h1>

  <form method=post action="[process]">
  <input type=hidden name=mv_todo value=submit>
  <input type=hidden name=mv_order_profile value=order_profile>
  <input type=hidden name=mv_cyber_mode value=minivend_test>

  <table cellpadding=3>

  <tr>
  <td align=right><b>First name:</b></td>
  <td><input type=text name=fname value="[value fname]"></td>
  </tr>

  <tr>
  <td align=right><b>Last name:</b></td>
  <td><input type=text name=lname value="[value lname]"></td>
  </tr>

  <tr>
  <td align=right rowspan=2><b>Address:</b></td>
  <td><input type=text name=address1 value="[value address1]"></td>
  </tr>

  <tr>
  <td><input type=text name=address2 value="[value address2]"></td>
  </tr>

  <tr>
  <td align=right><b>City:</b></td>
  <td><input type=text name=city value="[value city]"></td>
  </tr>

  <tr>
  <td align=right><b>State:</b></td>
  <td><input type=text name=state value="[value state]"></td>
  </tr>

  <tr>
  <td align=right><b>Postal code:</b></td>
  <td><input type=text name=zip value="[value zip]"></td>
  </tr>

  <tr>
  <td align=right><b>Country:</b></td>
  <td><input type=text name=country value="[value country]"></td>
  </tr>

  </table>

  <p>
  Note: We assume that your billing address is the same as your shipping address.
  </p>

  <table cellpadding=3>

  <tr>
  <td align=right><b>Credit card number:</b></td>
  <td><input type=text name=mv_credit_card_number value="" size=20></td>
  </tr>

  <tr>
  <td align=right><b>Credit card expiration date:</b></td>
  <td>
  Month (number from 1-12):
  <input type=text name=mv_credit_card_exp_month value="" size=2 maxlength=2>
  <br>
  Year (last two digits only):
  <input type=text name=mv_credit_card_exp_year value="" size=2 maxlength=2>
  </td>
  </tr>

  </table>

  <p>
  <input type=submit name=submit value="Finalize!">
  <input type=reset name=reset value="Reset">
  </p>

  </form>

  <p>[page index]Return to shopping instead</a></p>
  [include bottom]

The HTML form begins with a method of 'post' (which sends the form
data as its own stream, as opposed to the 'get' method which encodes
the data as part of the URL). The [process] tag creates a special URL
for form processing. Interchange has a built-in form processor that is
configured by submitting certain fields in the form. The Finalize
button will invoke this form processor and link the user to the
special_pages/receipt.html page, which is described later.

You are submitting some hidden form values that will tell Interchange
how to process this form. The first value, mv_todo was set as submit.
This causes the form to be submitted for validation. The second value,
mv_order_profile was set as order_profile. This determines the
validation process for the form. It is explained further in the next
section.

The last value, mv_cyber_mode, was set to be minivend_test. The
mv_cyber_mode value determines what method will be used to charge a
credit card. The value of minivend_test uses the internal test method,
which calculates a simple checksum against the card to determine if it
is a valid number.

When preparing an order for processing, Interchange looks for certain
named fields in the form values for name, address, and credit card
information. We are using all expected field names in this form so
that no translation needs to take place.

View the checkout page in your browser. The "Finalize!" link has not
been enabled, but the page should display properly.

41.2. etc/profiles.order
------------------------

Create the etc/ directory in the tutorial catalog directory now.

You need to set up verification for the order form by defining an
order profile for the form. An order profile determines what fields
are necessary for the form to be accepted. Create an order profile
verification page by typing the following and saving it as
etc/profiles.order. The section that follows explains the code used.

  __NAME__ order_profile

  fname=required
  lname=required
  address1=required
  city=required
  state=required
  zip=required

  &fatal=yes
  &final=yes

  __END__

A single file can contain multiple profile definitions. First the
profile is named using the __NAME__ pragma. (This is unrelated to the
__VARIABLE__ syntax seen elsewhere in Interchange.) Then in the
profile there is a list of the form fields that are required. The
&fatal setting indicates that validation will fail if any of the
requirements are not met. &final indicates that this form will
complete the ordering process. This setting is helpful if you have a
multi-page ordering process and you want to validate each page
individually. The __END__ pragma signals the end of this profile,
after which you can begin another one.

In order to activate your order profile, add the following
OrderProfile directive to the end of catalog.cfg:

  OrderProfile etc/profiles.order

41.3. special_pages/needfield.html
----------------------------------

If the submitted form lacks a required field, Interchange will display
an error page. The default location is special_pages/needfield.html.
To create this page, type the following text and save it as
special_pages/needfield.html.

  [include top]
  [include left]
  <p>The following information was not given:</p>

  <p><b>[error all=1 show_var=1 show_error=1 joiner='<br>']</b></p>

  <p>Please go back to the [page checkout]checkout page</a>
  and fill out the form properly.</p>

  [include bottom]

The [error] tag is the most important tag on this page. The all
parameter tells the tag to iterate through all of the errors reported
from the failed verification, and the show_var parameter indicates
that the failed variable name should be displayed. For example, if the
first name was left empty, fname would be shown. The show_error
parameter displays the actual error for the variable. The joiner
parameter inserts an HTML <br> tag between each error message, so each
error is displayed on its own line. In more complex configurations,
the [error] tag can be even more expressive.

41.4. Credit card processing
----------------------------

This tutorial uses a very simple order process. To accomplish this,
one more directive needs to be added to the file etc/profiles.order:

  &fatal=yes
  &final=yes
+ &credit_card=standard keep

  __END__

This issues two instructions to the credit card system.

The first option, standard, uses the standard built-in encryption
algorithm to encrypt the credit card number and erases the unencrypted
copy from memory. We are using the standard option not to encrypt the
number but to run the checksum verification on the number to verify
that it is a potentially correct number. We will not be checking with
a real payment processor to see if it actually is a valid card number.
For testing purposes, you can use the card number 4111 1111 1111 1111,
which will pass the checksum test.

The second option, keep, keeps the credit card number from getting
removed from memory. We want to keep the number in memory so that it
is available when it is mailed as part of the order.

If the credit card number passes and all of the required fields are
present, the customer will be sent to the final page. Interchange then
sends an e-mail to the store owner (you).

41.5. etc/report
----------------

When the customer's involvement in the order is complete, Interchange
composes an email and sends it to the recipient defined in the
MailOrderTo directive in catalog.cfg. The default location for the
template for this email report is etc/report. Interchange tags can be
used to fill in the body of the message.

The report should include at least the customer's name, address, and
the items they ordered. The following is a simple report template;
save it as etc/report.

               Name: [value fname] [value lname]
            Address: [value address1][if value address2]
                     [value address2][/if]
  City, State, etc.: [value city], [value state]  [value zip] [value country]

      Credit Card #: [cgi mv_credit_card_number]
    Expiration Date: [cgi mv_credit_card_exp_month]/[cgi mv_credit_card_exp_year]


  ************ ORDER ************
  [item-list]
  [item-quantity] x [item-description] ([item-code]), [item-price] ea.
  [/item-list]
  Subtotal: [subtotal]
     Total: [total-cost]

This file is in plain text format where, unlike HTML, white space is
relevant. It is fairly straightforward, except that the [if] tag was
added to only include the optional second address line if the customer
filled it in.

One of the special properties of the mv_credit_card_number field is
that Interchange specifically precludes the credit card number from
being saved. This makes it unavailable to you in the [value] tag. The
[cgi] tag is used to circumvent this important security measure in
order to get the value submitted from the last form.

WARNING! Obviously it is a bad idea to send a real credit card number
over an insecure channel like email. In a real configuration, you
would encrypt the number securely before emailing or storing it.

41.6. special_pages/receipt.html
--------------------------------

Once the report has been run, Interchange will finish the order
process on the customer side by displaying a success screen containing
a receipt. The default location for this page is
special_pages/receipt.html. To create a receipt page, type the
following code and save it as special_pages/receipt.html.

  [include top]
  [include left]
  <p>Thank you for ordering stuff from us.<br>Have a nice day!</p>
  <p>[page index]Return to our welcome page</a></p>
  [include bottom]

Once the order is processed, the customer's shopping cart is emptied.

At this point you have a more-or-less functional store.
Congratulations.

42. Enhancing the catalog
=========================

Now that you have a working catalog, you can go back and add
improvements and test them incrementally. This section walks you
through several and then suggests more enhancements you can attempt on
your own.

42.1. Price pictures
--------------------

You may have noticed that the product prices aren't formatted as
prices usually are. The way to correct this is with an Interchange
feature called price pictures.

There are several properties to price pictures: the currency symbol,
the thousands separator, the decimal point, the number of digits to
show behind the decimal, and so on. Most Unix systems have U.S.
currency and the English language as the default locale, which is
called en_US. The only thing you need to do on such a system is
specify the currency symbol, which, in this case, is the dollar sign.
To do this, add the following line to your catalog.cfg file:

  Locale en_US currency_symbol $

Restart Interchange and view your catalog. You will notice little has
changed on the welcome page or the flypages, but in the shopping cart
all your prices should be formatted as U.S. dollars ("1347.3" has
become "$1,347.30"). This is because Interchange automatically formats
shopping cart prices as currency. To turn off this feature, you would
have to change the [item-price] tag to [item-price noformat] in
pages/ord/basket.html.

But that's probably not what you want to do. You're probably more
interested in formatting your other prices as currency. To do that,
simply use the [currency] [/currency] tag pair for all price values.
Make the following change to pages/index.html:

  [loop search="ra=yes/fi=products"]
  <tr>
  <td>[loop-code]</td>
  <td>[loop-field description]</td>
- <td align=right>[loop-field price]</td>
+ <td align=right>[currency][loop-field price][/currency]</td>
  </tr>
  [/loop]

Note: The line that begins with '-' should be deleted. Do not type the
'-'. The next line, that starts with '+', replaces it.

A similar change to the [item-field price] tag in the
pages/flypage.html page will fix that currency display. View the page
in your browser. All your prices should be formatted for U.S.
currency.

If your prices are not being formatted correctly, your default system
locale may be set up differently or your en_US locale settings may be
wrong. There are a few other catalog.cfg directives you can use to
correct the situation:

  Locale en_US p_cs_precedes 1

Makes the currency symbol precede the currency value. A '0' setting
makes the symbol come after the currency value.

  Locale en_US mon_thousands_sep ,

Sets your thousands separator to a comma. It can be set to any value.

  Locale en_US mon_decimal_point .

Sets your decimal separator to a comma. Many countries use a comma
instead of a period to separate the integer from the decimal part.

Note: Consult the Interchange documentation and your operating system
manual for more information on locale settings.

42.2. Catalog variables
-----------------------

Interchange provides a very useful feature that has not been discussed
yet called catalog variables. It provides a way for you to set a
variable to a certain value in the catalog.cfg file and use it
anywhere in your catalog pages. The Variable directive allows an
Interchange catalog variable to be created with the name coming from
the first parameter and the value from the rest of the line, like
this:

  Variable SOMENAME whatever value you want

To access that variable in your pages, type the token __SOMENAME__.
Notice that there are two underscore characters before the variable
name and two after it, and that in place of the word SOMENAME you
would put the actual name of the variable. The first thing Interchange
does on a page is to replace the token with the variable's value. The
value can also include Interchange tags to be parsed.

42.3. A more interesting page footer
------------------------------------

You can put a contact email address at the bottom of each page in case
your customers want to contact you. You could just add it to the
footer, but by putting it into a variable you can use it in contact
pages as well. This allows you to easily change the variable
information and have that change reflected in all instances of that
variable. The following is an example of how to set a catalog variable
in catalog.cfg:

  Variable CONTACT_EMAIL someone@your.domain

Now make the following change to your template file bottom:

  </td>
  </tr>
- <tr><td colspan=2>(bottom)</td></tr>
+ <tr><td colspan=2><a href="mailto:__CONTACT_EMAIL__">Contact us</a>
+ if you have any questions.</td></tr>
  </table>
  </div>
  </body>
  </html>

Be sure to restart Interchange before reloading the page in your
browser, since you made a change to catalog.cfg.

Let's add another variable to your catalog. This variable demonstrates
how an Interchange tag can be included in the variable. This
Interchange tag returns the current date in a standard format. Add the
following to catalog.cfg:

  Variable DISPLAYDATE [time]%A, %B %d, %Y[/time]

Note: See the Interchange Tag Reference Guide for an explanation of
the [time] tag.

Now add the following to the left template piece:

  <tr>
- <td align=center>(left)</td>
+ <td align=center>__DISPLAYDATE__</td>
  <td align=center>

Restart Interchange and view the page.

42.4. Advanced credit card expiration date selection
----------------------------------------------------

To reduce the possibility of human error at checkout time, most online
stores use a pull-down option menu to list the months and the years
for the credit card expiration date, instead of having the user to
type the numbers by hand. It also lets you avoid explaining whether
the user should enter a 2- or 4-digit year.

Make the following change to your pages/checkout.html page. The
section that follows explains the code. Read the explanation section
below before typing the code to be sure you know where tabs should be
used instead of spaces and where to watch out for `backticks`.

  <tr>
  <td align=right><b>Credit card expiration date:</b></td>
  <td>
- Month (number from 1-12):
- <input type=text name=mv_credit_card_exp_month value="" size=2 maxlength=2>
- <br>
- Year (last two digits only):
- <input type=text name=mv_credit_card_exp_year value="" size=2 maxlength=2>
+
+ Month:
+ <select name=mv_credit_card_exp_month>
+ [loop
+    lr=1
+    option=mv_credit_card_exp_month
+    list="
+ 1     01 - January
+ 2     02 - February
+ 3     03 - March
+ 4     04 - April
+ 5     05 - May
+ 6     06 - June
+ 7     07 - July
+ 8     08 - August
+ 9     09 - September
+ 10    10 - October
+ 11    11 - November
+ 12    12 - December"]
+ <option value="[loop-code]">[loop-pos 1]
+ [/loop]
+ </select>
+
+ Year:
+ <select name=mv_credit_card_exp_year>
+ [comment]
+    This should always return the current year as the first, then
+    seven more years.
+ [/comment]
+ [loop option=mv_credit_card_exp_year lr=1 list=`
+   my $year = $Tag->time( '', { format => '%Y' }, '%Y' );
+   my $out = '';
+   for ($year .. $year + 7) {
+     /\d\d(\d\d)/;
+     $last_two = $1;
+     $out .= "$last_two\t$_\n";
+   }
+   return $out;
+ `]
+   <option value="[loop-code]">[loop-pos 1]
+ [/loop]
+ </select>
+
  </td>
  </tr>

  </table>

In the first set of <select> </select> tags a list is generated of the
months to choose from. This is accomplished by using a [loop] tag. In
this case we are looping over an explicit list. The list is provided
in the list parameter. Use caution when typing this, as it is
sensitive to formatting (which may not be reflected in this document).
Make sure that the numbers are the first characters on each new line
and that the elements are separated by a single tab. Since the columns
in this list are not named, the first element can be accessed using
[loop-code] or [loop-pos 0] with subsequent elements being accessed by
[loop-pos N] where N is the number of the element you want. Notice
that the elements are zero-indexed. Each time through this loop
Interchange generates a select <option> with a number as the value and
the name of the month as the text for the select menu.

For the next set of <select> </select> tags embedded Perl is used to
generate the list which is iterated over. Perl code can be embedded in
Interchange pages in order to extend the abilities of the system. Make
sure you typed backticks (grave accents) after "list=" and before the
closing bracket and not apostrophes. This code generates an entry for
seven years in addition to the current year. It is not necessary at
this point for you to understand this Perl code.

42.5. Sorting the product list
------------------------------

The products listed on your welcome page are shown in the same order
that you entered them into products/products.txt. As you add more
products, you will want this list to show up in a predictable order.
To do this, you need to change the search parameters in index.html,
which were originally:

  [loop search="ra=yes/fi=products"]

You will recall that 'ra' stands for 'return all' and 'fi' stands for
file. Let's add the search parameter 'tf', which specifies the sort
field. You can specify the field either by name or by number (starting
with 0), with names and order as given in the first line of
products/products.txt). Make the following change in index.html:

  [loop search="ra=yes/fi=products/tf=price"]

Refresh your browser. The default ordering is done on a
character-by-character basis, but we were looking to do a numeric
sort. For this you need to set 'to', the sort order, to 'n', for
numeric:

  [loop search="ra=yes/fi=products/tf=price/to=n"]

Refresh your browser. Now try reversing the sort order by adding 'r'
to the 'to' setting:

  [loop search="ra=yes/fi=products/tf=2/to=nr"]

You'll notice that it worked equally well to specify the sort field by
number instead of name. You could also do a reverse alphabetical sort
by description:

  [loop search="ra=yes/fi=products/tf=1/to=r"]

Now let's try narrowing the search down a bit. Instead of returning
all, we'll give 'se', the search parameter, and and use 'su', which
allows substring matches. To search only for products that have the
word "test" in one of their fields, and sort the results by
description, type:

  [loop search="se=test/su=yes/fi=products/tf=description"]

Which seems like something that would be better done in a search box
for your store visitors.

Before moving on, change this search back to the simple list, sorted
by description:

  [loop search="ra=yes/fi=products/tf=description"]

42.6. Adding a search box
-------------------------

Your customers might appreciate the ability to search for a test by
SKU or part of the test description. To do this, you need to add a
search box to the left portion of the page layout. Make the following
change to the file left:

  <tr>
- <td align=center>__DISPLAYDATE__</td>
+ <td align=center>
+ <form action="[area search]" method=post>
+ Search:<br>
+ [set testname]su=yes/fi=products/sf=sku/sf=description[/set]
+ <input type=hidden name=mv_profile value=testname>
+ <input type=text name=mv_searchspec size=15 value="">
+ </form>
+ <hr>
+ __DISPLAYDATE__
+ </td>
  <td align=center>

This is a simple HTML form with a single input box for text. The
action goes to a special Interchange processor called 'search' that
will perform the search and pass the results to a page called
pages/results.html (that has not been created yet).

The [set testname] ... [/set] tags set an Interchange 'value' variable
that, in this case, will be used as a predefined search profile. We
specify all the search parameters except the one the user will enter,
'mv_searchspec' (the long name for 'se'). We then tell Interchange we
want to use this search profile in a hidden form tag named
'mv_profile'.

The search box will now appear on all catalog pages, but you still
need to create the search results page. To create the search results
page, type the following code and save it as pages/results.html.

  [include top]
  [include left]
  <h3>Search Results</h3>
  [search-region]
    [on-match]
      <table cellpadding=5>
      <tr>
      <th>Test #</th>
      <th>Description</th>
      <th>Price</th>
      </tr>
    [/on-match]
    [search-list]
      <tr>
      <td>[item-code]</td>
      <td><a href="[item-code].html">[item-field description]</a></td>
      <td align=right>[item-field price]</td>
      <td>[order [item-code]]order now</a></td>
      </tr>
    [/search-list]
    [on-match]
      </table>
    [/on-match]
    [no-match]
      <p>Sorry, no matches were found for '[cgi mv_searchspec]'.</p>
    [/no-match]
  [/search-region]
  <hr>
  <p align=center>[page index]Return to welcome page</a></p>
  <p align=center>[page order]View shopping cart</a></p>
  [include bottom]

The search results will be contained in the [search-region]
[/search-region] tags. The text in the [on-match] [/on-match]
container will be displayed only if matches were found for the search.
The text in the [no-match] [/no-match] container will be displayed
only if no matches were found. The [search-list] [/search-list]
container functions just like [loop] [/loop], iterating over its
contents for each item in the search results list.

42.7. The default catalog page
------------------------------

As you know, a standard Interchange catalog page URL looks like this:

  http://localhost/cgi-bin/tutorial/index.html

But what happens if you leave off the page name, as people often do
when typing URLs in by hand? Type:

  http://localhost/cgi-bin/tutorial

and you get a server error message. We can change this by adding the
following directive to catalog.cfg:

  SpecialPage catalog index

Restart Interchange and try the above URL again.

Note: If you want to make the welcome page something other than
pages/index.html, modify the 'index' part of the directive
appropriately.

42.8. High-traffic changes
--------------------------

Through this tutorial you have created catalog pages that use the
[include] tag to include template pieces in the pages. This has worked
well, but there are a few drawbacks. First, if you want to rename any
of the template piece files or move them out of the main catalog
directory and into their own subdirectory, you would have to update
the [include] tag on every page. To avoid this, you can create catalog
variables set to the [include] tags. Add these lines to your
catalog.cfg file:

  Variable TOP    [include top]
  Variable LEFT   [include left]
  Variable BOTTOM [include bottom]

Now change every instance of [include top] to __TOP__, doing the same
for each [include] tag. At this point, you might not want to do a
search-and-replace on all the .html files you just created, but keep
this capability in mind for the next catalog you work on.

If you made all of the replacements and then renamed and moved your
top file, you would only have to make a single change for each region
in catalog.cfg to get your pages up to date:

  Variable TOP    [include templates/main-top]

And so on, depending on your naming scheme.

42.9. High traffic mode
-----------------------

Every time a catalog page is viewed, each file in an [include] tag
must be loaded from disk. In a test situation, this takes no
noticeable amount of time. But on a busy Interchange server, this can
slow your system.

You can switch to a high-traffic mode that doesn't require each
template piece to be read from disk every time the page is loaded.
Instead, all of the pieces are read into variables once when
Interchange is started and they remain in memory until Interchange is
restarted. On very busy Interchange catalogs, this can increase your
speed noticeably. The only drawback is that you need to restart the
Interchange daemon when you make changes to the template pieces in
order to have the changes take effect. You can set up high-traffic
templates by changing the Variable directives in catalog.cfg as
follows:

  Variable TOP    <top
  Variable LEFT   <left
  Variable BOTTOM <bottom

43. Ideas for further enhancements
==================================

You can expand your skill with Interchange by adding more
functionality to your test catalog. Here are some simple ideas to get
you started:

o    Send the customer a receipt by email

o    Allow customer to specify item quantities

o    Generate a unique order number for each order

o    Store each order in a database

o    Interface with GnuPG or PGP to encrypt credit card numbers in
     email reports

o    Organize your products into categories and group lists by
     category

G. Catalog directory structure
==============================

This diagram shows the directory and file structure used for the
'tutorial' catalog you built. The base will be a directory with the
name of your catalog:

  tutorial/
  |
  |----bottom
  |----catalog.cfg
  |----error.log *
  |----etc/
       |----profiles.order
       |----report
  |----left
  |----pages/
       |----checkout.html
       |----flypage.html
       |----index.html
       |----ord/
            |----basket.html
       |----results.html
  |----products/
       |----products.gdbm *
       |----products.txt
  |----session/
       |----(many subdirectories and files) *
  |----special_pages/
       |----missing.html
       |----needfield.html
       |----receipt.html
  |----tmp/ *
  |----top

* denotes files that are automatically created by Interchange at run
time. The name of products.gdbm may vary on your system depending on
your Perl setup and default system DBM libraries.

H. Document history
===================

October 2000. Conceived and written by Sonny Cook.

December 2000. Edited and expanded by Jon Jensen.

January 2001. Proofread and clarified by Alison Smith and David Adams.

12 January 2001. First public release.

12 April 2002. Remove mention of obsolete Red Hat Linux 6-specific
RPMs.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Configuration Reference
=======================

44. Interchange Configuration Files
===================================

This is an alphabetical reference to the configuration directives used
in Interchange global and catalog configuration files.

Interchange has multiple catalog capability, and therefore splits its
configuration into two pieces. One is global, interchange.cfg, and
affects every catalog running under it. The other, catalog.cfg is
specific to an individual catalog, and has no effect on other
catalogs.

44.1. Directive syntax
----------------------

Configuration directives are normally specified with the directive as
the first word on the line, with its value or values following.
Capitalization of the directive name is not significant. Leading and
trailing whitespace is stripped from the line.

Including files in directives

Additional files may be called with an include file notation like
this:

DirectiveName <includefile

Files included from interchange.cfg are relative to the Interchange
software directory. Files included from catalog.cfg are relative to
the catalog directory.

Here documents

A "here document" can be used to spread directive values over several
lines, with the usual Perl <<MARKER syntax. No semicolon is used to
terminate the marker. The closing marker must be the only thing on the
line. No leading or trailing characters are allowed, not even
whitespace. Here is a hypothetical directive using a here document:

          DirectiveName <<EOD
              setting1
              setting2
              setting3
          EOD

That is equivalent to:

          DirectiveName setting1 setting2 setting3

Include single setting from file

     Value can be pulled from a file with <file:

          Variable MYSTUFF <file

     This works well for includes that must be of the highest possible
     performance. They can be simply placed in a page with
     __VARIABLE__.

include

     Other configuration files can be included in the current one. For
     example, common settings can be set in one file:

          include common.cfg

     Or all files in one directory:

          include usertag/*

ifdef and ifndef

     ifdef/endif and ifndef/endif pairs can be used:

          Variable ORDERS_TO email_address
          
          ifdef ORDERS_TO
          ParseVariables Yes
          MailOrderTo __ORDERS_TO__
          ParseVariables No
          endif
          
          ifdef ORDERS_TO =~ /foo.com/
          # Send all orders at foo.com to one place now
          # Set ORDERS_TO to stop default setting
          Variable  ORDERS_TO  1
          MailOrderTo   orders@foo.com
          endif
          
          ifdef ORDERS_TO eq 'nobody@nowhere.com'
          # Better change to something else, set ORDERS_TO to stop default
          Variable  ORDERS_TO  1
          MailOrderTo   someone@somewhere.com
          endif
          
          ifndef ORDERS_TO
          #Needs to go somewhere....
          MailOrderTo  webmaster@localhost
          endif

45. interchange.cfg
===================

The VendRoot directory, specified in the main program interchange, is
the default location of all of the Interchange program, configuration,
special, and library files. Unless changed in the call to interchange,
the main Interchange server configuration file will be interchange.cfg
in the VendRoot directory.

The directives defined in interchange.cfg affect the entire
Interchange server and all catalogs running under it. Multiple
Interchange servers may be run on the same machine with totally
independent operation.

Following is an alphabetical listing of all global configuration
directives.

45.1. AcceptRedirect *global*
-----------------------------

Enables processing of HTTP server redirects, i.e. when handling
ErrorDocument for Apache. For instance, if you have in Apache
httpd.conf:

        ## Setting in httpd.conf
        ErrorDocument 404 /cgi-bin/foundation

At that point, a request for /somedir/index.html that is not found
will be equivalent to /cgi-bin/foundation/somedir/index.html and will
be indistinguishable from the Apache-served page by the client.

        AcceptRedirect  Yes

A Yes/No directive, default No.

Caution should be taken not to enable the ErrorDocument to redirect to
Interchange globally -- it would render you subject to a
denial-of-service attack at random URLs, i.e. a flood of MS Windows
"Code Red" attacks. It is recommended that you enable it only for
specific directories, as Apache or another HTTP server will stand up
much better under such a flood.

45.2. ActionMap *global*
------------------------

Allows setting of Interchange form actions, usually with a Perl
subroutine. Actions are page names like:

process  Perform a processing function
order    Order items
scan     Search based on path info
search   Search based on submitted form variables

The global version of ActionMap applies to all catalogs. If the same
action is specified in catalog.cfg, it will pertain. See ActionMap in
that section.

45.3. AddDirective *global*
---------------------------

Adds a configuration directive that will be parsed for every
catalog.cfg file. Accepts three parameters: the name of the directive,
the name of the parser (if any), and the default value (if any). The
following definition would add a directive "Foo," with parser
"parse_bar," and a default value of "Hello, world!":

   AddDirective  Foo  bar "Hello, world!"

If the parser is not defined, the directive value will be scalar and
the same as what the user passes in the config file. If defined, the
parser must be extant before it can be referenced, is always resident
in Vend::Config, and begins with the string parse_. Examples can be
found in the files in the distribution software directory compat/.

45.4. AllowGlobal *global*
--------------------------

Specifies catalog identifiers that may define subroutines and UserTag
entries that can operate with the full permissions of the server.
Don't use this unless the catalog user is trusted implicitly. Default
is blank.

   AllowGlobal  simple

Using AllowGlobal is never necessary, and is always dangerous in a
multi-user environment. Its use is not recommended.

45.5. AutoVariable *global*
---------------------------

Specifies directives which should be translated to Variable settings.
For scalars, the directive name becomes the Variable name and yields
its value, i.e. ErrorFile becomes __ErrorFile__, which would by
default be error.log. Array variables have a _N added, where _N is the
ordinal index, i.e. SafeUntrap becomes __SafeUntrap_0__,
__SafeUntrap_1__, etc. Hash variables have a _KEY added, i.e. SysLog
becomes __SysLog_command__, __SysLog_facility__, etc. Doesn't handle
hash keys that have non-word characters or whitespace. Only
single-level arrays and hashes are translated properly.

See AutoVariable in catalog.cfg.

45.6. Capability *global*
-------------------------

Just like Require or Suggest, but can never cause a warning or
message. This allows a module to be loaded if available and for a
program to check for that capability later and adapt itself to the
configuration.

   Capability  module  Archive::Zip

45.7. Catalog *global*
----------------------

Specifies a catalog that can run using this Interchange server. This
directive is usually inserted into interchange.cfg by the makecat
program when you build a new catalog.

There are three required parameters, as shown in this example:

   Catalog  simple /home/interchange/simple /cgi-bin/simple

The first is the name of the catalog. It will be referred to by that
name in error, warning, and informational messages. It must contain
only alphanumeric characters, hyphens, and underscores. It is highly
recommended that it be all lower case.

The second is the base directory of the catalog. If the directory does
not contain a catalog.cfg file, the server will report an error and
refuse to start.

The third is the SCRIPT_NAME of the link program that runs the
catalog. This is how the catalog is selected for operation. Any number
of alias script names may be specified as additional parameters. This
allows the calling path to be different while still calling the same
catalog:

   Catalog  simple /home/interchange/simple /cgi-bin/simple /simple

This is useful when calling an SSL server or a members-only alias that
requires a username/password via HTTP Basic authorization. All
branched links will be called using the aliased URL.

The script names must be unique among CGI program paths that run on
this server; the same name cannot be used for more than one catalog
unless the FullURL directive is specified. In this case, the parameter
may be specified as:

          www.yourcompany.com/cgi-bin/simple
          www.theirs.com/cgi-bin/simple

Each of those 'simple' catalogs would then call a different catalog.

Optionally, individual Catalog directives that specify each of the
different parameters may be used. The equivalent of our original
example directive above is:

   Catalog simple directory /home/interchange/simple
   Catalog simple script    /cgi-bin/simple
   Catalog simple alias     /simple

Global directives may be specified that will change for that catalog
only. This is mostly useful for ErrorFile and DisplayErrors:

   Catalog simple directive ErrorFile /var/log/interchange/simple_error.log

45.8. CheckHTML *global*
------------------------

Set to the name of an external program that will check the user's HTML
when they set [flag checkhtml] or [tag flag checkhtml][/tag] in their
page.

   CheckHTML  /usr/local/bin/weblint

45.9. CodeDef *global*
----------------------

A generic subroutine mapper that allows mapping of a subroutine as a
ActionMap, CoreTag, Filter, FormAction, GlobalSub, ItemAction,
LocaleChange, OrderCheck, UserTag, Widget.

45.10. ConfigAllAfter *global*
------------------------------

The name of a file (or files) which should be read as a part of every
catalog's configuration, after any other configuration files are read.
Default is catalog_after.cfg.

   ConfigAllAfter   check_actions.cfg check_variables.cfg

45.11. ConfigAllBefore *global*
-------------------------------

The name of a file (or files) which should be read as a part of every
catalog's configuration, before any other configuration files are
read. Default is catalog_before.cfg.

   ConfigAllBefore   set_actions.cfg set_variables.cfg

45.12. ConfigParseComments *global*
-----------------------------------

Set to No if you want old-style '#include', '#ifdef', or '#ifndef' to
be treated as the comments they appear to be. The default is Yes,
which means both '#include' and 'include' do the same thing. (Use a
space after the '#' if you really want to comment out the command.)

Interchange prior to version 4.7 used a different syntax for
meta-directives 'include', 'ifdef', and 'ifndef' in configuration
files. The commands were borrowed from the C preprocessor, and true to
their C heritage, they started with '#': '#include', '#ifdef',
'#ifndef'. Interchange configuration files, unlike C, uses '#' to
begin one-line comments, which meant that a newcomer at first glance
might assume that:

#Variable DEBUG 1
#include more.cfg

were both comments, when in fact the second was a live #include
command.

To begin to make things more consistent, Interchange 4.7 and up now
recognize those meta-directives without the leading '#', and the
included demo catalog sets this directive to No so that lines
beginning with '#' really are skipped as comments, regardless of what
comes after.

45.13. Database *global*
------------------------

Defines a database which is global and available to all catalogs.
Writing can be controlled by catalog. See Database.

45.14. DataTrace *global*
-------------------------

Set DBI to trace at the level specified. Valid values are:

0 - Trace disabled.

1 - Trace DBI method calls returning with results or errors.

2 - Trace method entry with parameters and returning with results.

3 - As above, adding some high-level information from the driver and
some internal information from the DBI.

4 - As above, adding more detailed information from the driver. Also
includes DBI mutex information when using threaded Perl.

5 and above - As above but with more and more obscure information.

Trace level 1 is best for most Interchange debug situations. Trace
will only be enabled when DebugFile is specified, as that file is the
target for the trace. Example:

    DataTrace   1

Default is 0. Directive added in 4.7.0.

45.15. DebugFile *global*
-------------------------

Names a file, relative to the Interchange root directory, which should
store the output of logDebug statements, and warnings if warnings are
enabled.

        DebugFile  /tmp/icdebug

45.16. DeleteDirective *global*
-------------------------------

Deletes a configuration directive from the list is parsed for every
catalog.cfg file. Can save memory for installations with large numbers
of catalogs.

   DeleteDirective  DescriptionField OfflineDir

The directive is not case-sensitive. Has no effect on global
directives.

45.17. DisplayErrors *global*
-----------------------------

While all errors are reported in the error log file, errors can also
be displayed by the browser. This is convenient while testing a
configuration. Unless this is set, the DisplayErrors setting in the
user catalogs will have no effect. Default is No.

   DisplayErrors       Yes

Note: This changes the value of $SIG{__DIE__} and may have other
effects on program operation. This should NEVER be used for normal
operation.

45.18. DomainTail *global*
--------------------------

Implements the domain/IP session qualifiers so that only the major
domain is used to qualify the session ID. This is a compromise on
security, but it allows non-cookie-accepting browsers to use multiple
proxy servers in the same domain. Default is Yes.

   DomainTail No

If encrypting credit cards with PGP or GPG, or are using a payment
service like CyberCash, look at the WideOpen directive, which enables
more browser compatibility at the cost of some security.

45.19. DumpStructure *global*
-----------------------------

Tells Interchange to dump the structure of catalogs and the
Interchange server to a file with the catalog name and the extension
.structure. Use this to see how directives have been set.

45.20. EncryptProgram *global*
------------------------------

Specifies the default encryption program that should be used to
encrypt credit card numbers and other sensitive information. Default
is gpg if found on the system; then pgpe, if found; then pgp, and
finally none, disabling encryption.

This is used to set the default in catalog.cfg, which has its own
independent setting of EncryptProgram.

45.21. Environment *global*
---------------------------

Environment variables to inherit from the calling CGI link program. An
example might be PGPPATH, used to set the directory which PGP will use
to find its key ring.

   Environment  MOD_PERL REMOTE_USER PGPPATH

45.22. ErrorFile *global*
-------------------------

Sets the name of the global error log. The default is error.log in the
Interchange software directory.

   ErrorFile  /var/log/interchange/log

Of course, the user ID running the Interchange server must have
permission to write that file.

Optionally, syslog error logging can be set up as well. See SysLog.

45.23. FormAction *global*
--------------------------

Allows a form action (like the standard ones return, submit, refresh,
etc.) to be set up. It requires a Perl subroutine as a target:

   FormAction foo <<EOR
   sub {
       $CGI->{mv_nextpage} = 'bar';
   }
   EOR

If it returns a true (non-zero, non-empty) value, Interchange will
display the page defined in $CGI->{mv_nextpage}. Otherwise,
Interchange will not display any page. The default Interchange actions
can be overridden, if desired. There is also a catalog-specific
version of this directive, which overrides any action of the same
name.

The global version affects all catalogs -- there is also a
catalog-specific version of FormAction which is protected by Safe.

45.24. FullUrl *global*
-----------------------

Normally Interchange determines which catalog to call by determining
the SCRIPT_NAME from the CGI call. This means that different (and
maybe virtual) hosts cannot use the same SCRIPT_NAME to call different
catalogs. Set FullUrl to Yes to differentiate based on the calling
host. Then, set the server name in the Catalog directive accordingly,
such as yourdomain.com/cgi-bin/simple. A yes/no directive, the default
is No.

   FullUrl  Yes

If it is set in this fashion, all catalogs must be defined in this
fashion. NOTE: The individual catalog setting will not work, as this
is used before the catalog name is known.

45.25. GlobalSub *global*
-------------------------

Defines a global subroutine for use by the [perl sub] subname arg
/perl] construct. Use the "here document" capability of Interchange
configuration files to make it easy to define:

   GlobalSub <<EOF

   sub count_orders {
       my $counter = new File::CounterFile "/tmp/count_orders", '1';
       my $number = $counter->inc();
       return "There have been $number orders placed.\n";
   }
   EOF

As with Perl "here documents," the EOF (or other end marker) must be
the ONLY thing on the line, with no leading or trailing white space.
Do not append a semicolon to the marker. (The above marker appears
indented. It should not be that way in the file!)

IMPORTANT NOTE: These global subroutines are not subject to security
checks. They can do most anything! For most purposes, scratch
subroutines or catalog subroutines (also Sub) are better.

GlobalSub routines are subject to full Perl use strict checking, so
errors are possible if lexical variables or complete package
qualifications are not used for the variables.

45.26. HammerLock *global*
--------------------------

The number of seconds after which a locked session could be considered
to be lost due to malfunction. This will kill the lock on the session.
Only here for monitoring of session hand-off. If this error shows up
in the error log, the system setup should be examined. Default is 30.

   HammerLock          60

This mostly doesn't apply to Interchange when using the default
file-based sessions.

45.27. HitCount *global*
------------------------

Increments a counter in ConfDir for every access to the catalog. The
file is named hits.catalogname, where catalogname is the short catalog
identifier. A Yes/No directive, default is No.

   HitCount  Yes

45.28. HouseKeeping *global*
----------------------------

How often, in seconds, the Interchange server will "wake up" and look
for user reconfiguration requests and hung search processes. On some
systems, this wakeup is the only time the server will terminate in
response to a stop command. Default is 60.

   HouseKeeping    5

45.29. Inet_Mode *global*
-------------------------

Determines whether INET-domain sockets will be monitored on startup.
Overridden by the command-line parameter -i. Default is Yes.

45.30. IpHead *global*
----------------------

Implements the domain/IP session qualifiers so that only the first
IpQuad dot-quads of the IP address are used to qualify the session ID.
The default is 1. This is a slight compromise on security, but it
allows non-cookie-accepting browsers, like AOL's V2.0, to use multiple
proxy servers.

DomainTail is preferable unless one of your HTTP servers does not do
host name lookups. Default is No, and DomainTail must be set to No for
it to operate.

   IpHead Yes

45.31. IpQuad *global*
----------------------

The number of dot-quads that IpHead will look at. Default is 1.

   IpQuad  2

45.32. Locale *global*
----------------------

Sets the global Locale for use in error messages. Normally set from a
file's contents, as in the example before:

   Locale <locale.error

45.33. LockoutCommand *global*
------------------------------

The name of a command (as it would be entered from the shell) that
will lock out the host IP of an offending system. The IP address will
be substituted for the first occurrence of the string %s. This will be
executed with the user ID that Interchange runs under, so any commands
that require root access will have to be wrapped with an SUID program.

On Linux, a host may be locked out with:

   ipfwadm -I -i deny -S %s

This would require root permissions, however, under normal
circumstances. Use sudo or another method to wrap and allow the
command.

A script can be written which modifies an appropriate access control
file, such as .htaccess for your CGI directory, to do another level of
lockout.  A simple command line containing perl -0777 -npi -e
's/deny/deny from %s\ndeny/' /home/me/cgi-bin/.htaccess would work as
well (remember, the %s will become the IP address of the offending
user).

   LockoutCommand   lockout %s

45.34. LockType *global*
------------------------

Allows selection of file locking method used throughout Interchange.
Options are 'flock', 'fcntl', and 'none'. Added in 4.7.0. Please note
that due to a bug this directive only works in Interchange 4.8.6 and
above.

Default is flock. See the flock(2) manpage for details.

The fcntl setting is needed for NFS filesystems; for NFS-based locking
to work, the NFS lock daemon (lockd) must be enabled and running on
both the NFS client and server. Locking with fcntl works on Linux and
should work on Solaris, but is not guaranteed to work on all OSes.

The none setting turns off file locking entirely, but that is never
recommended. It might be useful to check if locking is causing hangs
on the system.

If you are only accessing sessions on an NFS-mounted directory but the
rest of Interchange is on the local filesystem, you can instead set
the SessionType catalog directive to 'NFS', which enables fcntl
locking for sessions only on a per-catalog basis.

45.35. Mall *global*
--------------------

Set to Yes to issue cookies only for the current catalog's script. By
default, when Interchange issues a cookie it does so for the base
domain. This will allow multiple catalogs to operate on the same
domain without interfering with each others session ID.

A yes/no directive.

   Mall   Yes

45.36. MaxRequestsPerChild *global*
-----------------------------------

The maximum number of requests a page server will handle before it
commits suicide and asks for a replacement server.  This prevents
runaway memory leaks.

        MaxRequestsPerChild  100

Default is 50. Only applies in PreFork mode.

45.37. MaxServers *global*
--------------------------

The maximum number of servers that will be spawned to handle page
requests. If more than MaxServers requests are pending, they will be
queued (within the defined capability of the operating system, usually
five pending requests) until the number of active servers goes below
that value.

   MaxServers     4

Default is 10.

45.38. NoAbsolute *global*
--------------------------

Whether Interchange [file ...] and other tags can read any file on the
system (that is readable by the user id running the Interchange
daemon). The default is No, which allows any file to be read. This
should be changed in a multi-user environment to minimize security
problems.

   NoAbsolute     Yes

Note that this does not apply to tests for whether a file exists, as
with [if file ...]. Such operations are allowed regardless of the
NoAbsolute setting.

45.39. PIDcheck *global*
------------------------

If non-zero, enables a check of running Interchange processes during
the housekeeping routine. If a process has been running (or is hung)
for longer than PIDcheck seconds then a kill -9 will be issued and the
server count decremented. During the housekeeping routine, the number
of servers checked by MaxServers will be recounted based on PID files.

Default is 0, disabling the check.

   PIDcheck   300

If you have long-running database builds, this needs to be disabled.
Set it to a high value (perhaps 600, for 10 minutes), or use the
offline script.

45.40. PIDfile *global*
-----------------------

The file which will contain the Interchange server process ID so that
it can be read to determine which process should be sent a signal for
stopping or reconfiguring the server.

   PIDfile  /var/run/interchange/interchange.pid

This file must be writable by the Interchange server user ID.

45.41. PreFork *global*
-----------------------

Causes Interchange to run in pre-forking server mode, where a number
of Interchange server daemons (defined in StartServers) will be
pre-spawned to handle page requests. Each server will handle the
number of requests defined in MaxRequestsPerChild before committing
suicide and causing another server to pre-fork to replace it.

        PreFork Yes

This reduces system overhead due to forking and is the fastest and
best way to run a busy Interchange server. settings that will apply
for all catalogs.

A yes/no directive, default is No.

45.42. Profiles *global*
------------------------

Names a file (or files) which contain OrderProfile and SearchProfile
settings that will apply for all catalogs.

   Profiles     etc/profiles.common

45.43. RobotIP *global*
-----------------------

The RobotIP directive defines a list of IP numbers which will be
classed as crawler robots (search engines) and causes Interchange to
alter its behavior to improve the chance of Interchange-served content
being crawled and listed.

The directive accepts a wildcard list - * represents any number of
characters, ? represents a single character. The elements of the list
are separated by a comma.

See RobotUA for a full description of the behavioural changes.

Example:

  RobotIP   209.135.65, 64.172.5

45.44. RobotUA *global*
-----------------------

The RobotUA directive defines a list of User Agents which will be
classed as crawler robots (search engines) and causes Interchange to
alter its behavior to improve the chance of Interchange-served content
being crawled and listed.

The directive accepts a wildcard list - * represents any number of
characters, ? represents a single character. The elements of the list
are separated by a comma.

If a User Agent is recognised as a robot, the following will be
performed by Interchange:

o    mv_tmp_session scratch variable is set to 1, causing sessions to
     be disabled and therefore avoiding the writing of session data to
     disk.

o    mv_no_session_id scratch variable is set to 1, causing
     Interchange to generate URLs without a session id (eg.
     mv_session_id=KvWna2PT).

o    mv_no_count scratch variable is set to 1, causing Interchange to
     generate URLs without an incremental number, normally used to
     prevent proxy caching (eg. mv_pc=4).

It should be noted that once you have identified you are serving a
page to a robot, you should not use this to massively alter your page
content in an attempt to improve your ranking. If you do this, you
stand the chance of being blacklisted. You have been warned!

Example:

  RobotUA   Inktomi, Scooter, *Robot*, *robot*, *Spider*, *spider*

See also RobotIP.

45.45. SafeUntrap *global*
--------------------------

Sets the codes that will be untrapped in the Safe.pm module and used
for embedded Perl and conditional operations. View the Safe.pm
documentation by typing perldoc Safe at the command prompt. The
default is ftfile sort, which untraps the file existence test operator
and the sort operator. Define it as blank to prevent any operators but
the default restrictive ones.

   SafeUntrap     ftfile sort ftewrite rand

45.46. SendMailProgram *global*
-------------------------------

Specifies the program used to send email. Defaults to
'/usr/lib/sendmail'. If it is not found at startup, Interchange will
return an error message and refuse to start.

   SendMailProgram     /bin/mailer

A value of 'none' will disable the sending of emailed orders. Orders
must be read from a tracking file, log, or by other means.

45.47. SOAP *global*
--------------------

If set to Yes, allows handling of SOAP rpc requests.

45.48. SOAP_Host *global*
-------------------------

The list of hosts that are allowed to connect to for SOAP rpc
requests. Default is localhost 127.0.0.1.

45.49. SOAP_MaxRequests *global*
--------------------------------

The maximum number of requests a SOAP rpc server will handle before it
commits suicide and asks for a replacement server. This prevents
runaway memory leaks.

45.50. SOAP_Perms *global*
--------------------------

The permissions that should be set on a SOAP UNIX-domain socket.
Default is 0660, which allows only programs running as the same UID as
Interchange to access the socket.

45.51. SOAP_Socket *global*
---------------------------

A list of sockets which should be monitored for SOAP requests. If they
fit the form NNN.NNN.NNN.NNN:PPPP, they are IP addresses and ports for
monitoring INET-domain sockets, any other pattern is assumed to be a
file name for monitoring in the UNIX domain.

   SOAP_Socket 12.23.13.31:7770 1.2.3.4:7770 /var/run/interchange/soap

45.52. SOAP_StartServers *global*
---------------------------------

The number of SOAP servers which should be started to handle SOAP
requests. Default is 1.

   SOAP_StartServers   10

45.53. SocketFile *global*
--------------------------

The name of the file which is used for UNIX-domain socket
communications. Must be in a directory where the Interchange user has
write permission.

   SocketFile  /var/run/interchange/interchange.socket

Default is etc/socket or the value of the environment variable
MINIVEND_SOCKET. If set, it will override the environment. It can be
set on the command line as well:

   bin/interchange -r SocketFile=/tmp/interchange.socket

45.54. SocketPerms *global*
---------------------------

The permissions (prepend a 0 to use octal notation) that should be
used for the UNIX-domain socket. Temporarily set this to 666 on the
command line to debug a permission problem on vlink.

   bin/interchange -r SocketPerms=0666

45.55. StartServers *global*
----------------------------

The number of Interchange page servers which should be started to
handle page requests when in PreFork mode. Default is 1.

   StartServers   8

45.56. SubCatalog *global*
--------------------------

Allows definition of a catalog which shares most of the
characteristics of another catalog. Only the directives that are
changed from the base catalog are added. The parameters are: 1) the
catalog ID, 2) the base catalog ID, 3) the directory to use (typically
the same as the base catalog), and 4) the SCRIPT_NAME that will
trigger the catalog. Any additional parameters are aliases for the
SCRIPT_NAME.

The main reason that this would be used would be to conserve memory in
a series of stores that share most of the same pages or databases.

   SubCatalog   sample2 sample /usr/catalogs/sample /cgi-bin/sample2

45.57. SysLog *global*
----------------------

Set up syslog(8) error logging for Interchange.

   SysLog  command  /usr/bin/logger
   SysLog  tag      int1
   SysLog  alert    local3.warn
   SysLog  warn     local3.info
   SysLog  info     local3.info
   SysLog  debug    local3.debug

This would cause global errors to be logged with the command:

   /usr/bin/logger -t int1 -p local3.alert

and cause system log entries something like:

   Oct 26 17:30:11 bill int1: Config 'co' at server startup
   Oct 26 17:30:11 bill int1: Config 'homefn' at server startup
   Oct 26 17:30:11 bill int1: Config 'simple' at server startup
   Oct 26 17:30:11 bill int1: Config 'test' at server startup
   Oct 26 17:30:13 bill int1: START server (2345) (INET and UNIX)

This would work in conjunction with a UNIX syslogd.conf entry of:

        # Log local3 stuff to Interchange log
        local3.*                /var/log/interchange.log

A custom wrapper can be created around it to get it to behave as
desired. For instance, if you didn't want to use syslog but instead
wanted to log to a database (via DBI), you could create a Perl script
named "logdatabase" to log things:

    #!/usr/bin/perl

    my $script_name = "logdatabase";
    use DBI;
    use Getopt::Std;

    getopts('d:p:T:k:')
        or die "$script_name options: $@\n";

    use vars qw/$opt_d $opt_p $opt_T $opt_k/;

    my $dsn   = $opt_d || $ENV{DBI_DSN};
    my $template = $opt_T
        || "insert into log values ('~~KEY~~', '~~LEVEL~~', '~~MSG~~')";

    my $dbh = DBI->connect($dsn)
        or die "$script_name cannot connect to DBI: $DBI::errstr\n";

    my %data;

    $data{KEY} = $opt_k || '';

    local ($/);
    $data{MSG} = <>;

    $data{LEVEL} = $opt_p || 'interchange.info';

    $template =~ s/\~\~(\w+)\~\~/$dbh->quote($data{$1})/;

    my $sth = $dbh->prepare($template)
        or die "$script_name error executing query: $template\n";

    $sth->execute()
        or die "$script_name error executing query: $template\n";

    exit;

45.58. TagDir *global*
----------------------

Defines the directory or directories that Interchange will scan for
tag, filter, widget, and other code declarations.

   TagDir  code etc/other_code

Relative to the Interchange software root. Default is code.

45.59. TagGroup *global*
------------------------

Defines a group of tags for possible inclusion or exclusion in the set
of ITL tags Interchange will compile and use.

TagGroup :file "counter file include log value_extended"
EOF

Default is defined in lib/Vend/Config.pm, and is too lengthy to show
here. Above is the default :file group.

45.60. TagInclude *global*
--------------------------

Includes or excludes a set of IC tags for compilation and use. The
TagDir is scanned for files, and when found they are checked against
tag names and the groups defined in .TagGroup.

TagInclude ALL !:crufty !get_url

The above will include all tags by default, but not the group :crufty
nor the tag get_url.

Default is ALL.

45.61. TcpHost *global*
-----------------------

When running in INET mode, using tlink, specifies the hosts that are
allowed to send/receive transactions from any catalog on this
Interchange server. Can be either an name or IP number, and multiple
hosts can be specified in a space-separated list. Default is
localhost.

   TcpHost         localhost secure.domain.com

45.62. TcpMap *global*
----------------------

When running in INET mode, using tlink or the internal HTTP server,
specifies the port(s) which will be monitored by the Interchange
server. Default is 7786.

To use the internal HTTP server (perhaps only for password-protected
queries), a catalog may be mapped to a port. If three catalogs were
running on the server www.akopia.com, named simple, sample, and
search, the directive might look like this:

   TcpMap    7786 -  7787 simple 7788 sample 7789 search

Note: To map large numbers of ports, use the <<MARKER here document
notation in interchange.cfg. With this in effect, the internal HTTP
server would map the following addresses:

   *:7786   mv_admin
   *:7787   simple
   *:7788   sample
   *:7789   search

Note: This does not pertain to the use of tlink, which still relies on
the CGI SCRIPT_PATH. To enable this, the SCRIPT_PATH aliases /simple,
/sample, etc. must be set in the Catalog directive. This would look
like:

 Catalog  simple  /home/interchange/catalogs/simple /cgi-bin/simple /simple

To bind to specific IP addresses, add them in the same fashion that
they would as an Apache Listen directive:

   TcpMap <<EOF
       127.0.0.1:7786       -
       www.akopia.com:7787  -
   EOF

Note: As usual, the EOF should be at the beginning of a line with no
leading or trailing whitespace.

45.63. TemplateDir *global*
---------------------------

This can be used to supply some default pages so catalogs will not
need their own copies.

Supply one or more directory names, separated by whitespace, which
will be searched for pages not found in the catalog's PageDir
directory or the catalog-level TemplateDir directory list.

   TemplateDir    /usr/local/interchange/default_pages

This is undefined by default.

45.64. TolerateGet *global*
---------------------------

Set to 'Yes' to enable parsing of both GET data and POST data when a
POST has been submitted. The default is 'No', which means that GET
data is ignored during a POST. Unfortunately this has to be a global
setting because at URL parse time, the Interchange daemon doesn't yet
know which catalog it's dealing with (due to catalog aliases, etc.).

45.65. TrustProxy *global*
--------------------------

Allows the administrator to designate certain IP addresses or
hostnames as trusted HTTP proxies, whose claims (via the
HTTP_X_FORWARDED_FOR environment variable set by the web server) about
the original requesting host will be assumed accurate.

When using a front-end proxy for Interchange, all requests appear to
come from that proxy, for example, perhaps 127.0.0.1 if on the same
machine. This is effectively the same as running with WideOpen Yes,
because all sessions will have the same user IP address and thus can
be easily hijacked. Session hijacking can happen when someone
unknowingly includes a session ID in a URL they send to other users,
and all those users then end up with the same session and shopping
cart!

TrustProxy takes a comma-separated list of one or more IP addresses
and/or hostnames, which may include wildcards (* for any number of
characters, ? for a single character). For example:

TrustProxy 127.0.0.1, 10.0.0.*

I'm not sure why anyone would want to do this, but it could also be
used with external HTTP proxies in general (which you can only hope
aren't lying), with a simple 'TrustProxy *'.

Note that the environment variables are not modified in any way; only
Interchange's idea of the remote host is altered, as you see with
[data session host].

45.66. UrlSepChar *global*
--------------------------

Sets the character which separates form parameters in
Interchange-generated URLs. Default is &.

45.67. Unix_Mode *global*
-------------------------

Determines whether the UNIX-domain socket will be monitored on
startup. Overridden by the command-line parameter -u. Default is Yes.

45.68. UserTag *global*
-----------------------

This defines a UserTag which is global in nature, meaning not limited
by the Safe.pm module, and is is available to all Interchange catalogs
running on the server. Otherwise, this is the same as a catalog
UserTag.

45.69. Variable *global*
------------------------

Defines a global variable that will be available in all catalogs with
the notation @@VARIABLE@@. Variable identifiers must begin with a
capital letter, and can contain only word characters (A-Z,a-z,0-9 and
underscore). They are case-sensitive.

   Variable   DOCUMENT_ROOT   /usr/local/etc/httpd/htdocs

Only variables with ALL CAPS names will be parsed in catalog pages or,
when the ParseVariables directive is set, in catalog (not global)
configuration directives (other than Variable itself). These are
substituted first in any Interchange page, and can contain any valid
Interchange tags including catalog variables. If a variable is called
with the notation @_VARIABLE_@, and there is no catalog Variable with
its name, the global Variable value will be inserted.

There are several standard variables which you should not set:

MV_FILE

     Name of the last file read in, as in [file ...] or an externally
     located perl routine.

MV_NO_CRYPT

     Set this to 1 to disable encrypted passwords for the AdminUser.

MV_PAGE

     Name of the last page read in, as in the page called with
     mv_nextpage or mv_orderpage.

CURRENCY, MV_CURRENCY

     The current locale for currency.

LANG, MV_LANG

     The current locale for language.

Some global variables can be set to affect Interchange:

MV_DOLLAR_ZERO

     This determines what Interchange does to Perl's $0 variable,
     which contains the operating system's name of the running
     process, for example in the ps(1) or top(1) commands. Valid
     settings are:

Setting                            Result
.................................. .................................. 
(not set)                          'interchange'
0                                  (do nothing)
1                                  'interchange --> (CATROOT)'
string                             'string'

     Note that this is set globally once only when the Interchange
     daemon is started, so it's pointless to change the variable after
     that.

45.70. VarName *global*
-----------------------

Sets the names of variables that will be remapped to and from the URL
when Interchange writes it. For instance, to display the variable
mv_session_id as session in the user's URL:

   VarName   mv_session_id  session

The default can also be set in the etc/varnames file after the first
time Interchange is run. Setting it in interchange.cfg is probably
better for clarity.

There is also a catalog-specific version of this setting.

46. catalog.cfg
===============

Each catalog must have a catalog.cfg file located in its base catalog
directory. It contains most of the configurable parameters for
Interchange. Each is independent from catalog to catalog.

Additional configuration techniques are available in the catalog.cfg
file. First, set a Variable and use its results in a subsequent
configuration setting if ParseVariables is on:

   Variable   SERVER_NAME  www.akopia.com
   Variable   CGI_URL      /cgi-bin/demo

   ParseVariables Yes
   VendURL    http://__SERVER_NAME____CGI_URL__
   ParseVariables No

Define subroutine watches

     Almost any configuration variable can be set up to be tied to a
     subroutine if the Tie::Watch module is installed. It uses a
     notation like the <<HERE document, but <&HERE is the notation.
     See Interchange Programming for details.

46.1. Programming Watch Points in catalog.cfg
---------------------------------------------

Almost any configuration variable can be set up to be tied to a
subroutine if the Tie::Watch module installed. It uses a notation like
the <<HERE document, but <&HERE is the notation. Here is a simple
case:

   MailOrderTo orders@akopia.com
   MailOrderTo <&EOF
   sub {
       my($self, $default) = @_;
       if($Values->{special_handling}) {
           return 'vip@akopia.com';
       }
       else {
           return $default;
       }
   }
   EOF

When the order is mailed out, if the user has a variable called
special_handling set in their session (from UserDB, perhaps), the
order will be sent to 'vip@akopia.com.' Note the single quotes to
prevent problems with the @ sign. Otherwise, the order will get sent
to the previously defined value of orders@akopia.com.

If the configuration value being watched is a SCALAR, the subroutine
gets the following call:

   &{$subref}(SELF, PREVIOUS_VALUE)

The subroutine should simply return the proper value.

SELF is a reference to the Tie::Watch object (read its documentation
for what all it can do) and PREVIOUS_VALUE is the previously set value
for the directive. If set after the watch is set up, it will simply
have the effect of destroying the watch and having unpredictable
effects. (In the future, a "Store" routine may be able to be set up
that can subsequently set values).

If the configuration value being watched is an ARRAY, the subroutine
gets the following call:

   &{$subref}(SELF, INDEX, PREVIOUS_VALUE)

INDEX is the index of the array element being accessed. Setting up
watch points on array values is not recommended. Most Interchange
subroutines call arrays in their list context, and no access method is
provided for that.

If the configuration value being watched is a HASH, the subroutine
gets the following call:

   &{$subref}(SELF, KEY, PREVIOUS_VALUE)

KEY is the index into the hash, an example of HASH type Interchange
configuration values. NOTE: The following is not recommended for
performance reasons. The Variable is a commonly used thing and should
not bear the extra overhead of tieing, but it illustrates the power of
this operation:

   Variable TESTIT Unwatch worked.

   Variable <&EOV
   sub {
       my ($self, $key, $orig) = @_;
       if($key eq 'TESTIT') {
           # only the first time
           if($Scratch->{$key}++) {
               $self->Unwatch();
               return $orig->{TESTIT};
           }
           else {
               return "Tie::Watch works! -- name=$Values->{name}";
           }
       }
       else {
           return $orig->{$key};
       }
   }
   EOV

The first time __TESTIT__ is called for a particular user, it will
return the string "Tie::Watch works! -- name=" along with their name
set in the session (if that exists). Any other variables will receive
the value that they were set to previously. Once the TESTIT key has
been accessed for that user, the watch is dropped upon the next
access.

46.2. Configuration Directives in catalog.cfg
---------------------------------------------

All directives except MailOrderTo and VendURL have default values and
are optional, though most catalogs will want to configure some of
them.

46.3. ActionMap
---------------

Allows setting of Interchange actions, usually with a Perl subroutine.
Actions are page names like:

process  Perform a processing function
order    Order items
scan     Search based on path info
search   Search based on submitted form variables

These are the standard supplied actions for Interchange. They can be
overwritten with user-defined versions if desired. For example, to
ignore the order action, set:

   ActionMap  order  sub { return 1 }

When the leading part of the incoming path is equal to order, it will
trigger an action. The page name will be shifted up, and the order
stripped from the page name. So this custom order action would
essentially perform a no-op, and a URL like:

   <A HREF="[area order/nextpage]"> Go to the next page </A>

would be the equivalent of "[area nextpage]." If the action does not
return a true (non-zero, non-blank) status, no page will be displayed
by Interchange, not even the special missing page. A response may also
be generated via Perl or MVASP.

The standard process action has a number of associated FormAction
settings. Besides using Perl, Interchange tags may be used in an
action, though they are not nearly as efficient.

46.4. AlwaysSecure
------------------

Determines whether checkout page operations should always be secure.
Set it to the pages that should always be secure, separated by spaces
and/or tabs.

   AlwaysSecure    ord/checkout

46.5. AsciiTrack
----------------

A file name to log formatted orders in. Unless preceded by a leading
'/', will be placed relative to the catalog directory. Disabled by
default.

   AsciiTrack     etc/tracking.asc

If a Route is set up to supplant, this is ignored.

46.6. AutoEnd
-------------

Sets an action that is automatically performed at the end of every
access. It is performed after any page parsing occurs, just before the
transaction ends. It takes the same kinds of parameters as Autoload.

46.7. Autoload
--------------

Sets an action that is automatically performed for every access. It is
performed before any page parsing occurs, and before the action or
page is even determined. It can be set to a string containing ITL tags
or to the name of a catalog (Sub) or global subroutine. The return
value from the code run is discarded.

For example, to automatically run the Sub or GlobalSub named
'testsub':

   Autoload testsub

To remap any mv_nextpage accesses to the private subdirectory of
pages, set:

   Autoload   [perl] $CGI->{mv_nextpage} =~ s:^private/:public/:; [/perl]

You can temporarily change any of the catalog configuration settings,
for example, to use a different flypage depending on the user's
browser type:

   Autoload       <<EOA
   [perl]
   if ($Session->{browser} =~ /msie/i) {
      $Config->{Special}->{flypage} = 'ie_flypage';
   }
   [/perl]
   EOA

Please note that SpecialPage is the corresponding directive in the
catalog configuration, not Special. This is an exceptional case.
Usually the hash key has the same name as the catalog configuration
directive.

46.8. AutoModifier
------------------

Sets an attribute in a shopping cart entry to the field of the same
name in the ProductsFile pertaining to this item. This is useful when
doing shipping calculations or other embedded Perl that is based on
item attributes. To set whether an item is defined as "heavy" and
requires truck shipment, set:

   AutoModifier  heavy

When an item is added to the shopping cart using Interchange's
routines, the heavy attribute will be set to the value of the heavy
field in the products database. In the default demo that would be
products. Any changes to ProductFiles would affect that, of course.

Some values are used by Interchange and are not legal:

       mv_mi
       mv_si
       mv_ib
       group
       code
       quantity
       item

46.9. AutoVariable
------------------

Specifies directives which should be translated to Variable settings.
For scalars, the directive name becomes the Variable name and yields
its value, i.e. DescriptionField becomes __DescriptionField__, which
would by default be description. Array variables have a _N added,
where _N is the ordinal index, i.e. ProductFiles becomes
__ProductFiles_0__, __ProductFiles_1__, etc. Hash variables have a
_KEY added, i.e. SpecialPage becomes __SpecialPage_missing__,
__SpecialPage_violation__, etc. Doesn't handle hash keys that have
non-word characters or whitespace. Only single-level arrays and hashes
are translated properly.

46.10. CommonAdjust
-------------------

Settings for Interchange pricing. See Chained pricing.

   CommonAdjust    pricing:q2,q5,q10,q25, ;products:price, ==size:pricing

46.11. ConfigDir
----------------

The default directory where directive values will be read from when
using the <file notation. Default is config. The name is relative to
the catalog directory unless preceded by a /.

   ConfigDir      variables

This can be changed several times in the catalog.cfg file to pick up
values from more than one directory. Another possibility is to use a
Variable setting to use different templates based on a setting:

   Variable   TEMPLATE   blue

   ParseVariables Yes
   ConfigDir  templates/__TEMPLATE__
   ParseVariables No
   Variable   MENUBAR   <menubar
   Variable   LEFTSIDE  <leftside
   Variable   BOTTOM    <bottom
   ConfigDir config

This will pick the templates/blue template. If TEMPLATE is set to red,
it would read the variables from templates/red.

46.12. CookieDomain
-------------------

Allows a domain to be set so that multiple servers can handle traffic.
For example, to use server addresses of secure.yourdomain.com and
www.yourdomain.com, set it to:

   CookieDomain    .yourdomain.com

More than one domain can be set. It must have at least two periods or
browsers will ignore it.

46.13. CookieLogin
------------------

Allows users to save their username/password (for Vend::UserDB) in a
cookie. Expiration is set by SaveExpire and is renewed each time they
log in. To cause the cookie to be generated originally, the CGI
variable mv_cookie_password or mv_cookie_username must be set. The
former causes both username and password to be saved; the latter just
the username.

   CookieLogin  Yes

Default is No.

46.14. Cookies
--------------

Determines whether Interchange will send (and read back) a cookie to
get the session ID for links that go outside the catalog. Allows
arbitrary HREF links to be placed in Interchange pages, while still
saving the contents of the session. The default is Yes.

   Cookies         Yes

If the Cookies directive is enabled, and mv_save_session is set upon
submission of a user form (or in the CGI variables through a Perl
GlobalSub), the cookie will be persistent for the period defined by
SaveExpire.

Note: This should almost always be "Yes."

Caching, timed builds, and static page building will never be in
effect unless this directive is enabled.

46.15. CreditCardAuto
---------------------

If set to Yes, enables the automatic encryption and saving of credit
card information. In order for this to work properly, the
EncryptProgram directive must be set to properly encode the field. The
best way to set EncryptProgram is with PGP in the ASCII armor mode.
This option uses the following standard fields on Interchange order
processing forms:

mv_credit_card_number

     The actual credit card number, which will be wiped from memory
     after checking to see if it is a valid Amex, Visa, MC, or
     Discover card number. This variable will never be carried forward
     in the user session.

mv_credit_card_exp_all

     The expiration date, as a text field in the form MM/YY (will take
     a four-digit year as well). If it is not present, the fields
     mv_credit_card_exp_month and mv_credit_card_exp_year are looked
     at. It is set by Interchange when the card validation returns, if
     not previously set.

mv_credit_card_exp_month

     The expiration date month, used if the mv_credit_card_exp_all
     field is not present. It is set by Interchange when the card
     validation returns, if not previously set.

mv_credit_card_exp_year

     The expiration date year, used if the mv_credit_card_exp_all
     field is not present. It is set by Interchange when the card
     validation returns, if not previously set.

mv_credit_card_error

     Set by Interchange to indicate the error if the card does not
     validate properly. The error message is not too enlightening if
     validation is the problem.

mv_credit_card_force

     Set this value to 1 to force Interchange to encrypt the card
     despite its idea of validity. Will still set the flag for
     validity to 0 if the number/date does not validate. Still won't
     accept badly formatted expiration dates.

mv_credit_card_separate

     Set this value to 1 to cause Interchange encrypt only the card
     number and not accompany it with the expiration date and card
     type.

mv_credit_card_info

     Set by Interchange to the encrypted card information if the card
     validates properly. If PGP is used in ASCII armor mode, this
     field can be placed on the order report and embedded in the order
     email, replete with markers. This allows a secure order to be
     read for content, without exposing the credit card number to
     risk.

mv_credit_card_valid

     Set by Interchange to true, or 1, if the the card validates
     properly. Set to 0 otherwise.

GnuPG is recommended as the encryption program. Interchange will also
work with PGP.

   CreditCardAuto     Yes

46.16. Cron *5.0 and up*
------------------------

Configuration for jobs run with the --cron commandline option.

base_directory, use_global

Directory to search for cron jobs. The default is etc/cron in the
catalog directory. If use_global is set, the same directory is
searched in the global configuration directory.

initialize, autoload

The macros initialize and autoload are executed once resp. before each
job.

email, log, add_session

The output of a single run of cron jobs is written to a log file and
send by email if the corresponding configuration values email and log
are set. An email address passed by the commandline option --email has
higher preference than the email address in email.

If the run produces no output, neither the email will be send nor the
log file entry will be written.

add_session adds the current session to the output.

from, subject, reply_to, extra_headers

Additional configuration values for the generation of the email.

46.17. CustomShipping
---------------------

If not blank, causes an error log entry if the shipping file entry is
not found. Not otherwise used for shipping. See SHIPPING for how to go
about doing that.

   CustomShipping      Yes

46.18. Database
---------------

Definition of an arbitrary database, in the form "Database database
file type," where "file" is the name of an ASCII file in the same
format as the products database. The file is relative to VendRoot.
Records can be accessed with the [data database field key] tag.
Database names are restricted to the alphanumeric characters
(including the underscore), and it is recommended that they be either
all lower or all upper case. See DATABASES.

   Database      reviews  reviews.txt  CSV

46.19. DatabaseDefault
----------------------

Defines default parameters for a database. This can be used to set a
default WRITE_CONTROL setting, set a default USER or PASSWORD, etc. It
accepts any scalar setting, which means all except:

ALTERNATE_* BINARY COLUMN_DEF DEFAULT FIELD_ALIAS FILTER_* NAME
NUMERIC POSTCREATE WRITE_CATALOG

This default setting is made when the table is initially defined, i.e.
explicit settings for the database itself override the defaults set.

   DatabaseDefault      WRITE_CONTROL   1
   DatabaseDefault      WRITE_TAGGED    1

This setting must be made *before* the database is defined. To reset
its value to empty, use the Replace directive.

   Replace DatabaseDefault

46.20. DefaultShipping
----------------------

This sets the default shipping mode by initializing the variable
mv_ship_mode. If not set in catalog.cfg, it is default.

   DefaultShipping     UPS

Somewhat deprecated, the same thing can be achieved with:

   ValuesDefault   mv_shipmode UPS

46.21. DescriptionField
-----------------------

The field that will be accessed with the [item-description] element.

   DescriptionField    description

Default is description. It is not a fatal error if this field does not
exist. This is especially important for on-the-fly items. If there is
an attribute set to the same name as DescriptionField, this will be
used for display.

46.22. DirConfig
----------------

DirConfig allows you to batch-set a bunch of variables from files. The
syntax:

DirConfig  directive-name directory-glob

directive-name is usually Variable, but could be any hash-based
directive. (No other standard directives currently make sense to set
this way.)

directory-glob is a filespec that could encompass multiple
directories. Files are ignored.

The directories are read for file *names* that contain only word
characters, i.e. something that would be a valid Variable. (This alone
might make it not suitable for other uses, but picking up the junk
from the in-directory-backup-file people would be intolerable.)

Then the contents of the file is used to set the variable of the file
name.

The source file name is kept in
$Vend::Cfg->{DirConfig}{Variable}{VARNAME}, for use if
dynamic_variables Pragma is set.

Pragma dynamic_variables enables dynamic updating of variables from
files. Pragma dynamic_variables_files_only restricts dynamic variables
to files only -- otherwise variables are dynamically read from the
VarDatabase definition as well.

With dynamic variables, all @_VARIABLE_@ and __VARIABLE__ settings are
checked first to see if the source file is defined. If there is a key
present, even if its contents are blank, it is returned. Example -- in
the case of this catalog.cfg entry:

        DirConfig Variable templates/foundation/regions

If the file NOLEFT_TOP is present at catalog config time,
__NOLEFT_TOP__ will equal [include
templates/foundation/regions/NOLEFT_TOP].

46.23. DirectoryIndex
---------------------

If DirectoryIndex is set, and a page would normally be defined as
missing, it's value is appended (with a separating / if appropriate)
and the resulting page is looked for. To get the behavior normally
associated with an HTTP server, where "index.html" is looked for in a
directory, do:

        DirectoryIndex   index.html

Default is blank, disabling the behavior.

     NOTE: Unlike Apache, only one value is accepted.

46.24. DisplayErrors
--------------------

If the administrator has enabled DisplayErrors globally, setting this
to "Yes" will display the error returned from Interchange in case
something is wrong with embedded Perl programs, tags, or Interchange
itself. Usually, this will be used during development or debugging.
Default is No.

   DisplayErrors       Yes

46.25. DynamicData
------------------

When set to one or more Interchange database identifiers, any pages
using data items from the specified database(s) will not be cached or
built statically. This allows dynamic updating of certain arbitrary
databases (even the products database) while still allowing
static/cached page performance gains on pages not using those data
items.

   DynamicData         inventory

Overridden by [tag flag build][/tag], depending on context.

46.26. EncryptProgram
---------------------

Contains a program command line specification that indicates how an
external encryption program will work. Two placeholders, %p and %f,
are defined, which are replaced at encryption time with the password
and temporary file name respectively. See Order Security. This is
separate from the PGP directive, which enables PGP encryption of the
entire order.

If PGP is the encryption program (Interchange determines this by
searching for the string pgp in the command string), no password field
or file field need be used. The field mv_credit_card_number will never
be written to disk in this case.

   EncryptProgram      /usr/local/bin/pgp -feat sales@company.com

If the order Route method of sending orders is used (default in the
demo), this sets the default value of the encrypt_program attribute.

46.27. ErrorFile
----------------

This is where Interchange will write its runtime errors for THIS
CATALOG ONLY. It can be shared with other catalogs or the main
Interchange error log, but if it is root-based, permission to write
the file is required.

   ErrorFile   /home/interchange/error.log

46.28. ExtraSecure
------------------

Disallows access to pages which are marked with AlwaysSecure unless
the browser is in HTTPS mode. A Yes/No directive, the default is 'No.'

   ExtraSecure  Yes

46.29. Filter
-------------

Assigns one or more filters (comma separated) to be automatically
applied to a variable.

As an example, multiple form variable submissions on the same page
come back null-separated, like 'value1\0value2\0value3'. To
automatically change those nulls to spaces, you could use this
directive:

Filter  mail_list  null_to_space

Of course you could just as easily use the [filter] tag on the page if
the filter is only going to be used in a few places. See the [filter]
tag documentation for more information and a list of filters.

46.30. FormAction
-----------------

Allows set up of a form action (like the standard ones return, submit,
refresh, etc.). It requires a Perl subroutine as a target:

   FormAction foo <<EOR
   sub {
       $CGI->{mv_nextpage} = 'bar';
   }
   EOR

If it returns a true (non-zero, non-empty) value, Interchange will
display the page defined in $CGI->{mv_nextpage}. Otherwise,
Interchange will not display any page. The default Interchange actions
can be overridden if desired. There is also a global version of this
directive, which is overridden if a catalog-specific action exists.

46.31. FormIgnore
-----------------

Set to the name(s) of variables that should not be carried in the user
session values. Must match exactly and are case sensitive.

   FormIgnore    mv_searchtype

46.32. FractionalItems
----------------------

Whether the quantity field for items in the shopping cart should be
allowed to be fractional, i.e., 2.5 or 1.25. Default is No.

   FractionalItems     Yes

46.33. Glimpse
--------------

The pathname for the glimpse command, used if glimpse searches are to
be enabled. To use glimpseserver, the -C, -J, and -K tags must be
used.

   Glimpse  /usr/local/bin/glimpse -C -J srch_engine -K2345

46.34. History
--------------

How many of the most recent user clicks should be stored in the
session history. Default is 0.

46.35. HTMLsuffix
-----------------

The file extension that will be seen as a page in the pages directory.
Default is .html.

   HTMLsuffix .htm

46.36. ImageAlias
-----------------

Aliases for images, ala Apache/NCSA, ScriptAlias, and Alias
directives. Relocates images based in a particular directory to
another for Interchange use; operates after ImageDir. Useful for
editing Interchange pages with an HTML editor. Default is blank.

   ImageAlias  /images/  /thiscatalog/images/

46.37. ImageDir
---------------

The directory where all relative IMG and INPUT source file
specifications are based. IT MUST HAVE A TRAILING / TO WORK. If the
images are to be in the DocumentRoot (of the HTTP server or virtual
server) subdirectory images, for example, use the ImageDir
specification '/images/'. This would change SRC="order.gif" to
SRC="/images/order.gif" in IMG and INPUT tags. It has no effect on
other SRC tags.

   ImageDir /images/

Can be set in the Locale settings to allow different image sets for
different locales (MV3.07 and up).

46.38. ImageDirInternal
-----------------------

A value for ImageDir only when the internal HTTP server is in use. It
must have a trailing / to work, and should always begin with a
fully-qualified path starting with http://.

   ImageDirInternal http://www.server.name/images/

46.39. ImageDirSecure
---------------------

A value for ImageDir only when the pages are being served via HTTPS.
It must have a trailing / to work, and should always begin with a
fully-qualified path starting with http://.

   ImageDirSecure   /secure/images/

This is useful if using separate HTTPS and HTTP servers, and cannot
make the image directory path heads match.

46.40. Locale
-------------

Sets the special locale array. Tries to use POSIX setlocale based on
the value of itself, then tries to accept a custom setting with the
proper definitions of mon_decimal_point, thousands_sep, and
frac_digits, which are the the only international settings required.
Default, if not set, is to use US-English settings.

Example of the custom setting:

   Locale     custom mon_decimal_point , mon_thousands_sep . frac_digits 0

Example of POSIX setlocale for France, if properly aliased:

   Locale     fr

See setlocale(3) for more information. If embedded Perl code is used
to sort search returns, the setlocale() will carry through to string
collation.

See Internationalization.

46.41. LocaleDatabase
---------------------

Set to the Interchange database identifier of a table that contains
Locale settings. These settings add on to and overwrite any that are
set in the catalog configuration files, including any include files.

   Database       locale  locale.asc  TAB
   LocaleDatabase locale

46.42. MailOrderTo
------------------

Specifies the e-mail address to mail completed orders to.

       MailOrderTo  orders@xyzcorp.com

If 'none' is specified, no e-mailed order will be sent.

46.43. NoCache
--------------

The names of Interchange pages that are not to be built statically if
STATIC PAGE BUILDING is in use. If the name is a directory, no pages
in that directory (or any below it) will be cached or built
statically.

   NoCache    ord
   NoCache    special

46.44. NoImport
---------------

When set to one or more Interchange database identifiers, those
database(s) will never be subject to import. Normally, Interchange
checks to see if each database needs to be created and populated (from
the source text file) when the Interchange daemon is started or
restarted, or a catalog is reconfigured.

This is useful for SQL databases used by other applications besides
Interchange, or large databases you load and back up outside of
Interchange. With this option you can omit the source text file for
SQL databases entirely.

   NoImport   inventory

46.45. NoImportExternal
-----------------------

When set to true, this directive prevents database imports for all
"external" databases:

   NoImportExternal  Yes

External database types are DBI (all popular SQL databases) and LDAP.
Internal database types are the DBM variants (GDBM, DB_File, SDBM) and
in-memory databases.

The default setting is false (databases may be imported).

46.46. NonTaxableField
----------------------

The name of the field in the products database that is set (to 1 or
Yes) if an item is not to be taxed. Interchange will log an error and
tax it anyway if the field doesn't exist in the database. Blank by
default, disabling the feature.

   NonTaxableField    wholesale

46.47. NoSearch
---------------

Here you can provide one or more filename fragments that will be
matched against the file name used in any attempted search (the
mv_search_file or 'fi' attribute). You may separate multiple match
strings with whitespace, and may include shell-style wildcards.

The default setting is 'userdb', which means that by default you
cannot use Interchange-style searches on the userdb table. (Pure SQL
searches still work with it, however.)

For example, consider this setting:

   NoSearch  userdb  .*  *.secret

In this case any search file with 'userdb' in its name, or beginning
with a dot, or ending in '.secret', will not be searchable.

46.48. OfflineDir
-----------------

The location of the offline database files for use with the
Interchange offline database build command. Set to "offline" as the
default, and is relative to VendRoot if there is no leading slash.

   OfflineDir          /usr/data/interchange/offline

46.49. OnFly
------------

Enables on-the-fly item additions to the shopping cart. If set to the
name of a valid UserTag, that tag definition will be used to parse and
format the item with the following call:

   $item = Vend::Parse::do_tag($Vend::Cfg->{OnFly},
                                   $code,
                                   $quantity,
                                   $fly[$j],
                               );

$fly[$j] is the value of mv_order_fly for that item. A default onfly
tag is provided by Interchange. For more information, see the section
that describes how to set up an on-the-fly item.

46.50. OrderCounter
-------------------

The name of the file (relative to catalog root if no leading /) that
maintains the order number counter. If not set, the order will be
assigned a string based on the time of the order and the user's
session number.

   OrderCounter       etc/order.number

Bear in mind that Interchange provides the order number as a
convenience for display, and that no internal functions depend on it.
Custom order number routines may be defined and used without fear of
consequences.

If a Route is set up to supplant and the counter attribute is set
there, this is ignored.

46.51. OrderLineLimit
---------------------

The number of items that the user is allowed to place in the shopping
cart. Some poorly-mannered robots may "attack" a site by following all
links one after another. Some even ignore any robots.txt file that may
have been created. If one of these bad robots orders several dozen or
more items, the time required to save and restore the shopping cart
from the user session may become excessive.

If the limit is exceeded, the command defined in the Global directive
LockoutCommand will be executed and the shopping cart will be emptied.
The default is 0, disabling the check. Set it to a number greater than
the number of line items a user is ever expected to order.

   OrderLineLimit   50

46.52. OrderProfile
-------------------

Allows an unlimited number of profiles to be set up, specifying
complex checks to be performed at each of the steps in the checkout
process. The files specified can be located anywhere. If relative
paths are used, they are relative to the catalog root directory.

   OrderProfile    etc/profiles.order etc/profiles.login

The actions defined here are also used for mv_click actions if there
is no action defined in scratch space. They are accessed by setting
the mv_order_profile variable to the name of the order profile.
Multiple profiles can reside in the same file, if separated by __END__
tokens, which must be on a line by themselves.

The profile is named by placing a name following a __NAME__ pragma:

 __NAME__ billing

The __NAME__ must begin the line, and be followed by whitespace and
the name. The search profile can then be accessed by
<mv_order_profile="billing">. See Advanced Multi-level Order Pages.

46.53. OrderReport
------------------

The location of the simple order report file. Defaults to etc/report.

   OrderReport          /data/order-form

46.54. PageDir
--------------

Location of catalog pages. Defaults to the pages subdirectory in the
VendRoot directory.

   PageDir    /data/catalog/pages

Can be set in the Locale settings to allow different page sets for
different locales.

46.55. PageSelectField
----------------------

Sets a products database column which can be used to select the
on-the-fly template page. This allows multiple on-the-fly pages to be
defined. If the field is empty (no spaces), the default flypage will
be used.

   PageSelectField    display_page

46.56. ParseVariables
---------------------

Determines whether global and catalog variables will be parsed in
catalog configuration directives (not including the Variable directive
itself, which never parses its settings). Applies only to variables
with names in ALL CAPS. Default setting is No. The foundation
catalog.cfg turns ParseVariables on and usually expects it to be on.

   Variable STORE_ID  topshop
   ParseVariables Yes
   StaticDir  /home/__STORE_ID__/www/cat
   ParseVariables No

46.57. Password
---------------

The encrypted or unencrypted password (depending on Variable
MV_NO_CRYPT) that will cause internal authorization checks for
RemoteUser to allow access.

Below is the encrypted setting for a blank password.

   Password                bAWoVkuzphOX.

46.58. PGP
----------

If credit card information is to be accepted, and the e-mailed order
will go over an insecure network to reach its destination, PGP
security should be used. The key ring to be used must be for the user
that is running the Interchange server, or defined by the environment
variable PGPPATH, and the key user specified must have a key on the
public key ring of that user.

   PGP        /usr/local/bin/pgp -feat orders@company.com

If this directive is non-null, the PGP command string as specified
will be used to encrypt the entire order in addition to any encryption
done as a result if CreditCardAuto. If, for some reason, an error
comes from PGP, the customer will be given the special page failed.

If a Route is set up to supplant, this is ignored.

46.59. Pragma
-------------

Sets the default value of an Interchange pragma. The directive is set
like this:

   Pragma my_pragma_name

To enable a pragma for only a particular page, set it anywhere in the
page:

   [pragma my_pragma_name]

To disable a pragma for a particular page, set it anywhere in the
page:

   [pragma my_pragma_name 0]

Descriptions of each pragma follow.

dynamic_variables

dynamic_variables_file_only

init_page

Defines a Sub or GlobalSub which will run before page Variable
processing. A *reference* to the contents of the page is passed to the
routine.

For instance, if a page was found that did not have a @_VARIABLE_@ in
it, you could wrap it with a template:

    Pragma  init_page=wrap_page
        Sub <<EOS
        sub wrap_page {
                my $pref = shift;
                return if $$pref =~ m{\@_[A-Z]\w+_\@};
                $$pref =~ m{<!--+ title:\s*(.*?)\s+-->}
                        and $Scratch->{page_title} = $1;
                $$pref = <<EOF;
        \@_MYTEMPLATE_TOP_\@
        <!--BEGIN CONTENT -->
        $$pref
        <!-- END CONTENT -->
        \@_MYTEMPLATE_BOTTOM_\@
        EOF

                return;
        }
        EOS

post_page

Defines a Sub or GlobalSub which will run after page Variable
processing but before tag interpolation. A

o    reference* to the contents of the page is passed to the routine.

Example -- you want your users to be able to edit pages and just put
in <A href="someotherpage.html">. You can use post_page to handle
this. To do so, put in catalog.cfg:

  Pragma   post_page=relative_urls

  ### Take hrefs like <A HREF="about.html"> and make relative to current
  ### directory
  Sub <<EOR
  sub relative_urls {
      my $page = shift;
      my @dirs = split "/", $Tag->var('MV_PAGE', 1);
      pop @dirs;
      my $basedir = join  "/", @dirs;
      $basedir ||= '';
      $basedir .= '/' if $basedir;

      my $sub = sub {
          my ($entire, $pre, $url) = @_;
          return $entire if $url =~ /^\w+:/;
          my($page, $form) = split /\?/, $url, 2;
          my $u = $Tag->area({
                    href => "$basedir$page",
                    form => $form,
                });
          return qq{$pre"$u"};
      };
      $$page =~ s{
              (
                  (
                  <a \s+ (?:[^>]+?\s+)?
                      href \s*=\s*
                  )
                      (["']) ([^\s"'>]+) \3

              )}
              {
                  $sub->($1,$2,$4)
              }gsiex;
      return;
  }
  EOR

pre_page

Defines a Sub or GlobalSub which will run after page Variable
processing but before tag interpolation. A

o    reference* to the contents of the page is passed to the routine.

no_image_rewrite

Prevents image locations in pages from being altered by Interchange.
Added in Interchange 4.7.0.

Interchange normally rewrites image locations to point to ImageDir.
This applies to image locations mentioned in <img src="...">, <input
src="...">, <body background="...">, <table background="...">, and
<tr/th/td background="...">.

When this pragma is not set, the following tag:

   <img src="fancy.gif">

Would, assuming an ImageDir set to /foundation/images, be transformed
into:

   <img src="/foundation/images/fancy.gif">

When pragma no_image_rewrite is set, the <img> tag would remain
unchanged.

safe_data

By default Interchange does not allow data returned from databases to
be reparsed for Interchange tags. Setting the safe_data pragma
eliminates this restriction.

If for some reason you want to have tags in your database, for
example, to use [page ...] for catalog-internal hyperlinks in your
product descriptions, you need to enable safe_data. Some things to
consider:

1.   It may be better to use the safe_data attribute available to
     certain tags instead of the pragma, or perhaps to use [pragma]
     for a whole page or [tag pragma] ... [/tag] for a small block,
     instead of a catalog-wide Pragma directive.

2.   In any case it is strongly recommended that you surround the area
     with [restrict] ... [/restrict] tags to allow only the specific
     (hopefully relatively safe) set of tags you expect to appear,
     such as [page] or [area]. Expect security compromises if you
     allow [calc] or [perl], or other extremely powerful tags.

3.   Be certain that you know everywhere the data in your database
     will be used. Will it always be possible to reparse for tags?
     What about when it's used to create an emailed plain-text receipt
     -- will a literal '[page ...]' tag show up in the product
     description on the receipt? Would the desired output of '<a
     href="...">' be any better in a plaintext situation? What if you
     access your database from applications other than Interchange?
     You'll then have to decide what to do with such tags; perhaps you
     can simply strip them, but will the missing tag output cause you
     any trouble?

In short, safe_data is disabled by default for a reason, and you
should be very careful if you decide to enable it.

(Watch out for parse order with [tag pragma] or [restrict] when used
with lists that retrieve data from the database, as in [PREFIX-*] and
the flypage. Loops parse before regular tags like [tag] and
[restrict], and thus aren't affected by it.)

strip_white

Set this to strip whitespace from the tops of HTML pages output by
Interchange. Such whitespace usually comes from Interchange tags at
the top of the page. The pragma's purpose is mostly to make 'view
source' in the browser a slightly more tolerable experience.

Default is off; whitespace is unchanged.

46.60. PriceCommas
------------------

If no commas are desired in price numbers (for the [item-price] tag),
set this to No. The default is to use commas (or whatever is the
thousands separator for a locale).

   PriceCommas         no

This is overridden if a Locale price_picture is set.

46.61. PriceDivide
------------------

The number the price should be divided by to get the price in units
(dollars or such). The default is one. If penny pricing is used, set
it to 100.

   PriceDivide         100

Can be set in the Locale settings to allow a price adjustment factor
for different currencies.

46.62. PriceField
-----------------

The field in the product database that will be accessed with the
[item-price] element. Default is "price."

   PriceField          ProductPrice

Can be set in the Locale settings to allow different price fields for
different currencies.

46.63. ProductDir
-----------------

Location of the database files. Defaults to the products subdirectory
of the VendRoot directory. May not be set to an absolute directory
unless NoAbsolute is defined as No.

   ProductDir          /data/catalog/for-sale

Most people never set this directive and use the default of products.

46.64. ProductFiles
-------------------

Database tables that should be seen as the "products" database.

   ProductFiles    vendor_a vendor_b

The key thing about this is that each will be searched in sequence for
a product code to order or an [item-field ....] or [loop-field ...] to
insert. The main difference between [item-field ....] and [item-data
table ...] is this fall-through behavior.

Default is products.

46.65. ReadPermission and WritePermission
-----------------------------------------

By default, only the user account that Interchange runs under (as set
by the SETUID permission on vlink) can read and write files created by
Interchange. WritePermission and ReadPermission can be set to user,
group, or 'world'.

   ReadPermission      group
   WritePermission     group

46.66. RemoteUser
-----------------

The value of the HTTP environment variable REMOTE_USER that will
enable catalog reconfiguration. HTTP basic authentication must be
enabled for this to work. Default is blank, disabling this check.

   RemoteUser   interchange

46.67. Replace
--------------

Causes a directive to be emptied and re-set (to its default if no
value is specified). Useful for directives that add to the value by
default.

   Replace NoCache ord special multi reconfig query

Capitalization must be exact on each directive.

46.68. Require
--------------

Forces a Perl module, global UserTag, or GlobalSub to be present
before the catalog will configure. This is useful when transporting
catalogs to make sure they will have all needed facilities.

   Require usertag   email
   Require globalsub form_mail
   Require module    Business::UPS

46.69. RobotLimit
-----------------

The RobotLimit directive defines the number of consecutive pages a
user session may access without a 30 second pause. If the limit is
exceeded, the command defined in the Global directive LockoutCommand
will be executed and catalog URLs will be rewritten with host
127.0.0.1, sending the robot back to itself. The default is 0,
disabling the check.

   RobotLimit  200

46.70. Route
------------

Sets up order routes. See Custom Order Routing. There are examples in
the demo simple.

46.71. SalesTax
---------------

If non-blank, enables automatic addition of sales tax based on the
order form. The value is one of three types of values:

multi

     The special value "multi" enables table-based lookup of taxing
     rates based on the value of user form values, by default country
     and state.

[itl-tags]

     If the value has a left square bracket, it is interpolated for
     ITL tags and the result used as the amount of the salestax.

var1, var2

     A comma-separated list of the field names (as placed in the
     checkout page, for example ord/checkout.html) in priority order.
     These are be used to look up sales tax percentage in the
     salestax.asc ASCII table. (This table is not supplied with
     Interchange.)

        SalesTax            zip state

46.72. SalesTaxFunction
-----------------------

A Perl subroutine that will return a hash reference with the sales tax
settings. This can be used to query a database for the tax for a
particular vendor:

   SalesTaxFunction  <<EOR
         my $vendor_id = $Session->{source};
       my $tax = $TextSearch->hash( {
                           se => $vendor_id,
                           fi => 'salestax.asc',
                           sf => 'vendor_code',
                           ml => 1000,
                           } );
       $tax = {} if ! $tax;
       $tax->{DEFAULT} = 0.0;
       return $tax;
   EOR

or simply produce a table:

   SalesTaxFunction  <<EOR
    return {
        DEFAULT => 0.0,
        IL => 0.075,
        OH => 0.065,
    };
EOR

A DEFAULT value must always be returned or the function will be
ignored.

46.73. SaveExpire
-----------------

The default amount of time that a cookie will be valid (other than the
MV_SESSION_ID cookie). The ones used in Interchange by default are
MV_USERNAME and MV_PASSWORD for the CookieLogin feature. Specified the
same as SessionExpire, with an integer number followed by one of
minutes, hours, days, or weeks.

   SaveExpire 52 weeks

Default is 30 days.

46.74. ScratchDefault
---------------------

The default scratch variable settings that the user will start with
when their session is initialized.

To disable placing URL rewrite strings after the user has given a
cookie, set:

   ScratchDefault  mv_no_session_id  1
   ScratchDefault  mv_no_count       1
   ScratchDefault  mv_add_dot_html   1

To set the default locale:

   ScratchDefault  mv_locale         de_DE

46.75. ScratchDir
-----------------

The directory where temporary files will be written, notably cached
searches and retired session IDs. Defaults to tmp in the catalog
directory.

   ScratchDir          /tmp

46.76. SearchProfile
--------------------

Allows an unlimited number of search profiles to be set up, specifying
complex searches based on a single click. The directive accepts a file
name based in the catalog directory if the path is relative:

   SearchProfile    etc/search.profiles

As an added measure of control, the specification is evaluated with
the special Interchange tag syntax to provide conditional setting of
search parameters. The following file specifies a dictionary-based
search in the file 'dict.product':

 __NAME__ dict_search
 mv_search_file=dict.product
 mv_return_fields=1
 [if value fast_search]
   mv_dict_limit=-1
   mv_last=1
 [/if]
 __END__

The __NAME__ is the value to be specified in the mv_profile variable
on the search form, as in

 <INPUT TYPE=hidden NAME=mv_profile VALUE="dict_search">

or with mp=profile in the one-click search.

 [page scan se=Renaissance/mp=dict_search]Renaissance Art</a>

Multiple profiles can reside in the same file, if separated by __END__
tokens. __NAME__ tokens should be left-aligned, and __END__ must be on
a line by itself with no leading or trailing whitespace.

46.77. SecureURL
----------------

The base URL for secure forms/page transmissions. Normally it is the
same as VendURL except for the https: protocol definition. Default is
blank, disabling secure access.

   SecureURL   https://machine.com/xyzcorp/cgi-bin/vlink

46.78. SendMailProgram
----------------------

The location of the sendmail binary, needed for mailing orders. Must
be found at startup. This often needs to be set for FreeBSD or BSDI.

  SendMailProgram    /usr/sbin/sendmail

If set to none, no mail can be sent by standard Interchange
facilities. The default is the value in interchange.cfg and varies
depending on operating system.

46.79. SeparateItems
--------------------

Changes the default when ordering an item via Interchange to allowing
multiple lines on the order form for each item. The default, No, puts
all orders with the same part number on the same line.

Setting SeparateItems to Yes allows the item attributes to be easily
set for different instances of the same part number, allowing easy
setting of things such as size or color.

   SeparateItems       Yes

Can be overridden with the mv_separate_items variables (both scratch
and values).

46.80. SessionDatabase
----------------------

When storing sessions, specify the name of the directory or DBM file
to use. The file extensions of .db or .gdbm (depending on the DBM
implementation used) will be appended. If the default file-based
sessions are used, it is the name of the directory.

   SessionDatabase     session-data

Can be an absolute path name, if desired.

It is possible for multiple catalogs to share the same session file,
as well as for multiple Interchange servers to serve the same
catalogs. If serving a extremely busy store, multiple parallel
Interchange servers can share the same NFS-based file system and serve
users in a "ping-pong" fashion using the file-based sessions. On huge
systems, the level of directory hashing may be changed. By default,
only 48 * 48 hashing is done. See the source for SessionFile.pm.

46.81. SessionDB
----------------

The name of the Interchange database to be used for sessions if DBI is
specified as the session type. This is not recommended.

46.82. SessionExpire
--------------------

A customer can exit the browser or leave the catalog pages at any
time, and no indication is given to the web server aside from the lack
of further requests that have the same session ID. Old session
information needs to be periodically expired. The SessionExpire
specifies the minimum time to keep track of session information.
Defaults to one day. Format is an integer number, followed by
s(econds), m(inutes), h(ours), d(ays), or w(eeks).

   SessionExpire       20 minutes

If CookieLogin is in use, this can be a small value. If the customer's
browser has the Interchange session cookie stored, he/she will be
automatically logged back in with the next request. Note, however,
that the customer's cart and session values will be reset.

46.83. SessionLockFile
----------------------

The file to use for locking coordination of the sessions.

   SessionLockFile     session-data.lock

This only applies when using DBM-based sessions. It is possible for
multiple catalogs to share the same session file. SessionDatabase
needs to be set appropriately if the database is to be shared.
Defaults to session.lock, which is appropriate for separate session
files (and therefore standalone catalogs). Can be an absolute path
name, if desired.

46.84. SessionType
------------------

The type of session management to be used. Use one of the following:

   DB_File     Berkeley DB
   DBI         DBI (don't use this, normally)
   File        File-based sessions (the default)
   NFS         File-based sessions, forces use of fcntl locking
   GDBM        GDBM

The default is file-based sessions, which provides the best
performance and reliability in most environments.

If you are planning on running Interchange servers with an NFS-mounted
filesystem as the session target, you must set SessionType to "NFS".
The other requisites are usually:

1. fcntl() supported in Perl 2. lock daemon running on NFS server
system 3. lock daemon running on Interchange server

See also the global directive LockType.

46.85. SpecialPage
------------------

Sets a special page to other than its default value. Can be set as
many times as necessary. Will have no effect if not one of the
Interchange Required Pages.

   SpecialPage         checkout ord/checkout
   SpecialPage         failed special/error_on_order
   SpecialPage         interact special/browser_problem
   SpecialPage         noproduct special/no_product_found
   SpecialPage         order  ord/basket
   SpecialPage         search srch/results

46.86. SpecialPageDir
---------------------

The directory where special pages are kept. Defaults to special_pages
in the catalog directory.

   SpecialPageDir      pages/special

46.87. Static
-------------

A Yes/No directive. Enables static page building and display features.
Default is No.

    Static   Yes

46.88. StaticAll
----------------

A Yes/No directive. Tells Interchange to try and build all pages in
the catalog statically when called with the static page build option.
This is subject to the settings of StaticFly, StaticPath, and NoCache.
Default is No. Pages that have dynamic elements will not be built
statically, though that may be overridden with [tag flag build][/tag]
on the page in question.

    StaticAll   Yes

46.89. StaticDepth
------------------

The number of levels of static search building that will be done if a
search results page contains a search. Default is one, though it could
be very long if set higher. Set to 0 to disable re-scanning of search
results pages.

    StaticDepth 2

46.90. StaticDir
----------------

The absolute path of the directory which should be used as the root
for static pages. The user ID executing Interchange must have write
permission on the directory (and all files within) if this is to work.

    StaticDir   /home/you/www/catalog

46.91. StaticFly
----------------

A Yes/No directive. If set to Yes, static builds will attempt to
generate a page for every part number in the database using the
on-the-fly page build capability. If pages are already present with
those names, they will be overwritten. The default is No.

    StaticFly   Yes

46.92. StaticPage
-----------------

Tells Interchange to build the named page (or pages, whitespace
separated) when employing the static page-building capability of
Interchange. Not necessary if using StaticAll.

    StaticPage   info/about_us  info/terms_and_conditions

46.93. StaticPath
-----------------

The path (relative to HTTP document root) which should be used in
pages built with the static page-building capability of Interchange.

    StaticPath    /catalog

46.94. StaticPattern
--------------------

A perl regular expression which is used to qualify pages that are to
be built statically. The default is blank, which means all pages
qualify.

    StaticPattern  ^info|^help

46.95. StaticSuffix
-------------------

The extension to be appended to a normal Interchange page name when
building statically. Default is .html. Also affects the name of pages
in the Interchange page directory. If set to .htm, the pages must be
named with that extension.

    StaticSuffix   .htm

46.96. Sub
----------

Defines a catalog subroutine for use by the [perl][/perl] or [mvasp]
embedded perl languages. Use the "here document" capability of
Interchange configuration files to make it easy to define:

   Sub <<EOF
   sub sort_cart_by_quantity {
       my($items) = @_;
       $items = $Items if ! $items;
       my $out = '<TABLE BORDER=1>';
       @$items = sort { $a->{quantity} <=> $b->{quantity} } @$items;
       foreach $item (@$items) {
           my $code = $item->{code};
           $out .= '<TR><TD>';
           $out .= $code;
           $out .= '</TD><TD>';
           $out .= $Tag->data('products', 'name', $code);
           $out .= '</TD><TD>';
           $out .= $Tag->data('products', 'price', $code);
           $out .= '</TD></TR>';
       }
       $out .= '&lt/TABLE>';
       return $out;
   }
   EOF

As with Perl "here documents," the EOF (or other end marker) must be
the ONLY thing on the line, with no leading or trailing white space.
Do not append a semicolon to the marker. The above would be called
with:

   [perl]
       my $cart = $Carts->{main};
       return sort_cart_by_quantity($cart);
   [/perl]

and will display an HTML table of the items in the current shopping
cart, sorted by the quantity. Syntax errors will be reported at
catalog startup time.

Catalog subroutines may not perform unsafe operations. The Safe.pm
module enforces this unless global operations are allowed for the
catalog. See AllowGlobal.

46.97. Suggests
---------------

Generates a warning message when a Perl module, global UserTag, or
GlobalSub is not present at catalog configuration time. Same as the
Require directive except not fatal.

   Suggest usertag   table_editor
   Suggest globalsub file_info
   Suggest module    Business::UPS

46.98. TableRestrict
--------------------

Used to provide "views" in database-based searches. Does not affect
the text searches. Affects the table being searched.

Takes the form of field=session_param, where field is a column in the
table being iterated over, and session_param is a $Session key (i.e.,
[data session username]).

   TableRestrict  products  owner=username

The above would prevent the database search from returning any records
except those where the column owner contains the current value of
[data session username].

Probably most usefully set by embedded Perl code in certain
situations. For example:

   [calc]
       # Restrict edit to owned fields
       $Config->{TableRestrict}{products} = 'owner=username';
       return;
   [/calc]

When using SQL-based databases, in effect it turns the base search
query

   select * from products

into

   select * from products where owner = '[data session username]'

Interchange databases are similarly affected, though the methodology
is different. Also may be useful in "mall" situations, where user is
allowed to only see products from the current store ID.

46.99. TaxShipping
------------------

A comma or space-separated list of states or jurisdictions that tax
shipping cost, i.e., UT. Blank by default, never taxing shipping.

   TaxShipping         UT,NV,94024

46.100. TemplateDir
-------------------

Sets one or more directories (separated by whitespace) which will be
searched (in order) for pages not found in the PageDir. If a page is
not found in directories specified here, the search continues with the
global TemplateDir setting, if defined.

   TemplateDir    /var/lib/interchange/foundation/bonus_pages

This is undefined by default.

46.101. TrackFile
-----------------

Name of a logfile that tracks user traffic. This is used in the back
office administration report on traffic by affiliate.

The default is that no such file is kept.

See Usertracking for more information.

46.102. UpsZoneFile
-------------------

The file containing the UPS zone information, specified relative to
the catalog directory unless it begins with a /. It can be in the
format distributed by UPS or can be in a tab-delimited format, with
the three-letter zip prefix of the customer used to determine the
zone. It interpolates based on the value in mv_shipmode. A user
database named the same as the mv_shipmode variable must be present or
the lookup will return zero.

IMPORTANT NOTE: Zone information and updated pricing from UPS must be
obtained in order for this to work properly. The zone information is
specific to a region!

   UpsZoneFile         /usr/interchange/data/ups_zone.asc

46.103. UseModifier
-------------------

Determines whether any attributes, the modifiers specified in the
directive, can be attached to the item. See Item Attributes. The
default is no modifier. Don't use a value of quantity or this
directive will not work properly.

   UseModifier         size,color

Some values are used by Interchange and are not legal:

       mv_mi
       mv_si
       mv_ib
       group
       code
       quantity
       item

46.104. ValuesDefault
---------------------

Sets the initial state of the user values, i.e., [value key] or
$Values->{key}.

   ValuesDefault   fname  New
   ValuesDefault   lname  User

When the user session starts, [value fname] [value lname] will be "New
User."

46.105. Variable
----------------

Defines a catalog variable that will be available in the current
catalog with the notation __VARIABLE__. Variable identifiers must
begin with a capital letter, and can contain only word characters
(A-Z,a-z,0-9 and underscore). They are case-sensitive.

   Variable   DOCUMENT_ROOT   /usr/local/etc/httpd/htdocs

Only variables with ALL CAPS names will be parsed in catalog pages or,
when the ParseVariables directive is set, in catalog configuration
directives (other than in Variable directives themselves). These are
substituted second (right after global Variables) in any Interchange
page, and can contain any valid Interchange tags except global
variables. If a variable is called with the notation @_VARIABLE_@, and
there is no catalog Variable with its name, the global Variable value
will be inserted.

46.106. VariableDatabase
------------------------

The name of a database containing a field Variable which will be used
to set Interchange variable values. For example, a database defined
as:

   Database  var var.txt TAB
   VariableDatabase var

and containing

   code    Variable
   HELLO   Hi!

would cause __HELLO__ to appear as Hi!.

The field name is case-sensitive, and variable would not work.

The values are inserted at time of definition. Any single-level
hash-oriented Interchange directive, such as SpecialPage,
ScratchDefault, or ValuesDefault, can be set in the same way. If the
VariableDatabase named does not exist at definition time, a database
of the default type with an ASCII file source appending .txt is
assumed. In other words:

   VariableDatabase variable

is equivalent to

   Database         variable variable.txt TAB
   VariableDatabase variable

46.107. VendURL
---------------

Specifies the base URL that will run vlink as a cgi-bin program.

       VendURL  http://machine.company.com/cgi-bin/vlink

46.108. WideOpen
----------------

Disables IP qualification of user sessions. This degrades catalog
security. Do not use unless using encryption or a real-time payment
gateway.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Content Editor Reference
========================

47. Interchange UI -- Content Editor
====================================

Interchange is a web presentation framework which has powerful
database and content manipulation features. The Interchange Content
Editor provides a framework for manipulating pages and components
within pages.

47.1. Content management concept
--------------------------------

Interchange assumes that the page is the basic level of content. Each
page is typically a file on the filesystem, though it is possible to
maintain them in a database instead.

Each page is assumed to be based on a template, which is the layout
for that page. Each template can contain slots for components.

Components are interchangeable items that can be inserted in template
slots so that pages based on a common template can vary without having
to create a separate template.

A page may actually be a metacontent template in effect. Examples of
this are the flypage for building a product page, and the results page
that displays search lists.

47.2. A typical page
--------------------

Here is how the file for a page looks:

        [comment]
        ui_name: typical.html
        ui_page_template: leftonly
        [/comment]

        [set page_title] A typical page [/set]
        [set members_only]0[/set]

        [control reset=1]
        [control-set]
                [parameter1]setting1[/parameter1]
                [parameter2]setting2[/parameter2]
        [/control-set]
        [control-set]
                [parameter1]setting1[/parameter1]
                [parameter2]setting2[/parameter2]
        [/control-set]
        [control reset=1]

        @_LEFTONLY_TOP__@

        <!-- BEGIN CONTENT -->

                The content of a typical page.

        <!-- END CONTENT -->

        @_LEFTONLY_BOTTOM__@

You can see other examples in the standard Interchange foundation
demo.

We will tour the page, adding the PREAMBLE and POSTAMBLE sections.

Editor information

The comment at the top of the page is only used by the editor to
derive things it may need to know. If it were to be removed, the page
would display the same; it just may not read and publish the same when
edited.

        [comment]
        ui_template_name: leftonly
        ui_static: 0
        [/comment]

In the case above, the template is specified with ui_template_name and
the page will not be published statically (i.e. ui_static: 0).

PREAMBLE

The PREAMBLE is a section which allows page initialization prior to
the header portion of the template, and prior to the setting of the
page controls.

        <!-- BEGIN PREAMBLE -->
                [perl]
                        &custom_init();
                [/perl]
        <!-- END PREAMBLE -->

Page controls

Page controls are specified in the template definition, and the user
can set them from the page control menu when editing the page.

        [set page_title] A typical page [/set]
        [set members_only]0[/set]

The above sets two page controls, one used in the header to set the
HTML title for the page, and the other used to determine if the
customer must be logged in (a member) to access the page.

Component controls

As was said before, a page template can contain multiple components.
Each component can have an unlimited number of settings which can be
used to specify its behavior. These settings are manipulated in the
component control sections of the content editor, one for each
component slot.

        [control reset=1]
        [control-set]
                [parameter1]setting1[/parameter1]
                [parameter2]setting2[/parameter2]
        [/control-set]
        [control-set]
                [parameter1]setting1[/parameter1]
                [parameter2]setting2[/parameter2]
        [/control-set]
        [control reset=1]

Template header section

This is the Variable used to contain the top portion of the template,
which may use various page control settings and have multiple slots
for components.

        @_LEFTONLY_TOP__@

CONTENT section

This is the actual content of the page. It can be edited in a TEXTAREA
in the content editor.

        <!-- BEGIN CONTENT -->

                The content of a typical page.

        <!-- END CONTENT -->

Template footer section

This is the Variable used to contain the bottom portion of the
template, which may use various page control settings and have
multiple slots for components.

        @_LEFTONLY_BOTTOM__@

POSTAMBLE

The POSTAMBLE section can contain cleanup code for the page. It will
rarely be used.

        <!-- BEGIN POSTAMBLE -->
                [perl]
                        &custom_cleanup();
                [/perl]
        <!-- END POSTAMBLE -->

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Interchange Databases
=====================

48. Databases and Interchange
=============================

Interchange can use GDBM, DB_File, SQL, LDAP, or in-memory databases.
In most cases, these different database formats should operate the
same when called by Interchange's access methods.

Also, Interchange does not require an external SQL database. If you
have a small database and do not want to integrate your own tool set,
you might want to use Interchange's internal database. However, the
order management functions of Interchange will be slower and not as
robust without an SQL database. SQL is strongly recommended for at
least the orderline, transactions, and userdb tables.

Keeping a database in an SQL manager makes it easier to integrate
Interchange with other tools. Interchange can be used to maintain a
spreadsheet containing product information through modifying the file
products.txt as needed. References to SQL, DBI, and DBD can be
ignored.

48.1. Text Source Files
-----------------------

Interchange reads delimited text files to obtain data. However, the
text files are not the database. They are the source information for
the database tables.

By default, all database source files are located in the products
subdirectory of the catalog directory. The main products database is
in the products/products.txt file in the supplied demo catalog.

Note: If you are using one of the internal database methods, any
changes made to the ASCII source file will be reflected in the
database in the next user session. If the product database contains
less than a thousand records, updates will be instantaneous. If the
product database is larger, updates will take longer. Use the NoImport
reference tag to stop auto updating.

In the following configuration directive:

   Database  products  products.txt   TAB

the products table will obtain its source information from the file
products.txt. What is done with it depends on the type of underlying
database being used. The different types and their behavior are
described below:

GDBM

     The database source file is checked to see if it is newer than
     the actual database file, products.gdbm. If it is, the database
     table is re-imported from the file.

     This behavior can be changed in a few ways. If files should not
     be imported unless the .gdbm file disappears, set the NoImport
     directive:

              NoImport  products

     If the database source file is only to be imported at catalog
     start-up time, use the IMPORT_ONCE modifier:

              Database products IMPORT_ONCE 1

     GDBM is the default database type if the GDBM_File Perl module is
     installed (as it is on LINUX).

DB_File

     The database source file is checked to see if it is newer than
     the actual database file, products.db. If it is, the database
     table is re-imported from the file. You can change this behavior
     in the same way as GDBM_File, described above.

     DB_File is the default database type if the GDBM_File Perl module
     is not installed. This is common on FreeBSD. To specify DB_File
     as your database type, set it in catalog.cfg with a Database
     directive:

             Database  products  DB_FILE   1

DBI/SQL

     If a file named products.sql is in the same directory as
     products.txt, the database table will not be imported from the
     ASCII source. If there is no products.sql, the following will
     occur:

     DBI/SQL imports will only happen at catalog configuration time.

          Interchange will connect to the SQL database using the
          specified DSN. (DBI parameter meaning "Database Source
          Name".)

          The table will be dropped with "DROP TABLE products;". This
          will occur without warning. NOTE: This can be prevented in
          several ways. See NoImport External or the SQL documentation
          for more information.

          The table will be created. If there are COLUMN_DEF
          specifications in catalog.cfg, they will be used. Otherwise,
          the key (first field in the text file by default) will be
          created with a char(16) type and all other fields will be
          created as char(128). The table creation statement will be
          written to the error.log file.

          The text source file will be imported into the SQL database.
          Interchange will place the data in the columns. Data typing
          must be user-configured. This means that if "none" is placed
          in a field, and it is defined as a numeric type, the
          database import will not succeed. And if it does not
          succeed, the catalog will not become active.

In-Memory

     Every time the catalog is configured, the products.txt file is
     imported into memory and forms the database. Otherwise, the
     database is not changed. The in-memory database is the default
     database if there is no GDBM_File or DB_File Perl module
     installed; specify it with:

             Database   products   MEMORY   1

48.2. Interchange Database Conventions
--------------------------------------

This section describes naming and file usage conventions used with
Interchange.

Note: Throughout the documentation, the following terms and their
definitions are used interchangeably:

key, code

     A reference to the database key. In Interchange, this is usually
     the product code or SKU, which is the part number for the
     product. Other key values may be used to generate relationships
     to other database tables.

     It is recommended that the key be the first column of the ASCII
     source file, since Interchange's import, export, and search
     facilities rely on this practice.

field, column

     The vertical row of a database. One of the columns is always the
     key and it is usually the first one.

table, database

     A table in the database. Because Interchange has evolved from a
     single-table database to an access method for an unlimited number
     of tables (and databases, for that matter), a table will
     occasionally be referred to as a database. The only time the term
     database refers to something different is when describing the
     concept as it relates to SQL, where a database contains a series
     of tables. While Interchange cannot create SQL databases, it can
     drop and create tables with that database if given the proper
     permissions.

If necessary, Interchange can read the data to be placed in tables
from a standard ASCII-delimited file. All of the ASCII source files
are kept in the products directory, which is normally in the catalog
directory (where catalog.cfg is located). The ASCII files can have ^M
(carriage return) characters, but must have a new line character at
the end of the line to work. NOTE: Mac users uploading files must use
ASCII mode, not binary mode.

Interchange's default ASCII delimiter is TAB.

Note: The items must be separated by a single delimiter. The items in
this document are lined up for reading convenience.

TAB

     Fields are separated by ^I characters. No whitespace is allowable
     at the beginning of the line.

              code    description             price   image
              SH543   Men's fine cotton shirt 14.95   shirts.jpg

PIPE

     Fields are separated by pipe | characters. No whitespace is
     allowable at the beginning of the line.

              code|description|price|image
              SH543|Men's fine cotton shirt|14.95|shirts.jpg

CSV

     Fields are enclosed in quotes, separated by commas. No whitespace
     should be at the beginning of the line.

              "code","description","price","image"
              "SH543","Men's fine cotton shirt","14.95","shirts.jpg"

Note: Using the default TAB delimiter is recommended if you plan on
searching the ASCII source file of the database. PIPE works fairly
well, but CSV delimiter schemes might cause problems with searching.

IMPORTANT NOTE: Field names are usually case-sensitive. Use
consistency when naming or you might encounter problems. All lower or
all upper case names are recommended.

     Interchange uses one mandatory database, which is referred to as
     the products database. In the supplied demo catalog, it is called
     products and the ASCII source is kept in the file products.txt in
     the products directory. This is also the default file for
     searching with the THE SEARCH ENGINE.

     Interchange also has a two of standard, but optional, databases
     that are in fixed formats:

     shipping.asc

          The database of shipping options that is accessed if the
          CustomShipping directive is in use.  This is a fixed-format
          database, and must be created as specified. For more
          information, see the Shipping ITL tag in the Interchange Tag
          Reference Guide.

     salestax.asc

          The database of sales tax information if the [salestax] tag
          is to be used. A default is supplied. NOTE: Caution, these
          things change! This is a fixed-format database, and must be
          created as specified. See Sales Tax.

     These are never stored in SQL or DBM.

48.3. The Product Database
--------------------------

Each product being sold should be given a product code, usually
referred to as SKU, a short code that identifies the product on the
ordering page and in the catalog. The products.txt file is a
ASCII-delimited list of all the product codes, along with an arbitrary
number of fields which must contain at least the fields description
and price (or however the PriceField and DescriptionField directives
have been set). Any additional information needed in the catalog can
be placed in any arbitrary field. See Interchange Database Capability
for details on the format.

Field names can be case-sensitive depending on the underlying database
type. Unless there are fields with the names "description" and "price"
field, set the PriceField and DescriptionField directives to use the
[item-price] and [item-description] tags.

The product code, or SKU, must be the first field in the line, and
must be unique. Product codes can contain the characters A-Za-z0-9,
along with hyphen (-), underscore (_), pound sign/hash mark (#), slash
(/), and period (.). Note that slash (/) will interfere with
on-the-fly page references. Avoid if at all possible.

The words should be separated by one of the approved delimiting
schemes (TAB, PIPE, or CSV), and are case-sensitive in some cases. If
the case of the "description" or "price" fields have been modified,
the PriceField and DescriptionField directives must be appropriately
set.

Note: CSV is not recommended as the scheme for the products database.
It is much slower than TAB- or PIPE-delimited, and dramatically
reduces search engine functionality. No field-specific searches are
possible. Using CSV for any small database that will not be searched
is fine.

IMPORTANT NOTE: The field names must be on the first line of the
products.txt file. These field names must match exactly the field
names of the [item-field] tags in the catalog pages, or the
Interchange server will not access them properly. Field names can
contain the characters A-Za-z0-9 and underscore (_).

More than one database may be used as a products database. If the
catalog directive, ProductFiles, is set to a space-separated list of
valid Interchange database identifiers, those databases will be
searched (in the order specified) for any items that are ordered, or
for product information (as in the [price code] and [field code]
tags).

When the database table source file (i.e., products.txt) changes after
import or edit, a DBM database is re-built upon the next user access.
No restart of the server is necessary.

If changing the database on-the-fly, it is recommended that the file
be locked while it is being modified. Interchange's supplied import
routines do this.

48.4. Multiple Database Tables
------------------------------

Interchange can manage an unlimited number of arbitrary database
tables. They use the TAB delimiter by default, but several flexible
delimiter schemes are available. These are defined by default:

   Type 1      DEFAULT - uses default TAB delimiter
   Type 2      LINE
               Each field on its own line, a blank line
               separates the record. Watch those carriage
               returns! Also has a special format when CONTINUE
               is set to be NOTES.
   Type 3      %%
               Fields separated by a \n%%\n combination, records by
               \n%%%\n (where \n is a newline). Watch those carriage
               returns!
   Type 4      CSV
   Type 5      PIPE
   Type 6      TAB
   Type 7      reserved
   Type 8      SQL

The databases are specified in Database directives, as:

   Database    arbitrary arbitrary.csv CSV

This specifies a Type 4 database, the ASCII version of which is
located in the file arbitrary.csv, and the identifier it will be
accessed under in Interchange is "arbitrary." The DBM file, if any,
will be created in the same directory if the ASCII file is newer, or
if the DBM file does not exist. The files will be created as
arbitrary.db or arbitrary.gdbm, depending on DBM type.

The identifier is case sensitive, and can only contain characters in
the class [A-Za-z0-9_]. Fields are accessed with the [item_data
identifier field] or [data identifier field key] elements. NOTE: Use
of lower-case letters is strongly recommended.

If one of the first six types is specified, the database will
automatically be built in the default Interchange DB style. The type
can be specified with DB_FILE, GDBM, or MEMORY, if the type varies
from that default. They will coexist with an unlimited number of DBI
databases of different types.

In addition to the database, the session files will be kept in the
default format, and are affected by the following actions.

The order of preference is:

GDBM

     This uses the Perl GDBM_File module to build a GDBM database. The
     following command will indicate if GDBM is in Perl:

              perl -e 'require GDBM_File and print "I have GDBM.\n"'

     Installing GDBM_File requires rebuilding Perl after obtaining the
     GNU GDBM package, and is beyond the scope of this document. LINUX
     will typically have this by default; most other operating systems
     will need to specifically build in this capability.

DB_File (Berkeley DB)

     This uses the DB_File module to build a Berkeley DB (hash)
     database. The following command will indicate if DB_File is in
     Perl:

              perl -e 'require DB_File and print "I have Berkeley DB.\n"'

     Installing DB_File requires rebuilding Perl after obtaining the
     Berkeley DB package, and is beyond the scope of this document.
     BSDI, FreeBSD, and LINUX will typically have it by default; most
     other operating systems will need to specifically build this in.

     If using DB_File, even though GDBM_File is in Perl, set the
     environment variable MINIVEND_DBFILE to a true (non-zero,
     non-blank) value:

              # csh or tcsh
              setenv MINIVEND_DBFILE 1
          
              # sh, bash, or ksh
              MINIVEND_DBFILE=1 ; export MINIVEND_DBFILE

     Then, re-start the server.

     Or, to set a particular table to use Berkeley DB, the DB_FILE
     class in catalog.cfg can be specified:

              Database arbitrary  DB_FILE  1

In-memory

     This uses Perl hashes to store the data directly in memory. Every
     time the Interchange server is restarted, it will re-import all
     in-memory databases for every catalog.

     If this is used, despite the presence of GDBM_File or DB_File,
     set the environment variable MINIVEND_NODBM as above or specify
     the memory type in the Database directive:

              Database arbitrary  MEMORY  1

Note: The use of memory databases is not recommended.

48.5. Character Usage Restrictions
----------------------------------

To review, database identifiers, field names, and product codes
(database keys) are restricted in the characters they may use. The
following table shows the restrictions:

                                      Legal characters
                                      ---------------------
   Database identifiers               A-Z a-z 0-9 _
   Field names                        A-Z a-z 0-9 _
   Database keys (product code/SKU)   A-Z a-z 0-9 _ # - . /
   Database values                    Any (subject to field/record delimiter)

Some SQL databases have reserved words which cannot be used as field
names; Interchange databases do not have this restriction.

For easy HTML compatibility, it is not recommended that a / be used in
a part number if using the flypage capability. It can still be called
[page href=flypage arg="S/KU"].

48.6. Database Attributes
-------------------------

Especially in SQL databases, there are certain functions that can be
set with additional database attributes. For text import, the CONTINUE
extended database import attribute allows additional control over the
format of imported text.

Note: CONTINUE applies to all types except CSV. (Do not use NOTES
unless using type LINE.)

CONTINUE

     One of UNIX, DITTO, LINE, NONE, or NOTES. The default, NONE, is
     to simply split the line/record according to the delimiter, with
     no possible spanning of records. Setting CONTINUE to UNIX appends
     the next line to the current when it encounters a backslash (\)
     at the end of a record, just like many UNIX commands and shells.

     DITTO is invoked when the key field is blank. It adds the
     contents of following fields to the one above, separated by a new
     line character. This allows additional text to be added to a
     field beyond the 255 characters available with most spreadsheets
     and flat-file databases.

     Example in catalog.cfg:

            Database products products.txt  TAB
            Database products CONTINUE      DITTO

     Products.asc file:

            code     price     description
            00-0011  500000    The Mona Lisa, one of the worlds great masterpieces.
                               Now at a reduced price!

     The description for product 00-0011 will contain the contents of
     the description field on both lines, separated by a new line.

Note: Fields are separated by tabs, formatted for reading convenience.

     This will work for multiple fields in the same record. If the
     field contains any non-empty value, it will be appended.

     LINE is a special setting so a multi-line field can be used.
     Normally, when using the LINE type, there is only data on one
     line separated by one blank line. When using CONTINUE LINE, there
     may be some number of fields which are each on a line, while the
     last one spans multiple lines up until the first blank line.

     Example in catalog.cfg:

            Database products products.txt  LINE
            Database products CONTINUE      LINE

     Products.asc file:

              code
              price
              description
          
              00-0011
              500000
              The Mona Lisa, one of the worlds great masterpieces.
              Now at a reduced price!
          
              00-0011a
              1000
              A special frame for the Mona Lisa.

     NOTES reads a Lotus Notes "structured text" file. The format is
     any number of fields, all except one of which must have a field
     name followed by a colon and then the data. There is optional
     whitespace after the colon.

     Records are separated by a settable delimiting character which
     goes on a line by itself, much like a "here document." By
     default, it is a form feed (^L) character. The final field begins
     at the first blank line and continues to the end of the record.
     This final field is named notes_field, unless set as mentioned
     below.

     Interchange reads the field names from the first paragraph of the
     file. The key field should be first, followed by other fields in
     any order. If one (and only one) field name has whitespace, then
     its name is used for the notes_field. Any characters after a
     space or TAB are used as the record delimiter.

     If there are none, then the delimiter returns to the default form
     feed (^L) and the field name reverts to notes_field. The field in
     question will be discarded, but a second field with whitespace
     will cause an import error. Following records are then read by
     name, and only fields with data in them need be set. Only the
     notes_field may contain a new line. It is always the last field
     in the record, and begins at the first blank line.

     The following example sets the delimiter to a tilde (~) and
     renames the notes_field to description.

     Example in catalog.cfg:

            Database products products.txt  LINE
            Database products CONTINUE      NOTES

     Products.asc file:

              code
              title
              price
              image
              description ~
              size
              color
          
              title: Mona Lisa
              price: 500000
              code: 00-0011
              image: 00-0011.jpg
          
              The Mona Lisa, one of the worlds great masterpieces.
              Now at a reduced price!
              ~
              title: The Art Store T-Shirt
              code: 99-102
              size: Medium, Large*, XL=Extra Large
              color: Green, Blue, Red, White*, Black
              price: 2000
          
              Extra large 1.00 extra.
              ~

EXCEL

     Microsoft Excel is a widely-used tool to maintain Interchange
     databases, but has several problems with its standard
     TAB-delimited export, like enclosing fields containing commas in
     quotes, generating extra carriage returns embedded in records,
     and not including trailing blank fields. To avoid problems, use a
     text-qualifier of none.

     Set the EXCEL attribute to 1 to fix these problems on import:

              Database products EXCEL 1

     This is normally used only with TAB-delimited files.

LARGE

     Interchange databases containing many records can result in a
     noticeable slowdown when displayed by the UI.

     Set the LARGE attribute to 1 to avoid this problem:

        Database transactions LARGE 1

     In this case the UI supplies only input boxes to search records
     in the database instead of drawing all the records from the
     database, sorting them and creating more lists.

48.7. Dictionary Indexing With INDEX
------------------------------------

Interchange will automatically build index files for a fast binary
search of an individual field. This type of search is useful for
looking up the author of a book based on the beginning of their last
name, a book title based on its beginning, or other similar
situations.

Such a search requires a dictionary ordered index with the field to be
searched contained in the first field and the database key (product
code) in the second field. If the INDEX field modifier is specified,
Interchange will build the index upon database import:

  Database  products  products.txt   TAB
  Database  products  INDEX          title

If the title field is the fourth column in the products database
table, a file products.txt.4 will be built, containing two
tab-separated fields something like:

   American Gothic   19-202
   Mona Lisa         00-0011
   Sunflowers        00-342
   The Starry Night  00-343

Options can be appended to the field name after a colon (:). The most
useful will be f, which does a case-insensitive sort. The mv_dict_fold
option must be added to the search in this case.

Another option is c, which stands for "comma index." To index on
comma-separated sub-fields within a field, use the :c option:

  Database  products  products.txt   TAB
  Database  products  INDEX          category:c

This can get slow for larger databases and fields. Interchange will
split the field on a comma (stripping surrounding whitespace) and make
index entries for each one. This allows multiple categories in one
field while retaining the fast category search mechanism. It might
also be useful for a keywords field.

The fast binary search is described in greater detail in THE SEARCH
ENGINE below.

48.8. MEMORY for Memory-Only Databases
--------------------------------------

Interchange's memory-based databases are the fastest possible way to
organize and store frequently used data. To force a database to be
built in memory instead of DBM, use the MEMORY modifier:

  Database  country  country.asc   TAB
  Database  country  MEMORY        1

Obviously, large tables will use a great deal of memory, and the data
will need to be re-imported from the ASCII source file at every
catalog reconfiguration or Interchange restart. The big advantage of
using MEMORY is that the database remains open at all times and does
not need to be reinitialized at every connect. Use it for smaller
tables that will be frequently accessed.

The MEMORY modifier forces IMPORT_ONCE.

48.9. IMPORT_ONCE
-----------------

The IMPORT_ONCE modifier tells Interchange not to re-import the
database from the ASCII file every time it changes. Normally,
Interchange does a comparison of the database file modification time
with the ASCII source every time it is accessed, and if the ASCII
source is newer it will re-import the file.

IMPORT_ONCE tells it only to import on a server restart or catalog
reconfiguration:

  Database  products  products.txt   TAB
  Database  products  IMPORT_ONCE    1

SQL databases don't normally need this. They will only be imported
once in normal operation. Also see NoImport for a way to guarantee
that the table will never be imported.

IMPORT_ONCE is always in effect for MEMORY databases. A catalog
reconfiguration is required to force a change.

48.10. Importing in a Page
--------------------------

To add a data record to a database as a result of an order or other
operation, use Interchange's [import ...] tag.

[import table type*] RECORD [/import]

     Named parameters:

           [import table=table_name
                   file=filename*
                   type=(TAB|PIPE|CSV|%%|LINE)*
                   continue=(NOTES|UNIX|DITTO)*
                   separator=c*]

Import one or more records into a database. The type is any of the
valid Interchange delimiter types, with the default being TAB. The
table must already be a defined Interchange database table. It cannot
be created on-the-fly. If on-the-fly functionality is need, it is time
to use SQL.

The import type selected need not match the type the database was
specified. Different delimiters may be used.

The type of LINE and continue setting of NOTES is particularly useful,
for it allows fields to be named and not have to be in any particular
order of appearance in the database. The following two imports are
identical in effect:

   [import table=orders]
            code: [value mv_order_number]
   shipping_mode: [shipping-description]
          status: pending
   [/import]

   [import table=orders]
   shipping_mode: [shipping-description]
   status:        pending
   code:          [value mv_order_number]
   [/import]

The code or key must always be present, and is always named code. If
NOTES mode is not used, the fields must be imported in the same order
as they appear in the ASCII source file.

The file option overrides the container text and imports directly from
a named file based in the catalog directory. To import from
products.txt, specify file="products/products.txt". If the NoAbsolute
directive is set to Yes in interchange.cfg, only relative path names
will be allowed.

The [import ....] TEXT [/import] region may contain multiple records.
If using NOTES mode, a separator must be used, which, by default, is a
form-feed character (^L). See Import Attributes for more information.

48.11. Exporting from a Database
--------------------------------

To export an existing database to a file suitable for searching by
Interchange, create a page that contains a [tag export ...][/tag]
element. Perhaps a better method is to define the same sort of tags in
an OrderProfile, and use forms and buttons to access the profile.

48.12. Write Control
--------------------

Interchange databases can be written in the normal course of events,
either using the [import ...] tag or with a tag like [data table=table
column=field key=code value=new-value]. To control writing of a global
database, or to a certain catalog within a series of subcatalogs, or
make one read only, see the following:

To enable write control:

   Database   products  WRITE_CONTROL  1

Once this is done, to make a database read only, which won't allow
writing even if [tag flag write]products[/tag] is specified:

   Database   products  READ_ONLY  1

To have control with [tag flag write]products[/tag]:

   Database   products  WRITE_TAGGED  1

To limit write to certain catalogs, set:

   Database   products  WRITE_CATALOG  simple=0, sample=1

The "simple" catalog will not be able to write, while "sample" will if
[tag flag write]products[/tag] is enabled. If a database is to always
be writable, without having to specify [tag flag write] ... [/tag],
then define:

   Database   products  WRITE_ALWAYS  1

The default behavior of SQL databases is equivalent to WRITE_ALWAYS,
while the default for GDBM_File, DB_File, and Memory databases is
equivalent to:

   Database   products  WRITE_CONTROL 1
   Database   products  WRITE_TAGGED  1

48.13. Global Databases
-----------------------

If a database is to be available to all catalogs on the Interchange
server, it may be defined in interchange.cfg. Any catalog running
under that server will be able to use it. It is writable by any
catalog unless WRITE_CONTROL is used.

49. SQL Support
===============

Interchange can use any of a number of SQL databases through the
powerful Perl DBI/DBD access methods. This allows transparent access
to any database engine that is supported by a DBD module. The current
list includes mSQL, MySQL, Solid, PostgreSQL, Oracle, Sybase,
Informix, Ingres, Dbase, DB2, Fulcrum, and others. Any ODBC (with
appropriate driver) should also be supported.

No SQL database is included with Interchange, but there are a number
widely available on the Internet. Most commonly used with Interchange
are PostgreSQL, MySQL, and Oracle. It is beyond the scope of this
document to describe SQL or DBI/DBD. Sufficient familiarity is
assumed.

In most cases, Interchange cannot perform administrative functions,
like creating a database or setting access permissions. This must be
done with the tools provided with a SQL distribution. But, if given a
blank database and the permission to read and write it, Interchange
can import ASCII files and bootstrap from there.

49.1. SQL Support via DBI
-------------------------

The configuration of the DBI database is accomplished by setting
attributes in additional Database directives after the initial
defining line as described above. For example, the following defines
the database arbitrary as a DBI database, sets the data source (DSN)
to an appropriate value for an mSQL database named minivend on port
1114 of the local machine:

   Database arbitrary arbitrary.asc SQL
   Database arbitrary DSN           dbi:mSQL:minivend:localhost:1114

As a shorthand method, include the DSN as the type:

   Database arbitrary arbitrary.asc dbi:mSQL:minivend:localhost:1114

Supported configuration attributes include (but are not limited to):

DSN

     A specification of the DBI driver and its data source. To use the
     DBD::mSQL driver for DBI, use:

              dbi:mSQL:minivend:othermachine.my.com:1112

     where mSQL selects the driver (case IS important), minivend
     selects the database, othermachine.my.com selects the host, and
     1112 is the port. On many systems, dbi:mSQL:minivend will work
     fine. Of course, the minivend database must already exist.

     This is the same as the DBI_DSN environment variable, if the DSN
     parameter is not set. Then, the value of DBI_DSN will be used to
     try and find the proper database to connect to.

USER

     The user name used to log into the database. It is the same as
     the environment variable DBI_USER. If a user name is not needed,
     just don't set the USER directive.

PASS

     The password used to log into the database. It is the same as the
     environment variable DBI_PASS. If a password is not needed, just
     don't set the PASS directive.

COLUMN_DEF

     A comma-separated set of lines in the form NAME=TYPE(N), where
     NAME is the name of the field/column, TYPE is the SQL data type
     reference, and N is the length (if needed). Most Interchange
     fields should be the fixed-length character type, something like
     char(128). In fact, this is the default if a type is not chosen
     for a column. There can be as many lines as needed. This is not a
     DBI parameter, it is specific to Interchange.

NAME

     A space-separated field of column names for a table. Normally not
     used. Interchange should resolve the column names properly upon
     query. Set this if a catalog errors out with "dbi: can't find
     field names" or the like. The first field should always be code.
     This is not a DBI parameter, it is specific to Interchange. All
     columns must be listed, in order of their position in the table.

NUMERIC

     Tells Interchange not to quote values for this field. It allows
     numeric data types for SQL databases. It is placed as a
     comma-separated field of column names for a table, in no
     particular order. This should be defined if a numeric value is
     used because many DBD drivers do not yet support type queries.

UPPERCASE

     Tells Interchange to force field names to UPPER case for row
     accesses using the [item-data ...], [loop-data ...], [item-field
     ..., etc. Typically used for Oracle and some other SQL
     implementations.

DELIMITER

     A Interchange delimiter type, either TAB,CSV,PIPE,%%,LINE or the
     corresponding numeric type. The default for SQL databases is TAB.
     Use DELIMITER if another type will be used to import. This is not
     a DBI parameter. It is specific to Interchange.

KEY

     The keying default of code in the first column of the database
     can be changed with the KEY directive. Don't use this unless
     prepared to alter all searches, imports, and exports accordingly.
     It is best to just accept the default and make the first column
     the key for any Interchange database.

ChopBlanks, LongReadLen, LongTruncOK, RaiseError, etc.

     Sets the corresponding DBI attribute. Of particular interest is
     ChopBlanks, which should be set on drivers which by default
     return space-padded fixed-length character fields (Solid is an
     example).

     The supported list as of this release of Interchange is:

            ChopBlanks
            CompatMode
            LongReadLen
            LongTruncOk
            PrintError
            RaiseError
            Warn

     Issue the shell command perldoc DBI for more information.

Here is an example of a completely set up DBI database on MySQL, using
a comma-separated value input, setting the DBI attribute LongReadLen
to retrieve an entire field, and changing some field definitions from
the default char(128):

 Database   products  products.csv  dbi:mysql:minivend
 Database   products  USER          minivend
 Database   products  PASS          nevairbe
 Database   products  DELIMITER     CSV

 # Set a DBI attribute
 Database   products  LongReadLen   128

 # change some fields from the default field type of char(128)
 # Only applies if Interchange is importing from ASCII file
 # If you set a field to a numeric type, you must set the
 # NUMERIC attribute
 Database   products  COLUMN_DEF    "code=char(20) NOT NULL primary key"
 Database   products  COLUMN_DEF    price=float, discount=float
 Database   products  COLUMN_DEF    author=char(40), title=char(64)
 Database   products  COLUMN_DEF    nontaxable=char(3)
 Database   products  NUMERIC       price
 Database   products  NUMERIC       discount

MySQL, DBI, and DBD::mysql must be completely installed and tested,
and have created the database minivend, for this to work. Permissions
are difficult on MySQL. if having trouble, try starting the MySQL
daemon with safe_mysqld --skip-grant-tables & for testing purposes.

To change to ODBC, the only changes required might be:

   Database products  DSN         dbi:ODBC:TCP/IP localhost 1313
   Database products  ChopBlanks  1

The DSN setting is specific to a ODBC setup. The ChopBlanks setting
takes care of the space-padding in Solid and some other databases. It
is not specific to ODBC. Once again, DBI, DBD::ODBC, and the
appropriate ODBC driver must be installed and tested.

49.2. SQL Access Methods
------------------------

An Interchange SQL database can be accessed with the same tags as any
of the other databases can. Arbitrary SQL queries can be passed with
the [query sql="SQL STATEMENT"] ITL tag.

49.3. Importing from an ASCII File
----------------------------------

When importing a file for SQL, Interchange by default uses the first
column of the ASCII file as the primary key, with a char(16) type, and
assigns all other columns a char (128) definition. These definitions
can be changed by placing the proper definitions in COLUMN_DEF
Database directive attribute:

 Database  products  COLUMN_DEF  price=char(20), nontaxable=char(3)

This can be set as many times as desired, if it will not fit on the
line.

 Database  products  COLUMN_DEF  price=char(20), nontaxable=char(3)
 Database  products  COLUMN_DEF  description=char(254)

To create an index automatically, append the information when the
value is in quotes:

 Database  products  COLUMN_DEF  "code=char(14) primary key"

The field delimiter to use is TAB by default, but can be changed with
the Database DELIMITER directive:

 Database  products products.csv dbi:mSQL:minivend:localhost:1114
 Database  products DELIMITER  CSV

To create other secondary keys to speed sorts and searches, do so in
the COLUMN_DEF:

 Database  products COLUMN_DEF  "author=char(64) secondary key"

Or use external database tools. NOTE: Not all SQL databases use the
same index commands.

To use an existing SQL database instead of importing, set the NoImport
directive in catalog.cfg to include any database identifiers not to be
imported:

   NoImport  products inventory

WARNING: If Interchange has write permission on the products database,
be careful to set the NoImport directive or create the proper .sql
file. If that is not done, and the database source file is changed,
the SQL database could be overwritten. In any case, always back up the
database before enabling it for use by Interchange.

50. Managing DBM Databases
==========================

50.1. Making the Database
-------------------------

The DBM databases can be built offline with the offline command. The
directory to be used for output is specified either on the command
line with the -d option, or is taken from the catalog.cfg directive
OfflineDir -- offline in the catalog directory by default. The
directory must exist. The source ASCII files should be present in that
directory, and the DBM files are created there. Existing files will be
overwritten.

   offline -c catalog [-d offline_dir]

Do a perldoc VENDROOT/bin/offline for full documentation.

50.2. Updating Individual Records
---------------------------------

If it takes a long time to build a very large DBM database, consider
using the bin/update script to change just one field in a record, or
to add from a corrections list.

The database is specified with the -n option, or is 'products' by
default.

The following updates the products database price field for item
19-202 with the new value 25.00:

   update -c catalog -f price 25.00

More than one field can be updated on a single command line.

   update -c catalog -f price -f comment 25.00 "That pitchfork couple"

The following takes input from file, which must be formatted exactly
like the original database, and adds/corrects any records contained
therein.

   update -c catalog -i file

Invoke the command without any arguments for a usage message
describing the options.

51. Other Database Capabilities
===============================

Interchange has a number of other options that can affect operation of
or operations on a defined database.

51.1. Search Modification
-------------------------

Normally, Interchange can search any database and will return all
records that match the search specification. Some attributes affect
this.

51.1.1. HIDE_FIELD
------------------

When set to a field name, i.e.:

   Database  sometable  HIDE_FIELD  inactive

Interchange will not return records that have that field (in the
example, c<inactive>) set to a true (non-blank, non-zero) value.

51.1.2. NO_SEARCH
-----------------

An indication that the database should not be searchable by default.
Used to determine the default search files for a product searc.

   Database  sometable  NO_SEARCH  1

In the foundation demo, this is used to prevent the options table from
being searched for products.

51.2. Indexing
--------------

You can indicate that a database should be indexed on a field with the
INDEX modifier:

        Database sometable  INDEX  category

This will create an ASCII index on every import, and will also create
an index on the field at SQL creation time.

If you wish to create SQL indices at table creation time without
creating an ASCII index, use the NO_ASCII_INDEX parameter:

        Database sometable  NO_ASCII_INDEX  1

Of course you can create a SQL index manually at any time via your SQL
toolset.

52. The Search Engine
=====================

Interchange implements a search engine which will search the product
database (or any other file) for items based on customer input. It
uses either forms or link-based searches that are called with the
special page name scan. The search engine uses many special
Interchange tags and variables.

If the search is implemented in a link or a form, it will always
display formatted results on the results page, an Interchange page
that uses some combination of the [search-region], [search-list],
[more-list], [more], and other Interchange tags to format and display
the results. The search results are usually a series of product
codes/SKUs or other database keys, which are then iterated over
similar to the [item-list].

Note: Examples of search forms and result pages are included in the
demos.

Two search engine interfaces are provided, and five types of searching
are available. The default is a text-based search of the first
products database source file (i.e., products.txt). A binary search of
a dictionary-ordered file can be specified. An optional Glimpse search
is enabled by placing the command specification for Glimpse in the
catalog.cfg directive Glimpse. There is a range-based search, used in
combination with one of the above. And finally, there is a
fully-coordinated search with grouping.

The default, a text based search, sequentially scans the lines in the
target file. By default it returns the first field (delineated by the
delimiter for that database) for every line matching the search
specification. This corresponds to the product code, which is then
used to key specific accesses to the database.

The text-based search is capable of sophisticated field-specific
searches with fully-independent case-sensitivity, substring, and
negated matching.

52.1. The Search Form
---------------------

A number of variables can be set on search forms to determine which
search will be used, what fields in the database it will search, and
what search behavior will be.

Here is a simple search form:

 <FORM ACTION="[area search]" METHOD=POST>
 <INPUT TYPE="text" SIZE="30" NAME="mv_searchspec">
 <INPUT TYPE="submit" VALUE="Search">
 </FORM>

When the "Search" submit button is pressed (or <ENTER> is pressed),
Interchange will search the products.txt file for the string entered
into the text field mv_searchspec, and return the product code
pertaining to that line.

The same search for a fixed string, say "shirt," could be performed
with the use of a hot link, using the special scan URL:

 [page search="se=shirt"]See our shirt collection!</a>

The default is to search every field on the line. To match on the
string "shirt" in the product database field "description," modify the
search:

 <INPUT TYPE="hidden" NAME="mv_search_field" VALUE="description">

In the hot-linked URL search:

 [page search="
               se=shirt
               sf=category
           "]See our shirt collection!</a>

To let the user decide on the search parameters, use checkboxes or
radiobox fields to set the fields:

   Search by author
      <INPUT TYPE="checkbox" NAME="mv_search_field" VALUE="author">
   Search by title
       <INPUT TYPE="checkbox" NAME="mv_search_field" VALUE="title">

Fields can be stacked. If more than one is checked, all checked fields
will be searched.

52.2. Glimpse
-------------

To use the Glimpse search, the Glimpse index must be built based on
files in the ProductDir, or wherever the files to be searched will be
located. If the catalog is in /var/lib/interchange/foundation, the
command line to build the index for the products file would be:

   chdir /var/lib/interchange/foundation/products
   glimpseindex -b -H . products.txt

There are several ways to improve search speed for large catalogs. One
method that works well for large products.txt files is to split the
products.txt file into small index files (in the example, 100 lines)
with the split(1) UNIX/POSIX command. Then, index it with Glimpse:

   split -100 products.txt index.txt.
   glimpseindex -H /var/lib/interchange/foundation/products index.txt.*

This will dramatically increase search speeds for large catalogs, at
least if the search term is relatively unique. If it is a common
string, in a category search, for example, it is better to use the
text-based search.

To search for numbers, add the -n option to the Glimpse command line.

Note: A large catalog is one of more than several thousand items;
smaller ones have acceptable speed in any of the search modes.

If the Glimpse executable is not found at Interchange startup, the
Glimpse search will be disabled and the regular text-based search used
instead.

There are several things to watch for while using Glimpse, and a
liberal dose of the Glimpse documentation is suggested. In particular,
the spelling error capability will not work in combination with the
field-specific search. Glimpse selects the line, but Interchange's
text-based search routines disqualify it when checking to see if the
search string is within one of the specified fields.

To use field-specific searching on Glimpse, tell it what the field
names are. If the search is on the products database (file), nothing
is needed for the default is to use the field names from the products
database. If it is some other field layout, specify the file to get
the field names from with mv_field_file (ff).

52.3. Fast Binary Search
------------------------

Fast binary searching is useful for scanning large databases for
strings that match the beginning of a line. They use the standard Perl
module Search::Dict, and are enabled through use of the mv_dict_look,
mv_dict_end, mv_dict_limit, mv_dict_fold, and mv_dict_order variables.

The field to search is the first field in the file, the product code
should be in the second field, delimited by TAB. Set the
mv_return_fields=1 to return the product code in the search.

The search must be done on a dictionary-ordered pre-built index, which
can be produced with the database INDEX modifier. See Dictionary
indexing with INDEX.

If using the mv_dict_look parameter by itself, and the proper index
file is present, Interchange will set the options:

   mv_return_fields=1
   mv_dict_limit=-1

This will make the search behave much like the simple search described
above, except it will be much faster on large files and will match
only from the beginning of the field. Here is an example. A title
index has been built by including in catalog.cfg:

   Database   products   INDEX    title

Note: The ASCII source file must be "touched" to rebuild the index and
the database.

Now, specify in a form:

   <FORM ACTION="[process href=search]" METHOD=POST>
   <INPUT TYPE=hidden NAME=mv_dict_limit VALUE=title>
   <INPUT NAME=mv_dict_look>
   </FORM>

or in a URL:

   [page search="dl=Van Gogh/di=title"]

This search is case-sensitive. To do the same thing
case-insensitively:

   Database   products   INDEX    title:f

   <FORM ACTION="[process href=search]" METHOD=POST>
   <INPUT TYPE=hidden NAME=mv_dict_limit VALUE=title>
   <INPUT TYPE=hidden NAME=mv_dict_fold  VALUE=1>
   <INPUT NAME=mv_dict_look>
   </FORM>

   [page search="dl=Van Gogh/di=title/df=1"]

52.4. Coordinated and Joined Searching
--------------------------------------

Interchange will do a complete range of tests on individual columns in
the database. To use this function, set mv_coordinate to Yes (co=yes
in the one-click syntax). In order to use coordinated searching, the
number of search fields must equal the number of search strings.

To make sure that is the case, use the mv_search_map variable. It
allows variables to be mapped to others in the search specification.
For example:

   <INPUT TYPE=hidden NAME=mv_search_map VALUE="
       mv_searchspec=search1
       mv_searchspec=search2
       mv_searchspec=search3
       ">
   <INPUT TYPE=hidden NAME=mv_search_field VALUE=title>
   <INPUT TYPE=hidden NAME=mv_search_field VALUE=artist>
   <INPUT TYPE=hidden NAME=mv_search_field VALUE=category>
   Artist: <INPUT NAME=search1 VALUE="">
   Title:  <INPUT NAME=search2 VALUE="">
   Genre:  <INPUT NAME=search3 VALUE="">

Even if the user leaves one blank, the search will work.

Leading/trailing whitespace is stripped from all lines in the
mv_search_map variable, so it can be positioned as shown for
convenience.

Coordinated searches may be joined with the output of another table if
set one of the mv_search_field values is set to a table:column pair.
Note that this will slow down large searches considerably unless there
is another search specification, as the database must be accessed for
every search line If there is a search field that qualifies for a
regular expression search function, or conducting a binary search with
mv_dict_look, or are not doing an OR search, the penalty should not be
too great as only matching lines will cause an access to the database.

Individual field operations can then be specified with the
mv_column_op (or op) parameter. The operations include:

   operation            string     numeric   equivalent
   ---------
   equal to               eq         ==           =
   not equal              ne         !=           <>
   greater than           gt         >
   less than              lt         <
   less than/equal to     le         <=
   greater than/equal to  ge         >=
   regular expression     rm                       =~ , LIKE
   regular expression NOT rn                       !~
   exact match            em

An example:

   [page search="
           co=yes
           sf=title
           se=Sunflowers
           op=em
           sf=artist
           se=Van Gogh
           op=rm
   "] Sunflowers, Van Gogh </a>

   [page search="
           co=yes

           sf=title
           se=Sunflowers
           nu=0
           op=!~

           sf=artist
           se=Van Gogh
           op=rm
           nu=0

           sf=inventory:qty
           se=1
           op=>=
           nu=1
   "] Any in stock except Sunflowers, Van Gogh </a>

Note that in the second example, nu=0 must be specified even though
that is the default. This is to set the proper correspondence. To
avoid having to do this, use Interchange's option array feature:

   [page search.0="
                   sf=title
                   se=Sunflowers
                   op=!~
               "
         search.1="
                   sf=artist
                   se=Van Gogh
               "
         search.2="
                   sf=inventory:qty
                   se=1
                   op=>=
                   nu=1
               "
       ] Any in stock except Sunflowers, Van Gogh </a>

The co=yes is assumed when specifying a multiple search.

The second search will check the stock status of the painting provided
there is an inventory table as in some of the Interchange demo
catalogs. If the qty field is greater than or equal to 1, the product
will be picked. If out of stock, it will not be found.

It always helps to have an rm type included in the search. This is
used to pre-screen records so that database accesses only need be made
for already-matching entries. If accesses must be made for every
record, large searches can get quite slow.

52.5. Specifying a Text-Based Search with SQL Syntax
----------------------------------------------------

If the Perl SQL::Statement module is installed, SQL syntax can be
specified for the text-based search. This is not the same as the
external SQL database search, treated below separately. This works on
the ASCII text source file, not on the actual database.

This syntax allows this form setup:

   Artist: <INPUT NAME="artist">
   Title:  <INPUT NAME="title">
   <INPUT TYPE=hidden NAME="mv_sql_query"
           VALUE="
               SELECT code FROM products
               WHERE artist LIKE artist
               AND    title LIKE title">

If the right hand side of an expression looks like a column, i.e., is
not quoted, the appropriate form variable is substituted. (If used in
a one-click, the corresponding scratch variable is used instead.) The
assumption is reversed for the left-hand side. If it is a quoted
string, the column name is read from the passed values. Otherwise, the
column name is literal.

   Search for: <INPUT NAME="searchstring"><BR>
   Search in   <INPUT TYPE="radio" NAME="column" VALUE="title"> title
       <INPUT TYPE="radio" NAME="column" VALUE="artist"> artist
       <INPUT TYPE=hidden NAME="mv_sql_query"
         VALUE="SELECT code FROM products WHERE 'column' LIKE searchstring">

Once again, this does not conduct a search on an SQL database, but
formats a corresponding text-based search. Parentheses will have no
effect, and an OR condition will cause all conditions to be OR. The
searches above would be similar to:

   [page search="
               co=yes
               sf=artist
               op=rm
               se=[value artist]
               sf=title
               op=rm
               se=[value title]
           "  ]
       Search for [value artist], [value title]
   </a>

   [page search="
               co=yes
               sf=[value column]
               op=rm
               se=[value searchstring]
           "  ]
   Search for [value searchstring]
          in  [value column]
   </a>

52.6. One-Click Searches
------------------------

Interchange allows a search to be passed in a URL, as shown above.
Just specify the search with the special page parameter search or
special page scan. Here is an example:

    [page search="
               se=Impressionists
               sf=category
           "]
       Impressionist Paintings
    </a>

This is the same:

    [page scan se=Impressionists/sf=category]
       Impressionist Paintings
    </a>

Here is the same thing from a home page (assuming /cgi-bin/vlink is
the CGI path for Interchange's vlink):

    <A HREF="/cgi-bin/vlink/scan/se=Impressionists/sf=category">
       Impressionist Paintings
    </A>

The two-letter abbreviations are mapped with these letters:

 ac  mv_all_chars
 bd  mv_base_directory
 bs  mv_begin_string
 ck  mv_cache_key
 co  mv_coordinate
 cs  mv_case
 cv  mv_verbatim_columns
 de  mv_dict_end
 df  mv_dict_fold
 di  mv_dict_limit
 dl  mv_dict_look
 DL  mv_raw_dict_look
 do  mv_dict_order
 dr  mv_record_delim
 em  mv_exact_match
 er  mv_spelling_errors
 ff  mv_field_file
 fi  mv_search_file
 fm  mv_first_match
 fn  mv_field_names
 hs  mv_head_skip
 ix  mv_index_delim
 lb  mv_search_label
 lf  mv_like_field
 lo  mv_list_only
 lr  mv_search_line_return
 ls  mv_like_spec
 ma  mv_more_alpha
 mc  mv_more_alpha_chars
 md  mv_more_decade
 ml  mv_matchlimit
 mm  mv_max_matches
 MM  mv_more_matches
 mp  mv_profile
 ms  mv_min_string
 ne  mv_negate
 ng  mv_negate
 np  mv_nextpage
 nu  mv_numeric
 op  mv_column_op
 os  mv_orsearch
 pf  prefix
 ra  mv_return_all
 rd  mv_return_delim
 rf  mv_return_fields
 rn  mv_return_file_name
 rr  mv_return_reference
 rs  mv_return_spec
 se  mv_searchspec
 sf  mv_search_field
 sg  mv_search_group
 si  mv_search_immediate
 sm  mv_start_match
 sp  mv_search_page
 sq  mv_sql_query
 sr  mv_search_relate
 st  mv_searchtype
 su  mv_substring_match
 tf  mv_sort_field
 to  mv_sort_option
 un  mv_unique
 va  mv_value

These can be treated just the same as form variables on the page,
except that they can't contain a new line. If using the multi-line
method of specification, the characters will automatically be escaped
for a URL.

IMPORTANT NOTE: An incompatibility in earlier Interchange catalogs is
specifying [page scan/se=searchstring]. This is interpreted by the
parser as [page scan/se="searchstring"] and will cause a bad URL.
Change this to [page scan se=searchstring], or perhaps better yet:

   [page search="
                   se=searchstring
           "]

A one-click search may be specified in three different ways.

Original

     To do an OR search on the fields category and artist for the
     strings "Surreal" and "Gogh," while matching substrings, do:

           [page scan se=Surreal/se=Gogh/os=yes/su=yes/sf=artist/sf=category]
              Van Gogh -- compare to surrealists
           </a>

     In this method of specification, to replace a / (slash) in a file
     name (for the sp, bd, or fi parameter), the shorthand of :: must
     be used, i.e., sp=results::standard. (This may not work for some
     browsers, so put the page in the main pages directory or define
     the page in a search profile.)

Multi-Line

     Specify parameters one to a line, as well.

              [page scan
                  se="Van Gogh"
                  sp=lists/surreal
                  os=yes
                  su=yes
                  sf=artist
                  sf=category
              ] Van Gogh -- compare to surrealists </a>

     Any "unsafe" characters will be escaped. To search for trailing
     spaces (unlikely), quote.

Ampersand

     Substitute & for / in the specification and be able to use / and
     quotes and spaces in the specification.

           [page href=scan se="Van Gogh"&sp=lists/surreal&os=yes&su=yes&sf=artist&sf=category]
              Van Gogh -- compare to surrealists
           </a>

     Any "unsafe" characters will be escaped.

52.7. Setting Display Options with mv_value
-------------------------------------------

A value can be specified that will be set in the link with the
mv_value parameter. It takes an argument of var=value, just as setting
a normal variable in an Interchange profile. Actually mv_value is a
misnomer, it will almost never be used in a form where variable values
can be set. Always specify it in a one-click search with va=var=value.
Example:

   [page href=scan
         arg="se=Renaissance
              se=Impressionists
              va=category_name=Renaissance and Impressionist Paintings
              os=yes"]Renaissance and Impressionist Paintings</a>

Display the appropriate category on the search results page with
[value category_name].

52.8. In-Page Searches
----------------------

To specify a search inside a page with the [search-region parameters*]
tag. The parameters are the same as the one-click search, and the
output is always a newline-separated list of the return objects, by
default, a series of item codes.

The [loop ...] tag directly accepts a search parameter. To search for
all products in the categories "Americana" and "Contemporary," do:

   [loop search="
       se=Americana
       se=Contemporary
       os=yes
       sf=category9
       "]
   Artist: [loop-field artist]<BR>
   Title: [loop-field title]<P>
   [/loop]

The advantage of the in-page search is that searches can be embedded
within searches, and there can be straight unchanging links from
static HTML pages.

To place an in-page search with the full range of display in a normal
results page, use the [search-region] tag the same as above, except
that [search-list], [more-list], and [more] tags can be placed within
it. Use them to display and format the results, including paging. For
example:

   [search-region  more=1
                   search="
                        se=Americana
                        sf=category
                        ml=2
                   "]
   [more-list][more][/more-list]
   [search-list]
   [page [item-code]]
       [item-field title]<A>, by [item-field artist]
   [/search-list]
   [no-match]
       Sorry, no matches for [value mv_searchspec].
   [/no-match]
   [/search-region]

Note: The [item-code] above does not need to be quoted because it is
replaced before the [page ...] tag is interpolated. If building large
lists, this is worth doing because unquoted tags are twice as fast to
parse.

To use the same page for search paging, make sure to set the sp=page
parameter.

52.9. Search Profiles
---------------------

An unlimited number of search profiles can be predefined that reside
in a file or files. To use this, make up a series of lines like:

mv_search_field=artist
mv_search_field=category
mv_orsearch=yes

These correspond to the Interchange search variables that can be set
on a form. Set it right on the page that contains the search.

[set artist_profile]
mv_search_field=artist
mv_search_field=category
mv_orsearch=yes
[/set]

This is the same:

[set artist_profile]
sf=artist
sf=category
os=yes
[/set]

Then, in the search form, set a variable with the name of the profile:

   <INPUT TYPE=hidden NAME=mv_profile VALUE=artist_profile>

In a one-click search, use the mp modifier:

[page scan se=Leonardo/mp=artist_profile]A left-handed artist</a>

They can also be placed in a file. Define the file name in the
SearchProfile directive. The catalog must be reconfigured for
Interchange to read it. The profile is named by placing a name
following a __NAME__ pragma:

 __NAME__ title_search

The __NAME__ must begin the line, and be followed by whitespace and
the name.

The special variable mv_last stops interpretation of search variables.
The following variables are always interpreted:

   mv_dict_look
   mv_searchspec

Other than that, if mv_last is set in a search profile, and there are
other variables on the search form, they will not be interpreted.

To place multiple search profiles in the same file, separate them with
__END__, which must be on a line by itself.

52.10. Search Reference
-----------------------

The supplied simple/srchform.html and simple/results.html pages show
example search forms. Modify them to present the search in any way
desired. Be careful to use the proper variable names for passing to
Interchange. It is also necessary to copy the hidden variables as-is.
They are required to interpret the request as a search.

Note: The following definitions frequently refer to field name and
column and column number. All are the references to the columns of a
searched text file as separated by delimiter characters.

The field names can be specified in several ways.

ProductFiles

     If the file to be searched is left empty in the search form or
     definition (it is set with mv_search_file (fi)), the text files
     associated with the products databases will be searched, and
     field names are already available as named in the first line of
     the file(s). This is defined to be products.txt in the
     Interchange demo catalogs.

     Be careful if using SQL! If the database is changed and not
     exported with [tag export products][/tag], searches will not be
     successful.

Other database files

     If the file or files to be searched are ASCII delimited files,
     and have field names specified on the first line of the file,
     Interchange will read the first line (of the first file) and
     determine the field names.

Other files

     If the file or files to be searched are ASCII delimited files,
     but don't have field names specified on the first line of the
     file, set the variable mv_field_names to a comma-separated list
     of field names as they will be referenced.

Fields can also always be specified by an integer column number, with
0 as the first column.

mv_all_chars

     Scan abbreviation: ac=[1|0]. Set this if searching is anticipated
     for lots of punctuation characters that might be special
     characters for Perl. The characters ()[]\$^ are included.

mv_base_directory

     Scan abbreviation: bd=/directory/name. In the text search, set to
     the directory from which to base file searches. File names
     without leading / characters will be based from there. In the
     Glimpse search, passed to Glimpse with the -H option, and Glimpse
     will look for its indices there. Default is ProductDir.

     If an absolute path directory is used, for security enable it in
     the users session with:

              [set /directory/name]1[/set]

     This prevents users from setting an arbitrary value and viewing
     arbitrary files.

mv_begin_string

     If this is set, the string will only match if it is at the
     beginning of a field. The handling is a bit different for the
     default AND search compared to the OR search. With OR searches
     all words are searched for from the beginning of the field, with
     AND searches all are.

     This is a multiple parameter. If mv_coordinate is in force, it
     should be set as many times as necessary to match the
     field/searchstring combination. If set only once, it applies to
     all fields. If set more than once but not as many times as the
     fields, it will default to off.

mv_cache_key

     Not normally set by the user. It is a value that provides a
     pointer to the search reference by the more function.

mv_case

     If this item is set to No, the search will return items without
     regard to upper or lower case. This is the default. Set to Yes if
     case should be matched. Implement with a checkbox <INPUT
     TYPE=CHECKBOX> field.

     If stacked to match the mv_search_field and mv_searchspec
     variables, and mv_coordinate is set, it will operate only for the
     corresponding field.

     Scan abbreviation: cs

mv_column_op

     In the coordinated search, the operation that will be performed
     to check the field for a search match. These operations are
     supported:

        !=              Not equal to
        !~              Not matching regular expression
        <               Less than
        <=              Less than or equal to
        <>              Not equal to
        =               Equal to
        ==              Equal to
        =~              Matching regular expression
        >               Greater than
        >=              Greater than or equal to
        em              Exact match
        eq              Equal to
        ge              Greater than or equal to
        gt              Greater than
        le              Less than or equal to
        lt              Less than
        ne              Not equal to
        rm              Matching regular expression
        rn              Not matching regular expression

     If stacked to match the mv_search_field and mv_searchspec
     variables, and mv_coordinate is set, it will operate only for the
     corresponding field.

Note that several of the operators are the same. They do either
numeric or string comparisons based on the status of mv_numeric (alias
nu) for that column.

mv_coordinate

     If this item is set to Yes, and the number of search fields
     equals the number of search specs, the search will return only
     items that match field to spec. (The search specifications are
     set by stacked mv_searchspec and mv_search_field variables.)

     Case sensitivity, substring matching, and negation all work on a
     field-by field basis according to the following:

          If only one instance of the option is set, it will affect
          all fields.

          If the number of instances of the option is greater than or
          equal to the number of search specs, all will be used
          independently. Trailing instances will be ignored.

          If more than one instance of the options are set, but fewer
          than the number of search specifications, the default
          setting will be used for the trailing unset options.

          If a search specification is blank, it will be removed and
          all case-sensitivity/negation/substring options will be
          adjusted accordingly. If you need a blank string to match
          on, use quotes ("").

mv_dict_end

     If the string at the beginning of a line lexically exceeds this
     value, matching will stop. Ignored without mv_dict_look.

mv_dict_fold

     Make dictionary matching case-insensitive. Ignored without
     mv_dict_look.

Note: This is the reverse sense from mv_case.

mv_dict_limit

     Automatically set the limiting string (mv_dict_end) to be one
     character greater than the mv_dict_look variable, at the
     character position specified. A value of 1, for instance, will
     set the limiting string to "fprsythe" if the value of
     mv_dict_look is "forsythe". A useful value is -1, which will
     increment the last character (setting the mv_dict_end to
     "forsythf" in our example). This prevents having to scan the
     whole file once a unique match is found.

Note: The order of this and the mv_dict_end variable is significant.
Each will overwrite the other.

     If this is set to a non-numeric value, an automatic mode is
     entered which looks for a dictionary-indexed file that
     corresponds to the file name plus .field, where field is whatever
     mv_dict_limit is set to. The actual value of mv_dict_limit is set
     to -1. If the file does not exist, the original file is silently
     used. Also, the value of mv_return_fields is set to 1 to
     correspond to the location of the key in the auto-indexed file.

     To illustrate:

              <INPUT TYPE=hidden NAME=mv_dict_limit  VALUE=category>
              <INPUT TYPE=hidden NAME=mv_search_file VALUE="products.txt">

     is equal to:

              <INPUT TYPE=hidden NAME=mv_dict_limit    VALUE="-1">
              <INPUT TYPE=hidden NAME=mv_search_file   VALUE="products.txt.category">
              <INPUT TYPE=hidden NAME=mv_return_fields VALUE="1">

     The real utility would be in a form construct like

              Search for
              <SELECT NAME=mv_dict_limit>
              <OPTION> author
              <OPTION> title
              </SELECT> beginning with <INPUT NAME=mv_dictlook>

     which would allow automatic binary search file selection.

     Combined with the INDEX attribute to the Database directive, this
     allows fast binary search qualification combined with regular
     mv_searchspec text searches.

mv_dict_look

     The string at which to begin matching at in a dictionary-based
     search. If not set, the mv_dict_end, mv_dict_fold, and
     mv_dict_case variables will be ignored. May be set in a search
     profile based on other form variables.

mv_dict_order

     Make dictionary matching follow dictionary order, where only word
     characters and whitespace matter. Ignored without mv_dict_look.

mv_doit

     This can be set to search to make a form with a process action be
     a search page by default. The mv_todo variable takes precedence.

mv_exact_match

     Normally Interchange searches match words, as opposed to
     sentences. This behavior can be overridden with mv_exact_match,
     which when set will place quotes around any value in
     mv_searchspec or mv_dict_look.

mv_field_file

     If you want to search a file which has no field header on the
     first line, you can specify a file to get the field names from.
     It expects a single line with the field names separated by TAB
     characters.

mv_field_names

     Deprecated in favor of in-list sorting. Defines the field names
     for the file being searched. This guarantees that they will be
     available, and prevents a disk access if using named fields on a
     search file (that is not the product database ASCII source, where
     field names are already known). This must be exactly correct, or
     it will result in anomalous search operation. Usually passed in a
     hidden field or search profile as a comma-separated list.

Note: Use this on the product database only if planning on both
pre-sorting with mv_sort_field and then post-sorting with
[sort]field:opt[/sort].

mv_first_match

     Normally Interchange will return the first page of a search. If
     this variable is set, it will start the search return at the
     match specified, even if there is only one page. If set to a
     value greater than the number of matches, it will act as if no
     matches were found.

mv_head_skip

     Normally Interchange searches all lines of an index/product file
     but the first. Set this to the number of lines to skip at the
     beginning of the index. Default is 1 for the text search, which
     skips the header line in the product file. Default is 0 for a
     Glimpse search.

mv_index_delim

     Sets the delimiter for counting fields in a search index. The
     default is TAB. It should rarely be changed unless you are
     searching a pipe-delimited or colon-delimited file.

mv_like_field

     Specifies a field in a database search which should be used for a
     screening function based on the SQL like function. Needs
     mv_like_spec.

mv_like_spec

     The string that should be searched for in mv_like_field. The
     behavior of the % character and case-sensitivity depends on your
     SQL implementation.

mv_matchlimit

     Function depends upon context. When the search results display is
     handled by one of the mechanisms which works with [more] lists
     (such as [search-region]), mv_matchlimit determines the number of
     results per page. If more matches than mv_matchlimit are found,
     the search paging mechanism will be employed if the proper
     [more-list] is present. When the search results are displayed as
     one continuous list (i.e.: with [loop search="..."]),
     mv_matchlimit is equivalent in function to mv_max_matches.

     To have no matchlimit, use none instead of a number. all does the
     same thing (since returning "all" is just anothing way of looking
     at no matchlimit).

     If no matchlimit is provided, or an invalid setting (some other
     string or 0) the default is taken from catalog variable
     MV_DEFAULT_MATCHLIMIT, and if that's not set, is 50.

mv_max_matches

     The maximum number of records that will be returned in a search.
     Default is unlimited. If search results paging with [more-list]
     is to be employed, Use mv_matchlimit to set the number of results
     per page.

mv_min_string

     Sets the minimum size of a search string for a search operation.
     Default is 4 for the Glimpse search, and 1 for the text search.

mv_negate

     Specifies that records NOT matching the search criteria will be
     returned. Default is no. It is not operative for the Glimpse
     search.

     If stacked to match the mv_search_field and mv_searchspec
     variables, and mv_coordinate is set, it will operate only for the
     corresponding field.

mv_orsearch

     If this item is set to Yes, the search will return items matching
     any of the words in searchspec. The default is No.

mv_profile

     Selects one of the pre-defined search specifications set by the
     SearchProfile directive. If the special variable within that
     file, mv_last, is defined, it will prevent the scanning of the
     form input for further search modifications. The values of
     mv_searchspec and mv_dict_look are always scanned, so specify
     this to do the equivalent of setting multiple checkboxes or
     radioboxes with one click, while still reading the search input
     text.

mv_record_delim

     Sets the delimiter for counting records in a search index. The
     default is newline, which works for the products and most
     line-based index files.

mv_return_fields

     The field(s) that should be returned by the match, specified
     either by field name or by column number, separated by commas. Do
     not list the same field more than once per search. Specify 0 as
     the first field to be returned if searching the products
     database, since that is the key for accessing database fields.

As with SQL queries, you can use the '*' shortcut to return all
fields. For example:

    [loop search="fi=nation/ra=yes/rf=*"]

when used with a hypothetical 'nation' table would be equivalent to:

    [loop search="
          fi=nation
          ra=yes
          rf=code,sorder,region,name,tax
    "]

as well as:

    [loop search="fi=nation/ra=yes/rf=0,1,2,3,4"]

and:

    [query sql="select * from nation"][/query]

However, you probably rarely need to use every single field in a row.
For maximum maintainability and execution speed the best practice is
to list by name only the fields you want returned.

mv_return_spec

     Returns the string specified as the search (i.e., the value of
     mv_searchspec) as the one and only match. Typically used in a
     SKU/part number search.

mv_search_field

     The field(s) to be searched, specified either by column name or
     by column number.

     If the number of instances matches the number of fields specified
     in the mv_searchspec variable and mv_coordinate is set to true,
     each search field (in order specified on the form) will be
     matched with each search spec (again in that order).

mv_search_file

     In the text search, set this variable to the file(s) to be
     scanned for a match. The default, if not set, is to scan the
     default ProductFiles (i.e., products.txt). If set multiple times
     in a form (for a text search), will cause a search all the files.
     One file name per instance.

     In the Glimpse search, follows the Glimpse wildcard-based file
     name matching scheme. Use with caution and a liberal dose of the
     Glimpse man page.

mv_search_match_count

     Set by the search to indicate the total number of matches found.

mv_search_page

     The Interchange-style name of the page that should display the
     search results. This overrides the default value of search.

mv_searchspec

     The actual search string that is typed in by the customer. It is
     a text INPUT TYPE=TEXT field, or can be put in a select
     (drop-down) list to enable category searches. If multiple
     instances are found, they will be concatenated just as if
     multiple words had been placed in a text field.

     The user can place quotes around words to specify that they match
     as a string. To enable this by default, use the mv_exact_match
     variable.

     If mv_dict_look has a value, and mv_searchspec does not, then
     mv_searchspec will be set to the value of mv_dict_look.

     If the number of instances matches the number of fields specified
     in the mv_search_field variable and mv_coordinate is set to true,
     each search field (in order specified on the form) will be
     matched with each search spec (again in that order).

mv_searchtype

     If set to Glimpse, selects the Glimpse search (if Glimpse is
     defined).

     If set to db, iterates over every row of the database (not the
     associated text source file).

     If set to sql, same as db.

     If set to text, selects the text-based search.

     When using st=db, returned keys may be affected by TableRestrict.
     See CATALOG.CFG.

     Defaults to text if Glimpse is not defined; defaults to Glimpse
     if it is defined. This can allow use of both search types if that
     is desirable. For instance, searching for very common strings is
     better done by the text-based search. An example might be
     searching for categories of items instead of individual items.

mv_small_data

Tells the search engine that there is a small amount of data in the
file and that it should perform the search function on every line.

Normally, when Interchange can find a fixed search expression it
produces a "screening" function which will allow records to be quickly
rejected when they don't match. If there are less than 50 records in
the file or database, this may be counterproductive.

mv_sort_field

     The file field(s) the search is to be sorted on, specified in one
     of two ways. If the file(s) to be searched have a header line
     (the first line) that contains delimiter-separated field names,
     it can be specified by field name. It can also be specified by
     column number (the code or key is specified with a value of 0,
     for both types). These can be stacked if coming from a form or
     placed in a single specification separated by commas.

Note: If specifying a sort for the product database, mv_field_names
must be specified if doing a fieldname-addressed post-sort.

mv_sort_option

     The way that each field should be sorted. The flags are r, n, and
     f, reverse, numeric, and case-insensitive respectively. These can
     be stacked if coming from a form or placed in a single
     specification separated by commas. The stacked options will be
     applied to the sort fields as they are defined, presuming those
     are stacked.

mv_spelling_errors

     The number of spelling errors that will be tolerated. Ignored
     unless using Glimpse. For a large table, limit this to two.

mv_substring_match

     If mv_substring_match is set to Yes, matches on substrings as
     well as whole words. Typically set this for dictionary-based
     searches.

     If stacked to match the mv_search_field and mv_searchspec
     variables and mv_coordinate is set, it will operate only for the
     corresponding field.

mv_unique

     If set to a true value, causes the sort to return only unique
     results. This operates on whatever the search return is, as
     defined by mv_return_fields.

mv_value

     This is normally only used in the one-click search
     (va=var=value). It allows setting of a session variable based on
     the clicked link, which makes for easy definition of headers and
     other display choices. (If had trouble using mv_searchspec for
     this before, this is what is needed.)

52.11. The Results Page
-----------------------

Once a search has been completed, there needs to be a way of
presenting the output. By default, the SpecialPage search is used. It
is set to results in the distribution demo, but any number of search
pages can be specified by passing the value in the search form
specified in the variable mv_search_page.

On the search page, some special Interchange tags are used to format
the otherwise standard HTML. Each of the iterative tags is applied to
every code returned from the search. This is normally the product
code, but could be a key to any of the arbitrary databases. The value
placed by the [item-code] tag is set to the first field returned from
the search.

The basic structure looks like this:

[search-region]
[search-list]
    your iterating code, once for each match
[/search-list]
[no-match]
    Text / tags to be output if no matches found (optional but recommended)
[/no-match]
[more-list]
    More / paging area (optional)
[/more-list]
[/search-region]

Tip for catalogs upgraded from Minivend 3: A
[search-list][/search-list] must always be surrounded by a
[search-region][/search-region] pair. This is a change from Minivend
3.

[search-list]

     Starts the representation of a search list. Interchange tags can
     be embedded in the search list, yielding a table or formatted
     list of items with part number, description, price, and
     hyperlinks to order or go to its catalog page.

     The example tags shown have an item- prefix, which is the
     default. Set any prefix desired with the prefix parameter to
     [search-region]:

              [search-region prefix=my]
              [search-list]
                  SKU:   [my-code]
                  Title: [my-data products title]
              [/search-list]
              [/search-region]

     The standard set of Interchange iterative ITL tags are available.
     They are interpolated in this order:

                  [item-alternate N] true [else] false [/else] [/item-alternate]
                  [if-item-param named_field] true [else] false [/else] [/if-item-param]
                  [item-param named_field]
                  [if-item-pos N] true [else] false [/else] [/if-item-pos]
                  [item-pos N]
                  [if-item-field products_field] true [else] false [/else] [/if-item-field]
                  [item-field products_column]
                  [item-increment]
                  [item-accessories]
                  [item-code]
                  [item-description]
                  [if-item-data table column] true [else] false [/else] [/if-item-data]
                  [item-data table column]
                  [item-price N* noformat=1*]
                  [item-calc] [/item-calc]
                  [item-change marker]
                      [condition]variable text[/condition]
                      true
                      [else] false [/else]
                  [/item-change marker]
                  [item-last] condition [/item-last]
                  [item-next] condition [/item-next]

Note: those that reference the shopping cart do not apply, i.e.,
[item-quantity], [item-modifier ...] and friends.

[/search-list]

     Ends the search list.

[no-match]

     Starts the region of the search results page that should be
     returned if there is no match (and no error) for the search. If
     this is not on the page, the special page nomatch will be
     displayed instead.

[/no-match]

     Ends the no match region.

[sort database:field:option* database:field:option*]

     Sorts the search list return based on database fields. If no
     options are supplied, sorts according to the return code. See
     SORTING.

     This is slow, and it is far better to pre-sort the return in the
     search specification.

[item-change marker]

     Active only within [search-list][/search-list].

     Along with the companion [/item-change marker], surrounds a
     region which should only be output when a field (or other
     repeating value) changes its value. This allows indented lists
     similar to database reports to be easily formatted. The repeating
     value must be a tag interpolated in the search process, such as
     [item-field field] or [item-data database field].

     Of course, this will only work as expected when the search
     results are properly sorted.

     The marker field is mandatory, and is also arbitrary, meaning
     that any marker can be selected as long as it matches the marker
     associated with [/item-change marker]. The value to be tested is
     contained within a [condition]value[/condition] tag pair. The
     [item-change marker] tag also processes an [else] [/else] pair
     for output when the value does not change. The tags may be nested
     as long as the markers are different.

     The following is a simple example for a search list that has a
     field category and subcategory associated with each item:

           <TABLE>
           <TR><TH>Category</TH><TH>Subcategory</TH><TH>Product</TH></TR>
           [search-list]
           <TR>
              <TD>
                   [item-change cat]
          
                   [condition][item-field category][/condition]
          
                           [item-field category]
                   [else]
                           &nbsp;
                   [/else]
                   [/item-change cat]
              </TD>
              <TD>
                   [item-change subcat]
          
                   [condition][item-field subcategory][/condition]
          
                           [item-field subcategory]
                   [else]
                           &nbsp;
                   [/else]
                   [/item-change subcat]
              </TD>
              <TD> [item-field name] </TD>
           [/search-list]
           </TABLE>

     The above should output a table that only shows the category and
     subcategory once, while showing the name for every product. (The
     &nbsp; will prevent blanked table cells if using a border.)

[/item-change marker]

     Companion to [item-change marker].

[matches]

     Replaced with the range of match numbers displayed by the search
     page. Looks something like "1-50". Make sure to insert this item
     between a [more-list] and [/more-list] element pair.

[match-count]

     Replaced with the total number of matches. This tag works even on
     [query] searches where [value mv_search_match_count] isn't set
     unless the query is applied to a non-SQL database. Make sure to
     insert this item between a [more-list] and [/more-list] element
     pair.

[more-list next_img* prev_img* page_img* border* border_current*]

     Starts the section of the search page which is only displayed if
     there are more matches than specified in mv_matchlimit. If there
     are less matches than the number in mv_matchlimit, all text/html
     between the [more_list] and [/more_list] elements is stripped.

     Use in conjunction with the [more] element to place pointers to
     additional pages of matches.

     If the optional arguments next_img, prev_img, and/or page_img are
     present, they represent image files that will be inserted instead
     of the standard 'Next,' 'Previous,' and page number. If prev_img
     is none, then no previous link will be output. If page_img is
     none, then no links to pages of matches will be output. These are
     URLs, are substituted for with ImageDir and friends, and will be
     encased in IMG tags. Lastly, border is the border number to put.

     In addition, if page_img is used, it will be passed an argument
     of the digit that is to be represented. This would allow an image
     generator program to be used, generating page numbers on the fly.
     The border and border_selected values are integers indicating the
     border that should be put around images in the page_img
     selection. The <border_selected> is used for the current page if
     set.

     \Examples:

     [more-list next.gif prev.gif page_num.cgi 3] causes anchors of:

               Previous   <IMG SRC="prev.gif" Border=3>
               Page 1     <IMG SRC="/cgi-bin/page_num.cgi?1">
               Page 2     <IMG SRC="/cgi-bin/page_num.cgi?2">
               Next       <IMG SRC="next.gif" Border=3>

     [more-list next.gif prev.gif page_num.cgi] causes anchors of:

               Previous   <IMG SRC="prev.gif">
               Page 1     <IMG SRC="/cgi-bin/page_num.cgi?1">
               Page 2     <IMG SRC="/cgi-bin/page_num.cgi?2">
               Next       <IMG SRC="next.gif">

     [more-list next.gif prev.gif 0 0] causes anchors of:

               Previous   <IMG SRC="prev.gif" Border=0>
               Page 1     <IMG SRC="/cgi-bin/page_num.cgi?1">
               Page 2     <IMG SRC="/cgi-bin/page_num.cgi?2">
               Next       <IMG SRC="next.gif" Border=0>

     To set custom text for the "Previous" and "Next" usually used,
     define the next_img, prev_img, and page_img with
     [next-anchor][/next-anchor], [prev-anchor][/prev-anchor] and
     [page-anchor][/page-anchor]. The string $PAGE$ will be replaced
     with the page number in the latter. The same example:

              [more-list]
              [next-anchor] Forward | [/next-anchor]
              [prev-anchor] Back [/prev-anchor]
              [page-anchor] Page $PAGE$ (matches $MINPAGE$-$MAXPAGE$) | [/page-anchor]
              [more]
              [/more-list]

     will display Forward | Page 1 (matches 1-50) | Page 2 (matches
     51-77) | Back for 2 pages. Note that the following anchors are
     replaced with the page number, the minimum match on the page, and
     the maximum match on the page:

              $PAGE$       Page number
              $MINPAGE$    Minimum match on page
              $MAXPAGE$    Maximum match on page

     You can customize the HTML hyperlink with [link-template]
     [/link-template]. This is useful for adding a JavaScript onclick
     attribute, or setting the link target to a different window, etc.

              [link-template]<a href="$URL$" target="_top">$ANCHOR$</a>[/link-template]

     There are two tokens you can use as many times as needed in
     [link-template], which will be replaced as follows:

              $URL$      The URL for the 'more' page in question
              $ANCHOR$   The page number or the word "Next" or "Previous" for the link in question.

     If have many pages of matches and don't wish to have all
     displayed at once, set [decade-next][/decade-next] and
     [decade-prev][/decade-prev]. If set them empty, a search with 31
     pages will display pages 21-30 like:

            Previous 1 2 3 4 5 6 7 8 9 10 [more>>] Next

     and pages 11-20 like:

            Previous [<<more] 11 12 13 14 15 16 17 18 19 20 [more>>] Next

     If set to [decade-next](higher)[/decade-next] and
     [decade-prev](lower)[/decade-prev], the following will be
     displayed:

            Previous (lower) 11 12 13 14 15 16 17 18 19 20 (higher) Next

     Of course, image-based anchors can be used as well.

[/more-list]

     Companion to [more-list].

[more]

     Inserts a series of hyperlinks that will call up the next matches
     in a series. They look like this:

              Previous 1 2 3 4 5 6 Next

     The current page will not be a hyperlink. Every time the new link
     is pressed, the list is re-built to correspond to the current
     page. If there is no Next or Previous page, that link will not be
     shown.

     See the search.html file for examples. Make sure to insert this
     item between a [more-list] and [/more-list] element pair.

[process-search]

     Outputs the complete URL for a search, including Interchange
     session tags. Used as the ACTION value for the search form. This
     is exactly the same as [area search].

53. Sorting
===========

Interchange has standard sorting options for sorting the search lists,
loop lists, and item lists based on the contents of database fields.
In addition, it adds list slices for limiting the displayed entries
based on a start value and chunk size (or start and end value, from
which a chunk size is determined). All accept a standard format sort
tag which must be directly after the list call:

   [loop 4 3 2 1]
   [sort -2 +2]
       [loop-code]
   [/loop]

   [search-list]
   [sort products:category:f]
       [item-price] [item-description]<BR>
   [/search-list]

   [item-list]
   [sort products:price:rn]
       [item-price] [item-code]<BR>
   [/item-list]

   [loop search="ra=yes"]
   [sort products:category products:title]
   [loop-field category] [loop-field title] <BR>
   [/loop]

All sort situations, [search list], [loop list], [tag each table], and
[item-list], take options of the form:

 [sort database:field:option* -n +n =n-n ... ]

database

     The Interchange database identifier. This must be supplied and
     should normally be 'products' if using the default name for the
     database.

field

     The field (column) of the database to be sorted on.

option

     None, any, or combinations of the options:

            f   case-insensitive sort (folded) (mutually exclusive of n)
            n   numeric order (mutually exclusive of f)
            r   reverse sort

-n

     The starting point of the list to be displayed, beginning at 1
     for the first entry.

+n

     The number of entries to display in this list segment.

=n-n

     The starting and ending point of the list display. This is an
     alternative to -n and +n. They should be specified in only one
     form. If both are specified, the last one will take effect.

...

     Don't really put ... in. This means that many sort levels are
     specified. Lots of sort levels with large databases will be quite
     slow.

Multiple levels of sort are supported, and database boundaries on
different sort levels can be crossed. Cross-database sorts on the same
level are not supported. If using multiple product databases, they
must be sorted with embedded Perl. This is actually a feature in some
cases, all items in a used database can be displayed before or after
new ones in products.

Examples, all based on the simple demo:

Loop list

              [loop 00-0011 19-202 34-101 99-102]
              [sort products:title]
                  [loop-code] [loop-field title]<BR>
              [/loop]

     Will display:

              34-101 Family Portrait
              00-0011 Mona Lisa
              19-202 Radioactive Cats
              99-102 The Art Store T-Shirt

     \Alternatively:

              [loop 00-0011 19-202 34-101 99-102]
              [sort products:title -3 +2]
                  [loop-code] [loop-field title]<BR>
              [/loop]

     \Displays:

              19-202 Radioactive Cats
              99-102 The Art Store T-Shirt

     The tag [sort products:title =3-4] is equivalent to the above.

Search list

     A search of all products (i.e.,
     http://yoursystem.com/cgi-bin/simple/scan/ra=yes):

              [search-list]
              [sort products:artist products:title:rf]
                  [item-field artist] [item-field title]<BR>
              [/search-list]

     will display:

              Gilded Frame
              Grant Wood American Gothic
              Jean Langan Family Portrait
              Leonardo Da Vinci Mona Lisa
              Salvador Dali Persistence of Memory
              Sandy Skoglund Radioactive Cats
              The Art Store The Art Store T-Shirt
              Vincent Van Gogh The Starry Night
              Vincent Van Gogh Sunflowers

     Note the reversed order of the title for Van Gogh and the
     presence of the accessory item Gilded Frame at the front of the
     list. It has no artist field and, as such, sorts first).

     Adding a slice option:

              [search-list]
              [sort products:artist products:title:rf =6-10]
                  [item-field artist] [item-field title]<BR>
              [/search-list]

     will display:

              Sandy Skoglund Radioactive Cats
              The Art Store The Art Store T-Shirt
              Vincent Van Gogh The Starry Night
              Vincent Van Gogh Sunflowers

     If the end value/chunk size exceeds the size of the list, only
     the elements that exist will be displayed, starting from the
     start value.

Shopping cart

              [item-list]
              [sort products:price:rn]
                  [item-price] [item-code]<BR>
              [/item-list]

     will display the items in the shopping cart sorted on their
     price, with the most expensive shown first. NOTE: This is based
     on the database field and doesn't take quantity price breaks or
     discounts into effect. Modifier values or quantities cannot be
     sorted.

Complete database contents

              [tag each products]
              [sort products:category products:title]
              [loop-field category] [loop-field title] <BR>
              [/tag]

     A two level sort that will sort products based first on their
     category, then on their title within the category.

Note that large lists may take some time to sort. If a product
database contains many thousands of items, using the [tag each
products] sort is not recommended unless planning on caching or
statically building pages.

54. Shipping
============

Interchange has a powerful custom shipping facility that performs UPS
and other shipper lookups, as well as a flexible rule-based facility
for figuring cost by other methods.

54.1. Shipping Cost Database
----------------------------

The shipping cost database (located in ProductDir/shipping.asc) is a
tab-separated ASCII file with six fields: code, text description,
criteria (quantity or weight, for example), minimum number, maximum
number, and cost. None of the fields are case-sensitive.

To define the shipping database in a catalog configuration file, set
the Variable MV_SHIPPING to what would be its contents.

To set the file to be something other than shipping.asc in the
products directory, set the Special directive:

   Special  shipping.asc  /home/user/somewhere/shipping_defs

There are two styles of setting which can be mixed in the same file.
The first is line-based and expects six or more TAB-separated fields.
They would look like:

default No shipping weight  0   99999999    0

upsg    UPS Ground  weight  0   0   e Nothing to ship!
upsg    UPS Ground  weight  0   150 u Ground [default zip 98366] 3.00
upsg    UPS Ground  weight  150 999999  e @@TOTAL@@ lbs too heavy for UPS

The second is a freeform method with a mode: Description text
introducing the mode line. The special encoding is called out by
indented parameters. The below is identical to the above:

   upsg: UPS Ground
       criteria    weight
       min         0
       max         0
       cost        e Nothing to ship!

       min         0
       max         150
       cost        u
       table       2ndDayAir
       geo         zip
       default_geo 98366
       adder       3

       min         150
       max         999999
       cost        e @@TOTAL@@ lbs too heavy for UPS

The second format has several advantages. Multiple lines can be
spanned with the <<HERE document format, like so:

   upsg: UPS Ground
       criteria    <<EOF
   [perl]
       return 'weight' if $Values->{country} eq 'US';
       return 'weight' if ! $Values->{country};
       # Return blank, don't want UPS
       return '';
   [/perl]
   EOF

The definable fields are, in order, for the tab-separated format:

MODE

     The unique identifier for that shipping method. It may be
     repeated as many times as needed.

DESCRIPTION

     Text to describe the method (can be accessed on a page with the
     [shipping-description] element).

CRITERIA

     Whether shipping is based on weight, quantity, price, etc. Valid
     Interchange tags can be placed in the field to do a dynamic
     lookup. If a number is returned, that is used as the accumulated
     criteria. That is, the total of weight, quantity, or price as
     applied to all items in the shopping cart.

     See Criteria Determination below.

MINIMUM

     The low bound of quantity/weight/criteria this entry applies to.

MAXIMUM

     The high bound of quantity/weight/criteria this entry applies to.
     The first found entry is used in case of ties.

COST

     The method of developing cost. It can be a number which will be
     used directly as the shipping cost, or a function, determined by
     a single character at the beginning of the field:

             f       Formula (ITL tags OK, evaluated as Perl)
             x       Multiplied by a number
             [uA-Z]  UPS-style lookup
             m       Interchange chained cost lookup (all items summed together)
             i       Interchange chained cost lookup (items summed individually)

NEXT

     The next field supplies an alternative shipping mode to
     substitute if the cost of the current one is zero.

ZONE

     The UPS zone that is being defined.

QUERY

     Interchange tags which will return a SQL query to select lines
     matching this specification. The current mode is replaced with
     this selection. If there is a query parameter of ?, it will be
     replaced with the mode name.

QUAL

     The geographic qualification (if any) for this mode.

PERL

     Perl code that is read and determines the criterion, not the
     cost. Use the cost option with "f" as the prelim to supply Perl
     code to determine cost.

TOTAL

     Set to the accumulated criterion before passing to Perl.

OPT

     Used to maintain UPS and freeform options. Normally these are set
     by separate lines in the shipping definition.

54.2. Criteria Determination
----------------------------

The criteria field varies according to whether it is the first field
in the shipping file exactly matching the mode identifier. In that
case, it is called the main criterion. If it is in subsidiary shipping
lines matching the mode (with optional appended digits), it is called
a qualifying criterion. The difference is that the main criterion
returns the basis for the calculation (i.e., weight or quantity),
while the qualifying criterion determines whether the individual line
may match the conditions.

The return must be one of:

quantity

     The literal value quantity as the main criterion will simply
     count the number of items in the shopping cart and return it as
     the accumulated criteria. If using a database table field named
     quantity, use the table::field notation.

o <field name> or <table>::<field name>

     A valid database field (column) name as main criterion will cause
     the number of items in the shopping cart to be multiplied by the
     value of the field for each item to obtain the accumulated
     criteria. If the table is not supplied, defaults to the first
     ProductFiles table.

o n.nn

     Where n.nn is any number, it will be directly used as the
     accumulated criteria. This can be effectively returned from a
     Perl subroutine or Interchange [calc][item-list] ...
     [/item-list][/calc] to create custom shipping routines.

IMPORTANT NOTE: The above only applies to the first field that matches
the shipping mode exactly. Following criteria fields contain qualifier
matching strings.

54.3. Shipping Calculation Modes
--------------------------------

There are eight ways that shipping cost may be calculated. The method
used depends on the first character of the cost field in the shipping
database.

N.NN (digits)

     If the first character is a digit, a number is assumed and read
     directly as the shipping cost.

e

     If the first character is an e, a cost of zero is returned and an
     error message is placed in the session value ship_message (i.e.,
     [data session ship_message] or $Session->{ship_message}).

f

     If the character f is the first, Interchange will first interpret
     the text for any Interchange tags and then interpret the result
     as a formula. It is read as Perl code; the entire set of
     Interchange objects may be referenced with the code.

i

     Specifies a chained shipping lookup which will be applied to each
     item in the shopping cart.

m

     Specifies a chained shipping lookup which will be applied to the
     entire shopping cart.

u

     Calls the UPS-style lookup. Can pre-define as many as desired.
     Though if want to do the hundreds available, it is best done
     on-the-fly.

x

     If an x is first, a number is expected and is applied as a fixed
     multiplier for the accumulated criterion (@@TOTAL@@).

A-Z

     If the first character is a capital letter, calls one of the 26
     secondary UPS-style lookup zones. (Deprecated now that zones can
     be named directly).

54.4. How Shipping is Calculated
--------------------------------

1.   The base code is selected by reading the value of mv_shipmode in
     the user session. If it has not been explicitly set, either by
     means of the DefaultShipping directive or by setting the variable
     on a form (or in an order profile), it will be default.

     The mv_shipmode must be in the character class [A-Za-z0-9_]. If
     there are spaces, commas, or nulls in the value, they will be
     read as multiple shipping modes.

          The criterion field is found. If it is quantity, it is the
          total quantity of items on the order form. If it is any
          other name, the criterion is calculated by multiplying the
          return value from the product database field for each item
          in the shopping cart, multiplied by its quantity. If the
          lookup fails due to the column or row not existing, a zero
          cost will be returned and an error is sent to the catalog
          error log. If a number is returned from an Interchange tag,
          that number is used directly.

          Entries in the shipping database that begin with the same
          string as the shipping mode are examined. If none is found,
          a zero cost is returned and an error is sent to the catalog
          error log.

Note: The same mode name may be used for all lines in the same group,
but the first one will contain the main criteria.

2.   The value of the accumulated criteria is examined. If it falls
     within the minimum and maximum, the cost is applied.

3.   If the cost is fixed, it is simply added.

4.   If the cost field begins with an x, the cost is multiplied by the
     accumulated criterion, i.e., price, weight, etc.

5.   If the cost field begins with f, the formula following is
     applied. Use @@TOTAL@@ as the value of the accumulated criterion.

6.   If the cost field begins with u or a single letter from A-Z, a
     UPS-style lookup is done.

7.   If the cost field begins with s, a Perl subroutine call is made.

8.   If the cost field begins with e, zero cost is returned and an
     error placed in the session ship_message field, available as
     [data session ship_message].

Here is an example shipping file using all of the methods of
determining shipping cost.

Note: The columns are lined up for reading convenience. The actual
entries should have one tab between fields.

global Option   n/a               0   0      g PriceDivide

rpsg   RPS      quantity          0   0      R RPS products/rps.csv
rpsg   RPS      quantity          0   5      7.00
rpsg   RPS      quantity          6   10     10.00
rpsg   RPS      quantity          11  150    x .95

usps   US Post  price             0   0      0
usps   US Post  price             0   50     f 7 + (1 * @@TOTAL@@ / 10)
usps   US Post  price             50  100    f 12 + (.90 * @@TOTAL@@ / 10)
usps   US Post  price             100 99999  f @@TOTAL@@ * .05

upsg   UPS      weight [value state]  0   0    e Nothing to ship.
upsg   UPS      AK HI             0   150    u upsg [default zip 980] 12.00 round
upsg   UPS                        0   150    u Ground [default zip 980] 2.00 round
upsg   UPS                        150 9999   e @@TOTAL@@ lb too heavy for UPS

upsca  UPS/CA   weight            0   0      c C UPS_Canada products/can.csv
upsca  UPS/CA   weight            -1   -1    o PriceDivide=0
upsca  UPS/CA   weight            0   150    C upsca [default zip A7G] 5.00
upsca  UPS/CA   weight            150 99999  e @@TOTAL@@ lb too heavy for UPS

global

     This is a global option setting, called out by the g at the
     beginning. PriceDivide tells the shipping routines to multiply
     all shipping settings by the PriceDivide factor, except those
     explicitly set differently with the o individual modifier. This
     allows currency conversion. (Currently the only option is
     PriceDivide.)

rpsg

     If the user selected RPS, (code rpsg) and the quantity on the
     order was 3, the cost of 7.00 from the second rpsg line would be
     applied. If the quantity were 7, the next entry from the third
     rpsg line would be selected for a cost of 10.00. If the quantity
     were 15, the last rpsg would be selected and the quantity of 15
     multiplied by 0.95, for a total cost of 14.25.

usps

     The next mode, usps, is a more complicated formula using price as
     the criteria. If the total price of all items in the shopping
     cart (same as [subtotal] without quantity price breaks in place)
     is from 1 to 50, the cost will be 7.00 plus 10 percent of the
     order. If the total is from 50.01 to 100, the cost will be 12.00
     plus 9 percent of the order total. If the cost is 100.01 or
     greater, 5 percent of the order total will be used as the
     shipping cost.

upsg

     The next, upsg, is a special case. It specifies a UPS lookup
     based on the store's UPS zone and two required values (and two
     optional arguments):

              1. Weight
              2. The zip/postal code of the recipient of which only
                 the first three digits are used.
              3. A fixed amount to add to the cost found in the UPS
                 tables (use 0 as a placeholder if specifying roundup)
              4. If set to 'round,' will round the cost up to the next
                 integer monetary unit.

     If the cost returned is zero, the reason will be placed as an
     error message in the session variable ship_message (available as
     [data session ship_message]).

     UPS weights are always rounded up if any fraction is present.

     The routines use standard UPS lookup tables. First, the UPS Zone
     file must be present. That is a standard UPS document specific to
     the retailer's area that must be obtained from UPS. It is entered
     into and made available to Interchange in TAB-delimited format.
     (As of March 1997, use the standard .csv file distributed by UPS
     on their Web site at www.ups.com.) Specify it with the
     UpsZoneFile directive. It is usually named something like
     NNN.csv, where NNN is the first three digits of the originating
     zip code. If placed in the products directory, the directive
     would look like:

              UPSZoneFile  products/450.csv

     Second, obtain the cost tables from UPS (again, get them from
     www.ups.com) and place them into an Interchange database. That
     database, its identifier specified with the first argument
     (Ground in the example) of the cost specification, is consulted
     to determine the UPS cost for that weight and rate schedule.

     In the example below, use a database specification like:

              Database  Ground  Ground.csv  CSV

     A simple shipping cost qualification can be appended to a UPS
     lookup. If any additional parameters are present after the five
     usual ones used for UPS lookup, they will be interpreted as a
     Perl subroutine call. The syntax is the same as if it was encased
     in the tag [perl sub] [/perl], but the following substitutions
     are made prior to the call:

              @@COST@@  is replaced with whatever the UPS lookup returned
              @@GEO@@   is replaced with the zip (or other geo code)
              @@ADDER@@ is replaced with the defined adder
              @@TYPE@@  is replaced with the UPS shipping type
              @@TOTAL@@ is replaced with the total weight

     The example above also illustrates geographic qualification. If
     the value of the form variable state on the checkout form is AK
     or HI, the U.S. states Alaska and Hawaii, a $10.00 additional
     charge (over and above the normal $2.00 handling charge) is made.
      This can also be used to select on country, product type, or any
     other qualification that can be encoded in the file.

upsca

     The next entry is just like the UPS definition except it defines
     a different lookup zone file (products/can.csv) and uses a
     different database, upsca. It also disables the global
     PriceDivide option for itself only, not allowing currency
     conversion. Otherwise, the process is the same.

     Up to 27 different lookup zones can be defined in the same
     fashion. If one of the cost lines (the last field) in the
     shipping.asc file begins with a c, it configures another lookup
     zone which must be lettered from A to Z.  It takes the format:

              c X name file* length* multiplier*

     where X is the letter from A-Z. The name is used internally as an
     identifier and must be present. The optional file is relative to
     the catalog root (like UpsZoneFile is). If it is not present, the
     file equal to name in the products directory (ProductDir) will be
     used as the zone file. If the optional digit length is present,
     that determines the number of significant digits in the passed
     postal/geo code.

     When the optional multiplier is present, the weight is multiplied
     by it before doing the table lookup. This allows shipping weights
     in pounds or kilograms to be adapted to a table using the
     opposite as the key. Remember, the match on weight must be exact,
     and Interchange rounds the weight up to the next even unit.

     To define the exact equivalent of the UPS lookup zone, do the
     following:

              c U UPS products/450.csv 3 1

     The only difference is that the beginning code to call the lookup
     is upper-case U instead of lower-case u.

54.5. More On UPS-Style Lookup
------------------------------

The UPS-style lookup uses two files for its purposes, both of which
need to be in a format like UPS distributes for US shippers.

The zone file is a file that is usually specific to the originating
location. For US shippers shipping to US locations, it is named for
the first three digits of the originating zip code with a CSV
extension. For example, 450.csv.

It has a format similar to:

   low - high, zone,zone,zone,zone

The low entry is the low bound of the geographic location; high is the
high bound. (By geographic location, the zip code is meant.) If the
first digits of the zip code, compared alphanumerically, fall between
the low and high values, that zone is used as the column name for a
lookup in the rate database. The weight is used as the row key.

The first operative row of the zone file (one without leading quotes)
is used to determine the zone column name. In the US, it looks
something like:

Dest. ZIP,Ground,3 Day Select,2nd Day Air,2nd Day Air A.M.,Next Day
Air Saver,Next Day Air

Interchange strips all non-alpha characters and comes up with:

DestZIP,Ground,3DaySelect,2ndDayAir,2ndDayAirAM,NextDayAirSaver,NextDayAir

Therefore, the zone column (shipping type) that would be used for UPS
ground would be "Ground," and that is what the database should be
named. To support the above, use a shipping.asc line that reads:

   upsg  UPS Ground  weight  0  150  u Ground [default zip 983]

and a catalog.cfg database callout of:

   Database  Ground  Ground.csv  CSV

These column names can be changed as long as they correspond to the
identifier of the rate database.

The rate database is a standard Interchange database. For U.S.
shippers, UPS distributes their rates in a fairly standard
comma-separated value format, with weight being the first (or key)
column and the remainder of the columns corresponding to the zone
which was obtained from the lookup in the zone file.

To adapt other shipper zone files to Interchange's lookup, they will
need to fit the UPS US format. (Most of the UPS international files
don't follow the U.S. format). For example, the 1998 Ohio-US to Canada
file begins:

   Canada Standard Zone Charts from Ohio
   Locate the zone by cross-referencing the first three
   characters of the destination Postal Code in the Postal
   Range column.

   Postal Range  Zone
   A0A  A9Z      54
   B0A  B9Z      54
   C0A  C9Z      54
   E0A  E9Z      54
   G0A  G0A      51
   G0B  G0L      54
   G0M  G0S      51
   G0T  G0W      54

It will need to be changed to:

   Destination,canstnd
   A0A-A9Z, 54
   B0A-B9Z, 54
   C0A-C9Z, 54
   E0A-E9Z, 54
   G0A-G0A, 51
   G0B-G0L, 54
   G0M-G0S, 51
   G0T-G0W, 54

Match it with a canstnd CSV database that looks like this:

   Weight,51,52,53,54,55,56
   1,7.00,7.05,7.10,11.40,11.45,11.50
   2,7.55,7.65,7.75,11.95,12.05,12.10
   3,8.10,8.15,8.40,12.60,12.70,12.85
   4,8.65,8.70,9.00,13.20,13.30,13.55
   5,9.20,9.25,9.75,13.85,13.85,14.20
   6,9.70,9.85,10.35,14.45,14.50,14.90
   7,10.25,10.40,11.10,15.15,15.15,15.70
   8,10.80,10.95,11.70,15.70,15.75,16.35
   9,11.35,11.55,12.30,16.40,16.45,17.20

It is called out in catalog.cfg with:

   Database canstnd canstnd.csv CSV

With the above, a 4-pound shipment to postal code E5C 4TL would yield
a cost of 13.20.

54.6. Geographic Qualification
------------------------------

If the return value in the main criterion includes whitespace, the
remaining information in the field is used as a qualifier for the
subsidiary shipping modes. This can be used to create geographic
qualifications for shipping, as in:

upsg   UPS Ground   weight [value state]   0     0     e No items selected
upsg   UPS Ground   AK HI                  0     150   u Ground [value zip] 12.00
upsg   UPS Ground                          0     150   u Ground [value zip] 3.00

If upsg is the mode selected, the value of the user session variable
state is examined to see if it matches the geographic qualification on
a whole-word boundary. If it is AK or HI, UPS Ground with an adder of
12 will be selected. If it "falls through," UPS Ground with an adder
of 3 will be selected.

54.7. Handling Charges
----------------------

Additional handling charges can be defined in the shipping file by
setting the form variable mv_handling to a space, comma, or
null-separated set of valid shipping modes. The lookup and charges are
created in the same fashion, and the additional charges are added to
the order. (The user is responsible for displaying the charge on the
order report or receipt with a [shipping handling] tag, or the like.)
All of the shipping modes found in mv_handling will be applied. If
multiple instances are found on a form, the accordingly null-separated
values will all be applied. NOTE: This should not be done in an
item-list unless the multiple setting of the variables is accounted
for.

To only process a handling charge once, do the following:

   [item-list]
   [if-item-field very_heavy]
   [perl values]
       return '' if $Values->{mv_handling} =~ /very_heavy/;
       return "<INPUT TYPE=hidden NAME=mv_handling VALUE=very_heavy>";
   [/perl]
   [/if-item-field]
   [/item-list]

A non-blank/non-zero value in the database field will trigger Perl
code which will only set mv_handling once.

54.8. Default Shipping Mode
---------------------------

If a default shipping mode other than default is desired, enter it
into the DefaultShipping directive:

   DefaultShipping     upsg

This will make the entry on the order form checked by default when the
user starts the order process, if it is put in the form:

 <INPUT TYPE=RADIO NAME=mv_shipmode VALUE=upsg [checked mv_shipmode upsg]>

To force a choice by the user, make mv_shipmode a required form
variable (with RequiredFields or in an order profile) and set
DefaultShipping to zero.

55. User Database
=================

Interchange has a user database function which allows customers to
save any pertinent values from their session. It also allows the
setting of database or file access control lists for use in
controlling access to pages and databases on a user-by-user basis.

The database field names in the user database correspond with the form
variable names in the user session. If there is a column named
address, when the user logs in the contents of that field will be
placed in the form variable address, and will be available for display
with [value address]. Similarly, the database value is available with
[data table=userdb column=address key=username].

The ASCII file for the database will not reflect changes unless the
file is exported with [tag export userdb][/tag]. It is not advisable
to edit the ASCII file, as it will overwrite the real data that is in
the DBM table. User logins and changes would be lost. Note: This would
not happen with SQL, but editing the ASCII file would have no effect.
It is recommended that the NoImport configuration directive be set
accordingly.

The field names to be used are not set in concrete. They may be
changed with options. Fields may be added or subtracted at any time.
Most users will choose to keep the default demo fields for simplicity
sake, as they cover most common needs. As distributed in the demo, the
fields are:

   code
   accounts
   acl
   address
   address_book
   b_address
   b_city
   b_country
   b_name
   b_nickname
   b_phone
   b_state
   b_zip
   carts
   city
   country
   db_acl
   email
   email_copy
   fax
   fax_order
   file_acl
   mv_credit_card_exp_month
   mv_credit_card_exp_year
   mv_credit_card_info
   mv_credit_card_type
   mv_shipmode
   name
   order_numbers
   p_nickname
   password
   phone_day
   phone_night
   preferences
   s_nickname
   state
   time
   zip

A few of those fields are special in naming, though all can be changed
via an option. A couple of the fields are reserved for Interchange's
use.

Note: If not running with PGP or other encryption for credit card
numbers, which is never recommended, it is important that the
mv_credit_card_info field be removed from the database.

The special database fields are:

   accounts         Storage for billing accounts book
   address_book     Storage for shipping address book
   b_nickname       Nickname of current billing account
   carts            Storage for shopping carts
   p_nickname       Nickname for current preferences
   preferences      Storage for preferences
   s_nickname       Nickname for current shipping address
   db_acl           Storage for database access control lists
   file_acl         Storage for file access control lists
   acl              Storage for simple integrated access control

If not defined, the corresponding capability is not available.

Note: The fields accounts, address_book, carts, and preferences should
be defined as a BLOB type, if using SQL. This is also suggested for
the acl fields if those lists could be large.

Reserved fields include:

   code        The username (key for the database)
   password    Password storage
   time        Last time of login

55.1. The [userdb ...] Tag
--------------------------

Interchange provides a [userdb ...] tag to access the UserDB
functions.

[userdb
       function=function_name
       username="username"*
       assign_username=1
       username_mask=REGEX*
       password="password"*
       verify="password"*
       oldpass="old password"*
       crypt="1|0"*
       shipping="fields for shipping save"
       billing="fields for billing save"
       preferences="fields for preferences save"
       ignore_case="1|0"*
       force_lower=1
       param1=value*
       param2=value*
       ...
       ]

* Optional

It is normally called in an mv_click or mv_check setting, as in:

   [set Login]
   mv_todo=return
   mv_nextpage=welcome
   [userdb function=login]
   [/set]

   <FORM ACTION="[process]" METHOD=POST>
   <INPUT TYPE=hidden NAME=mv_click VALUE=Login>
   Username <INPUT NAME=mv_username SIZE=10>
   Password <INPUT NAME=mv_password SIZE=10>
   </FORM>

There are several global parameters that apply to any use of the
userdb functions. Most importantly, by default, the database table is
set to be userdb. If another table name must be used, include a
database=table parameter with any call to userdb. The global
parameters (default in parentheses):

 database          Sets user database table (userdb)
 show              Show the return value of certain functions
                   or the error message, if any (0)
 force_lower       Force possibly upper-case database fields
                   to lower case session variable names (0)
 billing           Set the billing fields (see Accounts)
 shipping          Set the shipping fields (see Address Book)
 preferences       Set the preferences fields (see Preferences)
 bill_field        Set field name for accounts (accounts)
 addr_field        Set field name for address book (address_book)
 pref_field        Set field name for preferences (preferences)
 cart_field        Set field name for cart storage (carts)
 pass_field        Set field name for password (password)
 time_field        Set field for storing last login time (time)
 outboard          Set fields that live in another table
 outboard_key_col  Set field providing key for outboard tables
 expire_field      Set field for expiration date (expire_date)
 acl               Set field for simple access control storage (acl)
 file_acl          Set field for file access control storage (file_acl)
 db_acl            Set field for database access control storage (db_acl)
 indirect_login    Log in field if different than real username ('')

By default the system crypt() call will be used to compare the
password. This is best for security, but the passwords in the user
database will not be human readable.

If no critical information is kept and Interchange administration is
not done via the UserDB capability, use the UserDB directive
(described below) to set encryption off by default:

   UserDB   default   crypt   0

Encryption can still be set on by passing crypt=1 with any call to a
new_account, change_pass, or login call.

55.2. Setting Defaults with the UserDB Directive
------------------------------------------------

The UserDB directive provides a way to set defaults for the user
database. For example, to save and recall the scratch variable tickets
in the user database instead of the form variable tickets, set:

   UserDB   default   scratch  tickets

That makes every call to [userdb function=login] equivalent to [userdb
function=login scratch=tickets].

To override that default for one call only, use [userdb function=login
scratch="passes"].

To log failed access authorizations, set the UserDB profile parameter
log_failed true:

   UserDB  default  log_failed 1

To disable logging of failed access authorizations (the default), set
the UserDB profile parameter log_failed to 0:

   UserDB  default  log_failed 0

The UserDB directive uses the same key-value pair settings as the
Locale and Route directives. If there are more than one set of
defaults, set them in a hash structure:

   UserDB  crypt_case  <<EOF
   {
       'scratch'        => 'tickets',
       'crypt'          => '1',
       'ignore_case'    => '0',
   }
   EOF

   UserDB  default  <<EOF
   {
       'scratch'        => 'tickets',
       'crypt'          => '1',
       'ignore_case'    => '1',
   }
   EOF

Note: The usual here-document caveats apply. The "EOF" must be on a
line by itself with no leading/trailing whitespace.

The last one to be set becomes the default.

The option profile selects the set to use. For usernames and passwords
to be case sensitive with no encryption, pass this call:

   [userdb function=new_account profile=case_crypt]

The username and password will be stored as typed in, and the password
will be encrypted in the database.

55.3. User Database Functions
-----------------------------

The user database features are implemented as a series of functions
attached to the userdb tag. The functions are:

login

     Active parameters: username, password, crypt, pass_field,
     ignore_case, indirect_login

     Log in to Interchange. By default, the username is contained in
     the form variable mv_username and the password in mv_password. If
     the login is successful, the session value username ([data
     session username]) will be set to the user name. If
     indirect_login is used, it should be set to a field name which
     can be used as a lookup for the real username. This also causes a
     new_account operation to create a user account based on an
     assigned username, and assign_username should always be set when
     using indirect login.

     This will recall the values of all non-special fields in the user
     database and place them in their corresponding user form
     variables.

     The CookieLogin directive (catalog.cfg) allows users to save
     their username/password in a cookie. Expiration time is set by
     SaveExpire, renewed every time they log in. To cause the cookie
     to be generated originally, the form variable mv_cookie_password
     or mv_cookie_username must be set in the login form. The former
     causes both username and password to be saved, the latter just
     the username.

logout

     Log out of Interchange. No additional parameters are needed.

new_account

     Active parameters: username, password, verify, assign_username,
     username_mask, ignore_case,indirect_login

     Create a new account. It requires the username, password, and
     verify parameters, which are by default contained in the form
     variables mv_username, mv_password, mv_verify respectively.

     If the assign_username parameter is set, UserDB will assign a
     sequential username. The counter parameter can be used to set the
     filename (must be absolute), or the default of
     CATALOG_DIR/etc/username.counter can be accepted. The first
     username will be "U0001" if the counter doesn't exist already.

     If assign_username is used, you can choose to have a
     pseudo-username that is different from the real username. (Email
     address is commonly used.) The field name is contained in the
     indirect_login parameter. When the user logs in this field name
     will also be used to find the real username. The value must be
     unique in the database or a "user already exists" error will be
     thrown.

     The ignore_case parameter forces the username and password to
     lower case in the database, in effect rendering the username and
     password case-insensitive. This is recommended if using email
     address as a login.

     If username_mask is set to a valid Perl regular expression
     (without the surrounding / /), then any username containing a
     matching string will not be allowed for use. For example, to
     screen out order numbers from being used by a random user:

              [userdb function=new_account
                      username_mask="^[A-Z]*[0-9]"
                      ]

     The CookieLogin directive (catalog.cfg) allows users to save
     their username/password in a cookie. Expiration time is set by
     SaveExpire, renewed every time they log in. To cause the cookie
     to be generated originally, the form variable mv_cookie_password
     or mv_cookie_username must be set in the login form. The former
     causes both username and password to be saved, the latter just
     the username.

     To automatically create an account for every order, set the
     following in the OrderReport file:

              [userdb function=new_account
                      username="[value mv_order_number]"
                      password="[value zip]"
                      verify="[value zip]"
                      database="orders"
                      ]

     This would be coupled with a login form that asks for order
     number and zip code, thereupon allowing the display of the
     contents of a transaction database with (presumably updated)
     order status information or a shipping company tracking number.

change_pass

     Active parameters: username, password, verify, oldpass

     Change the password on the currently logged-in account. It
     requires the username, password, verify, and oldpass parameters,
     which are by default contained in the form variables mv_username,
     mv_password, mv_verify, mv_password_old respectively.

set_shipping

     Active parameters: nickname, shipping, ship_field

     Place an entry in the shipping Address book. For example:

              [userdb function=set_shipping nickname=Dad]

     See Address Book below.

get_shipping

     Active parameters: nickname, shipping, ship_field

     Recall an entry from the shipping Address book. For example:

              [userdb function=get_shipping nickname=Dad]

     See Address Book below.

get_shipping_names

     Active parameters: ship_field

     Gets the names of shipping address book entries and places them
     in the variable address_book. By default, it does not return the
     values. To have the values returned, set the parameter show to 1,
     as in:

              [set name=shipping_nicknames
                   interpolate=1]
                [userdb function=get_shipping_names show=1]
              [/set]

set_billing

     Active parameters: nickname, billing, bill_field

     Place an entry in the billing accounts book. For example:

              [userdb function=set_billing nickname=discover]

     See Accounts Book below.

get_billing

     Active parameters: nickname, billing, bill_field

     Recall an entry from the billing accounts book. For example:

              [userdb function=get_billing nickname=visa]

     See Accounts Book below.

save

     Saves all non-special form values that have columns in the user
     database. If a field is defined as scratch, it retrieves the
     field from the Scratch storage area; otherwise from Values. If
     the field is one of the outboard fields, it will save it in the
     outboard table with the value of outboard_key_col as the key.

set_cart

     Save the contents of a shopping cart.

              [userdb function=set_cart nickname=christmas]

     See Carts below.

get_cart

     Active parameters: nickname, carts_field, target

     Recall a saved shopping cart.

              [userdb function=get_cart nickname=mom_birthday]

     Setting target saves to a different shopping cart than the
     default main cart. The carts_field controls the database field
     used for storage.

set_acl

     Active parameters: location, acl_field, delete

     Set a simple acl. For example:

              [userdb function=set_acl location=cartcfg/editcart]

     This allows the current user to access the page
     "cartcfg/editcart" if it is access-protected.

     To delete access, do:

              [userdb function=set_acl location=cartcfg/editcart delete=1]

     To display the setting at the same time as setting, use the show
     attribute:

              [userdb function=set_acl location=cartcf/editcart show=1]

check_acl

     Active parameters: location, acl_field

     Checks the simple access control listing for a location,
     returning 1 if allowed and the empty string if not allowed.

              [if type=explicit
                  compare="[userdb
                              function=check_acl
                              location=cartcfg/editcart]"
              ]
              [page cartcfg/editcart]Edit your cart configuration</a>
              [/if]

set_file_acl, set_db_acl

     Active parameters: location, mode, db_acl_field, file_acl_field,
     delete

     Sets a complex access control value. Takes the form:

              [userdb function=set_file_acl
                      mode=rw
                      location=products/inventory.txt]

     where mode is any value to be checked with check_file_acl. As
     with the simple ACL, use delete=1 to delete the location
     entirely.

check_file_acl, check_db_acl

     Active parameters: location, mode, db_acl_field, file_acl_field

     Checks a complex access control value and returns a true/false
     (1/0) value. Takes the form:

              [userdb function=check_db_acl
                      mode=w
                      location=inventory]

     where mode is any value to be checked with check_file_acl. It
     will return true, if the mode string is contained within the
     entry for that location. For example:

              [if type=explicit
                  compare="[userdb
                              function=check_db_acl
                              mode=w
                              location=inventory]"
              ]
              [userdb function=set_acl location=cartcfg/edit_inventory]
              [page cartcfg/edit_inventory]You may edit the inventory database</a>
              [else]
              [userdb function=set_acl location=cartcfg/edit_inventory delete=1]
              Sorry, you can't edit inventory.
              [/if]

55.4. Address Book
------------------

Address_book is a shipping address book. The shipping address book
saves information relevant to shipping the order. In its simplest
form, this can be the only address book needed. By default these form
values are included:

  s_nickname
  name
  fname
  lname
  address
  address1
  address2
  address3
  city
  state
  zip
  country
  phone_day
  mv_shipmode

The first field is always the name of the form variable that contains
the key for the entry. The values are saved with the [userdb
function=set_shipping] tag call, and are recalled with [userdb
function=get_shipping]. A list of the keys available is kept in the
form value address_book, suitable for iteration in an HTML select box
or in a set of links.

To get the names of the addresses, use the get_shipping_names
function:

   [userdb function=get_shipping_names]

By default, they are placed in the variable address_book. Here is a
little snippet that builds a select box:

   <FORM ACTION="[process]" METHOD=POST>
   [userdb function=get_shipping_names]
   [if value address_book]
   <SELECT NAME="s_nickname">
   [loop arg="[value address_book]"] <OPTION> [loop-code] [/loop]
   </SELECT>
   <INPUT TYPE=submit NAME=mv_check VALUE="Recall Shipping">
   </FORM>

The same principle works with accounts, carts, and preferences.

To restore a cart based on the above, put in an mv_check routine:

   [set Recall Shipping]
   mv_todo=return
   mv_nextpage=ord/basket
   [userdb function=get_shipping nickname="[value s_nickname]"]
   [/set]

When the mv_check variable is encountered, the contents of the scratch
variable Recall Shipping are processed and the shipping address
information inserted into the user form values. This is destructive of
any current values of those user session variables, of course.

To change the fields that are recalled or saved, use the shipping
parameter:

   [userdb function=get_shipping
           nickname=city_and_state
           shipping="city state"]

Only the values of the city and state variables will be replaced.

55.5. Accounts Book
-------------------

The accounts book saves information relevant to billing the order. By
default these form values are included:

  b_nickname
  b_name
  b_fname
  b_lname
  b_address
  b_address1
  b_address2
  b_address3
  b_city
  b_state
  b_zip
  b_country
  b_phone
  purchase_order
  mv_credit_card_type
  mv_credit_card_exp_month
  mv_credit_card_exp_year
  mv_credit_card_info

The values are saved with the [userdb function=set_billing] tag call,
and are recalled with [userdb function=get_billing]. A list of the
keys available is kept in the form value accounts, suitable for
iteration in an HTML select box or in a set of links.

55.6. Preferences
-----------------

Preferences are miscellaneous session information. They include, by
default, the following fields:

   email
   fax
   phone_night
   fax_order
   email_copy

The field p_nickname acts as a key to select the preference set. To
change the values that are included with the preferences parameter:

   [userdb function=set_preferences
           preferences="email_copy email fax_order fax"]

or in catalog.cfg:

   UserDB default preferences "mail_list email fax_order music_genre"

55.7. Carts
-----------

The contents of shopping carts may be saved or recalled in much the
same fashion. See the Simple demo application ord/basket.html page for
an example.

55.8. Controlling Page Access With UserDB
-----------------------------------------

Interchange can implement a simple access control scheme with the user
database. Controlled pages must reside in a directory which has a file
named .access that is zero bytes in length. (If it is more than 0
bytes, only the RemoteUser or MasterHost may access files in that
directory.)

Set the following variables in catalog.cfg:

   Variable   MV_USERDB_ACL_TABLE  userdb
   Variable   MV_USERDB_ACL_COLUMN acl

The MV_USERDB_ACL_TABLE is the table which controls access, and
likewise the MV_USERDB_ACL_TABLE names the column in that database
which will be checked for authorization.

The database entry should contain the complete Interchange-style page
name of the page to be allowed. It will not match substrings.

For example, if the user flycat followed this link:

   <A HREF="[area cartcfg/master_edit]">Edit</A>

Access would be allowed if the contents of the userdb were:

   code    acl
   flycat  cartcfg/master_edit

and disallowed if it were:

   code    acl
   flycat  cartcfg/master_editor

Access can be enabled with:

   [userdb function=set_acl location="cartcfg/master_edit"]

Access can be disallowed with:

   [userdb function=set_acl
           delete=1
           location="cartcfg/master_edit"]

Of course, a pre-existing database with the ACL values will work as
well. It need not be in the UserDB setup.

55.9. Using more than one table
-------------------------------

You can save/retrieve userdb information from more than one table with
the outboard specifier. It is a key-value comma-separated series of
field specifications. For instance, if the billing address is to be
stored in a separate table named "billing", you would do:

        UserDB  outboard  <<EOF
            b_fname=billing::first_name,
            b_lname=billing::last_name,
            b_address1=billing::address1,
            b_address2=billing::address2,
                b_etc=billing::etc
        EOF

When the user logs in, Interchange will access the first_name field in
table billing to get the value of b_fname. When the values are saved,
it will be saved there as well. If you wish to make the fields
read-only, just set UserDB default scratch "b_fname b_lname ..." and
the values will be retrieved/saved from there. To initialize the
values for a form, you could do a function after the user logs in:

 [calc]
        my @s_fields = grep /\S/, split /[\s,\0]+/, $Config->{UserDB}{scratch};
        for(@s_fields) {
                $Values->{$_} = $Scratch->{$_};
        }
        return;
 [/calc]

If the fields in the outboard table use another key besides username,
you can specify the column in the userdb that contains the key value:

        UserDB  default  outboard_key_col   account_id

56. Tracking and Back-End Order Entry
=====================================

Interchange allows the entry of orders into a system through one of
several methods. Orders can be written to an ASCII file or formatted
precisely for email-based systems. Or they can go directly into an SQL
or DBM database. Finally, embedded Perl allows completely flexible
order entry, including real-time credit card verification and
settlement.

56.1. ASCII Backup Order Tracking
---------------------------------

If AsciiTrack is set to a legal file name (based in VendRoot unless it
has a leading "/"), a copy of the order is saved and sent in an email.

If the file name string begins with a pipe "|", a program will be run
and the output "piped" to that program. This allows easy back-end
entry of orders with an external program.

56.2. Database Tracking
-----------------------

Once the order report is processed, the order is complete. Therefore,
it is the ideal place to put Interchange tags that make order entries
in database tables.

A good model is to place a single record in a database summarizing the
order and a series of lines that correspond to each line item in the
order. This can be in the same database table. If the order number
itself is the key for the summary, a line number can be appended to
the order number to show each line of the order.

The following would summarize a sample order number S00001 for part
number 00-0011 and 99-102:

   code     order_number part_number  quantity   price    shipping  tax
   S00001   S00001                    3          2010     12.72     100.50
   S00001-1 S00001       00-0011      2          1000     UPS       yes
   S00001-2 S00001       99-102       1          10       UPS       yes

Fields can be added where needed, perhaps with order status, shipping
tracking number, address, customer number, or other information.

The above is accomplished with Interchange's [import ....] tag using
the convenient NOTES format:

   [set import_status]
   [import table=orders type=LINE continue=NOTES]

   code: [value mv_order_number]
   order_number: [value mv_order_number]
   quantity: [nitems]
   price: [subtotal noformat=1]
   shipping: [shipping noformat=1]
   tax: [salestax noformat=1]

   [/import]

   [item-list]
   [import table=orders type=LINE continue=NOTES]

   code: [value mv_order_number]-[item-increment]
   order_number: [value mv_order_number]
   quantity: [item-quantity]
   price: [item-price noformat=1]
   shipping: [shipping-description]
   tax: [if-item-field nontaxable]No[else]Yes[/else][/if]

   [/import][/item-list]

56.3. Order Routing
-------------------

Interchange can send order emails and perform custom credit card
charges and/or logging for each item. The Route directive is used to
control this behavior, along with the mv_order_route item attribute.

If no Route is in the catalog, Interchange uses a default "mail out
the order and show a receipt" model.

Routes are established with the Route directive, which is similar to
the Locale directive. Each route is like a locale, so that key-value
pairs can be set. Here is an example setting:

   Route  mail  pgp_key         0x67798115
   Route  mail  email           orders@akopia.com
   Route  mail  reply           service@akopia.com
   Route  mail  encrypt         1
   Route  mail  encrypt_program "/usr/bin/pgpe -fat -q -r %s"
   Route  mail  report          etc/report_mail

Note: Values with whitespace in them must be quoted.

You can also set the route in a valid Perl hash reference string:

   Route  mail <<EOR
   {
        pgp_key         => '0x67798115',
        email           => 'orders@akopia.com',
        reply           => 'service@akopia.com',
        encrypt         => 1,
        encrypt_program => q{/usr/bin/gpg -e -a -r '%s' --batch},
        report          => 'etc/report_mail',
  }
  EOR

This route would be used whenever the mail route was called by one of
the three possible methods:

route called from master route

     Called via the cascade parameter from the master route. This is
     the way that most routes are called in Interchange's the
     Foundation manpage demo. These routes treat the order as a whole.

route set in item

     An item in the shopping cart has mail as the value in the
     attribute  mv_order_route. This method is item-specific to this
     item (or group of items in route mail).

route set in the form variable mv_order_route

     By setting a value in the mv_order_route form variable, you can
     specify one or more routes to run. This is the deprecated method
     used in earlier Interchange 4.6.x and Minivend 4 routes. It will
     still work fine.

The last route that is defined is the master route, by convention
named main. Besides setting the global behavior of the routing, it
provides some defaults for other routes. For example, if
encrypt_program is set there, then the same value will be the default
for all routes. Most settings do not fall through.

The attributes that can be set are:

attach

     Determines whether the order report should be attached to the
     main order report e-mail. This is useful if certain items must be
     printed separately from others, perhaps for FAX to a fulfillment
     house.

     cascade

     A list of routes which should be pushed on the stack of routes to
     run, after all currently scheduled routes are done. NOTE:
     cascades can cause endless loops, so only one setting is
     recommended, that being the main route.

commit

     Perl code which should be performed on a route commit.

commit_tables

     Tables that are to be pre-opened before running the Perl commit
     code.

counter

     The location of a counter file which should be used instead of
     OrderCounter for this route. It will generate a different value
     for mv_order_number for the route. This is normally used to
     obtain unique order references for multi-vendor routing.

credit_card

     Determines whether credit card encryption should be done for this
     order. Either this or encrypt should always be set.

dynamic_routes

     If set in the the master manpage route, will cause the the
     RouteDatabase manpage to be checked for a route. If it exists, it
     will be read in and the database copy used instead of the static
     copy build at catalog configuration time. If set in a subsidiary
     route, that route will be ignored during catalog.cfg, and
     dynamic_routes must be active for it to be seen.

email

     The email address(es) where the order should be sent. Set just
     like the MailOrderTo directive, which is also the default.

encrypt

     Whether the entire order should be encrypted with the
     encrypt_program. If credit_card is set, the credit card will
     first be encrypted, then the entire order encrypted.

encrypt_program

     The encryption program incantation which should be used. Set
     identically to the EncryptProgram directive, except that %s will
     be replaced with the pgp_key. Default is empty.

errors_to

     Sets the Errors-To: e-mail header so that bounced orders will go
     to the proper address. Default is the same as MailOrderTo.

expandable

     If set in the the master manpage route, route settings will be
     expanded for ITL tags. No effect if the route is not the master.

extended

     Extended route settings that take the form of an Interchange
     option list; normally a Perl hash reference that will be read.
     These settings always overwrite any that currently exist,
     regardless of the order in which they are specified. For example:

        Route  main   extended    { email => 'milton@akopia.com' }
        Route  main   email       papabear@minivend.com

The ultimate setting of email will be milton@akopia.com.

increment

     Whether the order number should be incremented as a result of
     this result. Default is not to increment, as the order number
     should usually be the same for different routes within the same
     customer order.

individual_track

     A directory where individual order tracking files will be placed.
     The file name will correspond to the value of mv_order_number.
     This can be useful for batching orders via download.

individual_track_ext

     The extension that will be added to the file name for
     individual_track. Must contain a period (.), if that is desired.

   individual_track_ext     .pgp

individual_track_mode

     A number representing the final permission mode for the
     individual_track file. Usually expressed in octal:

   individual_track_mode    0444

master

     If set, this route becomes the master route for supplant,
     dynamic_routes, errors_to, and expandable, and supplies the
     setting for receipt and the attach report.  Switching master in
     midstream is unlikely to be successful -- it should certainly be
     the first route in a cascade.

payment_mode

     If this is set, enables a payment mode for the route. (Payment
     modes are also set in the Route directive.)

pgp_cc_key

     The PGP/GPG key selector that is used to determine which public
     key is used for encryption of credit cards only. With PGP 5 and
     6, see appropriate values by using the command pgpk -l. For GPG,
     use gpg --list-keys. Defaults to the value of the pgp_key
     manpage.

pgp_key

     The PGP key selector that is used to determine which public key
     is used for encryption. If pgp_cc_key is set, that key will be
     used for credit card encryption instead of pgp_key. With PGP 5
     and 6, see appropriate values by using the command pgpk -l. For
     GPG, use gpg --list-keys. Defaults to the value of the pgp_key
     manpage.

profile

     The custom order profile which should be performed to check the
     order prior to actually running the route. If it fails, the route
     will not be performed. See OrderProfile and mv_order_profile.

receipt

     The receipt page that should be used for this routing. This only
     applies if supplant is set for the route, and that normally would
     only be in the default route.

report

     The report page that should be used for this routing. If attach
     is defined, the contents of the report will be placed in a MIME
     attachment in the main order report.

reply

     The Reply-To header that should be set. Default is the same as
     email.

     If there are only word characters (A-Za-z0-9 and underscore), it
     describes an Interchange variable name where the address can be
     found.

rollback

     Perl code which should be performed on a route rollback.

rollback_tables

     Tables that are to be pre-opened before running the Perl rollback
     code.

supplant

     Whether the master route should supplant the main order report.
     If set, the AsciiTrack operation will use this route and the
     normal Interchange order e-mail sequence will not be performed.
     This is normally set in the master route.

track

     The name of a file which should be used for tracking. If the
     supplant attribute is set, the normal order tracking will be used
     as well.

track_mode

     A number representing the final permission mode for the track
     file. Usually expressed in octal:

   track_mode    0444

transactions

     A list of tables to put in transactions mode at the beginning of
     the route. Used to ensure that orders get rolled back if another
     route fails.

     The first route to open a table must have this parameter,
     otherwise transactions will not work. If any route fails (except
     ones marked error_ok) then a rollback will be done on these
     tables. If all routes succeed, a commit will be performed at the
     end of all order routes.

Individual item routing causes all items labeled with that route to be
placed in a special sub-cart that will be used for the order report.
This means that the [item-list] LIST [/item-list] will only contain
those items, allowing operations to be performed on subsets of the
complete order. The [subtotal], [salestax], [shipping], [handling],
and [total-cost] tags are also affected.

Here is an example of an order routing:

   Route  HARD      pgp_key          0x67798115
   Route  HARD      email            hardgoods@akopia.com
   Route  HARD      reply            service@akopia.com
   Route  HARD      encrypt          1
   Route  HARD      report           etc/report_mail

   Route  SOFT      email            ""
   Route  SOFT      profile          create_download_link
   Route  SOFT      empty            1

   Route  mail      pgp_key          0x67798115
   Route  mail      email            orders@akopia.com
   Route  mail      reply            service@akopia.com
   Route  mail      encrypt          1
   Route  mail      report           etc/report_all

   Route  user      error_ok         1
   Route  user      email            email
   Route  user      reply            service@akopia.com
   Route  user      report           etc/user_copy

   Route  log       empty            1
   Route  log       report           etc/log_transaction
   Route  log       transactions     "transactions orderline inventory"
   Route  log       track            logs/log

   Route  main      supplant         1
   Route  main      receipt          etc/receipt.html
   Route  main      master           log mail user
   Route  main      cascade          log mail user
   Route  main      encrypt_program  "/usr/bin/gpg -e -a r '%s' --batch"


This will have the following behavior:

Order

     The master order route is main, the last one defined. It cascades
     the routes log, mail, and user, which means they will run in that
     order at the completion of the main route. The individual item
     routes HARD and SOFT, if applicable, will run before those.

Transactions

     The route log specifies the tables that will be put in
     transaction mode, in this case transactions orderline, and
     inventory.

Failure

     All order routes must succeed except user, which has error_ok set
     to 1.

Encryption The mail order route and the HARD order route will be sent
by email, and encrypted against different GPG key IDs. They will get
their encrypt_program setting from the main route.

To set the order routing for individual items, some method of
determining their status must be made and the mv_order_route attribute
must be set. This could be set at the time of the item being placed in
the basket, or have a database field called goods_type set to the
appropriate value. The following example uses a Perl routine on the
final order form:

  [perl table=products]
     my %route;
     my $item;
     foreach $item (@{$Items}) {
         my $code = $item->{code};
         my $keycode = $Tag->data('products', 'goods_type', $code);
         $item->{mv_order_route} = $keycode;
     }
     return;
  [/perl]

Now the individual items are labeled with a mv_order_route value which
causes their inclusion in the appropriate order routing.

Upon submission of the order form, any item labeled HARD will be
accumulated and sent to the e-mail address hardgoods@akopia.com, where
the item will be pulled from inventory and shipped.

Any item labeled SOFT will be passed to the order profile
create_download_link, which will place it in a staging area for
customer download. (This would be supported by a link on the receipt,
possibly by reading a value set in the profile).

57. SSL Support
===============

Interchange has several features that enable secure ordering via SSL
(Secure Sockets Layer). Despite their mystique, SSL servers are
actually quite easy to operate. The difference between the standard
HTTP server and the SSL HTTPS server, from the standpoint of the user,
is only in the encryption and the specification of the URL; https: is
used for the URL protocol specification instead of the usual http:
designation.

IMPORTANT NOTE: Interchange attempts to perform operations securely,
but no guarantees or warranties of any kind are made! Since
Interchange comes with source code, it is fairly easy to modify the
program to create security problems. One way to minimize this
possibility is to record digital signatures, using MD5 or PGP or
GnuPG, of interchange, interchange.cfg, and all modules included in
Interchange. Check them on a regular basis to ensure they have not
been changed.

Interchange uses the SecureURL directive to set the base URL for
secure transactions, and the VendURL directive for normal non-secure
transactions. Secure URLs can be enabled for forms through a form
action of [process secure=1]. An individual page can be displayed via
SSL with [page href=mvstyle_pagename secure=1]. A certain page can be
set to be always secure with the AlwaysSecure catalog.cfg directive.

Interchange incorporates additional security for credit card numbers.
The field mv_credit_card_number will not ever be written to disk.

To enable automated encryption of the credit card information, the
directive CreditCardAuto needs to be defined as Yes. EncryptProgram
also needs to be defined with some value, one which will, hopefully,
encrypt the number. PGP is now recommended above all other encryption
program. The entries should look something like:

 CreditCardAuto   Yes
 EncryptProgram   /usr/bin/pgpe -fat -r sales@company.com

See CreditCardAuto for more information on how to set the form
variables.

58. Frequently Asked Questions
==============================

58.1. I can't get SQL to work: Undefined subroutine &Vend::Table::DBI::create ...
---------------------------------------------------------------------------------

This probably means one of the following:

No SQL database.

     Interchange doesn't include a SQL database. You must select one
     and install it.

No DBI.

     You must install Perl's DBI module before using Interchange with
     SQL. You can see where to get it at http://www.cpan.org, or try:

              perl -MCPAN -e 'install DBI'

No DBD.

     You must install the specific Perl DBD module for your database
     before using Interchange with SQL. You can see where to get it at
     http://www.cpan.org, or try:

              perl -MCPAN -e 'install DBD::XXXXX'

     where XXXXX is the name of your module. Some of them are:

              Adabas
              DB2
              Informix
              Ingres
              ODBC
              Oracle
              Pg
              Solid
              Sybase
              Unify
              XBase
              mSQL
              mysql

     If you can't make this script run without error:

              use DBI;
              use DBD::XXXXX;

     Then you don't have one of the above, and Interchange can't use
     an SQL database until you get one installed.

I don't like the column types that Interchange defines!

     They can be changed. See the foundation/dbconf/mysql directory
     for some examples under MySQL.

I change the ASCII file, but the table is not updated. Why?

     Interchange writes an empty file TABLE.sql (where TABLE is the
     name of the table). When this is present, Interchange will never
     update the table from disk.

     Also, if you have changed the field names in the file, you must
     restart the catalog (Apply Changes) before they will be picked
     up.

Why do I even need an ASCII file?

     Interchange wants some source for column names initially. If you
     don't want to have one, just create a TABLENAME.sql file in the
     products directory. For example, if you have this:

              Database products products.txt dbi:mysql:test_minivend

     Then create a file products/products.sql.

     \For:

              Database pricing pricing.txt dbi:mysql:test_minivend

     Create a file products/pricing.sql. .

Interchange overwrites my predefined table!

     Yes, it will if you don't create a file called TABLENAME.sql,
     where TABLENAME is the name of the Interchange table. If you want
     this to happen by default, then set NoImport TABLENAME.

58.2. How can I use Interchange with Microsoft Access?
------------------------------------------------------

Though Interchange has ODBC capability, the Microsoft Access ODBC
driver is not a network driver. You cannot access it on a PC from your
ISP or UNIX system.

However, you can turn it around.  Once you have created a MySQL or
other SQL database on the UNIX machine, you may then obtain the
Windows ODBC driver for the database (MySQL has a package called
myODBC) and use the UNIX database as a data source for your PC-based
database program.

Here is a quick procedure that might get you started:

o    Get MySQL from:

              http://www.mysql.com/

     Install it on your UNIX box. On LINUX, it is as easy as getting
     the RPM distribution:

              http://www.mysql.com/rpm/

     You install it by typing, as root, rpm -i mysql-3.XX.XX.rpm. If
     you are not root, you will have to build the source distribution.

o    To avoid permissions problems for your testing, stop the MySQL
     daemon and allow global read-write access with:

              mysqladmin shutdown
              safe_mysqld --skip-grant-tables &

     Obviously, you will want to study MySQL permissions and set up
     some security pretty quickly. It has excellent capability in that
     area, and the FAQ will help you get over the hurdles.

o    Set up a database for testing on the UNIX machine:

              mysqladmin create test_odbc
              mysql test_odbc

     Make an SQL query to set up a table, for example:

              mysql> create table test_me ( code char(20), testdata char(20) );
              Query OK, 0 rows affected (0.29 sec)
          
              mysql> insert into test_me VALUES ('key1', 'data1');
              Query OK, 1 rows affected (0.00 sec)
          
              mysql> insert into test_me VALUES ('key2', 'data2');
              Query OK, 1 rows affected (0.00 sec)
          
              mysql>

o    Get and install myODBC, also from the MySQL site:

              http://www.mysql.com/

     You install this package on your Windows 95 or NT box. It is a
     simple setup.exe process which leads you to the control panel for
     setting up an ODBC data source. Set up a data source named
     test_odbc that points to the database test_odbc on the UNIX box.
     You will need to know the host name and the port (usually 3306).

o    With Microsoft Access, you can then open a blank database and
     select: File/Get External Data/Link Tables. Select File Type of
     'ODBC databases' and the proper data source, and you should have
     access to the database residing on the UNIX side.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Frequently Asked Questions
==========================

59. How does Interchange work?
==============================

59.1. Where are the pages?
--------------------------

Interchange pages are not kept in normal HTML space. Look in the
catalog subdirectory pages. The pages are always filtered through the
Interchange daemon before being delivered.

59.2. Where are the images?
---------------------------

Interchange is a CGI program, and if relative image paths are used,
IMG tags like the following will occur:

<IMG SRC="/cgi-bin/simple/../whatever.jpg">

Interchange, by default, uses an ImageDir for a prefix. In the demo,
image specs that have no absolute path information are prefixed with
/simple/images/.

In an Interchange page, this tag:

       <IMG SRC="ordernow.gif">

will become this:

       <IMG SRC="/simple/images/ordernow.gif">

This tag:

       <IMG SRC="items/00-0011.jpg">

will become this:

       <IMG SRC="/simple/images/items/00-0011.jpg">

Absolute image paths are not affected. An image such as
/other/images/whatever.gif will not be changed.

60. INSTALLATION
================

60.1. Configuration Problems
----------------------------

Most Interchange configuration and setup problems are due to one of
the following:

Wrong information given to makecat program.

     This is by far the most common problem. To install a working
     demo, Interchange needs to know what the DocumentRoot is and how
     to run CGI programs. Details of this setup are server- and
     site-specific, which may require some research.

     Re-run the configuration again, and pay close attention to the
     prompts given. There are examples given which apply to most
     systems.

     If the web server is Apache or NCSA, Interchange will try and
     parse its httpd.conf file to help you along, but many ISPs don't
     allow users to read these and it may fail.

Too-low version of Perl.

     If you have a Perl earlier than 5.005, Interchange will not work.
     Don't even try an earlier version.

Perl compiled with USE_THREADS.

     Run perl -V. If you see -DUSE_THREADS in the compilation
     definition, you might run into problems with Interchange.

     NOTE: You cannot run the Interchange software as root.

If you are setting Interchange up for the entire machine, and not just
as a virtual host user, it is usual to create a special interch user
to run the daemon and the link program. This means the directory
listing for your cgi-bin should be something like:

-rwsr-xr-x   1 interchange users        6312 Dec 30 11:39 cgi-bin/simple

and for the socket file it should be:

srw-------   1 interchange users           0 Dec 30 11:41 etc/socket

Once you have set up the software, you can easily install catalogs as
root as long as your umask is set to 2 or 22.

(The following assumes you have made the Interchange software owned
and run by the special user interchange and that each user has a
Interchange catalogs directory /home/user/catalogs).

The best way to set permissions on a multi-user system is to make all
files group readable and writable (660 or 664 mode). If you have a
system setup that places each user in their own group, make
interchange a member of each user's group and set ownership and
permissions with:

       find /home/user/catalogs -print | xargs chown user
       find /home/user/catalogs -print | xargs chgrp user
       find /home/user/catalogs -print | xargs chmod g+rw

For best results, set the user's default umask to 2, so that they
will, by default, create files that have the proper permissions. If
you have all users in the same group, the above is not secure. You
should put interchange in a group of which no user is a member
(perhaps interchange would be a good choice) and set all files owned
by the group interchange and all directories to mode 2770:

This will make files default to the proper group when created (on most
UNIX versions, anyway).

       find /home/user/catalogs -print | xargs chown user
       find /home/user/catalogs -print | xargs chgrp interchange
       find /home/user/catalogs -print | xargs chmod g+rw
       find /home/user/catalogs -type d -print | xargs chmod g+s

If you are on a virtual hosting system, the procedure varies. Making
the program setuid should work for most systems. If your setup uses
CGI-WRAP or another setuid scheme, it should still work. However, you
may have to unset the setuid bit with chmod u-s cgi-bin/simple or the
like. If you have a non-standard CGI setup, as some virtual host
systems do, you will need to know something about UNIX and the web or
engage a consultant to properly set up the paths. Usually switching to
TLINK/INET mode is the easiest thing to do, though with Iserver and a
few others it may take more than that.

If you used the makecat program to build the catalog, it should have
warned you if it was not able to make the link program setuid. To set
the program (in the file cgi-bin/simple in this example) to be setuid,
use the command:

   chmod u+s cgi-bin/simple

60.2. Error -- the Interchange server was not running...
--------------------------------------------------------

This indicates that the link CGI is not communicating with the
Interchange server. Important note: The server should always be
started by the same user ID which owns the suid vlink program. (This
does not apply to TLINK/INET mode.)

The server must be running, first of all. If you didn't start it, you
can do so by going to the Interchange home directory and typing:

   bin/interchange -restart

You can check to see if your server is running by typing:

   Linux, BSD:           ps -ax | grep interchange
   Most other systems:   ps -elf | grep interchange

Note: Solaris and IRIX truncate the string, and don't allow setting of
the $0 parameter. You may have to grep for 'perl' instead.

If the server is not running, it may have failed due to another
process occupying the TCP socket 7786. If using VLINK, try starting
Interchange with start -u, which will not monitor the internet-domain
socket.

If VLINK is not communicating with the server, there are a number of
possible reasons. First, if you are trying to run Interchange on an
ISP, go to the section about ISP problems. It is probably one of
those. If you are running Interchange on a single machine, it is
probably one of:

   1. Permissions problems
   2. Interchange on NFS-mounted file system

Check the error_log file for your HTTP server -- it will almost always
tell you what the problem is, unless there is a simple permissions
problem.

Permissions are easy. If starting Interchange like this works:

        interchange -r SocketPerms=666

then you have a socket permission problem. Try restarting interchange
without the above adjustment of SocketPerms=666, and then try
accessing it again with each of these mode changes:

        chmod u+s cgi-bin/storename
        chmod u-s cgi-bin/storename

           cgi-bin/storename = path to your executable

If neither of those work, either the UID the program is owned by is
wrong, or your HTTP server is interfering in some fashion. If you are
running Interchange on an NFS-mounted file system, it cannot run in
server mode because UNIX-domain sockets don't work on NFS. You will
need to change to static mode from server mode, or better yet, put
Interchange on a file system that is directly mounted.

You can use Interchange in INET mode along with the tlink.c program to
allow running across NFS boundaries. If you have not changed the
configured defaults, and still it will not communicate, you should try
setting the LINK_HOST and LINK_PORT directives in tlink.c and
recompiling.

60.3. I get messages like 'Config.pm not found.' What does it mean?
-------------------------------------------------------------------

This means your Perl is not properly installed, or that Interchange is
not using the proper Perl binary. On UNIX, try reinstalling
Interchange and using the standard Perl installation sequence:

   /complete/path/to/proper/perl Makefile.PL
   make
   make test
   make install

Otherwise, contact your system administrator.

60.4. Can't locate lib.pm in @INC. BEGIN failed--compilation aborted.
---------------------------------------------------------------------

Again, your Perl is not properly installed. Someone has put a Perl up
on your system, then either moved or removed the library directory.
Contact your system administrator and request that Perl be
re-installed.

60.5. Segmentation fault or other core dump.
--------------------------------------------

If this happens when you run the Interchange test or server, it is
always Perl that has a problem. Not sometimes, always. A proper Perl
should never have a segmentation violation, period. And it should not
dump core (unless you passed it a -u option somehow).

You will need to either update Perl or report the bug to the proper
personnel. Depending on your situation and technical ability, this may
be your system admin, ISP, or the Perl porters.

60.6. Configuring catalog whatever...Use of uninitialized value at Config.pm line 1614, <CONFIG> chunk 322.
-----------------------------------------------------------------------------------------------------------

This is a warning from Perl indicating that an empty value was found
where one is expected. The warning is left in so that you know that
something is missing. Whatever it is, it can be found at the specified
"chunk," or line, of catalog.cfg. If you use the include capability,
it would have to be factored in as well.

The usual reason is that a file is specified in one of the directives
(usually one of Help, SearchProfile, OrderProfile, Buttonbars, or
UpsZoneFile) and does not exist. See the documentation for the
directive on how the file name should be specified.

60.7. Why isn't the above error more enlightening?
--------------------------------------------------

Because Perl won't tell us what exactly went wrong. See its FAQ for
why.

60.8. XXXXXX.pm does not match executable version.
--------------------------------------------------

This is a Perl which does not have the right Perl library installed.
It usually results from a naive system administrator who thinks they
can bypass the 'make install' for Perl and just copy the Perl binary
or directories.

If you installed Bundle::Interchange locally in your Interchange
directory, it may mean that your system administrator updated Perl and
failed to select the binary compatibility option.

60.9. Can I run Interchange on the Macintosh or Windows?
--------------------------------------------------------

Interchange will not run on a MacOS 7, 8, or 9 operating system. It
will run on Mac OS X and other PowerPC Unix variants.

Interchange's *files* can be manipulated by any computer. As long as
uploads/downloads of database source, pages, and configuration files
are done in ASCII mode, there is no reason why they can't be edited on
a Mac. And with MySQL or other ODBC databases on your UNIX-based ISP,
you can even directly interface to the database you use with
Interchange provided you have the scarce ODBC middleware needed for
the Mac.

Interchange can be run on Windows with the Cygwin tool set (1.3.2 or
higher) available from http://www.cygwin.com/, but there are numerous
anomalies and it may be difficult to get operating reliably. It is
never recommended that you run a production catalog on a Windows
system; if you do get it working you should only use for catalog
development.

60.10. Error -- 'make: command not found'
-----------------------------------------

The error is caused when the system you are installing on does not
have the program called "make".  It is recommended that you install
make as well as a C compiler ("cc" or "gcc") for the installation of
Interchange.  If you are unsure of how to do this for your operating
system, it may help to ask a mailing list related to your operating
system.

60.11. Templates aren't showing, only the center content of the page itself
---------------------------------------------------------------------------

Example question:  "All that's showing up is the center section of the
template.  This happened after ____:  (moving my site to a new host,
or uploading a new catalog.cfg or theme.cfg file, or restarting
interchange)."

This can happen if:

o    The files were uploaded in binary instead of ASCII (when using
     FTP)

o    Windows-style carriage returns were put in the file by a windows
     editor or file transfer program

From unix, do an octal dump on some of the files to see if you have cr
chars:

od -a templates/foundation/theme.cfg | grep cr
od -a catalog.cfg | grep cr

If something appears on the screen, then your file needs to be
cleaned.  Among the other 10-million ways to clean it, here is one:

perl -pi -e 's/\r\n/\n/g' < old_file.cfg > new_file.cfg

Also, if you are using FTP to transfer the files from a Windows
machine, try using ASCII mode instead of binary mode.

60.12. When I try to install the RPM, I get "failed dependencies" errors
------------------------------------------------------------------------

There are two easy solutions to this problem:

o    Install the modules manually, then use the --nodeps RPM option.

perl -MCPAN -e "install Bundle::Interchange"

o    Install RPM modules to satisfy the dependencies. Some modules are
     available from http://ftp.icdevgroup.org/perl/ while others can
     be found on rpmfind.net.

61. SSL problems
================

61.1. Shopping cart is dropped when using SSL.
----------------------------------------------

If you are using a separate secure and non-secure domain, this is due
to the cookies from the user not matching as well as the session ID
not being able to be transferred due to differing source IP addresses.

     NOTE: Interchange does not support this configuration. You may be
     able to get it to work in some circumstances, but it is not
     supported. See the next set of questions for help on how you may
     be able to get it to work to some extent in your configuration.
     It will not work in every circumstance with every feature.

This is sometimes due to the HostnameLookups (Stronghold/Apache
parameter) not matching for the two servers, secure and non-secure. It
can also be caused by the user having different web proxy addresses
for HTTP and HTTPS. If it still does not work, try changing some of
the appropriate configuration parameters in interchange.cfg:

   DomainTail   No
   IpHead       Yes

If you still are having problems, try this combination in catalog.cfg,
the catalog configuration file:

   SessionExpire  10 minutes
   WideOpen       Yes

The above setting will typically make Interchange work when it is
possible to work. Sometimes when you have multiple Interchange servers
sharing the same secure server, you will have problems after accessing
the second one. (The first one issues a session ID cookie, and that
causes problems).

61.2. I have a different secure server domain. Why does the shopping cart get dropped?
--------------------------------------------------------------------------------------

First of all, it is questionable business practice to not certify your
secure server. Besides violating the terms of use of many certificate
issuers, customers notice the changed domain and it is proven by user
surveys and long experience that you will receive fewer orders as a
result. Certs can be obtained for $125 US per year, less than the
typical cost of one hour of a top consultant's time. Do your business
a favor -- spend the money to get a cert.

If you insist on doing it anyway, probably driven by the fact that you
need a dedicated IP address for a secure server, you can use the
solutions in the previous FAQ question and get some relief.

But by far the best way is to have all orders and shopping cart calls
go only to the secure domain.  Your users may get a different session
when browsing the non-secure catalog pages, but it will matter little.

To do this on the Foundation demo, place in catalog.cfg:

AlwaysSecure  order ord/basket ord/checkout

A more complete list might be:

AlwaysSecure <<EOF
         account
         change_password
         customerservice
         login
         logout
         new_account
         ord/basket
         ord/checkout
         order
         process
         query/check_orders
         query/order_detail
         query/order_return
         returns
         saved_carts
         ship_addresses
EOF

Add pages of your own that need to be sure of coherent session
information.

For all *forms* to be secure, make sure "process" is on that list.
(Your search forms will still be non-secure if you use
"[process-search]" to produce the form ACTION.)

To make individual order links secure, use this instead of "[order]":

<A HREF="[area href=order secure=1 form='mv_order_item=SKU_OF_ITEM'
]">Order it</A>

To make a form-based order button secure, use "[process secure=1]" as
the ACTION.

61.3. My images aren't there on the secure server!!!
----------------------------------------------------

You have a different document root, or the permissions are not such
that you can access them. You can set a different base URL for images
with:

        ImageDirSecure   https://your.secure.server/somewhere/images

Don't try to set it to an http:// URL -- images will be broken anyway.

61.4. My secure pages fail when the browser is MSIE.
----------------------------------------------------

MSIE has several SSL bugs, particularly in V5.01.  See the Apache-SSL
or mod_ssl FAQ. You can sometimes fix this with an httpd.conf change:

SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown

62. ISP Problems
================

The great majority of ISPs provide some CGI service, and more and more
run systems that are compatible with Interchange. The new catalog
configurator for Interchange makes setup much easier. A word of
warning: if you chose your ISP mostly on price, you can expect
problems. The low-cost providers typically have heavily-loaded
machines and many domains. The more domains and the more load the
unhappier you will be with Interchange. Interchange works best on a
fast machine with plenty of memory.

A few Internet Service Provider (ISP) systems still have difficulty
with one or the other aspect of running Interchange. A few cannot (or
will not) run Interchange at all. On top of that, many times ISP
personnel are too busy to help, won't help, or don't know enough to
help. Some are secretive about details of the setup of their systems.

All in all, you can have a fair amount of confidence that your ISP can
run Interchange. Or, you can get one who will. 8-)

62.1. No shell access allowed on my ISP.
----------------------------------------

Generally it is a waste of time to try to use Interchange without
shell access.

62.2. We're sorry, the Interchange server is unavailable...
-----------------------------------------------------------

(The following assumes that you were able to start the Interchange
server.)

This could be almost anything, but with a properly configured
Interchange it is almost undoubtedly due to your cgi-bin and/or your
Interchange directory being located on a different filesystem than the
actua machine that is executing the program. VLINK uses UNIX-domain
sockets, which don't work on NFS-mounted filesystems.

Iserver.com and other systems which use chroot HTTP servers require
quite a bit of extra configuration to get going. If you have not been
careful to set permissions properly when running in VLINK/UNIX mode,
the link CGI will not be able to communicate with the Interchange
server. Please read the documentation that covers this in detail.

You can run in INET mode with the tlink link program to prevent those
problems.

62.3. Document contains no data or premature end of script headers (especially on BSDI or FreeBSD).
---------------------------------------------------------------------------------------------------

This usually means that your HTTP server ran out of resources during
the execution of the link program. It couldn't create more sockets, is
unable to create a process, or can't open any more files.

This usually happens in frames catalogs, when Interchange is sending
more than one page simultaneously. And even more especially on FreeBSD
and BSDI, which are often distributed with the kernel parameters
SOMAXCONN and CHILD_MAX set to levels unsuitable for serving the web.

Go to <http://www.deja.com> and try searching for MAXUSERS. This
should give you plenty of pointers on how to set these parameters
properly.

62.4. Interchange server only runs for a while, then dies.
----------------------------------------------------------

Many ISPs don't allow your user ID to run a program unless it is
logged in! The moment a watchdog program notices a daemon running with
a non-logged-in UID, it terminates the program. Or, it terminates
programs that haven't been active for XX minutes. Contact your ISP
about this. They may be able to do something for you.

62.5. My entire home directory is in HTML document space.
---------------------------------------------------------

If working with an ISP where all of the files are in HTML document
space, disable all access to the Interchange catalog directory with
the proper HTTP access restrictions. Normally that is done by creating
a .htaccess file like this:

        <Limit GET POST>
        order allow,deny
        deny from all
        </Limit>

If unable to do this, do not run Interchange unless file permissions
can be set such that files will not be served. However, security will
be a problem and customers' personal information could be placed at
risk.

63. SYSTEM CONFIGURATION
========================

63.1. Can I run multiple catalogs on one server?
------------------------------------------------

Yes. Interchange supports multiple independent catalogs. There are
users who run more than 500 catalogs on a single machine. The capacity
is usually a function of how busy the catalogs are and how much memory
and processor speed your system has.

63.2. How do I start Interchange when I reboot?
-----------------------------------------------

Use the standard facility on your operating system. For BSD-style
systems, the file is usually called rc.local (in the /etc directory).

On SVR4 systems, it is quite a bit more complex. Look for the
/etc/rc.d directory and see what other programs do. Often the file is
called S99startup or something similar.

Important note: Interchange must not run as root, which is the user
identity that the startup file executes. (Interchange will refuse to
start if executed as root.) The technique to start up depends on the
facility of your su(1) command. This should work on most operating
systems:

   su interchange <<EOF
   /your/interchange/dir/bin/restart
   EOF

The EOF must be the only thing on the line (no leading or trailing
whitespace). If your su(1) command has a -c option (as most System 5
UNIXes do), you can just set:

   su -c /your/interchange/dir/bin/restart interchange

Interchange supplies a restart script which tries to do the above
portably. It works on many operating systems.

63.3. I installed the Interchange RPM, and I can't restart.
-----------------------------------------------------------

This usually means that you tried to run
/usr/lib/interchange/bin/interchange, which fails to take into account
the Linux Standard Base (LSB) file setup. Instead, run

/etc/rc.d/init.d/interchange restart

or

/usr/sbin/interchange -r

63.4. How do I set up a mall?
-----------------------------

Interchange can share product databases, session files, and any other
databases. It has many features which support mall building. You can
easily build separate and mostly identical catalogs which you link to
via HTML. But building a mall is as much an exercise in data and
process as in software. Consider the following questions:

9.   Who will be clearing payment?

10.  What happens if everyone doesn't have the same tax rate?

11.  How will you clear orders to multiple vendors?

12.  How will you bring together multiple types of shipping?

13.  How will the vendors get product data (including images) to you?

If you cannot answer those questions and visualize how to build a
mall, you probably should not try.

64. PRODUCT OPTIONS
===================

64.1. Can I attach a size or color to a product?
------------------------------------------------

Interchange has product modifiers, or attributes, which can be carried
around with the product. Inside an item list or the product page
(flypage), the [item-options] tag will automatically place suitable
widgets on an HTML form, and "remember" what should be selected. See
the Interchange documentation for Item Options.

You can use the SeparateItems directive or set the mv_separate_items
variable on the order form to cause ordered items to be put on
separate lines in the shopping basket. (This is the default in the
demo catalogs.)

64.2. Can I change the price based on size or color (or other attribute)?
-------------------------------------------------------------------------

Yes. Use the Interchange UI to set up your product options. It
operates on the options database table to set up options that can
effect price. Or see the next question.

64.3. How are simple product options structured?
------------------------------------------------

Interchange has three types of options; simple, matrix, and modular.
They are based on the options database table.

To enable options for a product, it needs to have a master record in
"options" with the SKU as the key. The only fields that matter in the
master record are:

code        The SKU of the item

o_master    Indicates not a product, but an option for a product in another database

o_enable    Options enabled for that item

o_matrix    Set to 1 for all-in-one widgets, 2 for separate widgets

o_modular   Modular options (alpha)

If o_enable is set, but neither o_matrix or o_modular are, the item is
using simple options.

For the option itself in simple mode, the following fields apply:

code        Arbitrary key
sku         SKU this option applies to
o_group     The attribute name of the option
o_label     The label the widget for the option will bear
o_value     The options, in IC option format
o_widget    The widget type used to display
o_height    The widget height (if any)
o_width     The widget width (if any)
price       Price adjustment

Here are the fields for an item with a simple size option:

code:os28009
o_master:1
o_enable:1
o_matrix:0
o_modular:0
#
code:os28009-size
sku:os28009
o_group:size
o_label:Size
o_value:S=Small,M=Medium,L=Large,XL=Extra Large
o_widget:select
o_height:
o_width:
price:S=-1.00,XL=1.00
#

The price field accepts option modifiers based on the option value;
for example, to adjust the price of an S down 1.00 and the price of an
XL up 1.00, you use the values shown above. This works in conjunction
with the special ==:options atom in CommonAdjust. To activate the
pricing adjustment, you must have something like this for your
CommonAdjust setting:

 CommonAdjust    :sale_price, ;:price, ==:options

The actual names of the fields used for these can be changed with the
Variable MV_OPTION_TABLE_MAP, i.e.

Variable MV_OPTION_TABLE_MAP <<EOM
        o_widget  widget
        o_value   value
EOM

That would allow you to use "widget" and "value" in place of o_widget
and o_value as field names.

64.4. But what do these options do? Where do they live?
-------------------------------------------------------

If you know Perl, you know what a hash reference is. An Interchange
shopping cart consists of an array of hash references. If you dump the
structure of the main shopping cart you would see something like:

        [
                {
                        mv_ip       => '0',
                        price_group => 'general',
                        mv_ib       => 'products',
                        code        => 'os28080',
                        quantity    => '1',
                },
                {
                        mv_ip       => '1',
                        price_group => 'general',
                        mv_ib       => 'products',
                        code        => 'os28080',
                        size        => 'L',
                        color       => 'black',
                        quantity    => '1',
                },
         ]

Each key of the hash is an attribute. There are a number of special
attributes:

Attribute                          Description
.................................. .................................. 
code                               The item SKU
sku                                The SKU of the base item (in the
                                   case of matrix options)
mv_ip                              The line number of the shopping
                                   cart (minus 1)
mv_ib                              The database table the product was
                                   ordered from
quantity                           The number on order
group                              The order group for a master item
                                   or subitem
mv_si                              Subitem indicator
mv_mi                              Master item code
mv_mp                              Modular item
mv_price                           Price of the item (to directly set
                                   pricing)
mv_order_route                     Special order route for this item

Any attribute besides the above is a product option or modifier, and
can be displayed with [item-modifier attribute_name].

65. ENCRYPTION
==============

65.1. PGP encryption -- Server Error
------------------------------------

As always, check the error log. The most common problem is something
like:

   akopia.com 3Ex5lvta:akopia.com - [01/Sep/1997:09:08:43] simple /cgi-bin/simple
   > Encryption error:
   >

Also, check the ScratchDir (usually tmp/) for .err files; they will
contain PGP or GPG's error output.

Probable causes:

Interchange user ID doesn't have keyring

     You must have a .pgp or .gnupg directory in the home directory of
     the user running Interchange. It is also possible to set an
     environment variable (variously PGPPATH or GNUPGHOME) to orient
     the program correctly.

EncryptProgram directive set wrong

     In Interchange 4.7.7 and above, you only need specify "gpg",
     "pgp", or "pgpe". The key is set in EncryptKey. If you don't set
     a value for EncryptProgram, Interchange will look for gpg first,
     then pgpe, then finally pgp, using the first it finds. If it
     can't find one of those, it is set to none and encryption can't
     be done. You can specify a full path to the program in the
     directive, but no arguments need be set. NOTE: old values in
     EncryptProgram will still work, just are not needed.

65.2. PGP encryption -- What do I do now that it is working?
------------------------------------------------------------

This depends on what you do with orders once you receive them by
email. Some PC mail agents (notably Eudora) will decrypt the PGP
message embedded within the message text. In that case, you can simply
embed the [value mv_credit_card_info] call right in the message and be
done with it.

If your mailer will not decrypt on the fly, the best way to read the
credit card number is to set up MIME encoding of the order email. To
do this, find the order report you are using. In the standard demos it
is pages/ord/report.html or etc/report.

Set up two MIME regions in that file. First, at the top of the file:

   [tag mime type TEXT/PLAIN; CHARSET=US-ASCII][/tag]
   [tag mime Order Text]

   ORDER DATE: [calc]localtime[/calc]
   ORDER NUMBER: [value mv_order_number]

   Name: [value name]
   Company: [value company]

   (Rest of order text, including item list)
   [/tag]

Then, at the bottom of the report.html file, put the credit card info:

   [if value mv_credit_card_info]
   [tag mime type application/pgp-encrypted][/tag]
   [tag mime Credit Card Information]

   [value mv_credit_card_info]

   [/tag]
   [/if]

Once this is done, you can read mail using your PGP client as a helper
application to decode the MIME attachment. This does not require a
fancy setup -- you can use the standard MIT PGP 2.6.2 if desired. If
you are using UNIX, set up as the helper for the MIME type
application/pgp-encrypted:

   xterm -e pgp -m %s

More automated or user-friendly setups are left as an exercise for the
user.

66. How do I....
================

66.1. How do I get the number of items in a shopping cart?
----------------------------------------------------------

If it is simply the total number, extended according to quantity, you
can use the [nitems] tag. If you need this number for use in an
embedded Perl script, you can use:

   $number = $Tag->nitems();

If it is the number of line items you need, then you can use a Perl
script:

   [perl]
       return scalar @{$Carts->{main}};
   [/perl]

(The 'main' refers to the main shopping cart.)

If you have SeparateItems in effect, and need the number of unique
items, you could use:

   [perl]
       my $cart = $Carts->{main};
       foreach my $item (@$cart) {
   @items = split /\|/, $items;
   $count = 0;
   for (@items) {
   $count++ unless $seen{$_}++;
   }
   $count;
   [/perl]

66.2. How do I delete an item from the cart in Perl?
----------------------------------------------------

(Answered by Racke)

[calc] @$Items = grep {$_->{code} ne '123.456.789'} @$Items [/calc]

66.3. The demo doesn't do ... (pick one)
----------------------------------------

That is because it is a demo. It is not intended to be a finished
catalog, just a starting point.

66.4. How can I trace the source of a purchase and run a partners program?
--------------------------------------------------------------------------

Interchange has a facility that adds a parameter called source to the
session database for that user. You should give your partners a source
code, which must contain at least one letter character (A-Za-z only).
It is placed in the sourcing URL as a query string of:

   mv_pc=Source1

If this is appended to the URL with which the user calls Interchange,
it will then be placed in the session identifier source.

This URL:

http://yourcatalog.com/cgi-in/yourcat/sp_offer?mv_pc=Source1

will yield Source1 from the Interchange tag [data session source].

The Minivend 3 idiom ?;;Source1 continues to be supported, so existing
partner sites should work without change.

66.5. How can I send an email copy of the receipt to a user?
------------------------------------------------------------

There are several ways, but this is a more complex question than it
may seem like it is. You will have to deal with bad email addresses,
deciding which information to send, showing delivery times, etc. You
also have to be very careful with credit card information. If you have
not taken the proper security measures (by enabling PGP credit card
encryption or using CyberCash), you might just mail them their own
unencrypted credit card number!

This is supported in Interchange via a UserTag, [email ...]. See the
"simple" and "basic" demos.

66.6. How do I display Euro pricing?
------------------------------------

You can use Interchange's II8N facilty via the Locale directive. In
catalog.cfg:

# to define the euro-Settings (PriceDivide is for converting from DM)
Locale eur_EUR PriceDivide         1.95583
Locale eur_EUR p_cs_precedes       0
# this is great - you can even use HTML-Tags to display an euro-image
Locale eur_EUR currency_symbol     "<IMG src="/path/to/image/euro.gif">"
Locale eur_EUR p_sep_by_space      2
Locale eur_EUR mon_decimal_point   ,

# and the DM
Locale de_DE
Locale de_DE p_cs_precedes  0
Locale de_DE p_sep_by_space 2

Note: Be sure to use the latest exchange rates when you establish your
catalog.

On your pages (this is from a search results page, the [item-.... ...]
notation may be different depending on your context):

[item-price]<br><!-- german is default -->
[setlocale eur_EUR]
  [currency convert=1][item-field price][/currency]<br><!-- the euro -->
[setlocale]

Any questions? Read the docs about "Internationalization."

66.7. How do I empty the shopping cart?
---------------------------------------

Here are three examples of ways to empty/drop/clear the shopping cart
contents.

66.7.1. Empty shopping cart
---------------------------

[calc]
        @{$Carts->{$CGI->{mv_cartname} || 'main'}} = ();
[/calc]

66.7.2. Empty shopping cart
---------------------------

[set clear_basket]
        [calc]
                @{$Carts->{$CGI->{mv_cartname} || 'main'}} = ();
        [/calc]
[/set]

[button
        text="Clear Basket"
        src="clear_basket.gif"
        hidetext=1
        form=basket
        ]
                mv_todo=refresh
                mv_click=clear_basket
[/button]

66.7.3. Erase the user session (includes shopping cart)
-------------------------------------------------------

[button
        text="Clear Basket"
        src="clear_basket.gif"
        hidetext=1
        form=basket
        ]
                mv_todo=cancel
                mv_nextpage=index
[/button]

66.8. How do I e-mail credit card numbers in plain text?
--------------------------------------------------------

(Answered by Mike Heins)

The position of ICDEVGROUP is that we will not tell you what you can
and cannot do, but that we simply will not help you send unencrypted
CC numbers by email.

66.9. How do I setup multiple shipping addresses?
-------------------------------------------------

Interchange has the facility to handle multiple addresses. See the
User Database Functions section of the Interchange Database manual.

66.10. How do I change the order number from TEST0001, TEST0002 to something else?
----------------------------------------------------------------------------------

(Answered by Aaron Hazelton & Paul Jordan)

o    Go to the IC admin and click on "Administration" then click on
     the 'last order' which will be something like "TEST00001".  It
     will bring up a page which will allow you to change it to
     whatever you want.

o    Or, modify the CATROOT/etc/order.number

66.11. How do I move a catalog from a test server to a production server?
-------------------------------------------------------------------------

(Answered by Jonathan Clark)



1) copy the complete catalog root with all files and subfolders.

2) make sure the permissions are appropriate (interchange daemon user
needs rw access to all of it.

3) link <catroot>/error.log to /var/logs/interchange/catalog/error.log
or wherever.

4) link catroot/images to images folder in your public html space.

5) link the admin ui images folder 'interchange' in public html space
to actual location.

6) copy any global usertags which are not in your catalog structure.

7) edit the variable.txt to set appropriate domain names if these have
changed.

8) if using MySQL/Postgres/Oracle, set up database access.

9) put a link program in your cgi-bin, make sure it is chmod u+s and
owned by the interchange daemon user.

10) add the catalog to the interchange.cfg file.

11) restart ic.

12) check global error.log for any error messages.

66.12. How do I access the raw match count?
-------------------------------------------

(Answered by Kevin Walsh)



[value mv_search_match_count]

66.13. How do I add the thumbnail to the results page?
------------------------------------------------------

(Answered by Ed LaFrance & Dan Browning)

It's as easy as <img src="thumb/[item-field thumb]">, but you may want
to add a check to see if the image is actually there before you try to
display it:

[if file images/thumb/[item-field thumb]]
        <img src="thumb/[item-field thumb]">
[/if]

For example:

--- results.html.orig   Sat Jun 29 21:25:49 2002
+++ results.html        Sat Jun 29 21:28:57 2002
@@ -100,6 +100,7 @@

 <table width="90%" border="0" cellspacing="0" cellpadding="3">
 <tr class="contentbar2">
+  <td>&nbsp;</td>
   <td><b>&nbsp;Product</b></td>
   <td align="center"><b>SK/b</td>
   <td align="center"><b>Stock</b></td>
@@ -120,6 +121,11 @@

 <tr valign="middle">
       <td>
+                  [if file images/thumb/[item-field thumb]]
+                     <img src="thumb/[item-field thumb]">
+                  [/if]
+      </td>
+      <td>
        <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="[item-code]">
        <a href="[area [item-code]]">[item-description]</a>
       </td>

66.14. How do I do a random display of items?
---------------------------------------------

(Answered by Bill Carr)

If you are using mysql (and others probably), you should be able to
add "ORDER BY RAND()" to your SQL query.  For example:

[query
   list=1
   sql=|SELECT * FROM products ORDER BY RAND() LIMIT 3|
]
[list]
        [sql-param description]<br>
[/list]
[/query]

66.15. How do I setup a new real time payment processor that isn't yet supported by Interchange?
------------------------------------------------------------------------------------------------

If the payment processor that you would like to use isn't supported by
Interchange out of the box, then a new payment module would need to be
developed for that processor before you could use them.

If you are up to the task of programming a new payment processor
module yourself, the ICDEVGROUP would be happy to add your
contribution to the growing list of Interchange-supported payment
processors.  Feel free to take a look at the lib/Vend/Payment
directory to see examples of current payment modules.

If developing the module on your own isn't an option, you may engage a
competent Interchange developer to do it for you or use one of the
already-supported payment modules.

66.16. How do I modify orders after they are placed, change items, shipping, etc.?
----------------------------------------------------------------------------------

Example question:  "Occasionally, I need to modify orders... Add an
Item, Change shipping, etc.   What is the best way or how can it be
done?"

The Foundation template does not have this functionality "out of the
box".  While one can manually modify the tables via the Admin UI, it
would not cause IC to automatically recalculate subtotals, tax,
shipping, etc. to account for the  modifications.

Until someone gets the "itch" to program that feature into the Admin
UI, some users are solving the problem by handling all of these
modifications in a Back Office / Accounting / ERP software system. 
For example, IC comes with "out of the box" support for integration
with Quickbooks.  At that point, however, it becomes necessary to
analyze what (if any) syncronization will be performed between the two
systems.

66.17. How do I make or get a certificate for SSL?
--------------------------------------------------

This is handled separately and independantly from Interchange, and
there are lots of documentation on buying and installing certificates
for your platform and http server, as well as generating certificate
signing requests (CSR).  Companies such as GeoTrust and Thawte sell
certificates, and often have some documentation on what the process
entails.  The Apache, mod_ssl, and OpenSSL user groups may be of
assistance as well.

While it is technically feasible to generate your own self-signed
certificate, modern browsers will display a warning if the certificate
is not signed by a signing authority known to that browser.

66.18. How do I perform multi-table SQL queries and/or joins using dot notation?
--------------------------------------------------------------------------------

(Answered by Mike Heins)

Example question: "How come I can't use [sql-param
tablename.fieldname] notation when I do a multi-table query?"

DBI simply does not support tablename.fieldname in the return value.

You can just refer to them by the fieldname. In the case of field
names that are the same but need to be selected from different tables,
you can use "SELECT orderline.quantity as o_quan,..." and refer to it
as [sql-param o_quan].

66.19. How do I modify the Save Cart and Recurring Cart feature?  How do they work?
-----------------------------------------------------------------------------------

The code for these features is in templates/components/cart.  The
relative portion that is executed first when you call the basket page
is this:

      [button
          text="Save This Cart"
          src="__THEME__/savecart.gif"
          extra="class=contentbar2"
          hidetext=1
          form=basket
          mv_check="Save This Cart"
      ]
          mv_todo=return
          mv_nextpage=ord/basket
          save_cart=cart
      [/button]
      [button
          text="Set As Recurring Order"
          src="__THEME__/saverecur.gif"
          extra="class=contentbar2"
          hidetext=1
          form=basket
          mv_check="Set As Recurring Order"
      ]
          [set save_cart]recurring[/set]
          mv_todo=return
          mv_nextpage=ord/basket
          save_cart=recurring
      [/button]

This creates two buttons that set save_cart to either 'cart' or
'recurring', then go to the ord/basket page (where you are already). 
When clicked, one of these two code blocks will be executed:

 [if value save_cart eq 'recurring']
            <FORM ACTION="[process-target]" METHOD=POST>
            To save this recurring order, give it a nickname, then press 'Save Cart'.<br>
            Nickname:
            <INPUT TYPE=TEXT NAME="c_nickname" SIZE=11 VALUE="[scratch just_nickname]">
            <input type=hidden name=mv_session_id value="[data session id]">
                        <INPUT TYPE=HIDDEN NAME="c_recurring" VALUE="1">
            <INPUT TYPE=HIDDEN NAME="save_cart" VALUE="recurring">
            <INPUT TYPE=HIDDEN NAME="mv_todo" VALUE="return">
            <INPUT TYPE=HIDDEN NAME="mv_check" VALUE="Save Cart">
            <INPUT TYPE=SUBMIT VALUE="Save Cart">
            </FORM>
  [elsif value save_cart eq 'cart']
            <FORM ACTION="[process-target]" METHOD=POST>
            To save this cart, give it a nickname, then press 'Save Cart'.<br>
            Nickname:
            <INPUT TYPE=TEXT NAME="c_nickname" SIZE=11 VALUE="[scratch just_nickname]">
            <INPUT TYPE=HIDDEN NAME="c_recurring" VALUE="0">
            <INPUT TYPE=HIDDEN NAME="save_cart" VALUE="cart">
            <INPUT TYPE=HIDDEN NAME="mv_todo" VALUE="return">
            <INPUT TYPE=HIDDEN NAME="mv_check" VALUE="Save Cart">
                        <input type=hidden name=mv_session_id vlaue="[data session id]">
            <INPUT TYPE=SUBMIT VALUE="Save Cart">
            </FORM>
  [/elsif]

The "nickname" for the cart is set earlier via:

[if !scratch just_nickname]
  [seti just_nickname][tag time]%b-%d-%Y[/tag][/seti]
[/if]

The real work is done because of this:  <INPUT TYPE=HIDDEN
NAME="mv_check" VALUE="Save Cart"> which calls the following code
after the the user clicks "Save Cart":

  [set Save Cart]
   mv_todo=return
   mv_nextpage=ord/basket
   save_cart=none
   [save_cart nickname="[value c_nickname]" recurring="[value c_recurring]"]
  [/set]

Which in turn calls the usertag "save_cart" with a nickname parameter
and a recurring parameter.  Depending on which button was clicked,
recurring will either be 0 (for "Save This Cart") or 1 (for "Set As
Recurring Order").  The save_cart usertag adds the cart to the
userdb.carts field as a Perl data structure (hashes, arrays, etc.).

67. Errors
==========

67.1. Sorting doesn't work across multiple pages.
-------------------------------------------------

If you are using the [sort table:field] idiom, it cannot. It sorts
data present in the list only.

67.2. I am searching for a string and it is not found. I know it is there!
--------------------------------------------------------------------------

Set mv_substring_match to yes (su=yes in one-clicks). This most
commonly happens when searching for non-ISO-8859 (Cyrillic, or
characters like umlaut and eacute) characters in word-match mode. The
problem is, that unless your locale is set up properly, Perl doesn't
think a non-ISO-8859 and a space character is a boundary.

Also, if you are searching for non-alpha characters, they will also
not be interpreted as word characters and the boundary problems will
still exist.

68. Performance Issues
======================

Interchange is not a lightweight program. If you are running it on a
low-end ISP, whose major selling point is low cost, you will
frequently find that Interchange performance is very poor. This is due
to either:

Not enough memory

     If memory is low, the program will "swap" to disk. If lots of
     swap is used, you can expect very bad performance. This is the
     most common speed problem.

     If your ISP uses IDE hard disks, you can expect REALLY bad
     performance. IDE disks are very slow for multi-user machines,
     which should have SCSI if ANY swapping is to be done.

Too many domains

     If there is a huge amount of traffic on the system, then it can
     run at a very high "load average." If the machine's load average
     is routinely above 2, you can expect problems.

Underpowered machine

     If it is an old machine, it may be too slow for Interchange. A
     Pentium of less than 300MHz is probably not good enough unless it
     is completely dedicated to Interchange. The faster the processor,
     the happier you will be.

68.1. Interchange runs, but it's sooo sllooowww...
--------------------------------------------------

This is almost certainly due to a system that has inadequate memory or
network bandwidth. On a moderately fast ISP server with sufficient
memory, pages should start displaying in less than 2 seconds. On a
fast server, pages should start loading almost instantaneously.

68.2. Interchange slows down over time.
---------------------------------------

There are many possible reasons for this, but most have to do with
memory or session database size.

o    See the documentation on Interchange administration (icadmin) and
     learn how to expire your session database. If it is megabytes in
     size, accessing a key will significantly slow down the session.

o    Second, if your machine is memory-poor, you will find that
     Interchange gets swapped to disk. Unless your system is very
     fast, this will greatly hurt performance. Interchange works best
     on a machine that rarely if ever swaps to disk.

o    Third, this often has nothing to do with Interchange at all but
     has to do with your HTTP server. Any long-running daemon has the
     potential for a memory leak. Try stopping and starting your HTTP
     server and seeing what happens to performance.

68.3. I am using SQL, and Interchange is slow ...
-------------------------------------------------

It isn't Interchange. First of all, did you index your 'SKU' or other
key fields? The reason Interchange doesn't do it for you is that every
SQL database seems to do that a bit differently. Even then, you can
try Interchange's COLUMN_DEF parameter:

Database  products  COLUMN_DEF  code=char(16) PRIMARY KEY

This will at least index the code field for MySQL. Other databases
differ.

Interchange can return VERY fast SQL search results. But you need to
at least give it something to work with. The proper method for fast
selection is:

[query sql="select code,category,title,price from products" ]

Category: [sql-param category]<BR>
Title:    <A HREF="[area [sql-code]]"> [sql-param title] </A><BR>
Price:    <A HREF="[area order [sql-param 0]]"> [sql-param price] </A><BR>

[/sql]

This is especially powerful when you consider a joined query like:

       SELECT code, price, title, extended.desc
       FROM   products, extended
       WHERE  products.category = 'Renaissance'

Note that the extended.desc field will be accessed as [sql-param
desc]. Don't forget that you must index your fields if you want fast
searching with them as a criteria.

69. Using Interchange with Apache and SUEXEC
============================================

Apache with SUEXEC: VLINK/UNIX socket mode will not work well unless
installed as a normal user. If supporting multiple users, the
TLINK/INET mode must be used.

70. A friendly reminder
=======================

When in doubt, restart the server. It won't take but a few seconds,
and changes in configurable options don't take effect until it is
done. You may even change a page and not see the effect until the
server is restarted.

71. Tips and tricks
===================

These are slightly edited postings to the Interchange-users mail list
made by Mike Heins, lead author of Interchange.

71.1. Locking down your system
------------------------------

Interchange has lots of built-in protections to make developing your
catalogs pretty care-free. But it will definitely pass you the ammo to
shoot yourself in the foot, as will any templating system that has
power. So you have to be careful, as you do in any scripting
environment.

Most of the protections have to do with:

14.  Tags like [cgi foo], [data ...] and such are not reparsed for
     tags.

15.  The [value foo] tag never allows a left square bracket to be
     output.

16.  Safe is used for Perl, which means that arbitrary perl code which
     reads/writes or uses IO is not possible.

17.  The Interchange files don't need to be readable or writable by
     any other user ID, so CGI/PHP programs run by the web server
     can't get at them.

18.  Dangerous operations are allowed only via global UserTag, and not
     by catalog UserTag.

But there are ways that user-entered data could end up getting parsed
for tags. The most common breach is to take possibly tainted user data
entered into a form and put it in a database without filtering it
first. There are several ways to do that:

o    For user-entered form fields like name, address, etc you should
     always use the [value ...] tag to display them.

o    You can filter lists of variables automatically with

         Filter  name     textarea_put
         Filter  address  textarea_put
         Filter  comments textarea_put
         Filter  email    textarea_put

     in catalog.cfg.

o    You can prevent problems in some cases by using the data tag
     (i.e. [data table=foo col=bar key="[item-param something]"])
     which is not reparsed for tags as [item-data ....] is. This is
     not foolproof unless you control the key in some fashion -- in
     most cases, you will use [data session username] or something you
     control.

o    You should never put user-entered data directly in a Scratch
     variable, which can be called with mv_click and mv_check.

o    Process all user-entered data before putting it in a database
     that could be displayed in a page later. Or process it before it
     is displayed.

o    When putting data inside a container tag, the output of which is
     reparsed for more tags by default, consider setting reparse=0.

There are other ways to nail down your system and make it more
difficult to have a security problem.

o    Use the WRITE_CONTROL database settings.

       Database products WRITE_CONTROL 1

     It is the default for MV DBM databases (i.e. you have to have a
     [flag type=write table=foo] to write) but not for SQL.

     The UI does the proper write flagging, so this should have no
     effect on it.

     AUTHORS NOTE: I should have made WRITE_CONTROL the default for
     SQL in MV4, my bad. As long as MV3 compatibility was as poor as
     it turned out to be, I should have gone for it.

o    Set "NoAbsolute Yes" in interchange.cfg, it prevents [file
     /some/dir] or [include /some/rogue/file] from being used. NOTE:
     This is the default starting in IC 4.7.x.

o    Split the admin server onto a different IC iteration from your
     production catalog, and disable the UI for the production
     catalog. That allows you to set the pages/ directory to be
     read-only for the production server, and to put WRITE_CONTROL in
     the production catalog_after.cfg or etc/<catalog id>.after file.

     You could also use a different username to access the SQL data,
     and make the production server username have read-only access.

     You can use a different UID for the admin server iteration, and
     make all directories except products/, upload/, tmp/, session/,
     and logs/ read-only for the production server UID.

o    Make as much stuff read-only as you can. Develop a script which
     sets things read-write while you are admin-ing, and read-only
     otherwise.

o    Always make ICDIR/*.cfg, ICDIR/bin/*, and ICDIR/lib/* read-only
     for the IC user.

o    Don't let the interchange daemon user ID have read or write
     permission on things it doesn't need.

o    Never use AllowGlobal in production if you have user-entered data
     going into a database. (AllowGlobal is not the default, so many
     people won't know what it is -- see Interchange Configuration.)

All in all, Interchange has been proven to be securable over time. But
we all have to do our part and think about what we are doing with
user-entered data.

71.2. Optimizing lists
----------------------

Interchange has powerful search capabilities that allow you to produce
lists of items for use in category lists, product lists, indexes, and
other navigation tools.

These are a two-edged sword, though. Lists of hundreds or thousands of
entries can be returned, and techniques that work well displaying only
a few items may slow to a crawl when a large list is returned.

In general, when you are returning one item (i.e. a flypage) or a
small list (i.e. a shopping cart) you can be pretty carefree in your
use of [if ...] and [calc] and [perl] tags. When there are hundreds of
items, though, you cannot; each complex test or embedded Perl snippet
causes the Safe module to have to evaluate code, and each ITL tag
requires parsing and argument building.

The Safe module is pretty fast considering what it does, but it can
only generate a few thousand instances per second even on a fast
system. And the ITL tag parser can likewise only parse thousands of
tags per CPU second.

What to do? You want to provide complex conditional tests but you
don't want your system to slow to a crawl. Luckily, there are
techniques which can speed up complex lists by orders of magnitude.

71.2.1. Benchmarking
--------------------

A non-precise benchmark of different iteration options can be done
with the following global UserTag. Place this in a file in the
usertag/ directory in the Interchange root:

UserTag benchmark Order start display
UserTag benchmark AddAttr
UserTag benchmark Routine <<EOR
my $bench_start;
my @bench_times;
sub {
    my ($start, $display, $opt) = @_;
    my @times = times();
    if($start or ! defined $bench_start) {
        $bench_start = 0;
        @bench_times = @times;
        for(@bench_times) {
            $bench_start += $_;
        }
    }
    my $current_total;
    if($display or ! $start) {
        for(@times) {
            $current_total += $_;
        }
        unless ($start) {
            $current_total = sprintf '%.3f', $current_total - $bench_start;
            for(my $i = 0; $i < 4; $i++) {
                $times[$i] = sprintf '%.3f', $times[$i] - $bench_times[$i];
            }
        }
        return $current_total if ! $opt->{verbose};
        return "total=$current_total user=$times[0] sys=$times[1] cuser=$times[2] csys=$times[3]";
    }
    return;
}
EOR

Then at the beginning of the code to check, call

        [benchmark start=1]

to start the measurement. At the end

        [benchmark]

will display the time used. Bear in mind that it is not precise, and
that there may be variation due to system conditions. Also, the longer
the times and the bigger the list, the better the comparison.

To see the system/user breakdown, do:

        [benchmark verbose=1]

In general, "user" time measures Interchange processing time and and
the rest are indicative of the database access overhead, which can
vary widely from database to database.

71.2.2. Optimizations
---------------------

o    [PREFIX-tag] is faster than [parsed-tag]

                [loop prefix=foo search="ra=yes"]

                        [foo-data products image]
                                is slightly faster than
                        [foo-field image]
                                which is MUCH faster than
                        [data products image [foo-code]]
                                which is faster than
                        [data table=products column=image key="[foo-code]"]

                [/loop]

The loop tags are interpreted by means of fast regular expression
scans of the loop container text, and fetch an entire row of data in
one query. The [data ...]  ITL tag interpretation is delayed until
after the loop is finished, whereby the ITL tag parser must find the
tag, build a parameter list, then fetch the data with a separate
query. If there are repeated references to the same field in the loop,
the speedup can be 10x or more.

o    Pre-fetch data with rf=field1,field2,field3 and access with
     [PREFIX-param field1].

mv_return_fields (otherwise known as "rf" in one-click terminology)
sets the fields that are returned from a search. Once they are
returned, they can be accessed with [PREFIX-param field]. They can
also be referenced with [PREFIX-pos N], where N is a digit
representing the ordinal position (i.e. starting with 0) in the list
of fields.

The following are equivalent:

        Benchmark loop-field list: [benchmark start=1]
        <!-- [loop search="ra=yes/st=db"]
                [loop-code] price: [loop-field price] [/loop] -->
        TIME: [benchmark]

        Benchmark loop-param list: [benchmark start=1]
        <!-- [loop search="ra=yes/st=db/rf=sku,price"]
                [loop-code] price: [loop-param price] [/loop] -->
        TIME: [benchmark]

but the second is much, much faster.

o    [PREFIX-alternate N] is available for row counting and display.

A common need when building tables is to conditionally close the table
row or data containers. I see a lot of:

        [loop search="ra=yes"]
        [calc] return '<TR>' if [loop-increment] == 1; return[/calc]
        [calc] return '' if [loop-increment] % 3; return '</TR>' [/calc]
        [/loop]

Much faster, by a few orders of magnitude, is:

        [loop search="ra=yes"]
        [loop-change 1][condition]1[/condition]<TR>[/loop-change 1]
        [loop-alternate 3]</TR>[/loop-alternate]
        [/loop]

        If you think you need to close the final row by checking the
        final count, look at this:

        [loop search="ra=yes"]
        [on-match]
                <TABLE>
                <TR>
        [/on-match]

        [list]
                        <TD>[loop-code]</TD>
                [loop-alternate 3]</TR><TR>[/loop-alternate]
        [/list]

        [on-match]
                </TR>
                </TABLE>
        [/on-match]

        [no-match]
                No match, sorry.
        [/no-match]

[/loop]

This is a hundred times faster than anything you can build with
multiple [calc] tags.

o    Use simple go/nogo comparisons in [if ...]

Consider these two snippets:

        [if scratch|value|cgi key] THEN [/if]

and:

        [if scratch|value|cgi key == '1'] THEN [/if]

The first one doesn't require Perl evaluation. It simply checks to see
if the value is blank or 0, and returns true if it is anything but. Of
course this requires setting your test values to blank or 0 instead of
"No" or " " or somesuch, but it is anywhere from 20-35% faster.

Try it on the foundation demo:

        ---- begin test ---

        Overhead:
        [benchmark start=1]
                <!-- [loop search="ra=yes"][set cert][loop-field gift_cert][/set][/loop] -->
        [benchmark]
        <P>


        if scratch compare:
        [benchmark start=1]
                <!--
                [loop search="ra=yes"]
                [set cert][loop-field gift_cert][/set]
                [loop-code] [if scratch cert] YES [else] NO [/else][/if]
                [loop-code] [if scratch cert] YES [else] NO [/else][/if]
                [loop-code] [if scratch cert] YES [else] NO [/else][/if]
                [loop-code] [if scratch cert] YES [else] NO [/else][/if]
                [loop-code] [if scratch cert] YES [else] NO [/else][/if]
                [/loop]
                -->

        [benchmark]
        <P>

        if scratch compare eq 1:
        [benchmark start=1]
                <!--
                [loop search="ra=yes"]
                [set cert][loop-field gift_cert][/set]
                [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
                [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
                [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
                [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
                [loop-code] [if scratch cert == 1] YES [else] NO [/else][/if]
                [/loop]
                -->
        [benchmark]
        <P>

        [page @@MV_PAGE@@]Again</a>

        ---- end test ---

o    Use [PREFIX-calc] instead of [calc] or [perl]

You can execute the same code as [calc] with [PREFIX-calc], which has
two benefits:

19.  It doesn't require ITL parsing.

20.  It is executed during the loop instead of after it.

The [PREFIX-calc] object has complete access to all normal embedded
Perl objects like $Values, $Carts, $Tag, and such. If you want to make
a data table (i.e. "products" or "pricing") available for access
inside of it, just do:

        [perl tables="products pricing"] [/perl]

prior to list start. Now you can do something like:

    [loop search="ra=yes"]
        [loop-calc]
            $desc = $Tag->data('products', 'description', '[loop-code]');
            $link = $Tag->page('[loop-code]');
            return "$link $desc </A>";
        [/loop-calc] <BR>
    [/loop]

o    ADVANCED: Precompile and execute with [PREFIX-sub] and
     [PREFIX-exec]

For repetitive routines, you can achieve a considerable savings in CPU
by pre-compiling your embedded Perl code.

In the "Construct Something" demo, the bar_link() routine in
catalog_before.cfg is an example of compiling the subroutine once at
catalog configuration time.

You can also compile routines at the time of the list execution with
[item-sub routine] CODE [/item-sub]. This means only one Safe
evaluation is done -- every time the [loop-exec routine] is called, it
is done fast as a call to the routine. This can be 10 times or more
faster than separate [calc] calls, or 5 times faster than separate
[PREFIX-calc] calls.

     Example:

        [benchmark start=1]
        loop-calc:
          <!--
                [loop search="st=db/fi=country/ra=yes/ml=1000"]
                [loop-calc]
                        my $code = q{[loop-code]};
                        return "code '$code' reversed is " . reverse($code);
                [/loop-calc]
                [/loop]
          -->

        [benchmark]

        <P>

        [benchmark start=1]
        loop-sub and loop-exec:
          <!--
                [loop search="st=db/fi=country/ra=yes/ml=1000"]
                [loop-sub country_compare]
                        my $code = shift;
                        return "code '$code' reversed is " . reverse($code);
                [/loop-sub]
                [loop-exec country_compare][loop-code][/loop-exec]
                [/loop]
          -->

        [benchmark]

o    ADVANCED: Execute and save with [query ...], then use an embedded
     Perl routine.

You can run [query arrayref=myref sql="query"], which saves the
results of the search/query in a Perl reference. It is then available
in $Tmp->{myref}. (Of course, "myref" can be any arbitrary name.)

This is the fastest possible method to display a list.

     Observe:

        --- begin test code ---
        [set waiting_for]os28004[/set]

        [benchmark start=1] Embedded Perl
        <!--
        [query arrayref=myref sql="select sku, price, description from products"]
                <!-- make query, this container text is not used. -->
        [/query]

        [perl]
                # Get the query results, has multiple fields
                my $ary = $Tmp->{myref};
                my $out = '';
                foreach $line (@$ary) {
                        my ($sku, $price, $desc) = @$line;
                        if($sku eq $Scratch->{waiting_for}) {
                                $out .= "We were waiting for this one!!!!\n";
                        }
                        $out .= "sku: $sku price: $price description: $desc\n";
                }
                return $out;
        [/perl]
        -->
        TIME: [benchmark]

        [benchmark start=1] All loop
        <!--
        [query list=1 sql="select sku, price, description from products"]
                [if scratch waiting_for eq '[sql-code]']We were waiting for this one!!!!
                [/if] sku: [sql-code]price: [sql-param price] desc: [sql-param description]
        [/query]
        -->

        TIME: [benchmark]

        --- end test code ---

o    Other things that help:

     o    Avoid interpolate=1 when possible. A separate tag parser
          must be spawned every time you do this. Many times people
          use this without needing it.

     o    Avoid saving large values to Scratch, as these have to be
          written to the users session. If you need them only for the
          current page, clear at the end by using [tmp scratch_var]
          contents [/tmp], which is the same as  [seti scratch_var]
          contents [/seti] except clears the value before the session
          is written. You can also use [scratchd scratch_var] to
          return the contents and delete them from the session at the
          same time.

     o    Use the [more-list] facility to break up your large
          searches. You can use them in [query ....] and [loop ...]
          searches as well -- see the docs.

72. Using Interchange with Oracle
=================================

Question: should we be using the DBI ChopBlanks setting for Oracle or
is Interchange trimming trailing space from CHAR fields itself?

IC daemon user should have environment variables ORACLE_HOME and
possibly NLS_LANG set.

Mark Johnson (mark@endpoint.com) wrote this trigger on TABLE_NAME to
update the MOD_TIME column on insert or update. The user must have
been granted the RESOURCE role to create triggers. Here it is:

CREATE TRIGGER tr_modtime_for_TABLE_NAME BEFORE INSERT OR UPDATE ON
TABLE_NAME FOR EACH ROW BEGIN

new.MOD_TIME := SYSDATE; END; /

73. Using Interchange with PostgreSQL
=====================================

Make sure you have DBD::Pg installed and tested. Make sure
POSTGRES_INCLUDE and POSTGRES_LIB environment variables are set.

74. Using Interchange with MySQL
================================

Permissions. test_ databases usually special.

75. Using Interchange with Apache
=================================

Slightly modified article posted to the old minivend-users mail list.
Minivend-users is now interchange-users.

Date: Thu, 7 Sep 2000 12:08:37 -0700
From: Bill Randle <billr@exgate.tek.com>
To: minivend-users@minivend.com
Subject: Re: [mv] no /cgi-bin/storename/

On Sep 6,  5:13am, Victor Nolton wrote:
} Subject: [mv] no /cgi-bin/storename/
} ******    message to minivend-users from Victor Nolton <ven@pragakhan.com> ******
}
} I've noticed some of the catalogs I've done are not indexed well with
} the search engine, though most pages have meta tags, there is a
} robot.txt file and so on and so forth.I assume it's due to the
} cgi-bin in the url (not sure).
}
} I'd like to start having stores be like
}
} http://www.yourdomain.com/index.html
} http://www.yourdomain.com/ord/basket.html
} instead of
} http://www.yourdomain.com/cgi-bin/yourstore/index.html
} http://www.yourdomain.com/cgi-bin/yourstore/ord/basket.html
}
} how do you accomplish this? I assume it can be done somehow.

In addition to using mod_minivend, previosuly suggested, you can do this
with Apache rewrite rules in the VirtualHost directive for yourdomain.com:

<VirtualHost a.b.c.d>
    ServerAdmin support@mainhost.com
    DocumentRoot /home/httpd/html/yourstore
    ServerName www.yourdomain.com
    ErrorLog logs/yourdomain-error_log
    CustomLog logs/yourdomain-access_log common
    ScriptAlias /cgi-bin/ "/home/httpd/cgi-bin/"
    RewriteEngine On
    RewriteRule ^$  /cgi-bin/yourstore/index.html            [PT,L]
    RewriteRule ^/$ /cgi-bin/yourstore/index.html            [PT,L]
    RewriteRule ^/index\.html$ /cgi-bin/yourstore/index.html [PT,L]
    RewriteRule ^/cgi-bin/yourstore/.* -                     [PT,L]
    RewriteRule ^/.*images/.* -                              [PT,L]
    RewriteRule ^/(.*) /cgi-bin/yourstore/$1                 [PT,L]
</VirtualHost>

I just did this for a client and it works quite well (as long as you're
using a fairly recent version of Apache as your webserver).

        -Bill

76. Perl/Interchange FAQ
========================

76.1. Cameron Prince's local Perl installation how-to
-----------------------------------------------------

21.  Login as user. In this example, we'll call the user bob. Bob's
     home directory is /home/bob.

22.  Get the perl tarball and extract it in /home/bob. (tar -xzvf
     perl-5.6.0.tar.gz)

23.  Create a directory for the local perl. (mkdir
     /home/bob/local-perl)

24.  Compile perl.

     1.   cd perl-5.6.0

     2.   sh Configure

     3.   Choose all the defaults until you get to: "Directories to
          use for library searches?" Here you want to enter the new
          local perl path, as well as the defaults. So you should
          enter something like: /home/bob/local-perl/lib
          /usr/local/lib /lib /usr/lib

     4.   Continue choosing defaults till you get to: "Any additional
          ld flags (NOT including libraries)?" This should be:
          -L/home/bob/local-perl/lib

     5.   Continue choosing defaults till you get to: "Installation
          prefix to use? (~name ok)" This should be:
          /home/bob/local-perl

     6.   Choose all defaults till you get to: "Directory
          /home/bob/local-perl/bin doesn't exist.  Use that name
          anyway?" Enter y.

     7.   Continue choosing defaults till you get to: "Do you want to
          install perl as /usr/bin/perl?" Enter n.

     8.   Continue choosing defaults till you get to: "Directory
          /home/bob/local-perl/bin doesn't exist.  Use that name
          anyway?" Enter y.

     9.   Directory /home/bob/local-perl/bin doesn't exist.  Use that
          name anyway? Enter y.

     10.  Continue taking defaults till you return to a prompt.

     11.  make

     12.  make test

     13.  make install

25.  /home/bob/local-perl/bin/perl -v

     You should see: This is perl, v5.6.0

26.  edit /home/bob/.bash_rc

     Change: PATH=$PATH:$HOME/bin

     To: PATH=/home/bob/local-perl/bin:$PATH:$HOME/bin

27.  Logout and log back in.

28.  which perl

     You should see: ~/local-perl/bin/perl or
     /home/bob/local-perl/bin/perl

29.  perl -MCPAN -e 'install Bundle::Interchange'

     Keep running this until you see:

MD5 is up to date.
MIME::Base64 is up to date.
URI is up to date.
Net::FTP is up to date.
MIME::Base64 is up to date.
Digest::MD5 is up to date.
HTML::Tagset is up to date.
HTML::Parser is up to date.
HTML::HeadParser is up to date.
LWP is up to date.
Term::ReadKey is up to date.
Term::ReadLine::Perl is up to date.
Business::UPS is up to date.
SQL::Statement is up to date.
Storable is up to date.
DBI is up to date.
Safe::Hole is up to date.

You may need to get the modules via ftp and install them by hand. For
instance, during the test used to create this document, I had to get
URI and LWP and install by hand before everything reported that it was
up to date. To do this, follow these steps:

     14.  ftp ftp.cpan.org

     15.  cd /CPAN/modules/by-module/URI

     16.  bin

     17.  get URI-1.10.tar.gz

     18.  quit

     19.  tar -xzvf URI-1.10.tar.gz

     20.  cd URI-1.10

     21.  perl Makefile.pl

     22.  make

     23.  make test

     24.  make install

Use the same basic steps for any module not properly installed by
using perl -MCPAN -e 'install Bundle::Interchange'

Now, install Interchange as normal.

77. Other / Miscellaneous Questions
===================================

77.1. What does the "mv_pc" variable added to every URL mean?
-------------------------------------------------------------

It can be used to prevent the users' browser from caching dynamic
content, or, combined with the session 'id', it can make every link
unique so that the users behind a proxy (e.g. AOL) will not have
dynamic content cached.

77.2. Where is process.html?
----------------------------

(Answered by Ed LaFrance & Kevin Walsh)

It is in the guts of Interchange. The [process] form action tells
interchange to process the posted form vars according to the action
set with mv_todo. The processing is not associated with any specific
target page (though a page to display when processing is complete can
be specified with mv_nextpage), so Interchange just builds a target
URL that ends in an 'imaginary' page called 'process.html'.

There are other ways to handle a form post. For more information, see
the Form Actions section Interchange Templates manual.

Basically, when you submit a <form> using the [process] tag, you get
sent to the 'imaginary' process.html page.  That page is derived from
the page specified in the form's mv_nextpage CGI submission.

77.3. What PGP / GPG encryption software is available for Windows?
------------------------------------------------------------------

(Answered by Daryl Houston, Jonathan Clark, Aaron Hazelton, Mike Heins
and Michael Goldfarb)

* PGP for various platforms:

     http://www.pgpi.org/products/pgp/versions/freeware/

* WinPT (Windows Privacy Tray)

     http://www.winpt.org

     A universal encrypt/decrypt program that operates generally via
     the clipboard so would be compatable with most programs, but
     there is also an Outlook Express plugin.  It comes with GPG
     (below).

* GPG Windows version

     http://www.gnupg.org/download.html

* MIT distribution of PGP

     http://web.mit.edu/network/pgp.html

     Only for US and Canada for non-commercial use. There may also be
     an international version without those restrictions.

77.4. When are the results_big.html or results_either.html files called/used?
-----------------------------------------------------------------------------

(Answered by Mike Heins)

They are just there as examples and are not used in the demo. If you
don't use them, you can delete them.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Foundation Store
================

78. The Foundation Store
========================

The Foundation store is distributed with Interchange to give you a
starting point with which to build your e-business. While the
Foundation store is designed to be relatively easy to start with, it
is still a full-featured demonstration of a number of Interchange
capabilities. Once you understand the Foundation store and how it
works you are well on your way to understanding the Interchange
software.

The following is a list of some popular features:

Category Searches

     Regardless of the number of products in a catalog, categorizing
     them makes them easier to find. Pick a field in the database,
     typically named category, and classify the products for search
     using Interchange.

Images

     You can display a thumbnail image for the items that have images.
     To do this, add an image field in the database. (See the 'image'
     field of the products database.)

Related Items

     You can embed searches of similar products on an individual
     product display page with the [query ...] or [loop ...] tags. Or,
     if customer data is developed, search a past order database and
     display products that would be of interest to that customer.

Reviews/Testimonials

     You can key the placement of a review or testimonial on the
     existence of a file being in a certain directory. This is
     reasonable to do when a user is viewing a single product.

78.1. Customizing Foundation
----------------------------

The foundation store has been customized to add just about every
ecommerce and content management feature under the sun. If you are
asking the question "can I do ...." the answer is almost assuredly
"Yes".

Note that customizing the foundation store will take some experience
in web design and database operations. Perl experience is also
helpful. Most of all it will take persistence and empowering yourself
to make changes and watch what happens.

It is usually helpful to make a test store, perhaps just an unmodified
copy of foundation, to test out your additions before you make them on
your own store. That way you can try anything you want without the
chance of causing problems on your own store.

79. Tree design
===============

By determining how users will enter and exit the catalog, complex and
intelligent conditional schemes are possible, especially if the
Cookies capability is exercised. However, it is recommended that
simplicity be used. Consumers will not make purchases if they can't
navigate their way around the catalog.

It is important to remember that users will lose their session (and
items in their shopping cart) if their browser does not accept cookies
and they leave the site. Interchange addresses this problem by using
the area and page tags. If you are  using frames, source all frame
panes containing Interchange links from an initial page served by
Interchange. If you don't do this, the user may have multiple session
IDs depending on which frame generated the link.

Note that Interchange can work properly even if the browser doesn't
store cookies. In this situation Interchange inserts a session ID into
each URL; if the ID is preserved as the user navigates from page to
page the session will remain intact.

80. The Catalog Directory
=========================

Interchange pages are contained in the catalog directory. Each
individual catalog has its own base directory. The catalog directory
has the following structure by default:

catalog.cfg

     File containing configuration directives for a particular
     catalog. Configuration settings established in the catalog.cfg
     directory will not effect any other catalogs running under the
     version of Interchange you are using. Subcatalogs can have
     differing information in a file named for that subcatalog.

config

     Directory that will be read when directives are set with the
     filename notation. For example, the file config/static.pages will
     be read when the following directive is encountered in the
     catalog.cfg file.

            StaticPage  <static.pages

     This directory also contains template information used with the
     makecat program.

error.log

     File which contains catalog-specific errors. It is also where any
     syntax errors in embedded Perl code are shown.

etc

     Directory normally used for tracking files, order profiles, and
     other configuration and log information.

pages

     Directory that contains the pages of the catalog. This can be
     considered to be the "document root" of the catalog. Pages
     contained therein are called with the path information after the
     script name. For example:

          /cgi-bin/simple/products/gold will call the page in the file
          pages/products/gold.html.

products

     Directory that contains database source files, including the
     special Interchange databases shipping.asc, pricing.asc (and
     other shipping database files).

session

     Directory that contains session files.

tmp

     The temporary or scratch directory used for various storage
     reasons, like retired ID numbers, search paging files, sort
     tests, import temporary files, etc. This is the default set by
     ScratchDir. It can be redefined to be located on another
     partition.

81. Page Templates
==================

This section describes the files located in the Foundation demo.

81.1. Template File Locations
-----------------------------

This diagram shows the directory and file structure used for the
default Foundation 'templates' directory. The base will be a directory
with the name of your catalog, here called CATROOT.

    CATROOT/
    |
    |----templates/
         |----cart
         |----components/
              |----affiliate_receptor
              |----best_horizontal
              |----best_vertical
              |----cart
              |----cart_display
              |----cart_tiny
              |----category_vertical
              |----cross_horizontal
              |----cross_vertical
              |----modular_buy
              |----modular_update
              |----none
              |----promo
              |----promo_horizontal
              |----promo_vertical
              |----random
              |----random_horizontal
              |----random_vertical
              |----saved_carts_list_small
              |----search_box_small
              |----upsell
              |----upsell_horizontal
              |----upsell_vertical
         |----default --> foundation
         |----foundation/
              |----cart
              |----fullwidth
              |----leftonly
              |----leftright
              |----regions/
                   |----LEFTONLY_BOTTOM
                   |----LEFTONLY_TOP
                   |----LEFTRIGHT_BOTTOM
                   |----LEFTRIGHT_TOP
                   |----NOLEFT_BOTTOM
                   |----NOLEFT_TOP
              |----simple
              |----theme.cfg
         |----fullwidth
         |----leftonly
         |----leftright
         |----regions/
         |----LEFTONLY_BOTTOM
         |----LEFTONLY_TOP
         |----LEFTRIGHT_BOTTOM
         |----LEFTRIGHT_TOP
         |----NOLEFT_BOTTOM
         |----NOLEFT_TOP
         |----sampledata/
         |----computers/
              |----images/
                   |----items/
                        |----generic.gif
                        |----gift_certificate_large.gif
                        |----yourimage.gif
                   |----thumb/
                        |----generic_thumb.gif
                        |----gift_certificate.gif
                        |----thumb.gif
              |----products/
                   |----inventory.txt
                   |----merchandising.txt
                   |----mv_metadata.asc
                   |----options.txt
                   |----pricing.txt
                   |----products.txt
                   |----userdb.txt
         |----reports/
              |----download/
                   |----00352as.pdf
                   |----11993ab.pdf
                   |----22083da.pdf
                   |----49503cg.pdf
                   |----59330rt.pdf
                   |----59402fw.pdf
                   |----66548ch.pdf
                   |----73358ee.pdf
                   |----83491vp.pdf
                   |----90773sh.pdf
              |----products/
                   |----mv_metadata.asc
                   |----products.txt
                   |----userdb.txt
         |----tools/
              |----etc/
                   |----after.cfg
                   |----before.cfg
              |----images/
                   |----items/
                        |----os28004.gif
                        |----os28005.gif
                        |----os28006.gif
                        |----os28007.gif
                        |----os28008.gif
                        |----os28009.gif
                        |----os28011.gif
                        |----os28044.gif
                        |----os28057a.gif
                        |----os28057b.gif
                        |----os28057c.gif
                        |----os28062.gif
                        |----os28064.gif
                        |----os28065.gif
                        |----os28066.gif
                        |----os28068.gif
                        |----os28068a.gif
                        |----os28068b.gif
                        |----os28069.gif
                        |----os28070.gif
                        |----os28072.gif
                        |----os28073.gif
                        |----os28074.gif
                        |----os28075.gif
                        |----os28076.gif
                        |----os28077.gif
                        |----os28080.gif
                        |----os28081.gif
                        |----os28082.gif
                        |----os28084.gif
                        |----os28085.gif
                        |----os28086.gif
                        |----os28087.gif
                        |----os28108.gif
                        |----os28109.gif
                        |----os28110.gif
                        |----os28111.gif
                        |----os28112.gif
                        |----os28113.gif
                        |----os29000.gif
                   |----thumb/
                        |----gift_certificate.gif
                        |----os28004_b.gif
                        |----os28005_b.gif
                        |----os28006_b.gif
                        |----os28007_b.gif
                        |----os28008_b.gif
                        |----os28009_b.gif
                        |----os28011_b.gif
                        |----os28044_b.gif
                        |----os28057a_b.gif
                        |----os28057b_b.gif
                        |----os28057c_b.gif
                        |----os28062_b.gif
                        |----os28064_b.gif
                        |----os28065_b.gif
                        |----os28066_b.gif
                        |----os28068_b.gif
                        |----os28068a_b.gif
                        |----os28068b_b.gif
                        |----os28069_b.gif
                        |----os28070_b.gif
                        |----os28072_b.gif
                        |----os28073_b.gif
                        |----os28074_b.gif
                        |----os28075_b.gif
                        |----os28076_b.gif
                        |----os28077_b.gif
                        |----os28080_b.gif
                        |----os28081_b.gif
                        |----os28082_b.gif
                        |----os28084_b.gif
                        |----os28085_b.gif
                        |----os28086_b.gif
                        |----os28087_b.gif
                        |----os28108_b.gif
                        |----os28109_b.gif
                        |----os28110_b.gif
                        |----os28111_b.gif
                        |----os28112_b.gif
                        |----os28113_b.gif
                        |----os29000_b.gif
               |----products/
                    |----affiliate.txt
                    |----area.txt
                    |----cat.txt
                    |----inventory.txt
                    |----merchandising.txt
                    |----mv_metadata.asc
                    |----options.txt
                    |----orderline.txt
                    |----pricing.txt
                    |----products.txt
                    |----transactions.txt
                    |----userdb.txt

81.2. Themes
------------

This section explains how themes are defined in Interchange via the
STYLE variable and the theme configuration file, theme.cfg.

81.2.1. STYLE
-------------

The STYLE variable in CATROOT/products/variable.txt indicates the
template style to be used as the theme for the catalog; the
appropriate templates for that theme are found in
CATROOT/templates/__STYLE__/. (To change the value of the STYLE
variable, either edit variable.txt directly or use the table editor
feature of the admin interface.)

The default theme for Interchange is the Foundation demo; hence, the
STYLE variable is assigned the value 'Foundation' in variable.txt. The
theme is defined in catalog.cfg as follows (line numbers added):

    # Here we set up the catalog theme.

  1 ParseVariables Yes

  2 ifndef STYLE
  3 Variable STYLE default
  4 endif
  5 include templates/__STYLE__/theme.cfg

Variables that make up the look and feel of the STYLE (theme) are
defined in the file CATROOT/templates/foundation/theme.cfg, which is
read by Interchange in line 5 above.

81.2.2. theme.cfg
-----------------

The file CATROOT/templates/foundation/theme.cfg serves three purposes:

1.   It defines the THEME and THEME_IMG_DIR variables,

2.   It defines a cascading style sheet for the theme, and

3.   It defines the location of region templates according to the
     traffic settings for the Interchange daemon.

The THEME variable is used to set the location of the region templates
in the traffic settings section of the theme.cfg file. It is also used
in the cart template definition file (CATROOT/templates/cart) to set
the path of an image. The THEME_IMG_DIR variable is used to set image
paths in the template region files and the template component files.

The look and feel of the Foundation theme are defined primarily in the
cascading style sheet specified in the theme.cfg file. This

The Interchange TRAFFIC setting, defined system-wide in
interchange.cfg, is described in the ??document??. The settings in
theme.cfg pertain to the location of region templates for the high and
low traffic settings. For example, if you need to define a separate
set of high traffic templates, you would change the ConfigDir variable
in theme.cfg to point to the directory containing those templates.

81.3. Template Definition Files
-------------------------------

The template definition files store the name and description of the
template as well as components and options for that template.

    templates/cart
    templates/fullwidth
    templates/leftonly
    templates/leftright

    templates/foundation/cart
    templates/foundation/fullwidth
    templates/foundation/leftonly
    templates/foundation/leftright
    templates/foundation/simple

81.3.1. Template Walkthrough -- leftonly
----------------------------------------

This section is best read while viewing the file
CATROOT/templates/leftonly and the 'Edit Page' page in the Content
Editor of the Interchange Administration Tool.

Looking at the example template definition file, all lines located
between the [comment] and [/comment] tags (lines 1 and 53) control
what is available in the Edit Page screen of the Administration Tool.

Lines 2-5: Template specification

    2  ui_template: Yes
    3  ui_template_name: leftonly
    4  ui_template_layout: LEFTONLY_TOP, UI_CONTENT, LEFTONLY_BOTTOM
    5  ui_template_description: Page with top/left areas.

Line 2 indicates that this file is a template for the user interface.
Line 3 names the template, while Line 4 indicates the regions that
comprise the template and that will eventually make up the new page
that is created from the template. Line 5 provides a description used
to identify the template when it appears in a Select Template
pull-down menu on the Edit Page of the Administration Tool. This
description can be changed or modified to better describe a new
template or a template that is created from the stock templates
provided with Interchange.

Lines 7-8: Break

    7  break:
    8          widget: break

This code creates a separation line in the Edit Page between sets of
options. In the default Interchange installation the line is grey, but
the color can be changed. Note - Changing this color applies the
change to any catalog served by Interchange.

Lines 10-11: Page Title

    10 page_title:
    11         description: Page title

This code tells Interchange to display a text field on the Edit Page
for entering the page title ('Title of New Page' in this example). The
value entered is assigned to the scratch variable page_title and is
set as a default value at the bottom of the template definition file
using the following ITL:

    54 [set page_title][set]

which, in turn, sets the scratch variable on the new page using the
tag

    [set page_title]Title of New Page[set]

The scratch variable page_title is parsed by the following code in the
region template specified in the template definition file and called
in the new page:

       <title>[scratch page_title]</title>

Lines 13-15: Page Banner

    13 page_banner:
    14         description: Page banner
    15         help: Defaults to page title

Assigns a textual title for the page to the scratch variable
page_banner, which is assigned by the following ITL:

    55 [set page_banner][set]

The scratch variable page_banner is set on the new page using the tag

    [set page_banner]Banner of New Page[set]

The scratch variable can be parsed in the region template by this
code:

    [either]
        [scratch page_banner]
    [or]
        [scratch page_title]
    [/either]

This results in the page banner being displayed if defined. Otherwise,
the page title is used.

Lines 17-20: Members Only

    17 members_only:
    18         options: 1=Yes,0=No*
    19         widget: radio
    20         description: Members only

This creates a radio-button form element on the Edit Page with the
user can specify whether the page can be accessed if a visitor is
logged in (Yes) or not (No). The default is indicated by an asterisk.

The scratch variable members_only is assigned by the ITL code

    56 [set members_only][set]

and set on the new page using the tag

       [set members_only]0[/set]

if the page can be accessed without logging in or

       [set members_only]1[/set]

if it can not.

The members_only function is handled by the following code within each
region template file:

    [if scratch members_only]
      [set members_only][/set]
      [if !session logged_in]
        [set mv_successpage]@@MV_PAGE@@[/set]
        [bounce page=login]
      [/if]
    [/if]

This code says that if "members only" is set to yes, and the visitor
is logged in, to display the page. Otherwise, redirect the visitor to
the login page.

Lines 22-23: Break

    22 break1:
    23         widget: break

Another separation line.

Lines 25-28: Horizontal Before Component

    25 component_before:
    26         options: =none, best_horizontal=Best Sellers, cross_horizontal=Cross sell, \
                promo_horizontal=Promotion, random_horizontal=Random items, \
                upsell_horizontal=Upsell
    27         widget: select
    28         description: Component before content

This allows the inclusion of a defined component (included in the
CATROOT/templates/components directory) to be displayed before, or
above, the page's content. It provides a pull-down menu on the Edit
Page displaying the available components. The components, identified
here on line 26, can be assigned a name via the value=name convention.

The scratch variable component_before is assigned in the template
definition file by the ITL code

    57 [set component_before][set]

It is called with the following code within the LEFTRIGHT_TOP,
LEFTONLY_TOP, and NOLEFT_TOP region templates:

    [if scratch component_before]
      [include file="templates/components/[scratch component_before]"]
    [/if]

Lines 30-33: Horizontal After Component

    30 component_after:
    31         options: =none, best_horizontal=Best Sellers, cross_horizontal=Cross sell, \
                promo_horizontal=Promotion, random_horizontal=Random items, \
                upsell_horizontal=Upsell
    32         widget: select
    33         description: Component after content

Similar to component_before, this allows the inclusion of a defined
component after, or below, the page's content.

The scratch variable component_before is assigned in the template
definition file by the ITL code

    58 [set component_after][set]

It is called with the following code within the LEFTRIGHT_BOTTOM and
LEFTONLY_BOTTOM region templates:


    [if scratch component_after]
      [include file="templates/components/[scratch component_after]"]
    [/if]

Lines 35-38: Horizontal Item Width

    35 component_hsize:
    36         options: 1,2,3*
    37         widget: select
    38         description: Component items horizontal

This setting allows you to choose how many items the horizontal
components display. For example, the horizontal best sellers component
("best_horizontal") uses this setting to randomly select the best
sellers. Notice the default is 3 if nothing is defined. It is called
by the following code in the promo_horizontal and random_horizontal
components in the Foundation demo.

    random="[either][scratch component_hsize][or]2[/either]"

Lines 40-45: Before/After Banner

    40 hbanner:
    41         options: =--custom--, Also see..., Best Sellers, New items, \
                Some of our fine products, Specials, You might also like
    42         widget: move_combo
    43         width: 40
    44         description: Before/after Banner
    45         help: Banner for Before/after component

Allows a title for the horizontal components to be defined to be
displayed in a header above the component's items. It is called with
the [scratch hbanner] tag and used in the Foundation demo in the
random_horizontal component.

Lines 47-51: Special Tag

    47 hpromo_type:
    48         options: specials=Specials, new=New items
    49         widget: select
    50         description: Special tag
    51         help: Only for a horizontal Promotion

This setting is only viable when a promotion is used for a horizontal
component. It tells the promotional component which row(s) to evaluate
in the merchandising table for display within the component. This
setting, used in the promo_horizontal component, typically correlates
to the featured column of the merchandising table as follows:

    [query arrayref=main
           sql="
            SELECT sku,timed_promotion,start_date,finish_date
            FROM merchandising
            WHERE featured = '[scratch hpromo_type]'
            "]
    [/query]

81.4. Edit Page Function
------------------------

Creating a page with the following specifications using the Edit Page
function results in the HTML and ITL code displayed below.

Specifications:

    Template:                    Page with top/left areas.
    Page title:                  test
    Page banner:                 test
    Members only:                No
    Component before content:    Best Sellers
    Component after content:     Random items
    Component items horizontal:  3
    Before/after Banner:         New items
    Special tag:                 Specials
    Content:                     <P>My first HTML/ITL page!

Resulting code:

    [comment]
    ui_template: Yes
    ui_template_name: leftonly
    [/comment]

    [set hbanner]New items[/set]
    [set page_title]test[/set]
    [set hpromo_type]specials[/set]
    [set component_hsize]3[/set]
    [set page_banner]test[/set]
    [set members_only]0[/set]
    [set component_before]best_horizontal[/set]
    [set component_after]random_horizontal[/set]
    @_LEFTONLY_TOP_@

    <!-- BEGIN CONTENT -->
    <P>My first HTML/ITL page!
    <!-- END CONTENT -->

    @_LEFTONLY_BOTTOM_@

An important point demonstrated here is the inclusion of the region
templates LEFTONLY_TOP and LEFTONLY_BOTTOM through the
@_VARIABLE_NAME_@ notation. These are included because of line 4 of
the leftonly template definition file:

    4  ui_template_layout: LEFTONLY_TOP, UI_CONTENT, LEFTONLY_BOTTOM

However, understand that you are free to change the region templates
used in the file by editing the file itself or, better yet, using an
existing region as a starting point for a region of your own design.

The next section explains the structure of region templates.

81.5. Region Templates
----------------------

Interchange region templates (or "regions") are portions of HTML and
ITL that are included in pages within a catalog. Using regions, along
with the cascading style sheet defined in theme.cfg, allows you to
control the look and feel of specific parts of each catalog page.

The default Foundation region set, found in
CATROOT/templates/foundation/regions, includes the following:

    LEFTONLY_TOP
    LEFTONLY_BOTTOM
    LEFTRIGHT_TOP
    LEFTRIGHT_BOTTOM
    NOLEFT_TOP
    NOLEFT_BOTTOM

The Foundation demo uses the Variable feature extensively to simplify
hand page editing. Basically, a Variable is a define that permits the
substitution of text for a simple __VARIABLE__ string in a page. For
example, in the test page above, the variables LEFTONLY_TOP and
LEFTONLY_BOTTOM correspond to region templates that provide a logobar,
menubar, leftside menu, and copyright footer. Content, consisting of
HTML and ITL, is placed within the BEGIN and END CONTENT comments. The
following illustration shows how this looks on the page:

   +--------------------------------------------------------+
   |                      LOGOBAR                           |
   |--------------------------------------------------------+
   |                      MENUBAR                           |
   |--------------+-----------------------------------------+
   |              |                                         |
   |              |                                         |
   |              |                                         |
   |   LEFTSIDE   |          This is your content           |
   |              |                                         |
   |              |                                         |
   |              |                                         |
   |              +-----------------------------------------|
   |              |               COPYRIGHT                 |
   +--------------------------------------------------------+

In this diagram, LEFTONLY_TOP contributes the LEFTSIDE, LOGOBAR, and
MENUBAR sections, while LEFTONLY_BOTTOM contributes the COPYRIGHT
section.

The following subsections provide an inventory of where each of the
region templates, included with the Foundation demo, are used in the
pages and template definition files that make up the catalog.

81.5.1. LEFTONLY_TOP
--------------------

The LEFTONLY_TOP template region is used in the following template
pages:

    pages/aboutus.html
    pages/account.html
    pages/affiliate/index.html
    pages/affiliate/login.html
    pages/canceled.html
    pages/contact.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/login.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/returns.html
    pages/saved_carts.html
    pages/ship_addresses.html
    pages/ship_addresses_added.html
    pages/ship_addresses_removed.html
    pages/stock-alert-added.html
    pages/stock-alert.html

The LEFTONLY_TOP template region is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/simple

81.5.1.1. Region Template Walkthrough -- LEFTONLY_TOP
-----------------------------------------------------

     1  <!-- BEGIN LEFTONLY_TOP -->
     2  [if scratch members_only]
     3      [set members_only][/set]
     4      [if !session logged_in]
     5      [set mv_successpage]@@MV_PAGE@@[/set]
     6      [bounce page=login]
     7      [/if]
     8  [/if]
     9
    10  <html>
    11  <head>
    12    <title>[scratch page_title]</title>
    13    __THEME_CSS__
    14  </head>
    15
    16  <body marginheight="0" marginwidth="0">
    17
    18  <!--- top left and right logo --->
    19  <table width="100%" border="0" cellspacing="0" cellpadding="0">
    20  <tr>
    21    <td align="left" valign="middle" class="maincontent">
    22      &nbsp;<img src="__THEME_IMG_DIR____LOGO__">
    23    </td>
    24    <td align="right" valign="middle" class="maincontent">
    25      <img width="174" height="60" src="__THEME_IMG_DIR__logo2.gif">&nbsp;
    26    </td>
    27  </tr>
    28  </table>
    29
    30  <!--- menu bar along the top --->
    31  <table width="100%" border="0" cellspacing="0" cellpadding="0">
    32  <tr>
    33    <td width="100%" class="menubar">
    34      <a href="[area index]"><img name="Home" border="0" src="__THEME_IMG_DIR__home.gif"></a>
    35        <img src="__THEME_IMG_DIR__sep.gif">
    36      <a href="[area login]">
    37      [if session logged_in]
    38        <img alt="Log Out" border="0" src="__THEME_IMG_DIR__logout.gif"></a>
    39      [else]
    40        <img alt="Log In" border="0" src="__THEME_IMG_DIR__login.gif"></a>
    41      [/else]
    42      [/if]
    43        <img src="__THEME_IMG_DIR__sep.gif">
    44      <a href="[area ord/basket]"><img alt="Your Cart" border="0" src="__THEME_IMG_DIR__cart.gif"></a>
    45        <img src="__THEME_IMG_DIR__sep.gif">
    46      <a href="[area ord/checkout]"><img alt="Check Out" border="0" src="__THEME_IMG_DIR__checkout.gif"></a>
    47        <img src="__THEME_IMG_DIR__sep.gif">
    48      <a href="[area customerservice]"><img alt="Customer Service" border="0" src="__THEME_IMG_DIR__service.gif"></a>
    49        <img src="__THEME_IMG_DIR__sep.gif">
    50      <a href="[area aboutus]"><img alt="About Us" border="0" src="__THEME_IMG_DIR__about.gif"></a>
    51    </td>
    52  </tr>
    53  </table>
    54
    55  <!--- left category column, main content column, and right special column --->
    56  <table width="100%" border="0" cellspacing="0" cellpadding="0">
    57  <tr>
    58    <td width="20%" valign="top" align="left" class="categorybar">
    59      <!--Left Sidebar-->
    60      <table width="100%" border="0" cellspacing="0" cellpadding="0">
    61        [include file="templates/components/[control component none]"][control]
    62        [include file="templates/components/[control component none]"][control]
    63        [include file="templates/components/[control component none]"][control]
    64      </table>
    65    </td>
    66    <td width="80%" valign="top" align="center" class="maincontent">
    67      [include file="templates/components/[control component none]"][control]
    68

81.5.2. LEFTONLY_BOTTOM
-----------------------

The LEFTONLY_BOTTOM template region is used in the following template
pages:

    pages/aboutus.html
    pages/account.html
    pages/affiliate/index.html
    pages/affiliate/login.html
    pages/canceled.html
    pages/contact.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/login.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/returns.html
    pages/saved_carts.html
    pages/ship_addresses.html
    pages/ship_addresses_added.html
    pages/ship_addresses_removed.html
    pages/stock-alert-added.html
    pages/stock-alert.html

The LEFTONLY_BOTTOM template region is used in the following
templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/simple

81.5.3. LEFTRIGHT_TOP
---------------------

The LEFTRIGHT_TOP template region is used in the following template
pages:

    pages/browse.html
    pages/index.html
    pages/results.html
    pages/results_big.html
    pages/swap_results.html

The LEFTRIGHT_TOP template region is used in the following templates:

    templates/foundation/leftright

81.5.4. LEFTRIGHT_BOTTOM
------------------------

The LEFTRIGHT_BOTTOM template region is used in the following template
pages:

    pages/browse.html
    pages/index.html
    pages/results.html
    pages/results_big.html
    pages/swap_results.html

The LEFTRIGHT_BOTTOM template region is used in the following
templates:

    templates/foundation/leftright

81.5.5. NOLEFT_BOTTOM
---------------------

The NOLEFT_BOTTOM template region is used in the following template
pages:

    pages/ord/checkout.html
    pages/splash.html

The NOLEFT_BOTTOM template region is used in the following templates:

    templates/foundation/fullwidth

81.5.6. NOLEFT_TOP
------------------

The NOLEFT_TOP template region is used in the following template
pages:

    pages/ord/checkout.html
    pages/splash.html

The NOLEFT_TOP template region is used in the following templates:

    templates/foundation/fullwidth

81.6. Template Page List
------------------------

/home/ic/catalogs/ft/pages/:

    aboutus.html
    account.html
    browse.html
    canceled.html
    change_password.html
    contact.html
    customerservice.html
    deliver.html
    flypage.html
    help.html
    index.html
    login.html
    logout.html
    lost_password.html
    modular_modify.html
    new_account.html
    privacypolicy.html
    process_return.html
    quantity.html
    results_big.html
    results_either.html
    results.html
    returns.html
    saved_carts.html
    ship_addresses_added.html
    ship_addresses.html
    ship_addresses_removed.html
    splash.html
    stock-alert-added.html
    stock-alert.html
    swap_results.html

/home/ic/catalogs/ft/pages/admin/report_def:

    Order%20Status.html
    Products%20to%20edit.html

/home/ic/catalogs/ft/pages/admin/reports:

    Order%20Status.html
    Products%20to%20edit.html

/home/ic/catalogs/ft/pages/affiliate:

    index.html
    login.html

/home/ic/catalogs/ft/pages/ord:

    basket.html
    checkout.html

/home/ic/catalogs/ft/pages/query:

    check_orders.html
    get_password.html
    order_detail.html
    order_return.html

81.7. Special Page List
-----------------------

/home/ic/catalogs/ft/special_pages/:

    badsearch.html
    canceled.html
    cc_not_valid.html
    confirmation.html
    failed.html
    interact.html
    missing.html
    needfield.html
    nomatch.html
    noproduct.html
    notfound.html
    order_security.html
    reconfig.html
    sec_faq.html
    security.html
    violation.html

81.8. Components
----------------

o    Added new [control] and [control-set] tags to set series of
     Scratch- like option areas. Used for components in UI content
     editing.

Interchange components are portions of HTML and ITL that are included
in pages within a catalog depending on options set in the
Administration Tool. The default component set includes the following:

    affiliate_receptor
    best_horizontal
    best_vertical
    cart
    cart_display
    cart_tiny
    category_vertical
    cross_horizontal
    cross_vertical
    modular_buy
    modular_update
    none
    promo
    promo_horizontal
    promo_vertical
    random
    random_horizontal
    random_vertical
    saved_carts_list_small
    search_box_small
    upsell
    upsell_horizontal
    upsell_vertical

/home/ic/catalogs/ft/templates/components:

81.8.1. affiliate_receptor
--------------------------

Not used in Foundation demo

81.8.2. best_horizontal
-----------------------

The best_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

Not used in Foundation demo pages

81.8.3. best_vertical
---------------------

The best_vertical component is used in the following template:

    templates/foundation/leftright

Not used in Foundation demo pages

81.8.4. cart
------------

The cart component is used in the following page:

    pages/ord/basket.html

81.8.5. cart_display
--------------------

The cart_display component creates a small shopping cart that is
displayed on the search results page (pages/results.html). It is
displayed after an item in a list of results from a search is added to
the shopping cart. cart_display is called in results.html by the
following include statement:

    [include file="templates/components/cart_display"]

The cart_display component is used in the following pages:

    pages/results.html

81.8.5.1. Component Walkthrough -- cart_display
-----------------------------------------------

The remainder of this section is best read in conjunction with the
file CATROOT/templates/components/cart_display in a text editor.

Lines 1-6: Component Specification

     1  [comment]
     2  ui_component: cart_display
     3  ui_component_group: info
     4  ui_component_label: Smaller cart for display in content area
     5
     6  [/comment]
     7

These lines control what is shown in the Edit page screen of the admin
interface.

     8  <!-- BEGIN COMPONENT [control component cart_display] -->

Line 8 is an HTML comment noting the start of the code for the
component. (Note that this can serve as a useful debugging tool to
help you locate the component in the resulting HTML generated by
Interchange when you view the source of a page loaded in the browser.)

     9  [if items]

Line 9 checks to see if there are items in the shopping basket. If
there are, the remaining code up to the closing [/if] tag on line 64
is executed. If not, Interchanges continues executing the remaining
code in results.html (the file that calls the cart_display component).

    10  <center>
    11    <table width="95%" border="0" cellspacing="0" cellpadding="0">
    12      <TR class="contentbar2" VALIGN=TOP>
    13        <td align=center class="contentbar2">Action</td>
    14        <td class="contentbar2">
    15          SKU
    16        </td>
    17        <td class="contentbar2">
    18          Description
    19        </td>
    20        <td class="contentbar2">
    21          Quantity
    22        </td>
    23        <td class="contentbar2">
    24          Price
    25        </td>
    26        <td class="contentbar2">
    27          Extension
    28        </td>
    29      </TR>

Line 10 centers the table started in line 11. Lines 12-29 create a
header row in the shopping cart consisting of the header titles
Action, SKU, Description, Quantity, Price, and Extension.

    30      <TBODY>
    31  [item-list]
    32

Line 30 defines the remainder of the table as a section while the
[item-list] tag on line 31 tells Interchange to execute the code up to
the closing tag ([/item-list] on line 59 for each item the customer
has ordered so far.

    33      <tr class="[item-alternate 2]maincontent[else]contentbar1[/else][/item-alternate]">
    34        <td align=center valign=top>
    35          [page ord/basket]edit</A>
    36        </TD>
    37        <td valign=top>[item-code]</TD>
    38        <td valign=top>[page [item-code]][item-description]</A>
    39        </TD>
    40

Line 33 begins the next row in the table. The [item-alternate] tag
provided as the value of the class attribute tells Interchange to
alternate between displaying the rows according to the "maincontent"
and "contentbar1" styles (gray and white, respectively).

Lines 34-36 create a link to the shopping cart (basket.html) where the
customer can remove or change the quantity of the item ordered.

Line 37 displays the SKU of the item. Lines 38 and 39 provide a link
to the product display page (flypage.html) for the item. The
[item-description] tag providing the content of the [page] tag enables
the item's name to be displayed as the link to the product display
page.

    41  [if-item-modifier gift_cert]
    42        <TD ALIGN=CENTER><small>Amount of gift:</small></TD>
    43        <TD ALIGN=CENTER>[item-quantity]</TD>
    44        <TD ALIGN=right>
    45          [item-subtotal]
    46        </TD>
    47  [else]
    48        <TD ALIGN=CENTER>[item-quantity]</TD>
    49        <TD ALIGN=right>
    50          [item-price]
    51        </TD>
    52        <TD ALIGN=right>
    53          [item-subtotal]
    54        </TD>
    55  [/else]
    56  [/if-item-modifier]
    57      </TR>
    58

Line 41 checks whether the item is a gift certificate. If it is it
displays "Amount of gift:" and the [item-quantity] (number of gift
certificates, in this case) under the headings "Quantity" and "Price",
respectively. Otherwise, lines 48 through 50 display the quantity and
price of the item ordered. Lines 45 or 53 (depending on whether the
item is a gift certificate) display the item subtotal (quantity
multiplied by price) for the item under the heading "Extension".

    59  [/item-list]
    60  </TBODY>
    61  </table>
    62  </FORM>
    63  </center>
    64  [/if]
    65
    66  <!-- END COMPONENT [control component cart_display] -->

Lines 59 through 64 close out the tags for the component, and line 66
indicates the end of the component code.

81.8.6. cart_tiny
-----------------

The cart_tiny component is used in the following pages:

    pages/account.html
    pages/browse.html
    pages/canceled.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/index.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/saved_carts.html
    pages/ship_addresses.html

81.8.7. category_horizontal
---------------------------

Not used in Foundation demo pages or templates.

81.8.8. category_vertical
-------------------------

The category_vertical component provides a listing of all products in
the catalog, organized by prod_group (e.g., Hand Tools, Ladders).
category_vertical is usually displayed in the LEFTSIDE section of the
page, under the search_box_small component.

The category_vertical component is used in the following pages:

    pages/aboutus.html
    pages/account.html
    pages/affiliate/index.html
    pages/affiliate/login.html
    pages/browse.html
    pages/canceled.html
    pages/contact.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/index.html
    pages/login.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/results.html
    pages/results_big.html
    pages/returns.html
    pages/saved_carts.html
    pages/ship_addresses.html
    pages/stock-alert-added.html
    pages/stock-alert.html
    pages/swap_results.html

81.8.8.1. Component Walkthrough -- category_vertical
----------------------------------------------------

The remainder of this section is best read while viewing the file
CATROOT/templates/components/cart_display in a text editor.

Lines 1-6: Component Specification

     1  [comment]
     2  ui_component: category_vertical
     3  ui_component_group: Navigation
     4  ui_component_label: Vertical category list
     5
     6  page_class:
     7          label: Page class
     8          widget: select
     9          lookup: which_page
    10          db: area
    11          help: Defines which sets of items should be displayed
    12          advanced: 1
    13
    14  set_selector:
    15          label: Page area selector
    16          widget: select
    17          db: area
    18          lookup: sel
    19          help: Defines which sets of items should be displayed
    20          advanced: 1
    21  [/comment]
    22

These lines control what is shown in the Edit page screen of the
Administration Tool.

    23  <tr><td align="center" class="categorybar">
    24    <br>
    25    <table>
    26
    27  <!-- BEGIN COMPONENT [control component category_vertical] -->

Lines 23-25 set up the row and table within that row that will hold
the vertical category list. Line 27 identifies the start of the code
for the list.

    28  [loop
    29          prefix=box
    30          search="
    31                  fi=area
    32                  st=db
    33                  tf=sort
    34                  ac=0
    35                  ac=0
    36                  co=yes
    37
    38                  sf=sel
    39                  op=eq
    40                  se=[control set_selector left]
    41
    42                  sf=which_page
    43                  op=rm
    44                  se=[control page_class all|@@MV_PAGE@@]
    45  "]
    46

Lines 28-45 build a list of product categories obtained through a
search of the area table.

    47    <tr>
    48      <td valign="top" class="categorybar">
    49        <b>[box-exec bar_link]area[/box-exec]</b>
    50      </td>
    51    </tr>
    52    <tr>
    53      <td valign="top" class="categorybar">
    54
    55  [set found_cat][/set]
    56  [loop prefix=cat
    57          search="
    58                  fi=cat
    59                  st=db
    60                  tf=sort
    61                  tf=name
    62                  rf=code,name
    63                  sf=sel
    64                  se=[box-code]
    65          "
    66          ]
    67        &nbsp;&nbsp;[cat-exec bar_link]cat[/cat-exec]<BR>
    68  [/loop]
    69
    70      </td>
    71    </tr>
    72  [/loop]
    73
    74    </table>
    75    <br>
    76  </td></tr>
    77
    78  <!-- END COMPONENT [control component category_vertical] -->

Lines 47-78 generate a list of links based on the products and product
categories identified in the search.

81.8.9. cross_horizontal
------------------------

The cross_horizontal component is used in the following pages:

    pages/browse.html
    pages/index.html
    pages/results.html
    pages/results_big.html

The cross_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

81.8.10. cross_vertical
-----------------------

Not used in Foundation demo pages.

The cross_horizontal component is used in the following templates:

    templates/foundation/leftright

81.8.11. modular_buy
--------------------

The modular_buy component is used in the following pages:

    pages/flypage.html

The modular_buy component is used in the following templates:

    templates/components/modular_update

81.8.12. modular_update
-----------------------

The modular_update component is used in the following pages:

    pages/modular_modify.html

81.8.13. promo
--------------

The promo component is used in the following pages:

    pages/contact.html
    pages/results_big.html

81.8.14. promo_horizontal
-------------------------

The promo_horizontal component is used in the following pages:

    pages/aboutus.html
    pages/canceled.html

The promo_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

81.8.15. promo_vertical
-----------------------

Not used in Foundation demo pages.

The promo_horizontal component is used in the following templates:

    templates/foundation/leftright

81.8.16. random
---------------

The random component is used in the following pages:

    pages/browse.html
    pages/index.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/results.html
    pages/swap_results.html

81.8.17. random_horizontal
--------------------------

Not used in Foundation demo pages.

The random_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

81.8.18. random_vertical
------------------------

Not used in Foundation demo pages.

The random_vertical component is used in the following templates:

    templates/foundation/leftright

81.8.19. saved_carts_list_small
-------------------------------

The saved_carts_list_small component is used in the following pages:

    pages/ord/basket.html

81.8.20. search_box_small
-------------------------

The search_box_small component is used in the following pages:

    pages/aboutus.html
    pages/account.html
    pages/affiliate/index.html
    pages/affiliate/login.html
    pages/browse.html
    pages/canceled.html
    pages/contact.html
    pages/customerservice.html
    pages/flypage.html
    pages/help.html
    pages/index.html
    pages/login.html
    pages/logout.html
    pages/modular_modify.html
    pages/new_account.html
    pages/ord/basket.html
    pages/privacypolicy.html
    pages/process_return.html
    pages/quantity.html
    pages/query/check_orders.html
    pages/query/order_detail.html
    pages/query/order_return.html
    pages/results.html
    pages/results_big.html
    pages/returns.html
    pages/saved_carts.html
    pages/ship_addresses.html
    pages/stock-alert-added.html
    pages/stock-alert.html
    pages/swap_results.html

The search_box_small component is used in the following templates:

    templates/regions/LEFTONLY_TOP
    templates/regions/LEFTRIGHT_TOP

81.8.21. upsell
---------------

Not used in Foundation demo pages.

81.8.22. upsell_horizontal
--------------------------

The upsell_horizontal component is used in the following pages:

    pages/flypage.html

The upsell_horizontal component is used in the following templates:

    templates/foundation/cart
    templates/foundation/leftonly
    templates/foundation/leftright

81.8.23. upsell_vertical
------------------------

Not used in Foundation demo pages.

The upsell_vertical component is used in the following templates:

    templates/foundation/leftright

82. The Database Tables
=======================

Interchange catalogs are centralized around the database. You can
alter any of the standard databases, add new databases, or remove
unneeded databases

The foundation catalog includes the following tables, organized here
by content:

o    Your site content data

          area.txt

          cat.txt

          downloadable.txt

          merchandising.txt

          options.txt

          pricing.txt

          products.txt

o    Customer data

          access.asc

          gift_certs.txt

          userdb.txt

o    Transaction-related data

          inventory.txt

          orderline.txt

          order_returns.txt

          transactions.txt

o    Third-party relationship data

          affiliate.txt

          banner.txt

o    Site administrative data

          component.txt

          files.txt

          ichelp.txt

          icmenu.txt

          locale.txt

          mv_metadata.asc

          route.txt

          shipping.asc

          variable.txt

o    Shipping and tax

          2ndDayAir.csv

          450.csv

          country.txt

          Ground.csv

          NextDayAir.csv

          salestax.asc

          state.txt

You may also see symbolic links pointing to index tables, for example
products.category.txt linking to products.txt.10. These are
automatically generated indexes, in this case into the products table
to speed category searches. See Dictionary Indexing With INDEX in the
database documentation for details about auto-indexing of text
databases.

The following dictionary lists and describes each table used in the
Foundation demo.

82.1. 2ndDayAir.csv
-------------------

Shipping table from UPS
(http://www.ups.com/using/services/rave/rate/). This and all shipping
tables should be updated periodically.

82.2. 450.csv
-------------

Shipping table from UPS for 450xx Zip Code origin.  You will probably
need to get your own from the UPS site
(http://www.ups.com/using/services/rave/rate/) and clip the headers.

82.3. Ground.csv
----------------

Shipping table from UPS
(http://www.ups.com/using/services/rave/rate/).

82.4. NextDayAir.csv
--------------------

Shipping table from UPS
(http://www.ups.com/using/services/rave/rate/).

82.5. access.asc
----------------

Administrative access table.  This table is used by the Administration
Tool. For more description on these fields, see the Interchange
Administration Tool guide.

Fields

Field                              Description
.................................. .................................. 
username                           Login name or group name (group
                                   names begin with ':')
password                           Hashed password
name                               Administrator's name
last_login                         Last login time
super                              Set to 1 if superuser
yes_tables                         Tables the user may edit
no_tables                          Tables the user may not edit
upload                             No Description
acl                                No Description
export                             No Description
edit                               No Description
pages                              No Description
files                              No Description
config                             No Description
reconfig                           No Description
groups                             Administrator's group memberships
meta                               No Description
no_functions                       Explicitly disallowed functions
yes_functions                      Allowed functions with permission
                                   flags
table_control                      No Description
personal_css                       Administrator's personal CSS (for
                                   admin screen presentation)

82.5.1. username
----------------

Example Data

   :ausers
   :busers
   BigUser
   goody
   ic

The login name for an administrator or an administration group. Group
names are prefixed with a colon (':').

82.5.2. password
----------------

Example Data

   Ksjs65bMNLjPQ

Hashed password.

82.5.3. name
------------

Example Data

   Interchange Site Administrator
   Interchange Site Associates
   Business Users
   2nd Shift
   Mr. Jones
   Inbound Sales

Descriptive name for the administrator or administration group.

82.5.4. last_login
------------------

Example Data

   989424489

Last login time (in unix time() format).

82.5.5. super
-------------

Boolean value.  If true (1), the administrator has Interchange Site
Administrator privilege.

82.5.6. yes_tables
------------------

Example Data

   affiliate=vcx component=v gift_certs=v inventory=vx ...
   NONE

Tables this administrator or administration group can access.  This is
a space-delimited list of 'table_name=permission_flags' entries.

82.5.7. no_tables
-----------------

Example Data

   access mv_metadata variable

Tables this administrator or administration group can not use.  This
is a space-delimited list of tables names.

82.5.8. upload
--------------

No Description

82.5.9. acl
-----------

No Description

82.5.10. export
---------------

No Description

82.5.11. edit
-------------

No Description

82.5.12. pages
--------------

No Description

82.5.13. files
--------------

No Description

82.5.14. config
---------------

No Description

Example Data

Allowed Values

82.5.15. reconfig
-----------------

No Description

82.5.16. groups
---------------

Example Data

   ausers
   busers

Allowed Values

Groups the site user belongs to. You can set permissions for groups.

82.5.17. meta
-------------

No Description

82.5.18. no_functions
---------------------

Example Data

   orderstats trafficstats

Space-delimited list of functions explicitly not allowed for the site
user.

82.5.19. yes_functions
----------------------

Example Data

   item=lvecd itemtype=lvc order=lvca orderstats trafficstats ...
   NONE

Functions the site user can perform. This is a space-delimited list of
functions, with permission flags if appropriate.

Usage examples

o    dist/lib/UI/pages/admin/access_permissions.html

82.5.20. table_control
----------------------

No Description

Usage examples

o    dist/lib/UI/Primitive.pm

o    dist/lib/UI/pages/admin/special/key_violation.html

o    dist/lib/UI/usertag/if_mm

82.5.21. personal_css
---------------------

Used in the Administration Tool screens to make personal changes to
the page presentation. This is done by creating your own personal CSS
(cascading style sheet).

Usage examples

o    dist/lib/UI/pages/admin/preferences.html

82.6. affiliate
---------------

cat_root/products/affiliate.txt

This table contains data related to your affiliate programs.  See also
the affiliate_receptor component.

Fields

Field                              Description
.................................. .................................. 
affiliate                          Affiliate ID
name                               Name of affiliate organization
campaigns                          Campaigns this affiliate
                                   participates in
coupon_amount                      Discount for customers from
                                   affiliate participating in coupon
                                   campaign
join_date                          When the affiliate signed with you
url                                Your default URL to use for
                                   customers coming from the
                                   affiliate site (not the
                                   affiliate's home page)
timeout                            Timeout in seconds after which
                                   purchases are no longer credited
                                   to the affiliate
active                             Boolean, set to 1 for active
                                   affiliates
password                           Affiliate login password
image                              Affiliate's logo

82.6.1. affiliate
-----------------

Example Data

   consolidated
   hardhat

This field contains the unique Affiliate ID.

82.6.2. name
------------

Example Data

   Consolidated Diversified
   Hardhat Construction

This is the descriptive name of the affiliate.

82.6.3. campaigns
-----------------

Example Data

   coupon

This field lists the campaigns that the affiliate participates and
enables campaign features and tracks traffic from advertising
campaigns. The foundation catalog implements a coupon campaign in the
affiliate_receptor component.  If you want to add campaigns, you will
also need to develop the appropriate logic within the
affiliate_receptor component and pages that use it.

82.6.4. coupon_amount
---------------------

Example Data

   5

This is the discount offered customers from the affiliate
participating in the coupon campaign.

Note --  This is implemented in the affiliate_receptor component as a
flat discount amount. If you wanted a percentage discount instead, you
would modify the [discount] tag in
catalog_root/templates/components/affiliate_receptor (see the
[discount] tag for more detail).

82.6.5. join_date
-----------------

Example Data

   20000827
   20000910

This is the date when the affiliate signed with you.

82.6.6. url
-----------

Example Data

   http://demo.akopia.com/~hardhat
   http://www.minivend.com/consolidated/

The value in this field is used to direct visitors coming from the
Affiliate to your home page or a page you have designed specifically
for visitors from that Affiliate's site. Note that this should not be
the URL of the Affiliate's home site.

82.6.7. timeout
---------------

Example Data

   0
   3600

The value in this field is used to specify the amount of time a
customer has to place an order to still give the Affiliate credit for
it. If the customer goes over this amount of time, the Affiliate
doesn't get credit for the customer visit. The timeout delay is
measured in seconds, with the value of 0 (zero) disabling it. It is
recommended that you use a value in the thousands to make sure the
customer has enough time to shop.

82.6.8. active
--------------

This is a boolean value indicating whether the affiliate is active.

82.6.9. password
----------------

Example Data

   akopia

Password for affiliate login (see
catalog_root//pages/affiliate/login.html). Note that the password is
stored in plaintext by default.

82.6.10. image
--------------

Example Data

   http://demo.akopia.com/~hardhat/images/logo.gif
   http://www.minivend.com/consolidated/conslogo.gif

Affiliate's logo image.

82.7. area
----------

cat_root/products/area.txt

This table is used to implement dynamic navigation bars. For example,
it is used in the category_horizontal and category_vertical
components. Note the similarity to the cat table, since both area and
cat tables supply data for building links to results pages.

When building entries in a navigation bar, it is the  bar_link
subroutine in the /dist/catalog_before.cfg configuration file that
actually reads and processes the values from the table.

See also the following catalog and administrative templates:

o    cat_root/templates/components/category_horizontal

o    cat_root/templates/components/category_vertical

o    dist/lib/UI/pages/admin/layout.html

o    dist/lib/UI/pages/admin/layout_auto.html

o    dist/lib/UI/pages/admin/wizard/do_launch.html

o    dist/lib/UI/pages/admin/wizard/do_save.html

Fields

Field                              Description
.................................. .................................. 
code                               Unique key
sel                                Space-delimited list of navigation
                                   bars to contain the entry
name                               Display label
which_page                         Page class in which the navigation
                                   bar may appear
sort                               Sorting prefix for entry (preempts
                                   standard alphanumeric sort)
display_type                       How to label links in the navbar
                                   (name, icon, url or image)
image                              Image URL (if appropriate)
image_prop                         HTML attributes for output <img>
                                   tag (if appropriate)
banner_image                       Image name for use in target page
banner_text                        Text for use in target page
link_type                          Type of links in the navbar
                                   (external, internal, simple,
                                   complex)
url                                Target for internal or external
                                   link_type
tab                                Database table file to use with
                                   'simple' link_type
page                               Results page to use with 'simple'
                                   link_type
search                             Search spec used with 'complex'
                                   link_type
selector                           The selector used to scan the
                                   products table for products in the
                                   category
link_template                      Overrides template used for
                                   building navbar links.

82.7.1. code
------------

Example Data

   1
   2
   3

Unique key.

82.7.2. sel
-----------

Example Data

   left

Space-delimited list of navigation bars that should contain the entry.
Note that comma or null should also work as a delimiter.

82.7.3. name
------------

Example Data

   Hand Tools
   Hardware
   Ladders
   Measuring Tools
   Painting Supplies
   Safety Equipment
   Specials
   Tool Storage

Label to display.

82.7.4. which_page
------------------

Example Data

   all

Page class in which the navigation bar may appear.

82.7.5. sort
------------

Example Data

   00
   03
   04
   05
   06

Lexographic (alphanumeric) sorting prefix.  Note use of '03' rather
than '3', which would sort after '13'. This controls the order of the
categories in your navigation bar.

If this is not set, your navbar entries will sort in alphabetical
order.

82.7.6. display_type
--------------------

Example Data

   name
   icon
   url
   image

What to use for the labels in the navigation bar (for example, name,
icon, url or image). The navigation bars in the foundation catalog are
set up with 'name' display_type.

display type                       Link shown as
.................................. .................................. 
name                               Displays name only
icon                               Displays name and specified image
image                              Displays image only
url                                Displays link

82.7.7. image
-------------

Image URL for image or icon display_type.

82.7.8. image_prop
------------------

For image or icon display_type, this contains the HTML attributes for
the HTML that will appear in the navbar, for example:

  <img src="image" alt="name" image_prop>name

82.7.9. banner_image
--------------------

Example Data

   promo_image.gif

This field is not related to banner ads.  It is useful if you want to
pass to your results page an image that is specific for the navbar
entry (perhaps to display a banner above your results).

If you are using an Interchange search for your links (i.e., 'simple'
or 'complex' link_type), then this will add
'va=banner_image=banner_image' to the resulting search specification.
This puts the contents of banner_image into the Values hash of your
search results page.  You can access it with [value banner_image] (see
the value tag). You will have to modify the standard results page (or
set up and specify your own) in order to display the image.

   <IMG src="[value banner_image]" alt="[value banner_text]">

The foundation catalog does not implement banner_image in the
preconfigured navigation bars.

82.7.10. banner_text
--------------------

Example Data

   This Is A Title For Hand Tools

This field is not related to banner ads.  It is useful if you want to
pass to your results page some text that is specific for the navbar
entry (perhaps to display a title above your results).

If you are using an Interchange search for your links (i.e., 'simple'
or 'complex' link_type), then this will add
'va=banner_text=banner_text' to the resulting search specification.
This puts the contents of banner_text into the Values hash of your
search results page.  You can access it with [value banner_text] (see
the value tag). You will have to modify the standard results page (or
set up and specify your own) in order to display the text.

The foundation catalog does not implement banner_text in the
preconfigured navigation bars.

82.7.11. link_type
------------------

Example Data

   none
   external
   internal
   simple
   complex

Link type to create in the navigation bar.

Link type     Description
............. ....................................................... 
none          No link
external      External link. The HTML specified in url will go
              directly into the navigation bar.
internal      Internal link. This will be highlit if it is the
              current page. If you specify both a page and a form for
              the link, the url field should contain "page form". See
              the Search Engine documentation for more detail on
              search forms.
simple        Allows you to specify an Interchange search with a few
              values. See the bar_link subroutine in the
              /dist/catalog_before.cfg configuration file for more
              detail.
complex       Allows you to fully specify an Interchange search
              specification. See the bar_link subroutine in the
              /dist/catalog_before.cfg configuration file for more
              detail if you need to use these.

82.7.12. url
------------

Target URL (external link or internal page/search specification). See
link_type . The foundation catalog navigation bars are not set up with
link types that use the url field.

82.7.13. tab
------------

Database table file to use with 'simple' link_type (searchspec
fi=tab). The foundation catalog navigation bars are not set up with
link types that use the tab field.

82.7.14. page
-------------

Results page to use with 'simple' link_type (searchspec sp=page). The
foundation catalog navigation bars are not set up with link types that
use the page field.

82.7.15. search
---------------

Search spec used with 'complex' link_type. See the Search Engine
documentation for more detail on search forms. The foundation catalog
navigation bars are not set up with link types that use the search
field.

82.7.16. selector
-----------------

The selector that is used to scan the products table for products in
the category. Used with 'simple' link_type. The foundation catalog
navigation bars are not set up with link types that use the selector
field.

82.7.17. link_template
----------------------

Overrides the usual HTML link template for navbar entries.  See the
bar_link subroutine in the /dist/catalog_before.cfg configuration file
if you need to modify link templates.

The foundation catalog navigation bars are not set up with link types
that use the link_template field.

82.8. banner
------------

cat_root/products/banner.txt

The banner ad table. The foundation catalog does not implement any
banner ads with this table.

You do not need to use this table to display ads served by third
parties (for example, doubleclick). Since most banner ads on the
internet are served by third parties and are not managed by your
catalog, you probably will not need to set up banners here unless you
do your own advertising.

See Banner/Ad rotation in the template documentation for a detailed
description of the columns and content of the banner table.  Also, see
the banner tag documentation.

Fields

Field                              Description
.................................. .................................. 
code                               Key for the item. If the banners
                                   are not weighted, this should be a
                                   category-specific code.
category                           Category for set of weighted
                                   banners
weight                             Display frequency weight for
                                   weighted banner
rotate                             Boolean: parse banner field for
                                   banners to rotate if true (1)
banner                             Banner name or list of banners to
                                   rotate

82.8.1. code
------------

Example Data

   MyBanner
   MyBanner2
   MyBanner3
   default

See Banner/Ad rotation.

82.8.2. category
----------------

Example Data

   BannerCat1

See Banner/Ad rotation.

82.8.3. weight
--------------

Example Data

   1
   2
   7

See Banner/Ad rotation.

82.8.4. rotate
--------------

Boolean value. If true (1), rotates banners listed in banner. See
Banner/Ad rotation.

82.8.5. banner
--------------

Example Data

   Default banner 1{or}Default banner 2{or}Default banner 3
   First MyBanner
   Second MyBanner
   Third MyBanner

See Banner/Ad rotation.

82.9. cat
---------

cat_root/products/cat.txt

This table contains properties of product categories.  Notice the
similarity to the area table, since both the area and cat tables
supply data for building links to results pages.

Fields

Field                              Description
.................................. .................................. 
code                               Unique key
sel                                Space-delimited list of foreign
                                   keys into area table
name                               Category name
which_page                         Page class in which the category
                                   may appear
sort                               Sorting prefix for entry (preempts
                                   standard alphanumeric sort)
display_type                       How to label the category links
                                   (name, icon, url or image)
image                              Image URL (if appropriate)
image_prop                         HTML attributes for output <img>
                                   tag (if appropriate)
banner_image                       Image name for use in target page
banner_text                        Text for use in target page
link_type                          Type of links in the navbar
                                   (external, internal, simple,
                                   complex)
url                                Target for internal or external
                                   link_type
tab                                Database table file to use with
                                   'simple' link_type
page                               Results page to use with 'simple'
                                   link_type
search                             Search spec used with 'complex'
                                   link_type
selector                           The selector used to scan the
                                   products table for products in the
                                   category
link_template                      Overrides template used for
                                   building links

82.9.1. code
------------

Example Data

   1
   4
   5

Unique key.

82.9.2. sel
-----------

Example Data

   6
   8 9
   9

Space-delimited list of foreign key(s) into area table. The category
will appear in each navbar section (defined by a row in the area
table) where the key from cat.sel matches the area.code.

For example, the foundation catalog (tools) places Gift Certificates
in more than one category of the left navbar.

82.9.3. name
------------

Example Data

   Breathing Protection
   Eye Protection
   Gift Certificate
   Picks & Hatchets
   Pliers
   Rulers
   Sandpaper
   Toolboxes

Category name for display.

82.9.4. which_page
------------------

The page class. When building links, you can select categories
matching a page class. This means you could set up your catalog to
show a different list of links on page 'foo.html' than on page
'bar.html'.

82.9.5. sort
------------

Example Data

   01
   03

Lexographic (alphanumeric) sorting prefix.  Notice use of '03' rather
than '3', which would sort after '13'. You can use this to control the
order of the categories in a list of links.

82.9.6. display_type
--------------------

Example Data

   name
   icon
   url
   image

What to use for the labels in the navigation bar (for example, name,
icon, url or image). The links in the foundation catalog are set up
with 'name' display_type.

display type                       Link shown as
.................................. .................................. 
name                               Displays name only
icon                               Displays name and specified image
image                              Displays image only
url                                Displays link

82.9.7. image
-------------

Image URL for image or icon display_type.

82.9.8. image_prop
------------------

For image or icon display_type, this contains the HTML <img ...> tag
attributes for the links, for example:

  <img src="image" alt="name" image_prop>name

82.9.9. banner_image
--------------------

Example Data

   promo_image.gif

This field is not related to banner ads.  It is useful if you want to
pass to your results page an image that is specific for the navbar
entry (perhaps to display a banner above your results).

If you are using an Interchange search for your links (i.e., 'simple'
or 'complex' link_type), then this will add
'va=banner_image=banner_image' to the resulting search specification.
This puts the contents of banner_image into the Values hash in your
search results page.  You can access it with [value banner_image] (see
the value tag). You will have to modify the standard results page (or
set up and specify your own) in order to display the image.  For
example, you might include the following in your results page:

   <IMG src="[value banner_image]" alt="[value banner_text]">

82.9.10. banner_text
--------------------

This field is not related to banner ads.  It is useful if you want to
pass to your results page some text that is specific for the navbar
entry (perhaps to display a title above your results).

If you are using an Interchange search for your links (i.e., 'simple'
or 'complex' link_type), then this will add
'va=banner_text=banner_text' to the resulting search specification.
This puts the contents of banner_text into the Values hash in your
search results page.  You can access it with [value banner_text] (see
the value tag). You will have to modify the standard results page (or
set up and specify your own) in order to display the text.

82.9.11. link_type
------------------

Example Data

   none
   external
   internal
   simple
   complex

The link type to create.

Link type     Description
............. ....................................................... 
none          No link
external      External link. The HTML specified in url will go
              directly into the link.
internal      Internal link. This will be highlit if it is the
              current page. If you specify both a page and a form for
              the link, the url field should contain "page form". See
              the Search Engine documentation for more detail on
              search forms.
simple        Allows you to specify an Interchange search with a few
              values. See the bar_link subroutine in the
              /dist/catalog_before.cfg configuration file for more
              detail.
complex       Allows you to fully specify an Interchange search
              specification. See the bar_link subroutine in the
              /dist/catalog_before.cfg configuration file for more
              detail if you need to use these.

82.9.12. url
------------

Target URL (external link or internal page/search specification). See
link_types above.

82.9.13. tab
------------

Example Data

   products

Database table file to use with 'simple' link_type (searchspec
fi=tab).

82.9.14. page
-------------

Example Data

   swap_results

Results page to use with 'simple' link_type (searchspec sp=page).

82.9.15. search
---------------

Example Data

   fi=merchandising^Msf=featured^Mse=new
   fi=merchandising^Msf=featured^Mse=special^Msu=yes

Search spec used with 'complex' link_type. See the Search Engine
documentation for more detail on search forms.

Note: The '^M' delimiters in the sample data represents a carriage
return character (Control-M, or hexadecimal 0x0d).

82.9.16. selector
-----------------

Example Data

   category=Breathing Protection
   category=Eye Protection
   category=Gift Certificate
   category=Picks & Hatchets
   category=Pliers
   category=Rulers
   category=Sandpaper
   category=Toolboxes

The element that is used to scan the products table for products in
the category. Used with 'simple' link_type.

82.9.17. link_template
----------------------

Overrides the usual HTML link template for navbar entries.  See the
bar_link subroutine in the /dist/catalog_before.cfg configuration file
if you need to modify link templates.

82.10. country
--------------

A list of countries used to build select boxes, calculate tax, and set
shipping mode choices based on the user's country.

    code          Country code
    sorder        Used to determine sort order
    region        An enumerator to group based on region
    selector      The code that should be used (same as code)
    shipmodes     Shipping modes to be presented for that country
    name          Textual name of the country
    iso           ISO three letter code for the country
    isonum        ISO numeric code for the country
    tax           Tax information (may redirect to a state table)

82.11. downloadable
-------------------

This table controls downloadable products. The Marketing Reports data
set for the foundation catalog demonstrates downloadable products. 
List a product's sku in this table if you want to deliver it through a
download. A customer can then download the file specified in the
dl_location field after checkout.

For reference, see the implementation in the following files:

o    catalog_root/pages/deliver.html

o    catalog_root/etc/receipt.html

o    catalog_root/pages/query/order_detail.html

Fields

Field                              Description
.................................. .................................. 
sku                                Unique key, matches product.sku
dl_location                        Location of downloadable file
dl_type                            MIME type of downloadable file

82.11.1. sku
------------

Example Data

Example Data from the Marketing Reports data set:

   00352as
   22083da
   49503cg
   59330rt
   59402fw
   73358ee
   83491vp
   90773sh

This is the unique key for this table that is also the common key into
the products table.

82.11.2. dl_location
--------------------

Example Data from 'reports' catalog

   download/00352as.pdf
   download/22083da.pdf
   download/49503cg.pdf
   download/59330rt.pdf
   download/59402fw.pdf
   download/73358ee.pdf
   download/83491vp.pdf
   download/90773sh.pdf

File location of downloadable product.

82.11.3. dl_type
----------------

Example Data from 'reports' catalog

   application/pdf

MIME type of downloadable content.

82.12. files
------------

A database where files (pages, etc.) can be kept instead of in the
Unix filesystem. Not normally used in foundation.

82.13. inventory.txt
--------------------

    sku            Quantity info
    quantity       Gets decremented after each sale.
    stock_message  The usual shipping time of the product. Example choices:

                                      In stock
                                      Ships in 3-5 days
                                      Ships in 4-6 weeks
                                      Special order

    account        Sales account for accounting links
    cogs_account   Inventory account for accounting links

82.14. locale.txt
-----------------

    code
    en_US
    de_DE
    fr_FR

Used to develop localization. Can be used in conjunction with other
types of locale information. See Internationalization.

82.15. merchandising.txt
------------------------

    sku
    featured
    banner_text
    banner_image
    blurb_begin
    blurb_end
        Closer (end text for feature display)
    timed_promotion
    start_date
        Start date
    finish_date
    upsell_to
        Cross-sell SKUs
    cross_sell
    cross_category
    others_bought
    times_ordered

82.16. mv_metadata
------------------

See the following sections in the icadvanced catalog for more
information:

o    display tag and mv_metadata

o    mv_metadata.asc

82.17. options
--------------

This table contains data for implementing simple, matrix and modular
options.

Simple options are options that a customer can combine arbitrarily,
such as size and color. The selected options might affect price.  See
the accessories tag for more detail on option values for simple
options.

Matrix options are preconfigured combinations of options. For example,
if you sell titanium and carbon-fiber bike frames, but offer only
certain combinations of frame material and color, your checkout page
might include a select box with only the following entries:

o    Silver Titanium: $1672

o    Black Titanium: $1672

o    Red Titanium: $1674

o    Black Carbon Fiber: $1290

o    Yellow Flame Carbon Fiber: $1300

Note that there is no Yellow Flame Titanium offering, for example.

Modular options are like a structured bill of materials, where one
product is a master item and other products are subitems for that
master item. The subitems can also be master items to subitems at a
lower level. In addition, subitems may be designated as 'phantom',
which means that they are placeholders in the hierarchy of the
structured bill of materials with their own subitems, but are not
actual items themselves.

The foundation catalog with the computer data set uses modular
options.

For more information, see the following pages and components in the
foundation catalog:

o    cat_root/pages/flypage.html

o    cat_root/templates/components/modular_buy

o    cat_root/templates/components/modular_update

Note: Subsequent foundation catalog releases may place simple, matrix,
and modular option types in separate tables.

Fields

Field                              Description
.................................. .................................. 
code                               Unique ID for the product option
o_master                           SKU of the master item for the
                                   option
sku                                SKU for the option (foreign key
                                   into products table)
o_group                            Product grouping code
o_sort                             Sorting prefix for list display
phantom                            Boolean - Item is a phantom
                                   placeholder (as in structured bill
                                   of materials) with suboptions.
o_enable                           Boolean - enables suboptions for
                                   the option
o_matrix                           Matrix-type option (preconfigured
                                   combinations of attributes)
o_modular                          Modular-type option
                                   (master/subitem relationship like
                                   modular bill of materials)
o_default                          Default selection for the option
                                   group or suboption for a phantom
                                   option
o_label                            Short name for option display
o_value                            Simple option values (in
                                   Interchange option format)
o_widget                           The HTML widget to use for
                                   displaying the option group
o_footer                           Not used in foundation catalog
o_header                           Not used in foundation catalog
o_height                           Height of widget (if applicable)
o_width                            Width of widget
description                        Option/Variant description (for
                                   description in display)
price                              Price of this option/variant
wholesale                          Dealer price of this
                                   option/variant
differential                       Differential to add to the base
                                   item price when using a phantom
                                   bill of materials
weight                             Weight difference with this
                                   option/variant (for shipping)
volume                             Volume difference with this
                                   option/variant
mv_shipmode                        No Description
o_exclude                          Option groups to exclude (trumped
                                   by o_include). Modular only.
o_include                          Option groups to include (trumps
                                   o_exclude). Modular only.

82.17.1. code
-------------

Example Data

   1002
   1003
   1004
   1005

Unique ID for the option.

82.17.2. o_master
-----------------

Example Data

   00010
   999000
   999001
   999002

SKU of the master item for the option. The master item is one level up
in the modular hierarchy, and must be one of the following:

o    An item in the products table (matching products.sku)

o    Another option in the options table (matching options.sku)

o    A phantom item in the options table.

If an option has a master item, then a customer can not choose that
option without having previously selected the master item.

The price for a master item is the sum of the master item's price and
the price for each of the subitems. Because the subitems are
recursively defined, the top-level item reflects the top level price
plus the price of all selected options.

82.17.3. sku
------------

Example Data

   00010
   999000
   7000015
   7000030

The sku for the item or option. This may not be unique for matrix
options or if an option that belongs to multiple o_masters is listed
for each master.

82.17.4. o_group
----------------

Example Data

   A
   B
   C
   I

Product group (scanned to see whether it applies to this product or
not)

82.17.5. o_sort
---------------

Example Data

   01
   02
   03
   04
   47
   48
   49
   50

Sorting prefix for listing order of options.

82.17.6. phantom
----------------

Modular options only.

Boolean - if true (1), then this is a phantom item acting as a
placeholder for other items rather than an actual product. The item's
sku will not match an entry in the products table, though the o_master
will match either the sku of another phantom item in the options table
or the sku of an item in the products table.

82.17.7. o_enable
-----------------

Boolean - Enables subitems for this item or option. Note that an
option with o_enable false may itself still be a subitem for an option
or item above it.

82.17.8. o_matrix
-----------------

Boolean. Set true (1) for matrix-type options.  See the options table
in the tools data set for examples of matrix options. Matrix options
that are part of a set have the same value for options.sku.

82.17.9. o_modular
------------------

Specifies a modular option.  See main heading for description of
modular options.

82.17.10. o_default
-------------------

Example Data

   1
   11002
   7000062
   7000087

Selects the default option for a group.

82.17.11. o_label
-----------------

Example Data

   Add a second hard drive
   Case Color
   Case color
   Case style
   Include tapes
   Red

This is the short name for option display.

82.17.12. o_value
-----------------

Example Data

   1=One 8GB tape,\r2=Two 8GB tapes,\r=None*
   a=One 8GB tape,\rb=Two 8GB tapes,\r=None*
   baby=Baby Tower,\rmid=Mid-tower,\rfull=Full Tower
   baby=Baby tower,\rmid=Mid-tower,\rfull=Full tower
   red=Passion Red,\rblue=Electric Blue,\rgreen=Sea Green,\rgrey=S...
   red=Passion Red,\ryellow=Lemon Yellow,\rblue=Electric Blue,\rgr...
   red=Rage Red,\ryellow=Honey Yellow

This is an Interchange value set for a simple option. It is typically
a comma-delimited list of labels and values with '*' indicating the
default value.  See the accessories tag for more detail.

Note that the "\r" characters in the above example represent carriage
returns in the actual data ("\r" in perl, or Ctrl-M, or hexadecimal
0D), and the ... indicates a line too long to show.

82.17.13. o_widget
------------------

Example Data

   select

This determines the HTML Widget type (e.g., a select box).  For
example, the [options] tag uses this entry when building HTML widgets
in a page.  See also the [accessories] tag for available widgets.

82.17.14. o_footer
------------------

Example Data

Allowed Values

82.17.15. o_header
------------------

Example Data

Allowed Values

82.17.16. o_height
------------------

This allows you to set the height of the HTML widget, if appropriate.

82.17.17. o_width
-----------------

This allows you to set the width of the HTML widget, if appropriate.

82.17.18. description
---------------------

Example Data

   ATX Mid Tower-Grey (3)5.25 (2)3.5 & (1)3.5 Hidden
   Enlight ATX Desktop Case (2)5.25 & (2)3.5
   Enlight ATX Tower Case (4) 5.25 & (2)3.5
   Micro ATX Tower - Honey Yellow
   Micro ATX Tower - Moody Blue
   Micro ATX Tower - Rage Red
   Micro ATX Tower - Smoky Grey
   Super Tower Case (6)5.25 & (3)3.5

Longer description to show when displaying the options.

82.17.19. price
---------------

Example Data

   0.00
   10
   20
   29
   75

This sets the retail price of the option.

82.17.20. wholesale
-------------------

Example Data

   13
   40.00

This sets the dealer price of the option.

82.17.21. differential
----------------------

Example Data

   -209
   -40
   -79

The phantom bill of materials for an option group can have a
differential, which is an amount to add to the base price of the
master product to get to a new base price that accommodates the
phantom bill of materials. Note that the differential can be negative.

For example, in the computer data set of the foundation catalog, SKU
00011 in the products table is an $849.95 pre-configured Athlon 800MHz
computer that includes a 17" monitor (in this case, SKU 7000087 in the
products table).

The monitor by itself would otherwise have cost $209. It is much more
convenient if you can use the same option part number and price for
each item.  To do this, you need a phantom option (in this case, SKU
999105 in the options table only) with a differential of -209 and the
available monitors as suboptions. When you include the phantom option
in the bill of materials for the computer (SKU 00011), the $-209
differential adjustment makes the price work out properly.

For instance, suppose that a $499 computer is configured as follows:

        500 MHz Athlon         --  $499
        32 MB SDRAM            --  ZERO
        10 GB disk             --  ZERO

        TOTAL                  --  $499

Suppose it costs $90 to upgrade the base computer to 128M of RAM and
$150 for a 30 GB hard disk.

If you also sell an 128MB 800 MHz $899 computer, and the customer
upgrades to the 30 GB hard disk,

        800 MHz Athlon          --  $899
        (memory differential)   --  $-90
        128 MB RAM              --   $90
        30 GB  disk             --  $150

        TOTAL                   -- $1039

If you did not have the differential, you would need a different
option part number for each item make the number come out right.

With the differential, you can use the same part number for 128MB RAM
no matter what the base part is. The price is always $90 -- there is
just a -90 differential when ordered with the 800MHz Athlon, making
the effective price zero.

82.17.22. weight
----------------

Example Data

   5

Shipping weight of the option. Interchange uses this to calculate
shipping cost.

82.17.23. volume
----------------

Volume added by the option.

82.17.24. mv_shipmode
---------------------

No Description

82.17.25. o_exclude
-------------------

Modular options only.

Lists the option groups to exclude once the include has been done. 
Takes the form of a number of wildcard atoms.

82.17.26. o_include
-------------------

Modular options only.

Lists the option groups to include with your item. Takes the form of a
number of wildcard atoms.

82.18. order_returns.txt
------------------------

    code
    order_number
    session
    username
    rma_number
    nitems
    total
    return_date
    update_date

82.19. orderline.txt
--------------------

Every line item that is actually ordered is detailed in this table.
The order as a whole is one record in the transactions table.

See the page query/check_orders.html for how it can be used. See
etc/report for how to add to it.

    code
    store_id
    order_number
    session
    username
    shipmode
    sku
    quantity
    price
    subtotal
    shipping
    taxable
    mv_mi
    mv_si
    size
    color
    options
    order_date
    update_date
    status
            pending = Pending
            shipped = Shipped
            backorder = Back ordered
            credit = Waiting for credit check
            canceled = Cancelled
    parent
    affiliate
    campaign
    description
    mv_mp

82.20. pricing
--------------

This database works in conjunction with the CommonAdjust directive to
allow quantity pricing for one product or for a group of products
(sometimes known as mix-and-match). The fields q2, q5, q10, etc. are
for the quantity levels; the price_group field selects the
mix-and-match category for the product.

Fields

Field                              Description
.................................. .................................. 
sku                                Unique key, shared with products
                                   table
price_group                        Mix-and-match category
q2                                 Retail, 2 or more
q5                                 Retail, 5 or more
q10                                Retail, 10 or more
q25                                Retail, 25 or more
q100                               Retail, 100 or more
w2                                 Wholesale, 2 or more
w5                                 Wholesale, 5 or more
w10                                Wholesale, 10 or more
w25                                Wholesale, 25 or more
w100                               Wholesale, 100 or more

82.20.1. sku
------------

Example Data

   os28004
   os28006
   os28057c
   os28069

Unique key, matching the sku for an entry in products table.

82.20.2. price_group
--------------------

Example Data

   general

This field determines mix-and-match categories if you want to allow
mix-and-match quantity pricing (i.e., where 5 of these plus 5 of those
afford the q10 price for both these and those).

82.20.3. q2
-----------

If set, this will be the price per item when the order quantity is 2
or greater.

82.20.4. q5
-----------

If set, this will be the price per item when the order quantity is 5
or greater.

82.20.5. q10
------------

If set, this will be the price per item when the order quantity is 10
or greater.

82.20.6. q25
------------

If set, this will be the price per item when the order quantity is 25
or greater.

82.20.7. q100
-------------

If set, this will be the price per item when the order quantity is 100
or greater.

82.20.8. w2
-----------

If set, this will be the dealer price per item when the order quantity
is 2 or greater.

82.20.9. w5
-----------

If set, this will be the dealer price per item when the order quantity
is 5 or greater.

82.20.10. w10
-------------

If set, this will be the dealer price per item when the order quantity
is 10 or greater.

82.20.11. w25
-------------

If set, this will be the dealer price per item when the order quantity
is 25 or greater.

82.20.12. w100
--------------

If set, this will be the dealer price per item when the order quantity
is 100 or greater.

82.21. products
---------------

This is the main table for product data. See also 'The Product
Database' section in the database documentation.

The sku is also the master key in many of the related tables.

Fields

Field                              Description
.................................. .................................. 
sku                                Unique product ID
description                        Short description for list display
title                              Full title for book, CD, artwork,
                                   etc.
template_page                      Not used in foundation catalog. No
                                   description.
comment                            Longer description for item
                                   display (e.g., flypage.html)
thumb                              Thumbnail image
image                              Regular-sized image
price                              Retail quantity one price
wholesale                          Dealer minimum quantity price
prod_group                         Product supercategory
category                           Product category
nontaxable                         Boolean. Set true (1) if
                                   nontaxable
weight                             Weight in your units. Should match
                                   shipping table.
size                               List of options used with
                                   accessories tag.
color                              List of options used with
                                   accessories tag.
gift_cert                          Boolean. Set true (1) if this is a
                                   gift certificate.
related                            Deprecated in favor of
                                   merchandising.upsell_to
featured                           Deprecated. Use merchandising
                                   table.
inactive                           Boolean. Set true (1) to
                                   inactivate a product
url                                Not Documented

82.21.1. sku
------------

Example Data

   gift_cert
   os28004
   os28006
   os28057c

Unique identifier for the product.  You should use only characters of
the class A-Z a-z 0-9 _ - (i.e., matching the regular expression,
'[-A-Za-z0-9_]+').  Although Interchange itself does not impose this
restriction, you may have problems with SQL databases, file systems,
and URL encoding if you use other characters. For example, a slash (/)
can interfere with URLs and filenames, a colon (:) can interfere with
database representations (or file names on some operating systems),
i<etc.>

82.21.2. description
--------------------

Example Data

   Brush Set
   Disposable Brush Set
   Ergo Roller
   Gift Certificate
   Painters Brush Set
   Painters Ladder
   Spackling Knife
   Trim Brush

A short description for the product that is used for displaying in the
shopping cart, receipt, and order report.

82.21.3. title
--------------

Example Data

   Brush Set
   Disposable Brush Set
   Ergo Roller
   Gift Certificate
   Painters Brush Set
   Painters Ladder
   Spackling Knife
   Trim Brush

This column is not used in the foundation catalog. Previously used in
the Art store (simple) demo for a painting title. You probably want to
use description instead.

You should modify the products and other tables to suit your catalog's
requirements. You might use this field if you want to show titles for
books, music, or other titled merchandise. If you do not use a title
that is distinct from the short description, then you probably do not
need this column in the table at all.

82.21.4. template_page
----------------------

Not used in foundation catalog.

No Description.

82.21.5. comment
----------------

Example Data

   A must have for all painters!  This spackling knife is ergon...
   Enjoy the perfect feel and swing of our line of hammers. Thi...
   This set includes 2" and 3" trim brushes and our ergonomical...
   This set of disposable foam brushes is ideal for any stainin...

This is the field for a long description of the product. If you are
using an Interchange text/gdbm database, the field size is unlimited;
if using another type of database, the length will be dependent on the
field type selected.  If you are using a SQL database, see the
appropriate cat_root/dbconf subdirectory for a place to set COLUMN_DEF
values.  See also the database documentation, 'Importing from an ASCII
File', for details about defaults for columns that you do not define.

82.21.6. thumb
--------------

Example Data

   gift_certificate.gif
   os28004_b.gif
   os28005_b.gif
   os28006_b.gif

This is the filename for a small (thumbnail) image of the product.

82.21.7. image
--------------

Example Data

   gift_certificate_large.gif
   os28004.gif
   os28005.gif
   os28006.gif

This is the filename for a regular-sized image of the product, as it
should appear in an HTML <img src="image"> tag. You do not need to
specify the path if the image files are in the usual Interchange image
directory.

82.21.8. price
--------------

Example Data

   1.00
   12.99
   14.99
   9.99

The quantity-one price of the product.  See the wholesale field and
the price table for dealer and quantity pricing.

82.21.9. wholesale
------------------

Example Data

   1
   10
   11
   12

This is the minimum dealer price for the item.  For quantity pricing,
see the price table.

82.21.10. prod_group
--------------------

Example Data

   Hand Tools
   Hardware
   Ladders
   Measuring Tools
   Miscellaneous
   Painting Supplies
   Safety Equipment
   Tool Storage

Product group (supercategory).  This indicates the grouping of product
categories, for example in the navigation bars created from the area
table (note the match with the name data in the area table).

82.21.11. category
------------------

Example Data

   Brushes
   Gift Certificate
   Hammers
   Ladders
   Nails
   Paintbrushes
   Putty Knives
   Rollers

This is the category the product should appear in when you select a
list. You can put a product in more than one category, but you may
need to accommodate this in display and banner headings.  Embedded
perl is helpful for this.

82.21.12. nontaxable
--------------------

Boolean value.  If true (1), the sales tax calculation for an order
will not include the cost of the product.  See also the salestax tag.

82.21.13. weight
----------------

Example Data

   1
   2
   3

This is a numeric value of the weight used for determining shipping
costs (with UPS, for example).  In the US, this is typically the
weight in pounds in order to match the UPS, Fed Ex and other standard
shipping tables.

82.21.14. size
--------------

Example Data

   1", 2", 3"
   1', 1.5'
   1/4", 1/2", 3/4", 1", 2", 3"
   10oz, 15oz, 20 oz
   2"
   6'
   set
   standard, metric

This is where the old Construct Something demo store kept the 'size'
options for a product.  The foundation catalog now uses the options
table instead to handle product options (also sometimes called product
attributes).

The accessories tag can build HTML widgets from the comma-delimited
list of product options.  You can use a delimiter other than comma (if
compatible with the table) as long as you also set the delimiter in
the accessories tag.

You probably do not need this field if you use the options table (for
example, if you are building from the foundation catalog).

82.21.15. color
---------------

Another product option column. No longer used in the foundation
catalog. See size above for description.

82.21.16. gift_cert
-------------------

Boolean value.  If true (1), specifies that this product is a gift
certificate. See also the gift_certs table.

82.21.17. related
-----------------

Used for displaying "upsells," opportunities to purchase an additional
item when this one is purchased. Contains a comma-separated list of
SKUs to be offered.

The foundation catalog now instead uses the upsell_to field of the
merchandising table for upselling.

82.21.18. featured
------------------

Deprecated in favor of the  merchandising table.

82.21.19. inactive
------------------

If true (1), renders the product inactive (i.e., it will not appear in
the catalog).

82.21.20. url
-------------

Not Documented

82.22. route.txt
----------------

    code
    attach
    continue
    commit
    commit_tables
    counter
    credit_card
    cyber_mode
    email
    empty
    encrypt
    encrypt_program
    errors_to
    increment
    inline_profile
    individual_track
    individual_track_ext
    partial
    pgp_cc_key
    pgp_key
    profile
    receipt
    reply
    report
    rollback
    rollback_tables
    supplant
    track

82.23. salestax.asc
-------------------

82.24. shipping.asc
-------------------

Shipping methods table

82.25. state.txt
----------------

State/territory/county information

    code
    sorder
    country
    state
    name
    tax
    postcode
    shipmodes
    tax_name

82.26. transactions.txt
-----------------------

Each individual customer order has an entry in this table. The line
items are not entered here, but in the orderline table.

See the page query/check_orders.html for how it can be used. See
etc/report for how to add to it.

    code
    store_id
    order_number
    session
    username
    shipmode
    nitems
    subtotal
    shipping
    handling
    salestax
    total_cost
    fname
    lname
        Last Name
    company
    address1
    address2
        Address line 2
    city
    state
    zip
    country
    phone_day
        Daytime Phone
    phone_night
        Home Phone
    fax
    email
    b_fname
    b_lname
        Billing Last Name
    b_company
    b_address1
    b_address2
        Billing Address Line 2
    b_city
    b_state
        Billing State
    b_zip
        Billing Postcode
    b_country
        Billing Country
    b_phone
    order_date
    order_ymd
    order_wday
    payment_method
    po_number
    avs
    order_id
    update_date
    status
    affiliate
    campaign
    parent
    archived
    deleted
    complete
    comments

82.27. userdb.txt
-----------------

The user database used for maintaining customer address information,
account information, preferences, and more. See icdatabase for more
information.

    username
    password
    acl
    mod_time
    s_nickname
    company
    fname
    lname
    address1
    address2
    address3
    city
    state
    zip
        Postcode
    country
        Country
    phone_day
    mv_shipmode
    b_nickname
    b_fname
    b_lname
    b_address1
    b_address2
    b_address3
    b_city
    b_state
    b_zip
    b_country
    b_phone
        Billing Phone
    mv_credit_card_type
    mv_credit_card_exp_month
    mv_credit_card_exp_year
    p_nickname
    email
    fax
    phone_night
    fax_order
        Payment method:
            (none) = Credit Card
            1 = Fax or Mail
            2 = Purchase order
            3 = COD
    address_book
    accounts
    preferences
    carts
    owner
    file_acl
    db_acl
    order_numbers
    email_copy
    mail_list
        Mailing lists the customer has joined:
            offer = Special offers
            newsletter = Newsletter
            alert = Alerts and Recalls
            upgrade = Upgrades
    project_id
    account_id
    order_dest
    credit_limit
    inactive
    dealer
        Dealer:
            (none) = No
            1 = Yes
    b_company
    feedback
        ???

82.28. variable.txt
-------------------

Configuration database

    code
        Variable name
    Variable
    pref_group
        Preferences area

83. HTML Hypertext links
========================

Normally, regular hypertext links are not used in Interchange pages.
These kinds of links will not include the session ID. If the customer
follows an external link back to the catalog, the list of products
ordered so far will have been lost. The area tag is used to generate a
hypertext link which includes a session ID.

Instead of:

   <A HREF="/cgi-bin/catlink/shirts">Shirts</A>

Use:

   <A HREF="[area shirts]">Shirts</A>

84. Images
==========

Inline images are placed in Interchange pages in the normal fashion
with <IMG SRC="URL">. But since Interchange pages are served by a CGI
program, it will by default automatically rewrite relative image links
as absolute ones based on the ImageDir and ImageDirSecure directives.

85. Browser Cookies
===================

The Foundation store enables the Cookies directive so that users with
cookie-capable browsers will retain session context. Then, standard
HREF and Interchange page links can be intermixed without the fear of
losing the shopping basket. Cookie capability is also required to use
search caching, page caching, and statically generated pages. If the
user's browser does not support cookies, the cache will be ignored.

If planning to use more than one host name within the same domain for
naming purposes (perhaps a secure server and non-secure server), set
the domain with the CookieDomain directive. This must contain at least
two periods (.) as per the cookie specification, and must be located
in the same server as the domain.

86. Dependencies in administration
==================================

In general, it's a good idea to leave fields empty if you don't want
to use them, instead of removing them from the database altogether.
That way nothing in the administration interface or the Foundation
pages will break.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Interchange I18N Features
=========================

87. Internationalization
========================

Interchange has a rich set of internationalization (I18N) features
that allow conditional message display, differing price formats,
different currency definitions, price factoring, sorting, and other
settings. The definitions are maintained in the catalog.cfg file
through the use of built-in POSIX support and Interchange's Locale
directive. All settings are independent for each catalog and each user
visiting that catalog, since customers can access the same catalog in
an unlimited number of languages and currencies.

87.1. Configuring the Locale
----------------------------

It is recommended to use the ScratchDefault directive for setting the
catalog's default locale:

   ScratchDefault mv_locale de_DE

87.2. Setting the Locale
------------------------

The locale could be set to fr_FR (French for France) in one of two
ways:

[setlocale locale=locale* currency=locale* persist=1*]

     Immediately sets the locale to locale, and will cause it to
     persist in future user pages if the persist is set to a non-zero,
     non-blank value. If the currency attribute is set, the pricing
     and currency-specific locale keys and Interchange configuration
     directives are modified to that locale. If there are no
     arguments, it sets it back to the user's default locale as
     defined in the scratch variables mv_locale and mv_currency.

     This allows:

              Dollar Pricing:
          
              [setlocale en_US]
              [item-list]
              [item-code]: [item-price]<BR>
              [/item-list]
          
              Franc Pricing:
          
              [setlocale fr_FR]
              [item-list]
              [item-code]: [item-price]<BR>
              [/item-list]
          
              [comment] Return to the user's default locale [/comment]
              [setlocale]

[page process/locale/fr_FR/page/catalog]

     This is the same as [page catalog], except when the link is
     followed it will set the locale to fr_FR before displaying the
     page. This is persistent.

[page process/locale/fr_FR/currency/en_US/page/catalog]

     This is the same as [page catalog], except when the link is
     followed it will set the locale to fr_FR and the pricing/number
     display to the locale en_US before displaying the page. This is
     persistent.

Once the locale is persistently set for a user, it is in effect for
the duration of their session.

87.3. Interchange Locale Settings
---------------------------------

The Locale directive has many possible settings that allow complete
internationalization of page sets and currencies. The Locale directive
is defined in a series of key/value pairs with a key that contains
word characters only being followed by a value. The value must be
enclosed in double quotes if it contains whitespace. In this example,
the key is Value setting.

   Locale fr_FR "Value setting" "Configuration de valeur"
   Locale de_DE "Value setting" Werteinstellung

When accessed using the special tag [L]Value setting[/L], the value
Configuration de valeur will be displayed only if the locale is set to
fr_FR. If the locale is set to de_DE, the string Werteinstellung will
be displayed. If it is neither, the default value of Value setting
will be displayed.

The [L] and [/L] must be capitalized. This is done for speed of
processing as well as easy differentiation in text.

Another, way to do this is right in the page. The [LC] ... [/LC]
pragma pair permits specification of locale-dependent text.

 [LC]
           This is the default text.
   [fr_FR] Text for the fr_FR locale. [/fr_FR]
   [de_DE] Text for the de_DE locale. [/de_DE]
 [/LC]

You can also place an entirely new page in place of the default one if
the locale key is defined. When a locale is in force, and a key named
HTMLsuffix is set to that locale, Interchange first looks for a page
with a suffix corresponding to the locale. For example:

<A HREF="[area index]">Catalog home page</A>

If a page index.html exists, it will be the default. If the current
locale is fr_FR, a page "index.fr_FR" exists, and Locale looks like
this:

   Locale fr_FR HTMLsuffix  .fr_FR

Then, the .fr_FR page will be used instead of the .html page. For a
longer series of strings, the configuration file recognizes:

   Locale fr_FR <<EOF
   {
       "Value setting",
       "Configuration de valeur",

       "Search",
       "Recherche"
   }
   EOF

This example sets two string substitutions. As long as this is a valid
Perl syntax describing a series of settings, the text will be matched.
It can contain any arbitrary set of characters that don't contain [L]
and [/L]. If using double quotes, string literals like \n and \t are
recognized.

A database can also be used to set locale information. Locale
information can be added to any database in the catalog.cfg file, and
the values in it will overwrite previous settings. For more
information, see LocaleDatabase. The [L]default text[/L] is set before
any other page processing takes place. It is equivalent to the
characters "default text" or the appropriate Locale translation for
all intents and purposes. Interchange tags and Variable values can be
embedded.

Because the [L] message [/L] substitution is done before any tag
processing, the command [L][item-data table field][/L] will fail.
There is an additional [loc] message [/loc] UserTag supplied with the
distribution. It does the same thing as [L] [/L] except it is
programmed after all tag substitution is done. See the
interchange.cfg.dist file for the definition.

Note: Be careful when editing pages containing localization
information. Even changing one character of the message can  change
the key value and invalidate the message for other languages. To
prevent this, use:

   [L key]The default.[/L]

The key msg_key will then be used to index the message. This may be
preferable for many applications.

A localize script is included with Interchange. It will parse files
included on the command line and produce output that can be easily
edited to produce localized information. Given an existing file, it
will merge new information where appropriate.

87.4. Special Locale Keys for Price Representation
--------------------------------------------------

Interchange honors the standard POSIX keys:

   mon_decimal_point    or      decimal_point
   mon_thousands_sep    or      thousands_sep
   currency_symbol      or      int_currency_symbol
   frac_digits  or      p_cs_precedes

See the POSIX setlocale(3) man page for more information. These keys
will be used for formatting prices and approximates the number format
used in most countries. To set a custom price format, use these
special keys:

price_picture

     Interchange will format a currency number based on a "picture"
     given to it. The basic form is:

              Locale en_US price_picture "$ ###,###,###.##"

     The en_US locale, for the United States, would display 4452.3 as
     $ 4,452.30. The same display can be achieved with:

               Locale en_US mon_thousands_sep ,
               Locale en_US mon_decimal_point .
               Locale en_US p_cs_precedes     1
               Locale en_US currency_symbol   $

     A common price_picture for European countries would be
     ###.###.###,##, which would display that same number as 4.452,30.
     To add a franc notation at the end for the locale fr_FR, use the
     setting:

              Locale fr_FR price_picture "##.###,## fr"

IMPORTANT NOTE: The decimal point in use, set by mon_decimal_point,
and the thousands separator, set by mon_thousands_sep must match the
settings in the price_picture. The frac_digits setting is not used in
this case. It is derived from the location of the decimal (if any).

     The same setting for fr_FR above can be achieved with:

               Locale fr_FR mon_thousands_sep .
               Locale fr_FR mon_decimal_point ,
               Locale fr_FR p_cs_precedes     0
               Locale fr_FR currency_symbol   fr

     If the number of digits is greater than the # locations in the
     price_picture, the digits will be changed to asterisks. An
     overflow number above would show as **.***,** fr.

picture

     Same as price_picture, but sets the value returned if the
     [currency] tag is not used. If the number of digits is greater
     than the # locations in the picture, the digits will be changed
     to asterisks, displaying something like **,***.**.

87.5. Dynamic Locale Directive Changes
--------------------------------------

If a Locale key is set to correspond to an Interchange catalog.cfg
directive, that value will be set when the locale is set.

PageDir

     To use a different page directory for different locales, set the
     PageDir key. For example, to have two separate language page
     sets, French and English, set:

              # Establish the default at startup
              PageDir   english
              Locale fr_FR  PageDir  francais
              Locale en_US  PageDir  english

ImageDir

     To use a different image directory for different locales, set the
     ImageDir key. To have two separate language button sets, French
     and English, set:

              # Establish the default at startup
              ImageDir   /images/english/
              Locale fr_FR  ImageDir   /images/francais/
              Locale en_US  ImageDir   /images/english/

ImageDirSecure

     See ImageDir.

PriceField

     To use a different field in the products database for pricing
     based on locale, set the PriceField locale setting. For example:

              # Establish the default at startup
              PriceField    price
              Locale fr_FR  PriceField  prix

     The default will always be price, but if the locale fr_FR is set,
     the PriceField directive will change to prix to give prices in
     francs instead of dollars.

     If PriceBreaks is enabled, the prix field from the pricing
     database will be used to develop the quantity pricing.

Note: If no Locale settings are present, the display will always be
price, regardless of what was set in PriceField. Otherwise, it will
match PriceField.

PriceDivide

     Normally used to enable penny pricing with a setting of 100,
     PriceField can be used to do an automatic conversion calculation
     factor based on locale.

              # Default at startup is 1 if not set
              # Franc is strong these days!
              Locale fr_FR  PriceDivide  .20

     The price will now be divided by .20, making the franc price five
     times higher than the dollar.

PriceCommas

     This controls whether the mon_thousands_sep will be used for
     standard currency formatting. This setting will be ignored if you
     are using price_picture. Set the value to 1 or 0, to enable or
     disable it. Do not use yes or no.

              # Default at startup is Yes if not set
              PriceCommas  Yes
              Locale fr_FR  PriceCommas  0
              Locale en_US  PriceCommas  1

UseModifier

     Changes the fields from the set shopping cart options.

              # Default at startup is 1 if not set
              # Franc is strong these days!
              UseModifier format
              Locale fr_FR  UseModifier formats

     If a previous setting was made for an item based on another
     locale, it will be maintained.

PriceAdjustment

     Changes the fields set by UseModifier that will be used to adjust
     pricing for an automatic conversion factor based on locale. For
     example:

              # Default at startup
              PriceAdjustment  format
              Locale fr_FR  PriceAdjustment  formats

TaxShipping,SalesTax

     Same as the standard directives.

DescriptionField

     This changes the field accessed by default with the
     [item-description] and [description code] tags. For example

              # Establish the default at startup
              DescriptionField    description
              Locale fr_FR  DescriptionField desc_fr

The [locale] tag

     Standard error messages can be set based on Locale settings. Make
     sure not to use any of the predefined keys. It is safest to begin
     a key with msg_ . The default message is set between the [locale
     key] and [/locale] tags. See the example above.

87.6. Sorting Based on Locale
-----------------------------

The Interchange [sort database:field] keys will use the LC_COLLATE
setting for a locale provided that:

o    The operating system and C compiler support locales for POSIX,
     and have the locale definitions set.

o    The locale setting matches any configured locales.

If this arbitrary database named letters:

   code        letter
   00-0011     f
   99-102      
   19-202      a

and this loop:

   [loop 19-202 00-0011 99-102]
   [sort letters:letter]
   [loop-data letters letter]   [loop-code]
   [/loop]

used the default C setting for LC_COLLATE, the following would be
displayed:

   a  19-202
   f  00-0011
     99-102

If the proper LC_COLLATE settings for locale fr_FR were in effect,
then the above would become:

   a  19-202
     99-102
   f  00-0011

87.7. Placing Locale Information in a Database
----------------------------------------------

Interchange has the capability to read its locale information from a
database, named with the LocaleDatabase directive. The database can be
of any valid Interchange type. The locales are in columns, and the
keys are in rows. For example, to set up price information:

   key                 en_US   fr_FR   de_DE
   PriceDivide         1       .1590   .58
   mon_decimal_point   .       ,       ,
   mon_thousands_sep   ,       .
   currency_symbol     $        frs    DM
   ps_cs_precedes      1       0       0

This would translate to the following:

   Locale en_US PriceDivide         1
   Locale en_US mon_decimal_point   .
   Locale en_US mon_thousands_sep   ,
   Locale en_US currency_symbol     $
   Locale en_US ps_cs_precedes      1

   Locale fr_FR PriceDivide         .1590
   Locale fr_FR mon_decimal_point   ,
   Locale fr_FR mon_thousands_sep   .
   Locale fr_FR currency_symbol     " frs"
   Locale fr_FR ps_cs_precedes      0

   Locale de_DE PriceDivide         .58
   Locale de_DE mon_decimal_point   ,
   Locale de_DE mon_thousands_sep   " "
   Locale de_DE currency_symbol     "DM "
   Locale de_DE ps_cs_precedes      1

These settings append and overwrite any that are set in the catalog
configuration files, including any include files.

Important note: This information is only read during catalog
configuration. It is not reasonable to access a database for
translation or currency conversion in the normal course of events.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Interchange Programmer Reference
================================

88. Introduction
================

Interchange is a highly-complex but very powerful web application
server focused on ecommerce. It is built on the power of Perl, using
many of its standard modules and capabilities while defining many
more.

While Interchange focuses on e-commerce, it is really a
general-purpose database access, retrieval, and templating systems.
Besides online stores, here are some of the applications have been
built on top of it:

    Auction
    Calendar
    Configuration management
    Content management
    Document archival and rental
    Guestbook
    Image archival and download
    Intranet
    MP3 jukebox
    Poll
    Quiz
    Software repository
    Web log

This reference attempts to illuminate the source code of Interchagne
and how you can write Perl enhancements, gadgets, and applications
that integrate with Interchange.

88.1. Software installation
---------------------------

To follow along, it is recommended you get the latest release of
Interchange (4.9.1 as of this writing), unpack it from the tar file,
and install it at a private directory. For the purposes of this
document, it will be assumed that Interchange is installed at
/usr/local/interchange and that the catalogs are installed at
/usr/local/catalogs.

88.2. Software prerequisites
----------------------------

Interchange only requires a few added Perl modules, which can be
installed by getting the Perl CPAN bundle Bundle::Interchange. Install
that (usually as root) with:

        perl -MCPAN -e 'install Bundle::Interchange'

To get most of the modules Interchange can use:

        perl -MCPAN -e 'install Bundle::InterchangeKitchenSink'

88.3. Audience
--------------

This reference is not meant for casual users of Interchange. Though
they might learn something from reading it, it would probably not do
them much targeted good. A reasonable set of prerequisites to make
reading this document profitable include:

Programming knowledge

A good knowledge of Perl or strong knowledge of other programming
languages is needed.

Database knowledge

Interchange is all about databases, and a knowledge of the concepts of
database programming and SQL is strongly recommended.

Networking knowledge

The more you know about networking and the web, the more comfortable
you will be with this document.

UNIX knowledge

Almost all production Interchange servers are UNIX-based, so knowledge
of that is helpful.

89. Overview of Interchange
===========================

Interchange is a daemon server, similar to a web server. Its entry
point is usually talking to it over a socket via its own protocol.
That socket can be either UNIX domain or INET domain, or an infinite
number of either.

89.1. Catalogs
--------------

Interchange as a server dispatches connections to a catalog, an
independently-configurable set of data and templates. These are for
the most part completely independent of each other, though they
inherit common global characteristics and settings. Almost all of
those can be overridden by the catalog.

89.2. Hacking
-------------

Of course Interchange's source is completely open and available. You
could, if you wished, hack on it all you wanted. However this is
strongly discouraged, for the simple reason that you can override
almost any behavior with configurations and tag definitions of your
own. In fact, if you want to override a core routine you can even do
that.

So if you are tempted to hack a routine in the core, simply override
it with:

GlobalSub <<EOR
sub override_me {
        package Vend::Interpolate;
        sub shipping {
                your_code();
        }
}
EOR


89.3. ITL -- Interchange Tag Language
-------------------------------------

Interchange delivers its content by parsing templates that contain
text and ITL, tags in the Interchange Tag Language.

ITL takes the form of HTML-like tags using [square brackets] as the
tag introduction. Here is an ITL tag sequence:

        [if value name]
        Your name is [value name], in case you forgot.
        [/if]

The above will show the contents of the [if ...] [/if] container
providing a non-blank, non-zero value is present in the user session.

ITL provides direct access to Perl via the ITL container tags [perl],
[calc] and [calcn], and [mvasp]. This allows ITL like:

        [calc]
                my $out = '';
                if($Values->{name}) {
                        $out = "Your name is $Values->{name}, in case you forgot.";
                }
                return $out;
        [/calc]

The above is completely identical to the ITL-only snippet above in
effect.

In addition, you can call defined ITL tags in your embedded Perl:

        [calc]
                my $out = '';
                my $name = $Tag->value('name');
                if($name) {
                        $out = "Your name is $Values->{name}, in case you forgot.";
                }
                return $out;
        [/calc]

Again, the result is identical to the previous two examples.

89.3.1. User Defined Tags
-------------------------

ITL is comprehensibly extensible. You can produce your own ITL tags
that are fully as powerful as the ones supplied with the distribution.
In fact they are indistinguishable, as you will see when you examine
the code hierarchy.

These tags can use any Perl module, use external programs, or
basically do most anything Perl can, providing you define them in the
Global configuration. Tags defined in the Catalog configuration are
restricted by Perl's standard Opcode and Safe facilities, though they
can optionally be allowed global capability.

See the ictags manpage for complete information on ITL.

89.4. Talking to Interchange via socket
---------------------------------------

Interchange can run in any of several modes:

Foreground

The foreground, meaning the same Interchange server listens for
connections and then runs the tasks those connections cause.

Forking mode

One master Interchange listens for connections, then forks instances
to handle the tasks those connections cause. The forked instance
terminates at the end of the task.

Prefork mode

Similar to the way Apache does, Interchange can fork off a number of
instances that all listen to the sockets open for connections. The
first one to answer gets the task, runs it, then returns to listen
again. After MaxChildRequests requests, it dies and causes another new
instance to take its place.

mod_perl mode

Interchange can be loaded into mod_perl. See the documentation in
scripts/ic_mod_perl.PL for information.

SOAP mode

Interchange can listen to a socket designed to accept a SOAP
connection -- those always run in prefork mode. This mode can co-exist
with other modes, so the same Interchange server can serve both page
and SOAP requests.

89.5. Talking to Interchange over the command line
--------------------------------------------------

Interchange starts its servers by being invoked from the command line.
Other command line invocations can stop the server via signal, cause
addition of additional catalogs to respond to, remove catalogs from
the list to respond to, or cause execution of "cron" jobs.

89.6. Data structure overview
-----------------------------

Interchange has three major data stuctures, which correspond to the
master server, the catalog, and the user.

You can examine two of these structures by setting in interchange.cfg:

        DumpStructure  Yes

This will by default dump an interchange.structure file which shows
the global configuration, and a CATALOGNAME.structure file in each
catalog directory showing that catalog's configuration.

The third structure, the user data session, can be viewed with the
following ITL placed in a page:

        <XMP>[dump]</XMP>

89.6.1. The Global configuration
--------------------------------

This is held in a set of variables inhabiting the Global package. They
define overall server behavior, and contain pointers to the catalog
structures.

The Global configuration is defined in interchange.cfg and any files
that it reads via include statements. The configuration is produced by
parsing interchange.cfg with the routine Vend::Config::global_config.

Directives can be defined for parsing by the catalog configuration
within the global configuration -- and they can be deleted as well.

The only way to define new global directives is via hacking the
source. Luckily, this is just about never needed -- you can define
settings for use by your programs in Variable or other repositories.

89.6.2. The Catalog configuration
---------------------------------

Each Interchange catalog has its own configuration completely
independent from others. It is basically produced from the file
catalog.cfg in the directory defined as the base for the catalog. It
is parsed by the subroutine Vend::Config::config.

We say basically, because there are many ways to alter catalog
configuration. (CATNAME below refers to the name of the catalog being
configured.)

ConfigAllBefore

Global catalog configuration preamble, affecting all catalogs, can be
defined by the Global directive ConfigAllBefore. It defaults to
catalog_before.cfg in the Interchange software directory
(/usr/local/interchange).

LI1. CATNAME.before

An individual per-catalog preamble configuration is defined in
$Global::ConfDir/CATNAME.before.

By default it would be /usr/local/interchange/etc/CATNAME.before.

CATNAME.site

A file in the catalog directory which is read before catalog.cfg.
Deprecated.

catalog.cfg

The normal configuration file.

CATNAME.after

An individual per-catalog postamble configuration is defined in
$Global::ConfDir/CATALOGNAME.after. This can be used to prevent user
catalogs from doing unsafe things -- for instance enforcing the use of
encryption, or preventing running in WideOpen mode.

By default it would be /usr/local/interchange/etc/CATALOGNAME.after.

ConfigAllAfter

Global catalog configuration postamble, affecting all catalogs, can be
defined by the Global directive ConfigAllAfter. It defaults to
catalog_after.cfg in the Interchange software directory
(/usr/local/interchange).

command line

Any configuration passed on the command line at Interchange startup is
applied last. For instance, to test out a catalog named foundation
with a different invocation URL without having to alter the config
files:

bin/interchange --foundation:VendURL=http://localhost/cgi-bin/found \

          o    foundation:SecureURL=http://localhost/cgi-bin/found \

          o    foundation:RobotLimit=1000

That will set the foundation catalog directive values VendURL,
SecureURL, and RobotLimit, overriding any settings in the
configuration files.

Tied configuration

Interchange has dynamic catalog configuration as well. See Programming
Watch Points in catalog.cfg.

89.7. Session data structure
----------------------------

Each user session is a hash reference saved in some sort of data
repository. By default it is file-based using the Storable manpage,
but it can reside in any Interchange database type as well.

It is placed at the global variable location $Vend::Session, which for
programming use in UserTag and GlobalSub routines is $Session (meaning
$Vend::Interpolate::Session).

The structure is initialized when the session is created (or canceled
by the user). The initial form is described in
Vend::Session::init_session:

    $Vend::Session = {
                'ohost'         => $CGI::remote_addr,
                'arg'           => $Vend::Argument,
                'browser'       => $CGI::useragent,
                'referer'       => $CGI::referer,
                'scratch'       => { %{$Vend::Cfg->{ScratchDefault}} },
                'values'        => { %{$Vend::Cfg->{ValuesDefault}} },
                'carts'         => {main => []},
                'levies'        => {main => []},
    };

This structure is used as a repository for the transitory user session
values like form values, scratch variable settings, payment
transaction results, errors, and any other user-tied values. It is
also possible to add code that can be run on a user-by-user basis with
the Autoload, Filter, and Profile facilities.

90. Tour the source
===================

Navigating the Interchange source requires a couple of clues. The main
program invocation point is bin/interchange in the Interchange
software directory.

90.1. From startup to serving content
-------------------------------------

Once Interchange is invoked, it does some basic program configuration
at the top of that file. The types of available database facilities
and modules are determined, and the base modules are brought in with
"use" or "require". Execution by a non-root user ID is checked.

After the initial program configuration, execution goes to the
main_loop() subroutine in bin/interchange. Some more initialization is
done, then the command line options are parsed. Options mostly will
set the program mode (i.e. start, stop, kill, test, cron, or other
command line actions), but can also set Global and Catalog
configuration values.

Once the options are parsed, Interchange will chdir() to the
Interchange software directory (/usr/local/interchange) and run its
global configuration. That means all file names passed to it during
this phase are relative to that program root.

Part of global configuration is determination of the ITL tags that
will be used by Interchange. By default, that is all files with
appropriate extensions under the code directory. Sets of tags to be
used can be set with the TagGroup and TagInclude directives.

Global configuration also includes specifying the catalogs that will
be configured and loaded in the next phase. This is done via the
Catalog directive. An important part of that directive is supplying
the script parameter, which is used to initialize the pointer
structure which will select the catalog based on the URL coming in.

After Global configuration, catalog configuration commences, via the
::config_named_catalog() routine, which calls Vend::Config::config().
Each catalog specified in the global configuration has a base
directory. Interchange does a chdir() to that directory and parses the
various configuration files, databases and specified command-line
parameters.

After the catalog is configured, the database is opened to ensure that
database table objects are initialized properly. It is then
immediately closed.

The resulting Catalog configuration structure reference is then saved
in $Global::Selector and $Global::SelectorAlias so that the calling
URL can map to the proper catalog.

Once all configuration is done, Interchange determines the program
mode. There are only two modes -- test and serve. The test mode simply
exits the program at this point -- it is used to test validity of the
configuration.

If the mode is serve, ::main_loop() calls Vend::Server::run_server().
Based on global configuration, one of the server modes discussed
previously is initialized and Interchange starts listening on one or
more sockets for a connection from a client. (This is not true for
mod_perl mode -- Interchange simply exits at that point and the code
is waiting for mod_perl to call it.)

While waiting for a connection, signals are disabled and handlers are
set up for TERM, HUP, INT, USR1, and USR2. TERM and INT both cause the
main server to exit; HUP signals Interchange to look for a
reconfiguration event; and USR1 and USR2 are optionally used to keep
track of how many servers are running.

NOTE: Because signals are not especially safe in Perl prior to 5.8.0,
occasionally a core dump can occur on receipt of USR1 or USR2. This is
especially true for BSD with its reentrant system calls. They can be
disabled by setting MaxServers to 0 -- PreFork mode is strongly
suggested if that is done.

Once a connection is received, the connector parameters are checked
for security constraints and Vend::Server::connection() is called. It
reads the input from the client and constructs the environment,
%CGI::values array, and any passed entity like an HTTP POST or
multipart form (for file upload). Those are stored and and object
referring to them and containing the connection file handle is
constructed. That object is passed to main::dispatch() for processing.

The main::dispatch() routine performs more transaction setup then
determines the catalog that will process the request. It sets
$Vend::Cfg to the preset configuration for that catalog, sets file
permissions as appropriate, and the catalog's database is opened.

Once initialiation of the catalog configuraion is complete, user
initialization begins. Interchange determines the user session ID, if
any, and restores the user session from the session database or starts
a new session as appropriate. Perl objects that will be used in the
session are initialized or constructed, auto-login is run, and the
locale is determined and set. After that, the URI path is parsed,
Autoload and Filter routines are run.

Finally a transaction action is determined. The action is the first
path component of the path passed to Interchange. The remainder is
passed to the subroutine implementing the action, and may be used as
default path information for content or for other purposes.

For example, if the catalog VendURL is /cgi-bin/foundation and the URI
sent to Interchange is /cgi-bin/foundation/order/something/or/another,
the action is order, and the path sent to the action routine is is
something/or/another.

If the transaction action is not mapped via standard system actions
defined in the variable %action, or in the ActionMap *global* or
ActionMap directives, then the action path component is restored to
the content path, and that page is served (order/something/or/another
in the example above).

If the action is mapped, it is run. If it returns a true value, the
page to be served is determined by the setting of
$CGI::values::mv_nextpage. The action can produce send its own output
and return a non-true value, in which case Interchange will terminate
the transaction at that time.

After the action is run and/or content is served, Interchange runs
AutoEnd, saves the user session, closes the catalog database, and
finally main::dispatch() returns. The calling
Vend::Server::connection() does some cleanup and returns to the server
loop. If the server was forked for that transaction only, it sends a
signal indicating it is done, cleans up PID files, and exits. If it is
in the foreground or in PreFork mode, it scrubs the Vend:: and CGI::
namespaces and returns to waiting for the next connection.

90.2. Notes about databases
---------------------------

Interchange maintains objects for all of its database tables defined
in Database. These can be of diverse SQL, DBM, and LDAP types.

When the database is initialized at catalog configuration time, the
individual database tables may be opened depending on type. In
general, SQL and LDAP types are always opened, and DBM types are not.

Opening a database table can be expensive in terms of CPU and IO time.
So when the database is opened for a page transaction, Interchange
creates a "dummy" table object that waits for a real access. Those
objects are trivial to create, and a fast processor can create
hundreds of thousands per second.

When  access is made, the database table is really opened and the
expensive initialization is done. This allows many tables to be ready
for access while only the ones used take up CPU and IO time.

91. Interchange Special Variables
=================================

Interchange defines some special variables which control behavior.
They can be of several types, and the conventions for using them
depend on whether you have based your catalog and server on the
standard "foundation" distribution.

We will distinguish between these by calling intrinsic variables CORE
variables, noting the distribution variables as DISTRIBUTION, and
noting the foundation catalog practices as FOUNDATION.

91.1. "Variable" configuration file definitions
-----------------------------------------------

Defined in interchange.cfg or catalog.cfg with the Variable
configuration directive, these are accessed with:

  Access in ITL with           From
  -----------------------      -------------------
  __VARNAME__                  (catalog.cfg only)
  @_VARNAME_@                  (catalog.cfg, falls back to interchange.cfg)
  @@VARNAME@@                  (interchange.cfg only)
  [var VARNAME]                (catalog.cfg only)
  [var VARNAME 1]              (interchange.cfg only)
  [var VARNAME 2]              (catalog.cfg, falls back to interchange.cfg)

  Embedded Perl                From
  -----------------------      -------------------
  $Variable->{VARNAME}         (catalog.cfg only)
  $Tag->var('VARNAME')         (catalog.cfg only)
  $Tag->var('VARNAME', 1)      (interchange.cfg only)
  $Tag->var('VARNAME', 2)      (catalog.cfg, falls back to interchange.cfg)
  $Global::Variable->{VARNAME} (interchange.cfg only, only in Global code)

Variables set with Variable are not normally modified dynamically,
though you can do it as a part of the Autoload routine or in other
code. They will not retain the value unless DynamicVariables is in
use.

91.2. Scratch
-------------

User scratch variables are initialized whenever a new user session is
created. They start with whatever is defined in the ScratchDefault
directive in catalog.cfg; otherwise they are not defined.

  Access in ITL with           Attributes
  -----------------------      -------------------
  [scratch varname]            Displays
  [scratchd varname]           Displays and deletes

  Embedded Perl                From
  -----------------------      -------------------
  $Scratch->{varname}          Accessor
  $Session->{scratch}{varname} Equivalent

They can be set in several ways:

  Set in ITL with              Attributes
  -----------------------      -------------------
  [set varname]VAL[/set]       Sets to VAL, no interpretation of ITL inside
  [seti varname]VAL[/seti]     Sets to VAL, interprets ITL inside
  [tmpn varname]VAL[/tmpn]     Sets to VAL, no ITL interpretation, temporary
  [tmp  varname]VAL[/tmp]      Sets to VAL, interprets ITL inside, temporary

  Embedded Perl                From
  -----------------------      -------------------
  $Scratch->{varname} = 'VAL'; Sets to VAL
  $Tag->tmp(varname);          Set as temporary, must set value afterwards.


91.3. CGI
---------

CGI variables are the raw data which comes from the user.

     WARNING: It is a security risk to use these variables for display
     in the page.

You can use them for testing without worry, though you should never
set their value into a database or display on the page unless you have
processed them first, as they can have arbitrary values. The most
common security risk is displaying HTML code, which allows remote
scripting exploits like cookie-stealing.

    [calc]
        ####  DO NOT DO THIS!!!!
        my $out = $CGI->{varname};
        return $out;
    [/calc]

That will transform the value. If you wish to output a safe value but
keep the actual value intact, do:

    [calc]
        ####  This is safe, makes value safe for rest of page
        my $out = $Tag->cgi( { name => 'varname', filter => 'entities' } );
        ####  This is safe too, doesn't transform value
        my $other = $Tag->filter($CGI->{varname}, 'entities');

        ### Now you can return stuff to the page
        return $out . $other;
    [/calc]

The access methods are:

  Access in ITL with                 Attributes
  -----------------------            -------------------
  [cgi varname]                      Doesn't stop ITL code, don't use!
  [cgi name=varname filter=entities] Use this for safety

  Embedded Perl                From
  -----------------------      -------------------
  $CGI->{varname}              Don't use for output values!

They can be set as well.

  Set in ITL with                       Attributes
  -----------------------               -------------------
  [cgi name=varname set="VAL"]          Sets to VAL, VAL can be ITL, shows VAL
  [cgi name=varname set="VAL" hide=1]   Sets to VAL, VAL can be ITL, no output

  Embedded Perl                From
  -----------------------      -------------------
  $CGI->{varname} = 'VAL';     Sets to VAL, next access to [cgi varname]
                               shows new value


91.4. Values
------------

User form variables are initialized whenever a new user session is
created. They start with whatever is defined in the ValuesDefault
directive in catalog.cfg; otherwise they are not defined except as
called out in other configuration directives, i.e. the obsolete
DefaultShipping.

  Access in ITL with           Attributes
  -----------------------      -------------------
  [value varname]              Displays

  Embedded Perl                From
  -----------------------      -------------------
  $Values->{varname}           Accessor

They can be set as well, though the normal method of setting is from
user input via form. If Interchange receives an action which performs
the update of values (by default go or return, refresh, or submit),
the value of CGI variables will be transferred to them subject to
other considerations (FormIgnore settings, credit card variables,
etc., discussed below).!block example

  Set in ITL with                         Attributes
  -----------------------                 -------------------
  [value name=varname set="VAL"]          Sets to VAL, VAL can be ITL, shows VAL
  [value name=varname set="VAL" hide=1]   Sets to VAL, VAL can be ITL, no output

  Embedded Perl                           Attributes
  -----------------------                 -------------------
  $Values->{varname} = 'VAL';             Sets to VAL, next access to
                                          [value varname] shows new value

91.5. Session variables
-----------------------

You can also directly access the user session. Normally you don't set
these values unless you are an experienced Interchange programmer, but
there are several values that are frequently used.

One example is username, which holds the logged-in user's username.

  Access in ITL with           Attributes
  -----------------------      -------------------
  [data session username]      Displays

  Embedded Perl                From
  -----------------------      -------------------
  $Session->{username}         Accessor

They can be set as well, but if you are experienced enough to
contemplate doing these things you will easily be able to figure it
out.

91.6. Values not transmitted from CGI
-------------------------------------

The following variables are never copied from CGI:

        mv_todo
        mv_todo.submit.x
        mv_todo.submit.y
        mv_todo.return.x
        mv_todo.return.y
        mv_todo.checkout.x
        mv_todo.checkout.y
        mv_todo.todo.x
        mv_todo.todo.y
        mv_todo.map
        mv_doit
        mv_check
        mv_click
        mv_nextpage
        mv_failpage
        mv_successpage
        mv_more_ip
        mv_credit_card_number
        mv_credit_card_cvv2

You can define more with the FormIgnore catalog.cfg directive.

91.7. Global program variables
------------------------------

If you are programming a GlobalSub or global UserTag, you have access
to all Interchange facilities including all the preset variables and
configuration directives.

The Global package is used to hold variables that are set at program
start and whose value is retained.

The Vend package is used for variables that might be set at some point
during program execution, but that will always be reset to undefined
at the end of the transaction.

One example is $Vend::Cookie, which holds the raw cookie value sent by
the user.

If you are going to set or access these variables, you should be
getting your documentation from the source code. A few will be shown
here, but most will not.

92. Variable listing
====================

92.1. Standard global (interchange.cfg) Variable values
-------------------------------------------------------

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Configuration Reference
=======================

93. Interchange Table Editor
============================

Interchange has a powerful, highly-configurable table editor
application implemented via its [table-editor] ... tag.

It is called in an Interchange page as simply as:

    [table-editor cgi=1]

Given that call, it reads the passed CGI query information and builds
a table editor for an interchange table.

Each field within the table editor is completely configurable for HTML
widget type, label, help links, and more. These configurations can be
saved in the mv_metadata database, or can be specified in the
table-editor tag call itself.

The table editor is portable. It will work with any DBI/SQL database,
with LDAP databases, and with Interchange DBM and plain-file
databases.

Much of the Interchange administrative user interface (UI) is built
around the table editor.

Its features include:

Complete range of widgets and data filters

Interchange has 18 different HTML widget types with data filters to
condition the data.

Link fields from any table

Though the table editor uses one table as its base, fields from other
tables can be brought in, and entire sets of records relationally
linked to the base record can be edited within the table editor.

Tabbed display

Interchange automatically builds a tabbed interface from your fields
specification.

"Wizard" mode

The table editor has a "wizard" mode that can collect information for
accomplishing installation or setup tasks, with Next, Back, Cancel and
Finish modes.

Templatable setup

You can completely control the way the table editor displays the
widgets without interfering with its functionality.

Complex data structures

Interchange can build arbitrarily-deep data structures from form
input. The collected data is serialized with the equivalent of Perl's
Data::Dumper and stored in a single database field.

93.1. Calling the table editor
------------------------------

In its simplest form, table-editor is called in an ITL page with:

    [table-editor table=products key=os28004][/table-editor]

That will edit the table products using its default configuration, for
the SKU os28004.

If no metadata is defined for the table, all fields are edited. To
limit it with the tag call:

    [table-editor
        table=products
        key=os28004
        fields="sku price description" ][/table-editor]

To specify that the field description should have a different widget
type, height, and width, you can specify:

    [table-editor
        table=products
        key=os28004
        fields="sku price description"
        widget.description=textarea
        width.description=50
        height.description=10
    ][/table-editor]

If you do this with the default foundation demo catalog, you will see:

   SKU            __________________________________

   Product Price  __________

                  +---------------------------------------------+
                  |                                             |
   Short          |                                             |
   Description    |                                             |
                  |                                             |
                  +---------------------------------------------+

Note that the labels are pulled from the mv_metadata definition -- any
attributes not specified in the options do that. You can override each
in turn -- to change SKU to "Part Number" you can do:

    [table-editor
        table=products
        key=os28004
        fields="sku price description"

        label.sku="Part number"

        widget.description=textarea
        width.description=50
        height.description=10
    ][/table-editor]

To change the style of the label column, you can set the style
information with:

    [table-editor
        table=products
        key=os28004
        fields="sku price description"

        label_cell_style="font-weight: bold"

        label.sku="Part number"
        widget.description=textarea
        width.description=50
        height.description=10
    ][/table-editor]

This should bold the label text.

These are just a few small examples. There are more than 150 options
for table editor which we will discuss below.

93.2. Attributes and attribute quoting
--------------------------------------

The [table-editor] is capable of accepting a large number of
attributes. It uses standard ITL tag quoting, explained in the
Interchange Tag Reference.

You can quote with single-quote (<'>), double-quote ("), backtick (`),
or pipe (|). Material placed in backticks is run through a safe Perl
interpreter. In fact, it is the equivalent of using the [calc] [/calc]
tag pair except that contained ITL tags are not interpolated.

Pipe-quoting has the attribute of stripping trailing and leading
whitespace; it is often convenient when specifying JavaScript (which
uses both single and double quotes frequently) in the various *_extra
parameters.

93.3. Templating
----------------

The [table-editor] is templated on several levels. In the most basic
use, where you rely on it to build the table rows, there is the
row_template option. By default, it is:

   <td$opt->{label_cell_extra}>
     {BLABEL}{LABEL}{ELABEL}{META_STRING}
   </td>
   <td$opt->{data_cell_extra}>
     <table cellspacing=0 cellmargin=0 width="100%">
       <tr>
         <td$opt->{widget_cell_extra}>
           {WIDGET}
         </td>
         <td$opt->{help_cell_extra}>
            {TKEY}
            {HELP?}<i>{HELP}</i>{/HELP?}
            {HELP_URL?}<BR><A HREF="{HELP_URL}">help</A>{/HELP_URL?}
         </td>
       </tr>
     </table>
   </td>

The values of $opt->{*_cell_extra} are constructed from the
*_cell_class,

o    _cell_width, *_cell_valign, *_cell_align, *_cell_style, and
     *_cell_extra options. You can watch the effect by trying
     different settings:

  [table-editor
            table=products
            key=os28004
            label_cell_class=myclass
            label_cell_width=10%
            label_cell_valign=top
            label_cell_extra=|bgcolor="cyan"|
            ][/table-editor]

The values specified with {LABEL}, {WIDGET}, etc. are what are used to
substitute the widget values constructed from the metadata. A
perfectly functional template would be:

<td>{LABEL}</td><td>{WIDGET}</td>

That would show the label and widget without any help being shown
(even if it is available) and using the default styles for at table
data cell.

There is also the overall template, which is passed as the container
text for [table-editor]. Something equivalent to the default can be
achieved with:

{TOP_OF_FORM} {HIDDEN_FIELDS} <table> <tr> <td>&nbsp;</td>
<td>{TOP_BUTTONS}</td> </tr> {:REST} <tr> <td>&nbsp;</td>
<td>{BOTTOM_BUTTONS}</td> </tr> </table> {BOTTOM_OF_FORM}

There are two other templates -- the break_template and the
combo_template. See "Templates".

93.4. Metadata
--------------

Interchange's foundation demonstration catalog and UI rely on a table
named mv_metadata, which contains the definitions for table and field
appearance. This table is supported with a table definition editor
(pages/admin/db_metaconfig) and a field definition editor
(pages/admin/meta_editor).

The mv_metadata table has the following fields:

code

The key for the table. Normally, it takes the form

    table::column

where table is the table the field is contained in, and column is the
table column name. It can also take the forms:

    view::table::column::key
    view::table::column
    table::column::key

Each is checked in turn to see if it exists, then applied. If none of
the above is found, then the field is displayed with a default widget
(a text box with size 50).

type

The widget type. The following, at least, are supported:

Type                   Name                    Description
...................... ....................... ...................... 
text                   Text entry              The normal HTML text
                                               entry field.
textarea               Textarea                The normal HTML
                                               textarea entry for
                                               putting in multiple
                                               lines of data.
select                 Select box              Also known as as a
                                               dropdown menu.
                                               Interchange has many
                                               ways to populate the
                                               options via automatic
                                               database lookup, and
                                               you can specify
                                               options to add or
                                               replace a lookup.
yesno                  Yes/No (Yes=1)          A dropdown/select
                                               looking for a Yes (1)
                                               or No (0) answer.
noyes                  No/Yes (No=1)           A dropdown/select
                                               looking for a Yes (0)
                                               or No (1) answer.
yesno radio            Yes/No (radio)          Same as the yesno
                                               widget except
                                               implmented with a
                                               radio box.
noyes radio            No/Yes (radio)          Same as the noyes
                                               widget except
                                               implmented with a
                                               radio box.
multiple               Multiple Select         A dropdown/select with
                                               SIZE greater than 1.
combo                  Combo Select            A dropdown/select with
                                               a preceding text entry
                                               field that can add a
                                               new entry. Needs the
                                               nullselect filter;
                                               usually combined with
                                               a lookup.
reverse_combo          Reverse Combo           A dropdown/select with
                                               a following text entry
                                               field that can add a
                                               new entry. Needs the
                                               last_non_null filter;
                                               usually combined with
                                               a lookup.
move_combo             Combo move              A dropdown select that
                                               sends clicked items to
                                               a textarea.
display                Text of option          Displays the label
                                               (only) for a
                                               select/radio choice.
hidden_text            Hidden (show text)      Shows the value of a
                                               field and includes a
                                               hidden field to put
                                               the value in the form.
                                               Usually used when you
                                               want to display a key
                                               for a record but not
                                               give the opportunity
                                               to change it (and
                                               create a new record).
radio                  Radio box               Select one of many
                                               options with a check
                                               box. Usually can be
                                               used instead of a
                                               select; can be grouped
                                               in matrices.
radio_nbsp             Radio (nbsp)            Select one of many
                                               options with a check
                                               box. Usually can be
                                               used instead of a
                                               select; can be grouped
                                               in matrices. This
                                               version puts no spaces
                                               in the outputted HTML,
                                               guaranteeing no wrap.
                                               (You can use the newer
                                               nowrap styles in CSS
                                               instead, often.)
checkbox               Checkbox                Select one or more
                                               options with a
                                               checkbox. Usually can
                                               be used instead of a
                                               multiple select.
check_nbsp             Checkbox (nbsp)         Select one or more
                                               options with a
                                               checkbox. Usually can
                                               be used instead of a
                                               multiple select. This
                                               version puts no spaces
                                               in the outputted HTML,
                                               guaranteeing no wrap.
                                               (You can use the newer
                                               nowrap styles in CSS
                                               instead, often.)
imagedir               Image listing           Shows a list of
                                               already existing
                                               images in a directory,
                                               with a link to a
                                               dialog to upload a new
                                               one.
imagehelper            Image upload            Combines input of an
                                               image name along with
                                               upload of the image.
date                   Date selector           Selects a date, with
                                               optional time. Used in
                                               combination with the
                                               date_change filter.
value                  Value                   Simply shows the value
                                               of the field, with no
                                               widget to set it.
option_format          Option formatter
show                   Show all options        Shows all options for
                                               a select/radio/checbox
                                               type input, without a
                                               widget to set the
                                               value.

These widgets are implemented with the Vend::Form module, and are
discussed in more detail later in this document.

width

The width of the widget. Meaningful in some way for most types.

height

In the field metadata, it is meaningful for textarea, multiple select
types (including the combo widgets), and for groups of radio and
checkboxes.

In the table metadata context, defines the number of rows that will be
shown on the record select page before a "more" list will be built.

field

The fields for an options lookup query if more than one. Default is
none -- the field in "lookup" is used.

db

The table to do the lookup query in. Default is the same table as the
column is in.

name

The name of the generated HTML form element. Default is the same name
as the column for the widget.

outboard

Catchall field used in several ways by different widgets. Normally
used to specify a foreign key, it can also contain a directory name or
other information needed for a widget.

options

Hard-coded options for the select, checkbox, and radio box widget
types.

attribute

Not normally used for table editor. Used in Interchange in the context
of an [item-list ...] for generating option names.

label

The label associated with the field for display in the table editor.
In the below example, "Foo" is the label:

    Foo: <input type=text value="bar" size=30>

help

Inline help to be displayed in the table editor.

lookup

A field name to look up options in. Normally this would be the same
field as the widget, to generate a list of unique values. The
equivalent to the query:

  SELECT DISTINCT foo FROM table ORDER BY foo

is done.

filter

A filter which should be applied to the data coming from a widget
before saving in the database. A few examples of the dozens of
standard filters are:

     nullselect

     Select first non-null from HTML fields, used for combo box widget

     digits_dot

     Helps keep currency symbols and punctuation from polluting
     decimal values.

     uc

     Uppercases the data.

     NN

     Where NN is an integer. A number that limits length of input.

There are many more filters, and it is easy to specify custom filters.
See Interchange's filters documentation.

help_url

A URL for extended help on a field.

pre_filter

For advanced use only. Specifies a filter that is run on the data
before it is used to set the widget value. Not normally used.

lookup_exclude

A regular expression that can exclude certain values from a lookup
list.

prepend

append

Valuse that are prepended and appended to the widget HTML, perhaps to
call an external formatter or tool.

display_filter

Not normally used.

default

The default value that should be given to a column when it is of
length zero.

extended

The repository for the serialized extended values set in metadata.

93.5. Extended settings
-----------------------

Interchange's meta editors use the table editor's serialization
capability to set many more than just the fields mentioned above.
There are over 150 different metadata settings, and it would be
impossible to have each occupy a field in a table.

Many of these settings can be passed in a CGI query string if the
cgi=1 option is specified.

across

The number of label-widget pairs which should be placed on each table
row. The default is 1. Not passable by CGI.

action

The Interchange form action to use for the generated form. In normal
mode, the default is "set". In wizard mode, the default is "return".
Not passable by CGI.

action_click

An mv_click action that should be run on the Wizard next function. The
default is "ui_override_next", which is usually a no-op on most
systems.  Not passable by CGI.

all_errors

Specifies that all form field entries should be checked for errors and
their label fields set to the CONTRAST setting if an error is found.

all_opts

An ITL tag option that specifies that the table-editor options should
be retrieved from one source.

If the option is a HASH reference, it will be used directly as a
structure that will set all options.

If it is a scalar value, it will be used as a key to select the
mv_metadata record which contains the options.

append

Active for every column in ui_data_fields. A value containing HTML
which should be appended to the widget HTML.

auto_secure

Instructs Interchange to build a write enable only for the tables,
columns, and keys that are specified in the table-editor call. Note
that you can allow unfettered writes by setting the scratch variable
mv_data_enable, but that it is rarely right to do so.

This prevents people from hacking together a duplicate of the
[table-editor] form and writing columns or records they shouldn't.

This option is automatically disabled if the cgi option is enabled.
Still, you should pay attention to what you are allowing users to
write to your database.

back_text

The text that should be used in the Wizard Back button. Automatially
translated for locale.

bottom_buttons

Indicates that buttons should always be only on the bottom. Normally,
[table-editor] provides a top row of buttons if more than four rows
are in the table.

break_cell_extra

Extra HTML attributes for the table cell in the standard break_row
template. You might pass a valign, align, class, or other attribute:

    break-cell-extra=|class="myclass"|

break_row_extra

Extra HTML attributes for the table row in the standard break_row
template. You might pass a valign, align, class, or other attribute:

    break-row-extra=|class="myclass"|

break_template

The HTML template that is used to present a break row. Default is:

        <tr$opt->{break_row_extra>
                <td colspan=$span $opt->{break_cell_extra>&nbsp;</td>
        </tr>

cancel_button_style

The HTML style for the cancel button.

cancel_text

The text placed in the "Cancel" button in both editor and wizard mode.
Default is "Cancel".

cell_span

The number of cells that are in the span of a normal widget-label
pair. The default is two, which is appropriate for the label in one
table cell and the widget in the other. If you have a row_template
like:

        <td>{LABEL}</td><td> --&gt; </td><td>{WIDGET}</td>

you would want a cell_span of three. For the row_template

        <td align=left>
                <b>{LABEL}</b><br>
                {WIDGET}
        </td>

you would want a cell_span of 1.

This allows the formatter to build the right number of cells for
spacers and whole_row templates.

cgi

Signifies that some options may come from the URL calling the page
where the [table-editor] resides.

This allows a simple:

        [table-editor cgi=1][/table-editor]

to be active for any table and key that are called with a URL like:

  http://your.catalog.url/cat/admin/flex_editor?mv_data_table=products?item_id=1

The auto-secure option is turned off if this option is set, for it
would then be possible for people to call a table and set their own
security.

check

A hash option that is active for every field. Defines a profile check
that should be run on the field before the record will be allowed to
be set (or the wizard allowed to go to the Next option.

This call

        [table-editor
                table=products
                item_id="[cgi sku]"
                check.description=required
        ][/table-editor]

ensures that the description field will be non-blank and non-zero
before the record is written.

Works in conjunction with the process_filter profile provided as a
part of the UI. If using the table editor outside the province of the
UI, you will need to make sure you get this profile included; it
normally resides in lib/UI/profiles.

clear_image

In cases where the table-editor templates need a transparent image for
display padding, can set the path where that image is. Default is
bg.gif, which comes with the Interchange UI.

color_fail

The color to set failure messages to in HTML. Default Red.

color_success

The color to set success messages to in HTML. Default Green.

data_cell_class

data_cell_style

data_cell_valign

data_cell_width

data_cell_align

data_cell_extra

The settable parameters allowing change of the HTML appearance of the
data cell in the standard [table-editor] presentation. The default is
data_cell_class set to cdata.

The easiest thing to do to alter the look is define the CSS class for
cdata how you want it. But you can individually set the width, style,
and alignments; and you can attach scripting events or other CSS calls
to the cell as well with data_cell_extra.

The following table-editor call:

        [table-editor
                table=products
                item_id="[cgi sku]"
                data_cell_class=newclass
                data_cell_style="color:red"
                data_cell_extra=|onMouseOver="alert('move that mouse!'"|
                data_cell_valign=top
        ][/table-editor]

will result in a templated row of:

        <td class=clabel>{LABEL}</td>
        <td class="myclass"
                style="color:red"
                valign="top"
                onMouseOver="alert('move that mouse!')">
                        {WIDGET}{HELP?}{HELP} ... (rest of template)
        </td>

database

A hash attribute with a key associated with every field. Specifies the
database table that will be used for a lookup (if any).

default

A hash attribute with a key associated with every field. Specifies the
default value that will be used in the field if none is found in the
table or otherwise available via the default_ref.

This is only active if the defaults flag is set.

default_ref

The hash reference that is used to set the defaults for the fields if
there is no data in the table for that row. Default is $Values, the
Interchange values hash.

You can set this in options with:

        [table-editor default_ref=`$CGI`]

Note the backticks. This calls Perl, which returns the $CGI reference.

If you have previously collected some defaults in a scratch variable,
you could use that with:

        [table-editor default_ref=`$Scratch->{myhash}`]

Not settable in metadata, and it *must* be a hash reference or there
will be a fatal error.

This is only active if the defaults flag is set.

defaults

Allows defaults to be set from the default hash above. When used in
combination with force_defaults=1 forces the passed defaults to
override any data previously residing in the table record.

enctype

The encoding type for the form generated by [table-editor]. If the
file_upload option is set, it defaults to multipart/form-data,
otherwise uses the form default for the browser (which is normally
application/x-www-form-urlencoded).

extra

A hash attribute with a key associated with every field. Specifies
some extra HTML parameter(s) which will be attached to the widget for
the field, based on the behavior of Vend::Form.

Normally used to pass an onChange or other scripting event.

field

A hash attribute with a key associated with every field. Specifies the
fields to be used as a value-label pair for a lookup (if there is
one). Works in conjunction with the lookup and database tags.

To build a list of products for selection by SKU in the foo widget,
without having to use the SKU as the label, you can do:

  [table-editor
        foo.widget=select
        foo.lookup=1
        foo.database=products
        foo.field="sku,description"
  /]

Essentiallly the same as:

  [table-editor
        foo.widget=select
        foo.lookup_query="select sku,description from products order by description"
  /]

file_upload

Specifies that file upload should be enabled by changing the form
encoding type. Forms using the imagehelper widget need this set.

filter

A hash attribute with a key associated with every field. Specifies a
filter that will be applied to the widget result data before it is put
in the database. To make sure that an integer value doesn't have
extraneous whitespace that could cause an error, do:

  [table-editor
        foo.widget=text_5
        foo.label="Seconds before we should become impatient and beep"
        foo.filter=digits
  /]

Filters can be chained; they are the normal Interchange filters active
in many situations.

Works in conjunction with the process_filter profile provided as a
part of the UI. If using the table editor outside the province of the
UI, you will need to make sure you get this profile included; it
normally resides in lib/UI/profiles.

force_defaults

Causes the entries in the "defaults" hash to be used to set the
initial value of fields, disabling the preference for data coming from
an existing record in the database.

form_extra

Extra information (usually scripting event calls) for the form. For
instance, if you are maintaining a series of event monitors in and
want to make sure the user knows that some changes will be lost, you
can set up a routine named check_change() in JavaScript. To check the
change and ask for a confirmation before submission, you can do:

  <script>
  var changed = new Array;
  function is_changed (element) {
        if(element != undefined)
                changed[changed.length] = element.name;
  }

  function check_change () {
        if(changed.length > 0)
          return
                confirm('the ' + changed.join(',') + ' elements were changed. Continue?');
        return true;
  }
  </script>

  [table-editor
        foo.widget=text_50
        foo.label="Important stuff"
        foo.extra='onChange="is_changed(this)"
        form_extra='onSubmit="return check_change()"'
  /]

You could also pass style information if that is ever appropriate. For
form name, action, and target,

form_name

The name of the form. Do not include the NAME= portion, that is
provided. Results in outputted HTML of:

        <FORM ACTION="$opt->{form_action}" METHOD=POST NAME="$opt->{form_name}">

get

Sets the method for the form to GET -- the default is POST.

height

A hash attribute with a key associated with every field. Sets the
height of the widget if that is appropriate -- for example, it sets
the ROWS parameter of a TEXTAREA, the SIZE parameter of a SELECT, etc.
Also acts on the combination widgets according to the behavior of
Vend::Form.

If you want to set the height of a cell, you should use the *_extra
parameters.

help

A hash attribute with a key associated with every field. Specifies
inline help that should be shown in the right-hand (data) portion of a
widget row.

help_anchor

Sets the text that is used to anchor the help_url link. Default is
help. Can also be used to set an image if you want to use that
instead:

  [table-editor
        table=products
        key=os28004
        help_anchor='<img src="question_mark.jpg" border=0>'
  /]

help_cell_class

help_cell_style

help_cell_valign

help_cell_width

help_cell_align

help_cell_extra

Sets the help cell attributes. See data_cell_extra.

help_url

A URL which leads to extended help on a field. For example:

  [table-editor
        table=products
        key=os28004
        widget.foo=text_50
        label.foo="Important stuff"
        help.foo="This is a complex field."
        help_anchor="Search for more help"
        help_url.foo="http://www.google.com/search?q=foo"
  /]

hidden

Allows setting of extra hidden variables in a form. This is a hash
attribute, with one key for every hidden variable you need to set.

  [table-editor
        table=products
        key=os28004
        hidden.foo=bar
        hidden.buz=baz
  /]

The above will include

        <input type="hidden" name="foo" value="bar">
        <input type="hidden" name="buz" value="baz">

href

Sets the action for the form. By default it is VendURL/ui, which
checks for authorization for setting table records. If the secure=1
parameter is set, SecureURL will be used instead. parameter is set,
the SecureURL the default

include_before

include_form

inner_table_width

item_id

js_changed

keep_errors

label

label_cell_extra

label_cell_width

layer_panel_style

layer_tab_style

left_width

link_before

link_extra

link_fields

link_key

link_label

link_sort

link_table

link_template

link_view

lookup

lookup_query

mailto

message_label

meta

meta_anchor

meta_anchor_specific

meta_append

meta_class

meta_extra

meta_prepend

meta_style

method

mv_auto_export

mv_blob_field

mv_blob_label

mv_blob_nick

mv_blob_only

mv_blob_pointer

mv_blob_title

mv_cancelpage

mv_data_auto_number

mv_data_fields

mv_data_function

mv_data_table

mv_failpage

mv_nextpage

mv_prevpage

next_text

no_bottom

no_meta

no_table_meta

no_top

nodelete

noexport

nosave

notable

ok_button_style

options

orig_back_text

orig_cancel_text

outboard

override

panel_append

panel_height

panel_id

panel_prepend

panel_style

panel_width

passed

pre_filter

prepend

promiscuous

reload

reparse

restrict_allow

row_template

save_meta

secure

show_reset

simple_row

start_at

start_at_index

tab_bgcolor_template

tab_height

tab_horiz_offset

tab_style

tab_vert_offset

tab_width

tabbed

table

table_width

td_extra

template

ui_blob_hidden

ui_blob_widget

ui_break_before

ui_break_before_label

ui_clone_id

ui_clone_tables

ui_data_fields

ui_data_fields_all

ui_data_key_name

ui_display_only

ui_hide_key

ui_meta_specific

ui_meta_view

ui_new_item

ui_profile

ui_profile_success

ui_wizard_fields

widget

widget_cell_extra

widgets_only

width

wizard

wizard_cancel

wizard_next

______________________________________________________________________

Copyright 2002 Interchange Development Group. Freely redistributable
under terms of the GNU General Public License. line:

Interchange Tags Reference
==========================

94. Interchange Tag Reference
=============================

Interchange functions are accessed via the Interchange Tag Language
(ITL). The pages in a catalog may be mostly HTML, but they will use
ITL tags to provide access to Interchange's functions. ITL is a
superset of MML, or Minivend Markup Language. Minivend was the
predecessor to Interchange.

These tags perform various display and modification operations for the
user session. There nearly 100 standard predefined tags, and the
UserTag facility allows you to create tags that perform your own
functions and can be just as powerful as the built-in tags.

This document covers Interchange versions 4.7 through 4.9.

95. Tag Syntax
==============

ITL tags are similar to HTML in syntax, in that they accept parameters
or attributes and that there are both standalone and container tags.

We will call an attribute a parameter if it may be called positionally
or if it must be included (see the parameter and attribute sections
below).

A standalone tag has no ending element, e.g.:

    [value name]

This tag will insert the user's name, providing they have given it to
you in a form. A container tag has both a beginning and an ending
element, as in:

    [if value name]
    You have a name. It is [value name].
    [/if]

95.1. Standard Syntax
---------------------

The most common syntax is to enclose the tag with its parameters and
attributes in [square brackets]. If the tag has an end tag, the tag
and its end tag will delimit contained body text:

  [tagname parameters attributes]Contained Body Text[/tagname]

Caveat - macros: Some macros look like tags or end tags. For example,
[/page] is a macro for </A>. This allows you to conveniently write
[page href]Target[/page], but 'Target' is not treated as contained
body text.



When using the [tagname ...] syntax, there must be no whitespace
between the left bracket ('[') and the tagname.

If a tag name includes an underscore or dash, as in [item_list], a
dash is just as appropriate (i.e. [item-list]). The two forms are
interchangeable, except that an ending tag must match the tag (i.e.,
don't use [item-list] list [/item_list]).

95.2. HTML-Comment
------------------

ITL also allows you to use '<!--[' and ']-->' as interchangeable
alternatives to plain square brackets: [tagname] and <!--[tagname]-->
are equivalent.

This allows you make your raw tags appear as comments to HTML browsers
or editors. You might want to do this if your editor has trouble with
ITL tags when editing Interchange page templates, or alternatively, if
you want to use one .html file both as an Interchange template and as
a static page delivered directly by your web server, without
Interchange processing.

To properly HTML-comment contained body text, place your comment-style
brackets appropriately, for example:

 <!--[tagname] Contained Body Text [/tagname]-->

Note that you must include whitespace between the HTML comment
delimiters and the square brackets if you wish to actually comment out
tag output in the browser. For example, if [value name] expands to
'Bill':

 '<!--[value name]-->'  becomes  'Bill'
 '<!-- [value name] -->'  becomes  '<!-- Bill -->'

95.2.1. Technical notes
-----------------------

While '<!--[' and '[' are completely interchangeable, the Interchange
parser does not replace ']-->' with ']' unless it also sees '<!--[' at
least once somewhere on the page. (This is a small parsing speed
optimization.)

See the Template Parsing Order appendix if you are modifying the
special administrative interface pages and intend to use this syntax.

95.3. Named vs. Positional Parameters
-------------------------------------

There are two styles of supplying parameters to a tag: named and
positional.

In the named style you supply a parameter name=value pair just as most
HTML tags use:

    [value name="foo"]

The positional-style tag that accomplishes the same thing looks like
this:

    [value foo]

The parameter name is the first positional parameter for the [value]
tag. Some people find positional usage simpler for common tags, and
Interchange interprets them somewhat faster. If you wish to avoid
ambiguity you can always use named calling.

In most cases, tag parameters specified in the positional fashion work
the same as named parameters. However, there are a few situations
where you need to use named parameters:

1.   If you want to specify a parameter that comes positionally after
     a parameter that you want to omit, e.g. omit the first parameter
     but specify the second. The parser would have no way of knowing
     which is which, so you just specify the second by name. This is
     rare, though, because the first positional parameters are usually
     required for a given tag anyway.

2.   When there is some ambiguity as to which parameter is which,
     usually due to whitespace.

3.   When you need to use the output of a tag as the parameter or
     attribute for another tag.

95.3.1. Interpolating parameters
--------------------------------

If you wish to use the value of a tag within a parameter of another
tag, you cannot use a positional call. You must also double-quote the
argument containing the tag you wish to have expanded. For example,
this will not work:

    [page scan se=[scratch somevar]]

To get the output of the [scratch somevar] interpreted, you must place
it within a named and quoted attribute:

    [page href=scan arg="se=[scratch somevar]"]

Note that the argument to href ('scan') did not need to be quoted;
only the argument to arg, which contained a tag, needed the quotes.

95.4. Universal Attributes
--------------------------

Universal attributes apply to all tags, though each tag specifies its
own default for the attribute. The code implementing universal
attributes is external to the core routines that implement specific
tags.

95.4.1. interpolate
-------------------

This attribute behaves differently depending upon whether the tag is a
container or standalone tag. A container tag is one which has an end
tag, i.e. [tag] stuff [/tag]. A standalone tag has no end tag, as in
[area href=somepage]. (Note that [page ...] and [order ..] are not
container tags.)

For container tags (interpolated)

o    If true ("interpolate=1"), the Interchange server will first
     process any tags within the body text before passing it to the
     enclosing tag.

o    If false ("interpolate=0"), the enclosing tag will receive the
     raw body text.

For standalone tags (reparsed)

o    If true, the server will process the output of the tag. This is
     identical to the behavior of the reparse attribute (see below for
     explanation and examples).

(Note: The mixing of 'interpolate' and 'reparse' logic occurred
because 'interpolate' already worked this way when 'reparse' was added
to Interchange. This may be fixed in a later release...)

Most standalone tags are not reparsed by default (i.e., interpolate=0
by default). There are some exceptions, such as the [include] tag.

Interpolation example:

Assuming that name is 'Kilroy',

   [log interpolate=1][value name] was here[/log]
   [log interpolate=0][value name] was here[/log]

the first line logs 'Kilroy was here' to catalog_root/etc/log, while
the second logs '[value name] was here'.

Reparsing example:

Suppose we set a scratch variable called 'now' as follows:

   [set name=now interpolate=0][time]%A, %B %d, %Y[/time][/set]

If today is Monday, January 1, 2001,

   [scratch name=now interpolate=0]
   [scratch name=now interpolate=1]

the first line yields

   [time]%A, %B %d, %Y[/time]

while the second yields

   Monday, January 1, 2001

95.4.2. reparse
---------------

If true ("reparse=1"), the server will process any tags in the text
output by the reparsed tag.

Reparse applies only to container tags (those with an end tag). The
interpolate attribute controls reparsing of the output of standalone
tags (see above).

Most container tags will have their output re-parsed for more
Interchange tags by default. If you wish to inhibit this behavior, you
must explicitly set the attribute reparse to 0. Note that you will
almost always want the default action. The only container ITL tag that
doesn't have reparse set by default is [mvasp].

Example:

Assuming that name is 'Kilroy',

  1.   [perl reparse=0]
          my $tagname = 'value';
          return "[$tagname name] was here\n"
       [/perl]

  2.   [perl reparse=1]
          my $tagname = 'value';
          return "[$tagname name] was here\n"
       [/perl]

expands to

  1.   [value name] was here

  2.   Kilroy was here

95.4.3. send
------------

Deprecated

95.5. Tag-specific Attributes
-----------------------------

Each tag may accept additional named attributes which vary from tag to
tag. Please see the entry for the tag in question for details about
tag-specific attributes.

95.6. Attribute Arrays and Hashes
---------------------------------

Some tags allow you to pass an array or hash as the value of an
attribute. For an ordinary tag, the syntax is as follows:

    attribute.n=value

    attribute.hashkey=value

where n is an integer array index. Note that you cannot use both an
array and a hash with the same attribute - if you use attribute.n, you
cannot also use attribute.key for the same attribute.

Here is an example of an attribute array:

    search.0="se=hammer
              fi=products
              sf=description"
    search.1="se=plutonium
              fi=products
              sf=comment"

The [page] tag, for example, treats a search specification array as a
joined search, automatically adding the other relevant search fields,
including the 'co=yes' to indicate a combined search (joined searches
are described in the Interchange database documentation).

Note that it is up to the tag to handle an array or hash value
properly. See the documentation for the specific tag before passing it
an attribute array or hash value.

95.6.1. Perl calls
------------------

Before passing attributes to a tag, the Interchange parser would
convert the above example to an anonymous array reference. It would
use the resulting arrayref as the value for the 'search' attribute in
this example.

If you were passing the above example directly to a tag routine within
a [perl] block or a usertag, you must actually pass an anonymous array
as the value of the attribute as follows:

    my $arrayref = [ "se=hammer/fi=products/sf=description",
                     "se=plutonium/fi=products/sf=description", ];

    $Tag->routine( { search => $arrayref, } );

Similarly to use a hash reference for the 'entry' attribute:

    my $hashref = { name   => "required",
                    date   => 'default="%B %d, %Y"', };

    $Tag->routine( { entry => $hashref } );

96. Looping tags and Sub-tags
=============================

Certain tags are not standalone; these are the ones that are
interpreted as part of a surrounding looping tag like [loop],
[item-list], [query], or [search-region].

     [PREFIX-accessories]

     [PREFIX-alternate]

     [PREFIX-calc]

     [PREFIX-change]

     [PREFIX-code]

     [PREFIX-data]

     [PREFIX-description] (Note safe-data and ed() escape)

     [PREFIX-discount]

     [PREFIX-discount-subtotal]

     [if-PREFIX-exec]

     [PREFIX-field] (Optimization note-- one query per field if you
     use this; we optimize around this if only one products table)

     [if-PREFIX-filter]

     [PREFIX-increment]

     [PREFIX-last]

     [PREFIX-line] (tab-delimited list of parameters returned)

     [if-PREFIX-match]

     [PREFIX-modifier]

     [PREFIX-next]

     [if-PREFIX-options]

     [PREFIX-param]

     [PREFIX-pos]

     [PREFIX-price]

     [PREFIX-quantity]

     [if-PREFIX-sub]

     [PREFIX-subtotal]

     [if-PREFIX-data]

     [if-PREFIX-field]

     [if-PREFIX-modifier] (hash list only)

     [if-PREFIX-param]

     [if-PREFIX-pos]

     [modifier-name]

     [quantity-name]

PREFIX represents the prefix that is used in that looping tag. They
are only interpreted within their container and only accept positional
parameters. The default prefixes:

Tag                    Prefix                  Examples
...................... ....................... ...................... 
[loop]                 loop                    [loop-code],
                                               [loop-field price],
                                               [loop-increment]
[item-list]            item                    [item-code],
                                               [item-field price],
                                               [item-increment]
[search-list]          item                    [item-code],
                                               [item-field price],
                                               [item-increment]
[query]                sql                     [sql-code], [sql-field
                                               price],
                                               [sql-increment]

Sub-tag behavior is consistent among the looping tags. Subtags are
parsed during evaluation of the enclosing loop, before any regular
tags within the loop.

There are two types of looping lists: ARRAY and HASH.

An array list is the normal output of a [query], a search, or a [loop]
tag. It returns from 1 to N return fields, defined in the
mv_return_fields or rf variable or implicitly by means of a SQL field
list. The two queries below are essentially identical:

    [query sql="select foo, bar from products"]
    [/query]

    [loop search="
                    ra=yes
                    fi=products
                    rf=foo,bar
    "]

Both will return an array of arrays consisting of the foo column and
the bar column. The Perl data structure would look like:

    [
        ['foo0', 'bar0'],
        ['foo1', 'bar1'],
        ['foo2', 'bar2'],
        ['fooN', 'barN'],
    ]

A hash list is the normal output of the [item-list] tag. It returns
the value of all return fields in an array of hashes. A normal
[item-list] return might look like:

    [
        {
            code     => '99-102',
            quantity => 1,
            size     => 'XL',
            color    => 'blue',
            mv_ib    => 'products',
        },
        {
            code     => '00-341',
            quantity => 2,
            size     => undef,
            color    => undef,
            mv_ib    => 'products',
        },

    ]

You can also return hash lists in queries:

    [query sql="select foo, bar from products" type=hashref]
    [/query]

Now the data structure will look like:

    [
        { foo => 'foo0', bar => 'bar0' },
        { foo => 'foo1', bar => 'bar1' },
        { foo => 'foo2', bar => 'bar2' },
        { foo => 'fooN', bar => 'barN' },
    ]

96.1. PREFIX-accessories
------------------------

   [PREFIX-accessories arglist]

Except for the usual differences that apply to all subtags (such as
parsing order), these are more or less equivalent for an array-type
list:

    [accessories code=current_item_code arg=arglist]
    [item-accessories arglist]

See the [accessories] tag for more detail. Note that you must use the
comma-delimited list to set attributes - you cannot set named
attributes with the usual 'attribute=value' syntax.

If the list is a hash list, i.e. an [item-list], then the value of the
current item hash is passed so that a value default can be
established.

96.2. PREFIX-alternate
----------------------

   [PREFIX-alternate N] DIVISIBLE [else] NOT DIVISIBLE [/else][/PREFIX-alternate]

Set up an alternation sequence. If the item-increment is divisible by
`N', the text will be displayed. If an `[else]NOT DIVISIBLE
TEXT[/else]' is present, then the NOT DIVISIBLE TEXT will be
displayed.

For example:

    [item-alternate 2]EVEN[else]ODD[/else][/item-alternate]
    [item-alternate 3]BY 3[else]NOT by 3[/else][/item-alternate]

96.3. PREFIX-calc
-----------------

   [PREFIX-calc] 2 + [item-field price] [/PREFIX-calc]

Executes Perl code in the tag body. This is equivalent to the [calc]
... [/calc] tag pair, except it's calculated at loop time instead of
later when the rest of the page is parsed.

96.4. PREFIX-change
-------------------

   [PREFIX-change][condition] ... [/condition] TEXT [/PREFIX-change]

Sets up a breaking sequence that occurs when the contents of
[condition] [/condition] change. The most common one is a category
break to nest or place headers.

The region is only output when a field or other repeating value
between [condition] and [/condition] changes its value. This allows
indented lists similar to database reports to be easily formatted. The
repeating value must be a tag interpolated in the search process, such
as [PREFIX-field] or [PREFIX-field database field]. If you need access
to ITL tags, you can use [PREFIX-calc] with a $Tag-foo()> call.

Of course, this will only work as you expect when the search results
are properly sorted.

The value to be tested is contained within a
[condition]value[/condition] tag pair. The [PREFIX-change] tag also
processes an [else] [/else] pair for output when the value does not
change.

Here is a simple example for a search list that has a field category
and subcategory associated with each item:

 <TABLE>
 <TR><TH>Category</TH><TH>Subcategory</TH><TH>Product</TH></TR>
 [search-list]
 <TR>
    <TD>
         [item-change cat]

         [condition][item-field category][/condition]

                 [item-field category]
         [else]
                 &nbsp;
         [/else]
         [/item-change cat]
    </TD>
    <TD>
         [item-change sub]

         [condition][item-field subcategory][/condition]

                 [item-field subcategory]
         [else]
                 &nbsp;
         [/else]
         [/item-change sub]
    </TD>
    <TD> [item-field name] </TD>
 [/search-list]
 </TABLE>

The above should put out a table that only shows the category and
subcategory once, while showing the name for every product. (The
&nbsp; will prevent blanked table cells if you use a border.)

96.5. PREFIX-code
-----------------

   [PREFIX-code]

The key or code of the current loop. In an [item-list] this is always
the product code; in a loop list it is the value of the current
argument; in a search it is whatever you have defined as the first
mv_return_field (rf).

96.6. PREFIX-data
-----------------

   [PREFIX-data table field]

Calls the column field in database table table for the current
[PREFIX-code] This may or may not be equivalent to [PREFIX-field
field] depending upon whether your search table is defined as one of
the ProductFiles.

96.7. PREFIX-description
------------------------

   [PREFIX-description]

The description of the current item, as defined in the catalog.cfg
directive DescriptionField. In the demo, it would be the value of the
field description in the table products.

If the list is a hash list, and the lookup of DescriptionField fails,
then the attribute description will be substituted. This is useful to
supply shopping cart descriptions for on-the-fly items.

96.8. PREFIX-discount
---------------------

   [PREFIX-discount]

The price of the current item is calculated, and the difference
between that price and the list price (quantity one) price is output.
This may have different behavior than you expect if you set the
[discount] tag along with quantity pricing.

96.9. PREFIX-discount-subtotal
------------------------------

   [PREFIX-discount-subtotal]

Inserts the discounted subtotal of the ordered items.

96.10. PREFIX-field
-------------------

   [PREFIX-field]

Looks up a field value for the current item in one of several places,
in this order:

    1. The first ProductFiles entry.
    2. Additional ProductFiles in the order they occur.
    3. The attribute value for the item in a hash list.
    4. Blank

A common user error is to do this:

    [loop search="
                    fi=foo
                    se=bar
                "]

    [loop-field foo_field]
    [/loop]

In this case, you are searching the table foo for a string of bar.
When it is found, you wish to display the value of foo_field. Unless
foo is in ProductFiles and the code is not present in a previous
product file, you will get a blank or some value you don't want. What
you really want is [loop-data foo field], which specifically addresses
the table foo. See also [PREFIX-param] and [PREFIX-pos].

96.11. PREFIX-increment
-----------------------

   [PREFIX-increment]

The current count on the list, starting from either 1 in a
zero-anchored list like [loop] or [item-list], or from the match count
in a search list.

If you skip items with [PREFIX-last] or [PREFIX-next], the count is
NOT adjusted.

96.12. PREFIX-last
------------------

   [PREFIX-last] CONDITION [/PREFIX-last]

If CONDITION evaluates true (a non-whitespace value that is not
specifically zero) then this will be the last item displayed.

96.13. PREFIX-line
------------------

   [PREFIX-line start_column]

Returns all array values from the current looping row in a single
string, with each value separated by a tab, roughly equivalent to
this:

  [PREFIX-pos 0](tab)[PREFIX-pos 1](tab)[PREFIX-pos 2](tab)[...]

for however many fields were returned in that row.

This is useful as a quick way to see all your results at a glance and
verify your search specification.

If the optional start_column attribute is given, the output starts
with that column instead of column 0.

96.14. PREFIX-modifier
----------------------

   [PREFIX-modifier attribute]

If the item is a hash list (i.e. [item-list]), this will return the
value of the attribute.

96.15. PREFIX-next
------------------

   [PREFIX-next] CONDITION [/PREFIX-next]

If CONDITION evaluates true (a non-whitespace value that is not
specifically zero) then this item is skipped.

96.16. PREFIX-param
-------------------

   [PREFIX-param name]

Returns the value of the column name associated with the looping tag
row. Each looping list returns an array of return fields, set in
searches with mv_return_field or rf. The default is only to return the
code of the search result, but by setting those parameters you can
return whichever columns you wish.

In a [query] ITL tag you can select multiple return fields with
something like:

    [query prefix=prefix sql="select foo, bar from baz where foo='buz'"]
        [prefix-code]  [prefix-param foo]  [prefix-param bar]
    [/query]

In this case, [prefix-code] and [prefix-param foo] are synonyms, as
foo is the first returned parameter and becomes the code for this row.
Another synonym is [prefix-pos 0].

Note that the following code is invalid:

    [query prefix=prefix sql=|
        SELECT  table1.foo,
                table2.bar
        FROM    table1, table2
        WHERE   table1.code = table2.code
        AND     table1.foo = 'buz'
    |]
        [prefix-param table1.foo] [prefix-param table2.bar]
    [/query]

The problem with the above code is that DBI doesn't support column
names such as table1.foo in its resultsets.  The following query
syntax is fully supported by DBI and therefore by Interchange:

    [query prefix=prefix sql=|
        SELECT  table1.foo AS foo,
                table2.bar AS bar
        FROM    table1, table2
        WHERE   table1.code = table2.code
        AND     table1.foo = 'buz'
    |]
        [prefix-param foo] [prefix-param bar]
    [/query]

96.17. PREFIX-pos
-----------------

   [PREFIX-pos N]

Returns the value of the array parameter associated with the looping
tag row. Each looping list returns an array of return fields, set in
searches with mv_return_field or rf. The default is only to return the
code of the search result, but by setting those parameters you can
return whichever columns you wish.

[PREFIX-pos N] outputs the data from the Nth column as returned
(starting with zero). [PREFIX-param] lets you access the data by
column name instead of by number.

In a [query ...] ITL tag you can select multiple return fields with
something like:

    [query prefix=prefix sql="select foo, bar from baz where foo='buz'"]
        [prefix-code]  [prefix-param foo]  [prefix-param bar]
    [/query]

In this case, [prefix-code] and [prefix-param foo] are synonyms, as
foo is the first returned parameter and becomes the code for this row.
Another synonym is [prefix-pos 0].  [prefix-pos 1] is the same as
[prefix-param bar].  The following code will produce exactly the same
output as the above:

    [query prefix=prefix sql="select foo, bar from baz where foo='buz'"]
        [prefix-pos 0]  [prefix-pos 0]  [prefix-pos 1]
    [/query]

Note that if you use the [PREFIX-pos] tag, you may have to review your
column numbers whenever you modify the columns you select.  For this
reason, queries that make use of the [PREFIX-param] tag may be easier
to maintain and will be less prone to future surprises.

96.18. PREFIX-price
-------------------

   [PREFIX-price]

The price of the product identified by the current code, formatted for
currency. If Interchange's pricing routines cannot determine the price
(i.e. it is not a valid product or on-the-fly item) then zero is
returned. If the list is a hash list, the price will be modified by
its quantity or other applicable attributes (like size in the demo).

96.19. PREFIX-quantity
----------------------

   [PREFIX-quantity]

The value of the quantity attribute in a hash list. Most commonly used
to display the quantity of an item in a shopping cart [item-list].

96.20. PREFIX-subtotal
----------------------

   [PREFIX-subtotal]

The [PREFIX-quantity] times the [PREFIX-price]. This does take
discounts into account.

96.21. if-PREFIX-data
---------------------

   [if-PREFIX-data table field] IF text [else] ELSE text [/else] [/if-PREFIX-data]

Examines the data field, i.e. [PREFIX-data table field], and if it is
non-blank and non-zero then the IF text will be returned. If it is
false, i.e. blank or zero, the ELSE text will be returned to the page.

This is much more efficient than the otherwise equivalent [if
type=data term=table::field::[PREFIX-code]].

You cannot place a condition; i.e. [if-PREFIX-data table field eq
'something']. Use [if type=data ...] for that.

Careful, a space is not a false value!

96.22. if-PREFIX-field
----------------------

   [if-PREFIX-field field] IF text [else] ELSE text [/else] [/if-PREFIX-field]

Same as [if-PREFIX-data ...] except uses the same data rules as
[PREFIX-field].

96.23. PREFIX-modifier-name
---------------------------

   [PREFIX-modifier-name attribute]

Outputs a variable name which will set an appropriate variable name
for setting the attribute in a form (usually a shopping cart). Outputs
for successive items in the list:

    1. attribute0
    2. attribute1
    3. attribute2

etc.

[PREFIX-modifier-name quantity] would be the same as
[PREFIX-quantity-name].

96.24. PREFIX-quantity-name
---------------------------

   [item-quantity-name]

Outputs for successive items in the list:

    1. quantity0
    2. quantity1
    3. quantity2

etc.

[PREFIX-modifier-name quantity] would be the same as
[PREFIX-quantity-name].

97. Tags
========

Each ITL tag is show below. Calling information is defined for the
main tag, sub-tags are described in Looping tags and Sub-tags.

97.1. accessories
-----------------

A Swiss-army-knife widget builder, this provides access to
Interchange's product option attributes (e.g., to choose or access
product options such as a shirt's size or color).

Can build selection objects (radio, check, select boxes, etc), forms
or hyperlinks, or can simply return a value.

Or more - see also Looping tags and Sub-tags.

97.1.1. Summary
---------------

    [accessories code arg]
    [accessories code=os28044 arg="size, radio, ... " other_named_attributes] deprecated
    [accessories code=os28044 attribute=size type=radio ... other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
code          Value of the master key in the product    none
              (or specified other) table
arg           Positionally interpreted comma-delimited  none
              list of values for the following
              attributes:"attribute, type, column,
              table, name, outboard, passed"

Attributes                         Default
.................................. .................................. 
attribute                          none
typeOne of select, value, text,    select
textarea, hidden, password, combo,
move_combo, reverse_combo, show,
options, labels, checkbox, radio,
links
column                             attribute
table                              products
name                               mv_order_attribute
outboard                           none
passed                             none
key (alias for code)               none
row (alias for code)               none
base (alias for table)             products
database (alias for table)         products
db (alias for table)               products
col (alias for column              attribute
field (alias for column            attribute
delimiter                          comma (',')
prepend                            none
append                             none
extra                              none
js                                 none
rows                               varies with type; often 4
cols                               varies with type; often 40
width                              none
default                            none
price                              none
price_data                         none
contains (type=radio or check)     none
joiner (type=links)                none
href (type=links)                  none
template (type=links)              none
form (type=links)                  mv_action=return
empty (type=links)                 none
secure (type=links)                none
new                                none
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      No
Has Subtags                        No

Tag expansion example:

    [accessories os28044 size]
---
    <SELECT NAME="mv_order_size"><OPTION VALUE="10oz">10oz\
    <OPTION VALUE="15oz">15oz<OPTION VALUE="20oz">20oz</SELECT>

ASP-like Perl call:

    $Tag->accessories(  { code   => '[[EXAMPLE_SKU]]',
                          arg    => 'color, radio'
                          table  => 'special_products', }  );

or similarly with positional parameters,

    $Tag->accessories($code, $arg, $attribute_hash_reference);

97.1.1.1. See Also
------------------

Looping tags and Sub-tags.

97.1.2. Description
-------------------

This is the swiss-army-knife widget builder for providing access to
Interchange's product option attributes (e.g., to choose or access
product options such as a shirt's size or color).

Interchange allows you to choose item attribute values for each
ordered item - you can attach a size, color, or other modifier to a
line item in the shopping cart. You can also resubmit previous
attribute values via hidden fields on a form.

The catalog.cfg file directive UseModifier is used to set the name of
the modifier or modifiers. For example

    UseModifier        size color

will attach both a size and color attribute to each item code that is
ordered.

Important Note -- You may not use the following names for attributes:

item  group  quantity  code  mv_ib  mv_mi  mv_si



You can also set modifier names with the mv_UseModifier scratch
variable - [setnbspmv_UseModifier] size color [/set] has the same
effect as above. This allows multiple options to be set for products.
Whichever one is in effect at order time will be used. Be careful; you
cannot set it more than once on the same page. Setting the
mv_separate_items or global directive SeparateItems places each
ordered item on a separate line, simplifying attribute handling. The
scratch setting for mv_separate_items has the same effect.

The modifier value is accessed in the [item-list] loop with the
[item-param attribute] tag, and form input fields are placed with the
[modifier-name attribute] tag. This is similar to the way that
quantity is handled.

Note: You must be sure that no fields in your forms have digits
appended to their names if the variable is the same name as the
attribute name you select, as the [PREFIX-modifier-name size]
variables will be placed in the user session as the form variables
size0, size1, size2, etc.



Interchange will automatically generate the select boxes when the
[accessories code="os28044" attribute="size"] or [item-accessories
size] tags are called. They have the syntax:

    [item-accessories attribute, type, column, table, name, outboard, passed]

    [accessories code=sku
                attribute=modifier
                type=select
                column=db_table_column_name
                table=db_table
                name=varname
                outboard=key
                passed="value=label, value2*, value3=label 3"]

    [accessories js=| onChange="set_description(simple_options, variant)"; |
                type=select
                name="[item-param o_group]"
                passed="=--choose--,[item-param o_value]"]

Notes:

1.   The 'attribute' attribute is required.

2.   See the type attribute for a list of types.

3.   The trailing '*' in value2 will mark it as the default
     ('SELECTED') value in the select widget (see below).



When called with an attribute, the database is consulted and looks for
a comma-separated list of item attribute options. They take the form:

   name_a=Label Text1, default_name=Default Label Text*, name_b, etc.

The label text is optional - if none is given, the name will be used
(as in 'name_b' above).

If an asterisk is the last character of the label text, the item is
the default selection. If no default is specified, the first will be
the default. An example:

    [item-accessories color]

This will search the product database for a field named "color". If an
entry "beige=Almond, gold=Harvest Gold, White*, green=Avocado" is
found, a select box like this will be built:

    <SELECT NAME="mv_order_color">
    <OPTION VALUE="beige">Almond
    <OPTION VALUE="gold">Harvest Gold
    <OPTION SELECTED>White
    <OPTION VALUE="green">Avocado
    </SELECT>

In combination with the mv_order_item and mv_order_quantity session
variables, you can use this to allow a customer to enter an item
attribute during an order.

If used in an item list, and the user has changed the value, the
generated select box will automatically retain the current value the
user has selected.

The value can then be displayed with [item-modifier color] on the
order report, order receipt, or any other page containing an
[item-list].

97.1.2.1. Emulating with a loop
-------------------------------

You can also build widgets directly, without using the accessories
tag. You may have to do so if you need more control of the content
than the tag offers. Below is a fragment from a shopping basket
display form which shows a selectable size with "sticky" setting and a
price that changes based upon the modifier setting. (Note that this
example would normally be contained within the [item-list][/item-list]
pair.)

    <SELECT NAME="[loop-modifier-name size]">
    [loop option="[loop-modifier-name size]" list="S, M, L, XL"]
    <OPTION> [loop-code] -- [price code="[item-code]" size="[loop-code]"]
    [/loop]
    </SELECT>

The output of the above would be similar to the output of
[item-accessories size, select] if the product database field size
contained the value S, M, L, XL. The difference is that the options in
the loop emulation show the adjusted price in addition to the size
within each option value.

97.1.2.2. Hash Lists - Technical Note
-------------------------------------

As a technical note, some of the features of this tag work differently
depending upon whether it was called with an '$item' hash reference,
for example, as [item-accessories] within an [item-list].

In this context, the tag will have access to ancillary data from the
item (including, perhaps, a user's chosen item attribute value). For
example, if building a TEXTAREA widget within an [item-list], the
widget will show the chosen item attribute value. On the other hand,
within an array list such as a [search-list] in a [search-region], the
widget would be empty.

If you really know what you're doing, you can pass it the item hash
reference within a [perl] tag like this:

   $Tag->accessories( $code,
                      undef,              # 'arg' parameter value
                      $named_attribute_hashref,
                      $item_hashref );

See also Looping tags and Sub-tags for information about hash-context
and array-context in looping tags.

97.1.2.3. code
--------------

This is the master key of the specified table (commonly sku in a
product table). If no table is specified, the tag uses the products
table by default.

You should not specify a code when looping on [item_accessories]
because it internally sets 'code' to the key for the current item in
the loop.

97.1.2.4. arg
-------------

Deprecated after Interchange 4.6

This allows you to pass values for some of the more commonly used
attributes in the manner of the [item-accessories] tag, as a
comma-delimited positional list:

  arg="attribute, type, column, table, name, outboard, passed"

Whitespace within the list is optional.

If you leave out one or more of the above attributes, be sure to keep
the comma(s) if you are setting anything after it in the list:

  arg="attribute, type, , table"

The above examples show the attribute names for clarity; you would
actually use the values. Hence, the previous example might actually be
something like the following:

  arg="color, radio, , products"

Although you must use such a comma-delimited list to pass attributes
to the [item-accessories] tag, please use named attributes instead for
the [accessories] tag. The 'arg' attribute is deprecated.

For detail about a specific attribute, please see its subheading
below.

97.1.2.5. attribute
-------------------

Despite the name, this has nothing to do with tag attributes. You can
set attributes for items in a database table (typically the products
table) with the UseModifier configuration directive. Typical are size
or color.

This selects the item attribute the tag will work with.

97.1.2.6. type
--------------

This determines the action to be taken. One of:

Action                             Description
.................................. .................................. 
select                             Builds a dropdown <SELECT> menu
                                   for the item attribute, with the
                                   default item attribute value
                                   SELECTED. The accessories tag
                                   builds a select widget by default
                                   if type is not set.
display                            Shows the label text for *only the
                                   selected option* if called in Hash
                                   List context (e.g., within an
                                   [item-list]). Ignored otherwise
                                   (i.e., the tag will build the
                                   default <SELECT> menu).
show                               Returns the list of possible
                                   attributes for the item (without
                                   labels or any HTML widget). For
                                   example, if sku os28044 is
                                   available in several
                                   sizes:[accessories os28044
                                   size,show]-----------------------------------------Sm=10oz,
                                   Med=15oz*, Lg=20oz
options                            This shows the attribute options
                                   as a newline delimited
                                   list:[accessories os28044
                                   size,options]-----------------------------------------SmMedLg
labels                             This shows the attribute option
                                   labels:[accessories os28044
                                   size,options]-----------------------------------------10oz15oz*20oz
radio                              Builds a radio box group for the
                                   item, with spaces separating the
                                   elements.
radio nbsp                         Builds a radio box group for the
                                   item, with &nbsp; separating the
                                   elements.
radio break                        Builds a radio box group for the
                                   item, with '<br>' separating the
                                   radio button/label pairs from one
                                   another.
radio left n                       Builds a radio box group for the
                                   item, inside a table, with the
                                   checkbox on the left side. If "n"
                                   is present and is a digit from 2
                                   to 9, it will align the options in
                                   that many columns.You can also set
                                   FONT SIZE like this: type="radio
                                   left n fontsizem"where -9 <= m <=
                                   9
radio right n                      Builds a radio box group for the
                                   item, inside a table, with the
                                   checkbox on the right side. If "n"
                                   is present and is a digit from 2
                                   to 9, it will align the options in
                                   that many columns.You can also set
                                   FONT SIZE like this: type="radio
                                   right n fontsizem"where -9 <= m <=
                                   9
check                              Builds a checkbox group for the
                                   item, with spaces separating the
                                   elements.
check nbsp                         Builds a checkbox group for the
                                   item, with '&nbsp;' separating the
                                   checkbox/label pairs from one
                                   another.
check break                        Builds a checkbox group for the
                                   item, with '<br>' separating the
                                   checkbox/label pairs from one
                                   another.
check left n                       Builds a checkbox group for the
                                   item, inside a table, with the
                                   checkbox on the left side. If "n"
                                   is present and is a digit from 2
                                   to 9, it will align the options in
                                   that many columns.You can also set
                                   FONT SIZE like this: type="check
                                   left n fontsizem"where -9 <= m <=
                                   9
check right n                      Builds a checkbox group for the
                                   item, inside a table, with the
                                   checkbox on the right side. If "n"
                                   is present and is a digit from 2
                                   to 9, it will align the options in
                                   that many columns.You can also set
                                   FONT SIZE like this: type="check
                                   right n fontsizem"where -9 <= m <=
                                   9
textarea_XX_YY                     A textarea with XX columns and YY
                                   rows. The textarea will contain
                                   the selected item attribute value
                                   if used in Hash List context
                                   (e.g., within an [item-list]).If
                                   you simply use 'type=textarea',
                                   the size will default to 4 rows by
                                   40 columns, unless you have set
                                   the rows or cols tag attributes.
text_YY                            A text box with YY width in
                                   characters. The HTML tag's VALUE
                                   will be set to the selected item
                                   attribute value if used in Hash
                                   List context (e.g., within an
                                   [item-list]).If you simply use
                                   'type=text', the width will
                                   default to 60, unless you have set
                                   the cols tag attribute.
combo                              Special type, used with nullselect
                                   filter, for selecting from a list
                                   or inputting a new value
reverse_combo                      Special type, used with
                                   last_non_null filter, for
                                   selecting from a list or inputting
                                   a new value - differs from combo
                                   in order of presentation
move_combo                         Special type, used with
                                   null_to_space or null_to_comma
                                   filter, for selecting multiple
                                   non-ordered values from a list or
                                   inputting into a textarea
links                              Produces a series of links based
                                   on the option values. The base
                                   form value is passed via the form
                                   parameter, just like in an [area
                                   ...] or [page ...] tag, and the
                                   value is named with the passed
                                   NAME attribute.
value                              Returns the selected value if
                                   called in Hash List context (e.g.,
                                   within an [item-list]), or nothing
                                   otherwise.
hidden                             Creates a hidden form field. The
                                   hidden field's VALUE will be set
                                   to the selected item attribute
                                   value if used in Hash List context
                                   (e.g., within an [item-list]).
password_YY                        A password box with YY width in
                                   characters. The HTML tag's VALUE
                                   will be set to the selected item
                                   attribute value if used in Hash
                                   List context (e.g., within an
                                   [item-list]).If you simply use
                                   'type=password', the width will
                                   default to 12, unless you have set
                                   the cols tag attribute.

The default is 'select', which builds an HTML select form entry for
the attribute.

Some types build widgets that use the ROWS=m, COLS=n, or certain other
HTML attributes. For these, you can define widget rows and columns
within the string that sets the type; for example,
type="textarea_6_33_wrap=virtual" specifies a TEXTAREA widget with
ROWS=6, COLS=33, and WRAP=virtual. You should resort to this only when
you cannot use the named parameters, for example within an
[item-accessories] tag. Otherwise, use the rows=m and cols=n tag
attributes instead.

The result of setting conflicting values in the type string and the
rows or cols attributes is undefined.

The following list shows syntax for type strings, where rows is the
number of rows and cols is the number of columns.

o    text

     o    textarea   (default is 4 rows, 40 columns, like
          'textarea_4_40')

     o    textarea_rows_cols

     o    text_cols

     o    textarea rows=rows cols=cols wrap=WRAP value

o    password

     o    password   (default is 12 columns, like 'password_12')

     o    password_cols

o    combo (similarly for reverse_combo and move_combo)

     o    combo   (default is 1 row, 16 columns, like 'combo_1_16')

In any of the option building types, you can append the string ranges
and a special option processing will be done -- any option matching
the pattern [A-Za-z0-0]..[A-Za-z0-0] will be expanded into a comma
separated range between the bounds. The same behavior is accomplished
by passing the accessories tag option ranges. For example:


    [accessories name=foo type=select ranges=1 "A..C,1..5,10,20"]
      and
    [accessories name=foo type="select ranges" passed="A..C,1..5,10,20"]

      will both output:

    <select NAME="foo">
    <option VALUE="A">A
    <option VALUE="B">B
    <option VALUE="C">C
    <option VALUE="1">1
    <option VALUE="2">2
    <option VALUE="3">3
    <option VALUE="4">4
    <option VALUE="5">5
    <option VALUE="10">10
    <option VALUE="15">15
    <option VALUE="20">20
    </select>

The above applies to any of the option building types -- check, combo,
combo_move, labels, multiple, options, radio, reverse_combo, and
select. It will refuse to produce more than 5000 options -- that limit
can be changed with Limit option_list N in catalog.cfg, where N is an
integer greater than 0.

97.1.2.7. column
----------------

The column of the table corresponding to the attribute will
traditionally have the same name as the attribute, though it need not.

This specifies the table column that contains an item's attribute
values. The tag will find item attribute names and values in a
comma-delimited list of name=value pairs stored in this field of an
item's table entry. If unspecified, the column name will default to
the name given for the 'attribute' attribute.

For example, if an item in the products table has a 'size' attribute,
and each item's comma-delimited list of available sizes is stored in
the 'how_big' column, then you would need to specify "column=how_big"
because the tag's default column choice (size) would be missing or
used for some other purpose.

97.1.2.8. table
---------------

This is the database table containing the item's attribute values. It
defaults to the first products file where the item code is found.

If you have configured your database so that the attributes are kept
in a different table from other item data, 'code' should be set to the
master key in this table. See 'outboard') if you are using
[item-accessories] and cannot specify code=key.

97.1.2.9. name
--------------

This sets the name of the form variable to use if appropriate for the
widget being built. Defaults to 'mv_order_attribute' - i.e. if the
attribute is size, the form variable will be named mv_order_size.

If the variable is set in the user session, the widget will "remember"
its previous setting. In other words, [value name] will contain the
previous setting, which the widget will use as its default setting.
See also the default attribute.

97.1.2.10. outboard
-------------------

If calling the item-accessories tag, and you wish to select from an
outboard database table whose master key is different from the item
code, you can pass the key the tag should use to find the accessory
data.

97.1.2.11. passed
-----------------

You can use this to pass your own values to the widget the tag will
build. If you have set passed to a list of widget options, then the
tag will simply build a widget of the specified type with your values
instead of fetching an attribute value list from the database.

For example, to generate a select box with a blank option (perhaps
forcing a select), the value of blue with a label of Blue, and the
value of green with a label of Sea Green, do:

    [accessories type=select
                 name=color
               passed="=--select--*, blue=Blue, green=Sea Green"]

This will generate:

    <SELECT NAME="color"><OPTION VALUE="" SELECTED>--select--\
    <OPTION VALUE="blue">Blue\
    <OPTION VALUE="green">Sea Green</SELECT>

Note: trailing backslashes ('\') in the above example indicate line
continuation and are not part of the tag output.

97.1.2.12. delimiter
--------------------

The list of attribute values will be a delimited string. This allows
you to specify an alternative delimiter if the list is not
comma-delimited (the default).

97.1.2.13. prepend
------------------

You can set a string to prepend to the returned output of the tag.
Note that this is not a list to prepend to the fetched attribute value
list, which is treated within the tag.

For example,

    [accessories code=os28044
                 type=select
            attribute=size
               append="Append Me<br>"
              prepend="Prepend Me"]
---
    Prepend Me<SELECT NAME="mv_order_size">\
    <OPTION VALUE="10oz">10oz\
    <OPTION VALUE="15oz">15oz\
    <OPTION VALUE="20oz">20oz</SELECT>Append Me<br>

97.1.2.14. append
-----------------

You can set a string to append to the returned output of the tag. Note
that this is not a list to append to the fetched attribute value list,
which is treated within the tag.

97.1.2.15. extra
----------------

Setting the 'extra' attribute appends its value as the last attribute
of the HTML output tag. The following example illustrates the append,
extra and js options:

    [accessories code=os28044
                 type=select
            attribute=size
               append="Append Me<br>"
                extra="Last=Extra"
                   js="javascript_here"]
---
    <SELECT NAME="mv_order_size" javascript_here Last=Extra>\
    <OPTION VALUE="10oz">10oz\
    <OPTION VALUE="15oz">15oz\
    <OPTION VALUE="20oz">20oz</SELECT>Append Me<br>

97.1.2.16. js
-------------

This allows you to place javascript within the start tag of the HTML
output. See the example given above for extra.

js has no default, except when 'type=move_combo', where the default
is:

  onChange="addItem(this.form.Xname,this.form.name)"

97.1.2.17. rows
---------------

The tag will pass the number you choose through to the HTML 'ROWS=n'
attribute in HTML widgets that accept it.

For some types, you can also define widget rows and columns within the
string that sets the type; for example,
type="textarea_6_33_wrap=virtual" specifies a TEXTAREA widget with
ROWS=6, COLS=33, and WRAP=virtual. You should resort to this only when
you cannot use the named parameters, for example within an
[item-accessories] tag.

The result of setting conflicting values in the type string and the
rows=n attribute is undefined.

97.1.2.18. cols
---------------

The tag will pass the number you choose through to the HTML 'COLS=n'
attribute in HTML widgets that accept it.

See also 'rows' above.

97.1.2.19. width
----------------

This is a quasi-alias for 'cols' that only works with the 'text' and
'<password>' types. Use 'cols' instead.

97.1.2.20. default
------------------

Sets the default attribute option in the widget returned by the tag.
This will override a default indicated with a trailing '*' in the
database or 'passed' string. This will also override the default of a
user's previous selection when the tag would otherwise have preserved
it.

For example the following selects blue by default rather than green as
it would otherwise have done,

    [accessories type=select
                 name=color
               passed="blue=blue, green=Sea Green*"
              default="blue"]
---
    <SELECT NAME="color"><OPTION VALUE="blue" SELECTED>blue\
    <OPTION VALUE="green">Sea Green</SELECT>
---

Obscure technical note: the tag ignores the 'default' attribute if it
has an item hash reference - see Hash Lists above.

97.1.2.21. price
----------------

When combined with the price_data tag attribute, this allows you to
force prices for item attributes. You probably do not want to use
this; just let the tag pick up prices from your database table(s) when
appropriate.

If you are passing attribute values, you can use this to control the
displayed price in the widget.

    [accessories type=check
                 name=color
                price=1
           price_data="blue=20, green=50"
               passed="blue=Blue, green=Sea Green*"]
---
    <INPUT TYPE="checkbox" NAME="color" VALUE="blue" >&nbsp;Blue&nbsp;($20.00)
    <INPUT TYPE="checkbox" NAME="color" VALUE="green" CHECKED>&nbsp;Sea Green&nbsp;($50.00)

97.1.2.22. price_data
---------------------

97.1.2.23. contains
-------------------

Requires 'type=radio' or 'type=check'.

Used to determine whether a substring match of the value will cause a
radio box or check box to be selected. If true, the match will happen
whether the value is on a word boundary or not -- if false, the value
must be on a word boundary. (When we speak of a word boundary, it is
in the Perl sense -- a word character [A-Za-z0-9_] followed or
preceded by a non-word character, or beginning or end of the string.)

97.1.2.24. joiner
-----------------

Requires 'type=links'.

With type=links, the accessories tag returns a link for each option.
This allows you to override the default string ('<BR>') that joins
these links. You can use Perl's metacharacter escapes, such as '\n'
for newline or '\t' for tab.

97.1.2.25. href
---------------

Requires 'type=links'.

This sets the base HREF for the link in a links type. Default is the
current page.

97.1.2.26. template
-------------------

Requires 'type=links'.

Allows you to override the standard Interchange template for a
hyperlink. You probably don't need to use this - grep the code to grok
it if you do (see 'sub build_accessory_links').

97.1.2.27. form
---------------

Requires 'type=links'.

This sets the base value for the form in a links type. Default is
mv_action=return, which will simply set the variable value in the
link.

For example, to generate a series of links - one per item attribute
value passed - that set the variable "color" to the corresponding
passed value (blank, blue, or green), do this:

    [accessories type=links
                 name=color
               passed="=--select--, blue=Blue, green=Sea Green"]

This will generate something like the following:

    <A HREF="VENDURL/MV_PAGE?mv_action=return&color=blue">Blue</A><BR>
    <A HREF="VENDURL/MV_PAGE?mv_action=return&color=green">Sea Green</A>

where VENDURL is your Interchange URL for the catalog MV_PAGE is the
current page.

If you want the empty "--select--" option to show up, pass an empty=1
parameter.

97.1.2.28. empty
----------------

Requires 'type=links'.

Setting 'empty=1' includes a hyperlink for the empty "--select--"
option. See the example in form above; if empty=1 had been specified,
three links would have been generated.

97.1.2.29. secure
-----------------

Requires 'type=links'.

Setting secure=1 causes the generated link(s) to point to your secure
Interchange URL.

97.1.2.30. new
--------------

Requires 'type=combo' or 'reverse_combo'.

You can use this to set a value in place of the 'New' or 'Current'
option in a combo box. For example, if item 'os28044' has size
attribute values of "Sm=10oz, Med=15oz, Lg=20oz":

    [accessories code=os28044 attribute=size type=combo new="my_new_value"]
---
    <INPUT TYPE=text NAME="mv_order_size" SIZE=16 VALUE="">
    <SELECT NAME="mv_order_size" SIZE="1">
    <OPTION VALUE="my_new_value">my_new_value
    <OPTION VALUE="Sm">10oz
    <OPTION VALUE="Med">15oz
    <OPTION VALUE="Lg">20oz</SELECT>

Or, with the default new value:

    [accessories code=os28044 attribute=size type=combo]
---
    <INPUT TYPE=text NAME="mv_order_size" SIZE=16 VALUE="">
    <SELECT NAME="mv_order_size" SIZE="1">
    <OPTION VALUE="">&lt;-- New
    <OPTION VALUE="Sm">10oz
    <OPTION VALUE="Med">15oz
    <OPTION VALUE="Lg">20oz</SELECT>

Default is no VALUE with option text set to '&lt;-- New' for a combo
box or 'Current --&gt;' for a reverse_combo box.

97.2. and
---------

97.2.1. Summary
---------------

Parameters: type term op compare

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Note: This tag has special positional parameter handling.

    [and type term op compare]

Parameters    Description                               Default
............. ......................................... ............. 
base          Alias for type                            DEFAULT_VALUE
comp          Alias for compare                         DEFAULT_VALUE
compare                                                 DEFAULT_VALUE
op                                                      DEFAULT_VALUE
operator      Alias for op                              DEFAULT_VALUE
term                                                    DEFAULT_VALUE
type                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [value name=fname set="Mike" hide=1]
    [value name=lname set="" hide=1]

    ...

    [if value fname]
    [and value lname]
        Both first and last name are present.
    [else]
        Missing one of "fname" and "lname" from $Values.
    [/else]
    [/if]
---
    Missing one of "fname" and "lname" from $Values.

ASP-like Perl call:

Not applicable. The [and ...] tag only is used with [if ...], and Perl
logic obviates the [if ...] tag.

97.2.2. Description
-------------------

The [and ...] tag is only used in conjunction with [if ...].  Example:

        [if value fname]
        [and value lname]
        Both first and last name are present.
        [else]
        Missing one of "fname" and "lname" from $Values.
        [/else]
        [/if]

See the description of the [if] tag.

97.2.2.1. compare
-----------------

97.2.2.2. op
------------

97.2.2.3. term
--------------

97.2.2.4. type
--------------

97.3. area
----------

Alias:  href

Expands to the URL for an Interchange page or action, including the
Interchange session ID and supplied arguments. This is very similar to
the page tag - these are equivalent:

    [page href=dir/page arg=mv_arg]TargetName</A>
    <A HREF="[area href=dir/page arg=mv_arg]">TargetName</A>

97.3.1. Summary
---------------

    [area href arg]
    [area href=dir/page arg=page_arguments other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
href          Path to Interchange page or actionSpecial process
              arguments'scan' links to a search (using
              search arguments in arg)'http://...'
              external link (requires form attribute)
arg           Interchange arguments to page or action   none

Attributes                         Default
.................................. .................................. 
form                               none
search                             No
secure                             No
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        No

Tag expansion example:

    [area href=dir/page.html arg="arg1=AA/arg2=BB"]

    www.here.com/cgi-bin/mycatalog/page.html?mv_session_id=6CZ2whqo&\
    mv_pc=1&mv_arg=arg1%3dAA/arg2%3dBB

ASP-like Perl call:

    $Tag->area(  { href => "dir/page",
                   arg  => "arguments", }  );

or similarly with positional parameters,

    $Tag->area($href, $arg, $attribute_hash_reference);

97.3.1.1. See Also
------------------

page

97.3.2. Description
-------------------

The area tag is very similar to the [page] tag. It produces the URL to
call an Interchange page, but it differs from page in that it does not
supply the surrounding <A HREF ...> notation. This can be used to get
control of your HREF items, perhaps to place an ALT string or a
Javascript construct.

It was originally named area because it also can be used in a
client-side image map.

The area tag has an alias of href. The two links below are identical
in operation:

   <A HREF="[area href=catalog]" ALT="Main catalog page">Catalog Home</A>
   <A HREF="[href href=catalog]" ALT="Main catalog page">Catalog Home</A>

The optional arg is used just as in the page tag.

97.3.2.1. form
--------------

The optional form argument allows you to encode a form in the link.

   <A HREF="[area form="mv_order_item=os28044
                        mv_order_size=15oz
                        mv_order_quantity=1
                        mv_separate_items=1
                        mv_todo=refresh"]"> Order 15oz Framing Hammer</A>

See the description of the [page] tag for more detail.

97.3.2.2. search
----------------

Interchange allows you to pass a search in a URL. There are two ways
to do this:

1.   Place the search specification in the named search attribute.

     o    Interchange will ignore the href parameter (the link will be
          set to 'scan'.

     o    If you give the arg parameter a value, that value will be
          available as [value mv_arg] within the search display page.

2.   Set the href parameter to 'scan' and set arg to the search
     specification.

     o    Note that you can use this form positionally - the values go
          into href and arg, so you do not have to name parameters.

These are identical:

   <A HREF="[area scan
                  se=Impressionists
                  sf=category]">Impressionist Paintings</A>

   <A HREF="[area href=scan
                   arg="se=Impressionists
                        sf=category"]">Impressionist Paintings</A>

   <A HREF="[area search="se=Impressionists
                          sf=category"]">Impressionist Paintings</A>


See the description of the page tag for more detail.

97.3.2.3. secure
----------------

97.3.2.4. Examples
------------------

Tag expansion example:

    [area href=dir/page.html arg="arg1=AA/arg2=BB"]

    www.here.com/cgi-bin/mycatalog/page.html?mv_session_id=6CZ2whqo&\
    mv_pc=1&mv_arg=arg1%3dAA/arg2%3dBB

Positional call example:

    <A HREF="[area ord/basket]">Check basket</A>

Named call example:

    <A HREF="[area ord/basket]">Check basket</A>

97.4. assign
------------

Allows you to assign numeric values to preempt calculation of one or
more of the following tags:

[handling], [salestax], [shipping], and [subtotal]

The assignment is persistent within a user's session until you clear
it, an assigned tag will return your value instead of calculating a
value.

Warning - please be sure you understand the dependencies within the
pricing system before using the assign tag. In particular, you must
have the value mv_shipmode set to assign to shipping, and likewise you
must set mv_handling to assign to handling. The salestax and subtotal
settings don't require any session variables be set.

97.4.1. Summary
---------------

    [assign tag_name=value tag_name=value ...]
    [assign clear=1]

Attributes    Description                               Default
............. ......................................... ............. 
clear         Clears all pending 'assign' tag           none
              assignments
handling      Assigns an override value for [handling]  none
              tags
salestax      Assigns an override value for [salestax]  none
              tags
shipping      Assigns an override value for [shipping]  none
              tags
subtotal      Assigns an override value for [subtotal]  none
              tags

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      No

ASP-like Perl call:

    $Tag->assign(  { shipping => 2.99, }  );

97.4.1.1. See Also
------------------

[handling], [salestax], [shipping], [subtotal], [Shipping]

97.4.2. Description
-------------------

The assign tag allows you to assign numeric override values to one or
more of the following tags:

[handling], [salestax], [shipping], and [subtotal]

An assigned tag will return your value rather than calculating its own
until you clear the assignment.

Assignment is persistent within the user's session (unless cleared)
and affects only that user.

Assigning an empty string clears the tag's assignment. You can also
clear all pending assignments at once with the clear attribute.

For example, the following eliminates salestax and sets shipping to
$4.99 regardless of weight and destination:

    [assign salestax=0 shipping=4.99]

This restores the [salestax] tag and eliminates handling charges:

    [assign salestax="" handling=0]

This restores the normal behavior to the [shipping] and [handling]
tags:

    [assign clear=1]

Assignment affects only the value returned by a tag. Other behavior,
such as formatting for the local currency, is not affected by the
assignment.

Note - you will get an error in the error log (and any pending
assignment for the specified tag will be cleared) if you try to assign
a value other than a number or the empty string ("").

97.4.2.1. clear
---------------

Setting this to a true value clears all pending assignments (i.e., all
assignable tags return to normal behavior).

97.4.2.2. shipping
------------------

This sets the total value of shipping, rounded to locale-specific
fractional digits. Always active if assigned a numeric value. See the
[shipping] tag for detail about rounding, etc.

97.4.2.3. handling
------------------

This option sets the total value of handling, rounded to fractional
digits.

Important note

The [handling] tag is unlike the others in that it will be inactive
(despite your assignment) unless the [value mv_handling] variable is
true (i.e., a nonzero, non-blank value).



97.4.2.4. salestax
------------------

This preempts the salestax calculation. The assigned value is not
rounded.

97.4.2.5. subtotal
------------------

This preempts the cart subtotal derived from prices. The assigned
value is not rounded.

Note that you cannot assign to [total-cost] - it will always be the
sum of the four above.

Before using the assign tag, please be sure you understand the
dependencies within the pricing system, such as the relationship
between [total-cost] and assigned tags.

97.5. attr-list
---------------

This tag is intended for use within embedded perl rather than as a
standalone tag within a template (i.e., the [attr-list ...] syntax
does not apply).

The $Tag->attr_list($template, $hashref) usage provides a shorthand
for accessing values of a hash within embedded perl. It also allows
you to control defaults or set up conditional values.

97.5.1. Summary
---------------

    $Tag->attr_list($template, $hashref)

Parameters    Description                               Default
............. ......................................... ............. 
hash                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      NA (Though the template is
                                   technically body text)
Has Subtags                        No
Nests                              No

Tag expansion example (ASP-like Perl call):

    [perl tables=products]
        my %opt = ( hashref => 1,
                 sql     => 'select * from  products', );

        my $ary_of_hash = $Db{products}->query(\%opt);

        my $template = <<EOF;
            {sku} - {description} - {price|Call for price}
            {image?}<IMG SRC="{image}">{/image?}
            {image:}No image available{/image:}
            <br>
            More body Text here
            <br>
EOF

        foreach my $ref (@$ary_of_hash) {
            $out .= $Tag->attr_list($template, $ref);
        }
        return $out;
     [/perl]
---
     os28113 - The Claw Hand Rake - Call for price
     <IMG SRC="/mycatalog/images/os28113.gif">

     <br>
     More body Text here
     <br>
     os28006 - Painters Brush Set - 29.99
     No image available

     <br>
     More body Text here
     <br>
     ...

97.5.2. Description
-------------------

Tags an attribute list with values from a hash. Designed for use in
embedded Perl.

Tags according to the following rules:

97.5.2.1. {key}
---------------

Inserts the value of the key for the reference. In a database query,
this is the column name.

97.5.2.2. {key|fallback string}
-------------------------------

Displays the value of {key} or if it is zero or blank, the fallback
string (i.e., default).

97.5.2.3. {key true string}
---------------------------

Displays true string if the value of {key} is non-blank, non-zero, or
displays nothing if the key is false.

97.5.2.4. {key?} true text {/key?}
----------------------------------

Displays true text if the value of {key} is non-blank, non-zero, and
nothing otherwise.

97.5.2.5. {key:} false text {/key:}
-----------------------------------

Displays false text if the value of {key} is blank or zero, and
nothing otherwise.

97.5.2.6. hash
--------------

This is the hash reference whose keys will be expanded within the
template (see above).

97.6. banner
------------

Implements random or rotating banner ads. See also Banner/Ad rotation.

97.6.1. Summary
---------------

    [banner category]
    [banner category=my_category other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
category                                                default

Attributes                         Default
.................................. .................................. 
table                              banner
r_field (unweighted)               rotate
b_field                            banner
separator (unweighted)             ':'
delimiter (unweighted)             '{or}'
weighted                           No
once (weighted)                    No
c_field (weighted)                 category
w_field (weighted)                 weight
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      No

Tag expansion example:

    [banner category=my_category]

ASP-like Perl call:

    $Tag->banner(  { category => $key, } );

or similarly with positional parameters,

    $Tag->banner($category, $attribute_hash_reference);

97.6.1.1. See Also
------------------

Banner/Ad rotation

97.6.2. Description
-------------------

Implements random or rotating banner ads. See Banner/Ad rotation in
the Interchange Template documentation.

You will need a banner ad table (typically called 'banner') which
contains banner data. The following is an example:

code          category      weight        rotate        banner
............. ............. ............. ............. ............. 
m_3           cat1          7             0             my banner 3
m_1           cat1          1             0             my banner 1
default                                   1             Default
                                                        1{or}Default
                                                        2{or}Default
                                                        3
m_2           cat1          2             0             my banner 2
t_1           cat2          4             0             their banner
                                                        1
t_2           cat2          1             0             their banner
                                                        2

97.6.2.1. category
------------------

Default: category="default"

This specifies the category for weighted ad, or the table row (i.e.,
code value) for an unweighted ad.

97.6.2.2. table
---------------

Default: table="banner"

Setting 'table="my_banner_table"' forces the tag to refer to
'my_banner_table' rather than the default 'banner' table for banner ad
information.

97.6.2.3. r_field
-----------------

Default: r_field="rotate"

Unweighted ads only.

A table row may include multiple banners in the 'banner' column. The
column specified by r_field contains a boolean that determines whether
to rotate banners. In the above table example, 'Default 1', 'Default
2' and 'Default 3' would rotate.

97.6.2.4. b_field
-----------------

Default: b_field="banner"

This specifies the column containing the banner descriptor(s). The
default is 'banner'. Note that an entry might be a delimited list of
banner descriptors to rotate (see delimiter below).

97.6.2.5. separator
-------------------

Default: separator=":"

Unweighted ads only.

This sets the separator within the table key (i.e., code) for
multi-level categorized ads. See Banner/Ad rotation.

97.6.2.6. delimiter
-------------------

Default: delimiter="{or}"

Unweighted ads only.

This specifies the delimiter between rotating banner descriptors in
the 'banner' column.

97.6.2.7. weighted
------------------

The banner tag will not apply weighting from the table unless you set
weighted=1. Note that the tag will behave as if you gave it a standard
unweighted entry - it will look for a matching row rather than a
matching category.

97.6.2.8. once
--------------

Weighted ads only.

If the option once is passed (i.e., [banner once=1 weighted=1], then
the banners will not be rebuilt until the total_weight file is
removed. See Banner/Ad rotation.

97.6.2.9. c_field
-----------------

Default: c_field="category"

Weighted ads only.

This specifies the column containing the banner category for weighted
ads. The banner tag will display ads from rows in the table whose
category matches the category given in the tag, with frequency
corresponding to the weights in the table.

97.6.2.10. w_field
------------------

Default: w_field="weight"

Weighted ads only.

This specifies the column containing the banner weight.

97.7. bounce
------------

97.7.1. Summary
---------------

Parameters: href if

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

None. This tag doesn't work with embedded Perl due to special
processing.

    [bounce href if]

Parameters    Description                               Default
............. ......................................... ............. 
href                                                    DEFAULT_VALUE
if                                                      DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [bounce href if]
---
    TAG RESULT

ASP-like Perl call:

None. This tag doesn't work with embedded Perl due to special
processing.

97.7.2. Description
-------------------

The [bounce ...] tag is designed to send an HTTP redirect (302 status
code) to the browser and redirect it to another (possibly
Interchange-parsed) page.

It will stop ITL code execution at that point; further tags will not
be run through the parser. Bear in mind that if you are inside a
looping list, that list will run to completion and the [bounce] tag
will not be seen until the loop is complete.

Example of bouncing to an Interchange parsed page:

        [if !scratch real_user]
        [bounce href="[area violation]"]
        [/if]

Note the URL is produced by the [area ...] ITL tag.

Since the HTTP says the URL needs to be absolute, this one might cause
a browser warning:

        [if value go_home]
        [bounce href="/"]
        [/if]

But running something like one of the Interchange demos you can do:

        [if value go_home]
        [bounce href="__SERVER_NAME__/"]
        [/if]

        [if value go_home]
        [bounce href="/"]
        [/if]

97.7.2.1. href
--------------

97.7.2.2. if
------------

97.8. calc
----------

Calculates the value of the enclosed arithmetic expression.

97.8.1. Summary
---------------

    [calc] Expression [/calc]

No parameters

No attributes (though you can break it if you set 'interpolate=0')

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Has Subtags                        No
Container tag                      Yes
Nests                              No

ASP-like Perl call:

There is never a reason to call this tag from within Perl or ASP code.
Simply do the calculation directly.

97.8.2. Description
-------------------

Calculates the value of the enclosed arithmetic expression.

Use it as follows: [calc] Expression [/calc]

The enclosed region where the arguments are calculated according to
normal arithmetic symbols. For instance:

    [calc] 2 + 2 [/calc]

will expand to:

    4

The [calc] tag is really the same as the [perl] tag, except that it
doesn't accept arguments, interpolates surrounded Interchange tags by
default, and is slightly more efficient to parse.

Tip: The [calc] tag will remember variable values inside one page, so
you can do the equivalent of a memory store and memory recall for a
loop.

ASP Note: There is never a reason to call this tag from within Perl or
ASP code.

97.9. calcn
-----------

Calculates the value of the enclosed arithmetic expression.

97.9.1. Summary
---------------

    [calcn] Expression [/calcn]

No parameters

No attributes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Has Subtags                        No
Container tag                      Yes
Nests                              No

ASP-like Perl call:

There is never a reason to call this tag from within Perl or ASP code.
Simply do the calculation directly.

97.9.2. Description
-------------------

Equivalent to the [calc] tag, except that it does not interpolate by
default.

NOTE: This tag was introduced in Interchange 4.9 and is therefore not
available in earlier versions.

97.10. cart
-----------

97.10.1. Summary
----------------

Parameters: name

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->cart(
        {
         name => VALUE,
        }
    )

 OR

    $Tag->cart($name);
    [cart name]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [cart name]
---
    TAG RESULT

ASP-like Perl call:

   $Tag->cart(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->cart(name, $attribute_hash_reference, $body);

97.10.2. Description
--------------------

Sets the name of the current shopping cart for display of shipping,
price, total, subtotal, shipping, and nitems tags.

97.10.2.1. name
---------------

97.11. catch
------------

The page content contained within the [catch label][/catch] block
executes if the correspondingly labelled  try block fails.

You can also return a result based on the error message caught in the
try block with paired subtags, like this:

    [error message]body text[/error message]

Note that this feature excises all tag/endtag pairs if interpolation
is turned off, so the catch tag interpolates by default.

See also [try].

97.11.1. Summary
----------------

    [try my_label]
        Body text to return if no error
    [/try]
    .
    .
    .
    [catch label=my_label other_named_attributes]
        [/Pattern matching error message 1/]
            Return this if error 1 occurs
        [/Pattern matching error message 1/]

        [/Pattern matching error message 2/]
            Return this if error 2 occurs, etc.
        [/Pattern matching error message 2/]

        Default body text to process if try block caused an error
    [/catch]

Parameters    Description                               Default
............. ......................................... ............. 
label         The label shared by the paired try and    'default'
              catch blocks

Attributes                         Default
.................................. .................................. 
interpolate                        Yes
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      Yes
Has Subtags                        [Error message text]body[/Error
                                   message text]

Tag expansion example

Ignoring whitespace, the following would return division result if
successful, 0 on a division by zero, or an error message:

    [set divisor]0[/set]
    [try label=div]
        [perl] eval(1 / [scratch divisor]) [/perl]
    [/try]
    [catch div]
        [/Illegal division by zero/]
            0
        [/Illegal division by zero/]
        [/eval "string" trapped by operation mask/]
            Perl Safe error
        [/eval "string" trapped by operation mask/]
        Other division error
    [/catch]
---
   Perl Safe error

ASP-like Perl call:

    $Tag->catch(  { label => I<'my_label'>, },
                  $body  );

or similarly with positional parameters,

    $Tag->catch($label, $attribute_hash_reference, $body);

97.11.1.1. See Also
-------------------

try

    [catch]

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [catch]
---
    TAG RESULT

ASP-like Perl call:

   $Tag->catch(  {
}, $body  );

or similarly with positional parameters,

    $Tag->catch(, $attribute_hash_reference, $body);

97.11.2. Description
--------------------

The page content contained within the [catch label][/catch] block
executes if the correspondingly labelled  try block fails. The catch
block executes in place on the page if triggered (i.e., it does not
return its result in place of the try block).

You can also return a result based on the error message caught in the
try block with paired subtags, like this:

    [/error message/]special catch block for the error[/error message/]

The error message to use in the special block will generally be part
of the entry the error generates in your error log.  For example, a
division by zero error generates something like the following in the
error log:

   127.0.0.1 4cU3Pgsh:127.0.0.1 - [24/May/2001:14:45:07 -0400]\
   tag /cgi-bin/tag72/tag Safe: Illegal division by zero\
   at (eval 526) line 2.

(note that trailing backslashes in the example indicate a continued
line).

97.11.2.1. label
----------------

This is the label specifying the corresponding [try block. Defaults to
'default'.

97.12. cgi
----------

Returns the the current value of the named CGI input variable.
HTML-escapes Interchange tags in the result for security.

Can also set a new CGI value within the current page.

97.12.1. Summary
----------------

    [cgi name]
    [cgi name=cgi_var_name other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
name          This is the name of the CGI variable      None
              whose value you want.

Attributes                         Default
.................................. .................................. 
set                                none
hide                               No
filter                             none
keep (with filter)                 No
enable_html                        No
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes

Tag expansion example:

Assuming CGI variable 'foo' = 'bar',

    [cgi foo]
---
    bar

ASP-like Perl call:

    $Tag->cgi( { name => var_name } );

    # or if you simply want the value:
    $CGI->{var_name};

    # or:
    $CGI::values{var_name};

or similarly with positional parameters,

    $Tag->cgi($name, $attribute_hash_reference);

97.12.2. Description
--------------------

Displays the value of a CGI variable submitted to the current page.
This is similar to [value ...], except it displays the transitory
values that have been submitted with the current request.

For instance, if you access the following URL:

        http://VENDURL/pagename?foo=bar

bar will be substituted for [cgi foo].

This is the same as $CGI->{foo} in embedded Perl.

97.12.2.1. name
---------------

This is the name of the CGI variable whose value you want.

97.12.2.2. set
--------------

You can change a value with 'set=new_value'. The tag will return the
CGI value you set unless you also set the hide=1 attribute.

Note that this is only available in new-style tags, for safety
reasons.

97.12.2.3. hide
---------------

Setting hide=1 suppresses the tag's return value, which can be useful
with the set attribute.

97.12.2.4. filter
-----------------

See the filter tag for a list of filters.

Setting 'filter="filter"' modifies the named CGI variable with the
specified filter.

97.12.2.5. keep (with filter)
-----------------------------

Set keep=1 if you want the tag to return a filtered result but do not
want the filter to modify the CGI value itself in the $CGI::values
hash.

97.12.2.6. default
------------------

This sets a return value in case the named CGI variable is missing or
otherwise false. The following will expand to "Using default":

    [cgi name=myname set=0 hide=1]
    [cgi name=myname default="Using default"]

97.12.2.7. enable_html
----------------------

Any '<' characters will normally be converted into '&lt;' for safety
reasons. This conversion can be disabled using 'enable_html=1'.

97.13. checked
--------------

97.13.1. Summary
----------------

Parameters: name value

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->checked(
        {
         name => VALUE,
         value => VALUE,
        }
    )

 OR

    $Tag->checked($name, $value, $ATTRHASH);
    [checked name value other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
case                                                    DEFAULT_VALUE
cgi                                                     DEFAULT_VALUE
default                                                 DEFAULT_VALUE
name                                                    DEFAULT_VALUE
multiple                                                DEFAULT_VALUE
value                                                   DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [value name=example set=neato]
    <INPUT TYPE=checkbox NAME=neato VALUE=1 [checked name=neato value=1]>
    <INPUT TYPE=checkbox NAME=silly VALUE=1 [checked name=silly value=1]>
    <INPUT TYPE=checkbox NAME=neato VALUE=1 CHECKED>
    <INPUT TYPE=checkbox NAME=silly VALUE=1 >

97.13.2. Description
--------------------

You can provide a "memory" for drop-down menus, radio buttons, and
checkboxes with the [checked] and [selected] tags.

    <INPUT TYPE=radio NAME=foo
            VALUE=on [checked name=foo value=on default=1]>
    <INPUT TYPE=radio NAME=foo
            VALUE=off [checked name=foo value=off]>

This will output CHECKED if the variable var_name is equal to value.
Not case sensitive unless the optional case=1 parameter is used.

The default parameter, if true (non-zero and non-blank), will cause
the box to be checked if the variable has never been defined.

Note that CHECKBOX items will never submit their value if not checked,
so the box will not be reset. You must do something like:

    <INPUT TYPE=checkbox NAME=foo
            VALUE=1 [checked name=foo value=1 default=1]>
    [value name=foo set=""]

By default, the Values space (i.e. [value foo]) is checked - if you
want to use the volatile CGI space (i.e. [cgi foo]) use the option
cgi=1.

Use the parameter default=1 to specify that this checkbox should be
marked CHECKED if the value/CGI variable has never been set.

If the parameter multiple=1 is set, the value parameter can contain
multiple (stacked) values that should be checked, separated by ASCII
null characters ("\0" in Perl).

97.13.2.1. case
---------------

97.13.2.2. cgi
--------------

97.13.2.3. default
------------------

97.13.2.4. name
---------------

97.13.2.5. multiple
-------------------

97.13.2.6. value
----------------

97.14. control
--------------

Returns named scratchpad field or copies named scratch variable to
scratchpad. Returns value specified by 'default' attribute if
scratchpad variable is undefined or empty. Calling without a name
moves to next scratchpad. Calling without a name and 'reset=1' returns
to first scratchpad page.

97.14.1. Summary
----------------

    [control name default other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
default       Value to return if scratchpad variable    DEFAULT_VALUE
              missing or empty
name          Name of scratchpad variable to set or     DEFAULT_VALUE
              return
reset         Resets scratchpad (i.e. $::Control array) DEFAULT_VALUE
              by setting special scratch variable
              'control_index' to 0. Control_index is an
              index into the $::Control ==
              $Vend::Session->{control} array of
              hashrefs.(must not specify name; may
              specify default)
set           Copies named scratch variable (i.e., from DEFAULT_VALUE
              $::Scratch) to scratchpad with current
              control index.

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [control name default]
---
    TAG RESULT

ASP-like Perl call:

   $Tag->control(  { default => VALUE_default
                      name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->control(name,default, $attribute_hash_reference, $body);

97.14.2. Description
--------------------

Returns named scratchpad field or copies named scratch variable to
scratchpad. Returns value specified by 'default' attribute if
scratchpad variable is undefined or empty. Calling without a name
moves to next scratchpad. Calling without a name and 'reset=1' returns
to first scratchpad page.

97.14.2.1. default
------------------

Value to return if scratchpad variable missing or empty

97.14.2.2. name
---------------

Name of scratchpad variable to set or return

97.14.2.3. reset
----------------

Resets scratchpad (i.e. $::Control array) by setting special scratch
variable 'control_index' to 0. Control_index is an index into the
$::Control == $Vend::Session->{control} array of hashrefs.

o    (must not specify name; may specify default)

97.14.2.4. set
--------------

Copies named scratch variable (i.e., from $::Scratch) to scratchpad
with current control index.

97.15. control_set
------------------

Bulk-sets scratchpad variables on the scratchpad page specified by
'index'. Note that, unlike [control], this does not copy values from
scratch.

97.15.1. Summary
----------------

This example sets var_one, var_two and var_three in the scratchpad on
page 5 (index begins with 0).

    [control_set index=4]
        [var_one]var_one_value[/var_one]
        [var_two]var_two_value[/var_two]
        [var_three]var_three_value[/var_three]
    [/control_set]

Parameters: index

Positional parameters in same order.

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [control_set] FOO [/control_set].
Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->control_set(
        {
         index => VALUE,
        },
        BODY
    )

 OR

    $Tag->control_set($index, $ATTRHASH, $BODY);
    [control_set index other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
index                                                   DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [control_set index]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->control_set(  { index => VALUE_index
}, $body  );

or similarly with positional parameters,

    $Tag->control_set(index, $attribute_hash_reference, $body);

97.15.2. Description
--------------------

Bulk-sets scratchpad variables on the scratchpad page specified by
'index'. Note that, unlike [control], this does not copy values from
scratch.

97.15.2.1. index
----------------

97.16. counter
--------------

97.16.1. Summary
----------------

Parameters: file

Positional parameters in same order.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->counter(
        {
         file => VALUE,
         sql => VALUE,
         start => VALUE,
        }
    )

 OR

    $Tag->counter($file, $ATTRHASH);

Attribute aliases

            name ==> file
    [counter file]

Parameters    Description                               Default
............. ......................................... ............. 
file                                                    DEFAULT_VALUE
name          Alias for file                            DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [counter file]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->counter(  { file => VALUE_file, sql => 'table:seq', start => VALUE, }  );

or similarly with positional parameters,

    $Tag->counter(file, $attribute_hash_reference);

97.16.2. Description
--------------------

Manipulates a persistent counter, by default incrementing it and
returning the new value.

The counter value is stored in the specified file. If the file name
begins with a "/" then it is an absolute path. Otherwise, it is
relative to VendRoot. The default file is etc/counter. If the file
does not exist, it is created and initialized to the value of the
start parameter.

The counter is implemented using Perl's File::Counter module, which
protects the file against simultaneous access by multiple processes.

If the optional sql attribute is used, a SQL sequence will be used.
Currently MySQL and Postgres are supported. The sequence must already
exist. If no bypass parameter is sent, the table in the sequence
callout (explained below) will be used and must be an Interchange
table (i.e. set up with Database setting). If bypass is set, then the
DSN for the sequence will be passed in the dsn parameter.

WARNING: This tag may not work under Safe, i.e. in embedded Perl.

Additional parameters:

97.16.2.1. decrement=1
----------------------

Causes the counter to count down instead of up. This option is not
applicable to SQL counters.

97.16.2.2. start=50
-------------------

Causes a new counter to be created and to start from 50 (for example)
if it did not exist before. This option is not applicable to SQL
counters.

97.16.2.3. value=1
------------------

Shows the value of the counter without incrementing or decrementing
it. This option is not applicable to SQL counters.

97.16.2.4. sql="table:sequence"
-------------------------------

The table and sequence name of the SQL counter.

If the type of database is Postgres, the table is used to derive the
database and the sequence will be a named sequence independent of the
table; the sequence is incremented and accessed by "SELECT
nextval('sequence_name')".

If the type of database is MySQL, an AUTO_INCREMENT key column is
assumed and an insert of 0 followed by "select last_insert_id()" will
increment then access the counter.

97.16.2.5. file
---------------

97.16.3. SQL Counter Examples
-----------------------------

To set up a Postgres counter, simply create a named sequence in the
database:

  CREATE SEQUENCE "foo" start 1 increment 1 maxvalue 2147483647 minvalue 1 cache 1

You will want to make sure you have an Interchange table that uses
that database ("sometable" in the below example).

Then access it with:

    [counter sql="sometable:foo"]

You can create as many sequences as you like.

To set up a MySQL counter, add a table to your MySQL database in
catalog.cfg or other place like dbconf/mysql:

  Database sequence_name sequence_name.txt dbi:mysql:test_foundation
  Database sequence_name COLUMN_DEF "id=int NOT NULL AUTO_INCREMENT PRIMARY KEY"

Make sure you set up the sequence.txt file if you want Interchange to
create the table for you. Otherwise you can create the table yourself
from a mysql client:

mysql> create table sequence_name(id int NOT NULL AUTO_INCREMENT
PRIMARY KEY);

Then access it with:

    [counter sql="sequence_name:sequence_name"]

Alternatively, you can create the table without Interchange definition
as long as it is in the same database as an Interchange table:

  mysql> create table sequence_name(id int NOT NULL AUTO_INCREMENT PRIMARY KEY);

Then access it by calling the Interchange-defined table name followed
by the table that has the AUTO_INCREMENT key:

    [counter sql="products:sequence_name"]

To set up an Oracle counter, create a sequence:

  SQL> CREATE SEQUENCE foo START WITH 10000 INCREMENT BY 1
                 MAXVALUE 2147483647 MINVALUE 1 CACHE 2;

Then access via a table already connected to Oracle, in below
sometable:

    [counter sql="sometable:foo"]
  Database sequence_name sequence_name.txt dbi:mysql:test_foundation
  Database sequence_name COLUMN_DEF "id=int NOT NULL AUTO_INCREMENT PRIMARY KEY"

Make sure you set up the sequence.txt file if you want Interchange to
create the table for you. Otherwise you can create the table yourself
from a mysql client:

mysql> create table sequence_name(id int NOT NULL AUTO_INCREMENT
PRIMARY KEY);

Then access it with:

    [counter sql="sequence_name:sequence_name"]

Alternatively, you can create the table without Interchange definition
as long as it is in the same database as an Interchange table:

  mysql> create table sequence_name(id int NOT NULL AUTO_INCREMENT PRIMARY KEY);

Then access it by calling the Interchange-defined table name followed
by the table that has the AUTO_INCREMENT key:

    [counter sql="products:sequence_name"]

97.17. currency
---------------

97.17.1. Summary
----------------

Parameters: convert noformat

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Interpolates container text by default.

This is a container tag, i.e. [currency] FOO [/currency]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->currency(
        {
         convert => VALUE,
         noformat => VALUE,
        },
        BODY
    )

 OR

    $Tag->currency($convert, $noformat, $BODY);
    [currency convert noformat]

Parameters    Description                               Default
............. ......................................... ............. 
convert                                                 DEFAULT_VALUE
noformat                                                DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [currency convert noformat]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->currency(  { convert => VALUE_convert
                       noformat => VALUE_noformat
}, $body  );

or similarly with positional parameters,

    $Tag->currency(convert,noformat, $attribute_hash_reference, $body);

97.17.2. Description
--------------------

When passed a value of a single number, formats it according to the
currency specification. For instance:

    [currency]4[/currency]

will display:

    4.00

or something else depending on the Locale and PriceCommas settings. It
can contain a [calc] region. If the optional "convert" parameter is
set, it will convert the value according to PriceDivide> for the
current locale. If Locale is set to fr_FR, and PriceDivide for fr_FR
is 0.167, the following sequence

    [currency convert=1] [calc] 500.00 + 1000.00 [/calc] [/currency]

will cause the number 8.982,04 to be displayed.

97.17.2.1. convert
------------------

97.17.2.2. noformat
-------------------

97.18. data
-----------

97.18.1. Summary
----------------

Parameters: table field key

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->data(
        {
         table => VALUE,
         field => VALUE,
         key => VALUE,
        }
    )

 OR

    $Tag->data($table, $field, $key, $ATTRHASH);

Attribute aliases

            base ==> table
            code ==> key
            col ==> field
            column ==> field
            database ==> table
            name ==> field
            row ==> key
    [data table field key other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
base          Alias for table                           DEFAULT_VALUE
code          Alias for key                             DEFAULT_VALUE
col           Alias for field                           DEFAULT_VALUE
column        Alias for field                           DEFAULT_VALUE
database      Alias for table                           DEFAULT_VALUE
field                                                   DEFAULT_VALUE
hash                                                    DEFAULT_VALUE
key                                                     DEFAULT_VALUE
name          Alias for field                           DEFAULT_VALUE
row           Alias for key                             DEFAULT_VALUE
table                                                   DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [data table field key]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->data(  { field => VALUE_field
                   key => VALUE_key
                   table => VALUE_table
}, $body  );

or similarly with positional parameters,

    $Tag->data(table,field,key, $attribute_hash_reference, $body);

97.18.2. Description
--------------------

Syntax:             [data table=db_table column=column_name key=key
filter="uc|lc|name|namecase|no_white|etc."* append=1* value="value to
set to"* increment=1*]

Returns the value of the field in a database table, or from the
session namespace. If the optional value is supplied, the entry will
be changed to that value. If the option increment* is present, the
field will be atomically incremented with the value in value. Use
negative numbers in value to decrement. The append attribute causes
the value to be appended; and finally, the filter attribute is a set
of Interchange filters that are applied to the data 1) after it is
read; or 2)before it is placed in the table.

If a DBM-based database is to be modified, it must be flagged writable
on the page calling the write tag. Use [tag flag write]products[/tag]
to mark the products database writable, for example. This must be done
before ANY access to that table.

In addition, the [data ...] tag can access a number of elements in the
Interchange session database:

    accesses           Accesses within the last 30 seconds
    arg                The argument passed in a [page ...] or [area ...] tag
    browser            The user browser string
    cybercash_error    Error from last CyberCash operation
    cybercash_result   Hash of results from CyberCash (access with usertag)
    host               Interchange's idea of the host (modified by DomainTail)
    last_error         The last error from the error logging
    last_url           The current Interchange path_info
    logged_in          Whether the user is logged in (add-on UserDB feature)
    pageCount          Number of unique URLs generated
    prev_url           The previous path_info
    referer            HTTP_REFERER string
    ship_message       The last error messages from shipping
    source             Source of original entry to Interchange
    time               Time (seconds since Jan 1, 1970) of last access
    user               The REMOTE_USER string
    username           User name logged in as (UserDB feature)

Note: Databases will hide session values, so don't name a database
"session". or you won't be able to use the [data ...] tag to read
them. Case is sensitive, so in a pinch you could call the database
"Session", but it would be better not to use that name at all.

97.18.2.1. field
----------------

The name of the field whose value you want to fetch. Required unless
returning the entire row in combination with the hash option.

97.18.2.2. hash
---------------

The hash option causes the data tag to return its results (the entire
row, if you omit the field parameter) as a reference to a hash with
column names as keys into the values of the row.

An example:

        $row_hash = $Tag->data({
                table => 'products',
                key   => 'os28004',
                hash  => 1,
        });

You could then access desired values this way:

        $out = 'Price: ' . $row_hash->{price};

97.18.2.3. key
--------------

The key that identifies the row containing the value(s) you want to
fetch. Required.

97.18.2.4. table
----------------

The name of the Interchange-defined table you want to fetch data from.
Required.

97.19. default
--------------

97.19.1. Summary
----------------

Parameters: name default

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->default(
        {
         name => VALUE,
         default => VALUE,
        }
    )

 OR

    $Tag->default($name, $default, $ATTRHASH);
    [default name default other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
default                                                 DEFAULT_VALUE
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [default name default]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->default(  { default => VALUE_default
                      name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->default(name,default, $attribute_hash_reference, $body);

97.19.2. Description
--------------------

Returns the value of the user form variable variable if it is
non-empty. Otherwise returns default, which is the string "default" if
there is no default supplied. Got that? This tag is DEPRECATED anyway.

97.19.2.1. default
------------------

97.19.2.2. name
---------------

97.20. description
------------------

97.20.1. Summary
----------------

Parameters: code base

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->description(
        {
         code => VALUE,
         base => VALUE,
        }
    )

 OR

    $Tag->description($code, $base);
    [description code base]

Parameters    Description                               Default
............. ......................................... ............. 
base                                                    DEFAULT_VALUE
code                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [description code base]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->description(  { base => VALUE_base
                          code => VALUE_code
}, $body  );

or similarly with positional parameters,

    $Tag->description(code,base, $attribute_hash_reference, $body);

97.20.2. Description
--------------------

Expands into the description of the product identified by code as
found in the products database. This is the value of the database
field that corresponds to the catalog.cfg directive DescriptionField.
If there is more than one products file defined, they will be searched
in order unless constrained by the optional argument base.

This tag is especially useful for multi-language catalogs. The
DescriptionField directive can be set for each locale and point to a
different database field; for example desc_en for English, desc_fr for
French, etc.

97.20.2.1. base
---------------

97.20.2.2. code
---------------

97.21. discount
---------------

97.21.1. Summary
----------------

Parameters: code

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [discount] FOO [/discount]. Nesting: NO

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->discount(
        {
         code => VALUE,
        },
        BODY
    )

 OR

    $Tag->discount($code, $BODY);
    [discount code]

Parameters    Description                               Default
............. ......................................... ............. 
code                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [discount code]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->discount(  { code => VALUE_code
}, $body  );

or similarly with positional parameters,

    $Tag->discount(code, $attribute_hash_reference, $body);

97.21.2. Description
--------------------

Product discounts can be set upon display of any page. The discounts
apply only to the customer receiving them, and are of one of three
types:

    1. A discount for one particular item code (code/key is the item-code)
    2. A discount applying to all item codes (code/key is ALL_ITEMS)
    3. A discount applied after all items are totaled
       (code/key is ENTIRE_ORDER)

The discounts are specified via a formula. The formula is scanned for
the variables $q and $s, which are substituted for with the item
quantity and subtotal respectively. In the case of the item and all
items discount, the formula must evaluate to a new subtotal for all
items of that code that are ordered. The discount for the entire order
is applied to the entire order, and would normally be a monetary
amount to subtract or a flat percentage discount.

Discounts are applied to the effective price of the product, including
any quantity discounts.

To apply a straight 20% discount to all items:

    [discount ALL_ITEMS] $s * .8 [/discount]

or with named attributes:

    [discount code=ALL_ITEMS] $s * .8 [/discount]

To take 25% off of only item 00-342:

    [discount 00-342] $s * .75 [/discount]

To subtract $5.00 from the customer's order:

    [discount ENTIRE_ORDER] $s - 5 [/discount]

To reset a discount, set it to the empty string:

    [discount ALL_ITEMS][/discount]

Perl code can be used to apply the discounts. Here is an example of a
discount for item code 00-343 which prices the second one ordered at 1
cent:

    [discount 00-343]
    return $s if $q == 1;
    my $p = $s/$q;
    my $t = ($q - 1) * $p;
    $t .= 0.01;
    return $t;
    [/discount]

If you want to display the discount amount, use the [item-discount]
tag.

    [item-list]
    Discount for [item-code]: [item-discount]
    [/item-list]

Finally, if you want to display the discounted subtotal in a way that
doesn't correspond to a standard Interchange tag, you can use the
[calc] tag:

    [item-list]
    Discounted subtotal for [item-code]: [currency][calc]
                                            [item-price noformat] * [item-quantity]
                                            [/calc][/currency]
    [/item-list]

97.21.2.1. code
---------------

97.22. dump
-----------

Dumps client connection information, cart contents, query value,
contents of environment, session, and CGI with Data::Dumper to the
page. This is useful for debugging.

97.22.1. Summary
----------------

No parameters.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->dump(
        {
        }
    )

 OR

    $Tag->dump($);
    [dump]

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [dump]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->dump(  {
}, $body  );

or similarly with positional parameters,

    $Tag->dump(, $attribute_hash_reference, $body);

97.22.2. Description
--------------------

Dumps client connection information, cart contents, query value,
contents of environment, session, and CGI with Data::Dumper to the
page. This is useful for debugging.

97.23. ecml
-----------

Uses ECML (Electronic Commerce Markup Language) module to map
Interchange forms/userdb to ECML checkout

97.23.1. Summary
----------------

    [ecml name function other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
function      ecml function (default = 'widget')        DEFAULT_VALUE
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [ecml name function]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->ecml(  { function => VALUE_function
                   name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->ecml(name,function, $attribute_hash_reference, $body);

97.23.2. Description
--------------------

This package implements the ECML standard for the Interchange demo.
ECML stands for "Electronic Commerce Modeling Language", but at this
writing it is a simple standard for naming variables so that
"electronic wallets" can pre-fill-in your checkout form based on users
past purchase from other companies.

It translates into ECML from the following Interchange variables:

ECML                                      Interchange variable
......................................... ........................... 
Ecom_BillTo_Online_Email                  b_email
Ecom_BillTo_Postal_City                   b_city
Ecom_BillTo_Postal_CountryCode            b_country
Ecom_BillTo_Postal_Name_First             b_fname
Ecom_BillTo_Postal_Name_Last              b_lname
Ecom_BillTo_Postal_Name_Middle            b_mname
Ecom_BillTo_Postal_Name_Prefix            b_title
Ecom_BillTo_Postal_Name_Suffix            b_name_suffix
Ecom_BillTo_Postal_PostalCode             b_zip
Ecom_BillTo_Postal_StateProv              b_state
Ecom_BillTo_Postal_Street_Line1           b_address1
Ecom_BillTo_Postal_Street_Line2           b_address2
Ecom_BillTo_Postal_Street_Line3           b_address3
Ecom_BillTo_Telecom_Phone_Number          b_phone_day
Ecom_ConsumerOrderID                      mv_order_number
Ecom_Payment_Card_ExpDate_Day             mv_credit_card_exp_day
Ecom_Payment_Card_ExpDate_Month           mv_credit_card_exp_month
Ecom_Payment_Card_ExpDate_Year            mv_credit_card_exp_year
Ecom_Payment_Card_Name                    c_name
Ecom_Payment_Card_Number                  mv_credit_card_number
Ecom_Payment_Card_Protocol                payment_protocols_available
Ecom_Payment_Card_Type                    mv_credit_card_type
Ecom_Payment_Card_Verification            mv_credit_card_verify
Ecom_ReceiptTo_Online_Email               r_email
Ecom_ReceiptTo_Postal_City                r_city
Ecom_ReceiptTo_Postal_CountryCode         r_country
Ecom_ReceiptTo_Postal_Name_First          r_fname
Ecom_ReceiptTo_Postal_Name_Last           r_lname
Ecom_ReceiptTo_Postal_Name_Middle         r_mname
Ecom_ReceiptTo_Postal_Name_Prefix         r_title
Ecom_ReceiptTo_Postal_Name_Suffix         r_name_suffix
Ecom_ReceiptTo_Postal_PostalCode          r_zip
Ecom_ReceiptTo_Postal_StateProv           r_state
Ecom_ReceiptTo_Postal_Street_Line1        r_address1
Ecom_ReceiptTo_Postal_Street_Line2        r_address2
Ecom_ReceiptTo_Postal_Street_Line3        r_address3
Ecom_ReceiptTo_Telecom_Phone_Number       r_phone
Ecom_SchemaVersion                        ecml_version
Ecom_ShipTo_Online_Email                  email
Ecom_ShipTo_Postal_City                   city
Ecom_ShipTo_Postal_CountryCode            country
Ecom_ShipTo_Postal_Name_Combined          name
Ecom_ShipTo_Postal_Name_First             fname
Ecom_ShipTo_Postal_Name_Last              lname
Ecom_ShipTo_Postal_Name_Middle            mname
Ecom_ShipTo_Postal_Name_Prefix            title
Ecom_ShipTo_Postal_Name_Suffix            name_suffix
Ecom_ShipTo_Postal_PostalCode             zip
Ecom_ShipTo_Postal_StateProv              state
Ecom_ShipTo_Postal_Street_Line1           address1
Ecom_ShipTo_Postal_Street_Line2           address2
Ecom_ShipTo_Postal_Street_Line3           address3
Ecom_ShipTo_Telecom_Phone_Number          phone
Ecom_TransactionComplete                  end_transaction_flag

Once the form variables are input and sent to Interchange, the [ecml
function=mapback] tag will cause the input results to be mapped back
from the ECML names to the Interchange names.

If you only have a name variable in your UserDB, the module will
attempt to split it into first name and last name for ECML purposes
and map the results back. If you have fname and lname, then it will
not.

97.23.2.1. function
-------------------

ecml function (default = 'widget')

97.23.2.2. name
---------------

97.24. either
-------------

The [either]this[or]that[/either] implements a check for the first
non-zero, non-blank value. It splits on [or], and then parses each
piece in turn. If a value returns true (in the Perl sense: non-zero,
non-blank) then subsequent pieces will be discarded without
interpolation.

97.24.1. Summary
----------------

    [either]
        This
    [or]
        That
    [or]
        The other
    [/either]

No parameters.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [either] FOO [/either]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->either(
        {
        },
        BODY
    )

 OR

    $Tag->either($BODY);
    [either]

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [either]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->either(  {
}, $body  );

or similarly with positional parameters,

    $Tag->either(, $attribute_hash_reference, $body);

97.24.2. Description
--------------------

NO Description

97.25. error
------------

97.25.1. Summary
----------------

Parameters: name

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->error(
        {
         name => VALUE,
        }
    )

 OR

    $Tag->error($name, $ATTRHASH);
    [error name other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [error name]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->error(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->error(name, $attribute_hash_reference, $body);

97.25.2. Description
--------------------

    [error var options]
        var is the error name, e.g. "session"

The [error ...] tag is designed to manage form variable checking for
the Interchange submit form processing action. It works in conjunction
with the definition set in mv_order_profile, and can generate error
messages in any format you desire.

If the variable in question passes order profile checking, it will
output a label, by default bold text if the item is required, or
normal text if not (controlled by the <require> parameter. If the
variable fails one or more order checks, the error message will be
substituted into a template and the error cleared from the user's
session.

(Below is as of 4.03, the equivalent in 4.02 is [if type=explicit
compare="[error all=1 keep=1]"] ... [/if].)

To check errors without clearing them, you can use the idiom:

    [if errors]
    <FONT SIZE="+1" COLOR=RED>
        There were errors in your form submission.
    </FONT>
    <BLOCKQUOTE>
        [error all=1 show_error=1 joiner="<BR>"]
    </BLOCKQUOTE>
    [/if]

The options are:

97.25.2.1. all=1
----------------

Display all error messages, not just the one referred to by <var>. The
default is only display the error message assigned to <var>.

text=<optional string to embed the error message(s) in>

place a "%s" somewhere in 'text' to mark where you want the error
message placed, otherwise it's appended on the end. This option also
implies show_error.

97.25.2.2. joiner=char
----------------------

Character used to join multiple error messages. Default is '\n', a
newline.

97.25.2.3. keep=1
-----------------

keep=1 means don't delete the error messages after copy; anything else
deletes them.

97.25.2.4. show_error=1
-----------------------

show_error=1 means return the error message text; otherwise just the
number of errors found is returned.

97.25.2.5. show_label=1
-----------------------

show_label=1 causes the field label set by a previous [error] tag's
std_label attribute (see below) to be included as part of the error
message, like this:

First Name: blank

If no std_label was set, the variable name will be used instead. This
can also be used in combination with show_var to show both the label
and the variable name.

show_label was added in 4.7.0.

97.25.2.6. show_var=1
---------------------

show_var=1 includes the name of the variable the error was found in as
part of the error message, like this:

email: 'bob#nothing,net' not a valid email address

97.25.2.7. std_label
--------------------

std_label=<label string for error message>

used with 'required' to display a standardized error format. The HTML
formatting can be set via the global variable MV_ERROR_STD_LABEL with
the default being:

        <FONT COLOR=RED>{LABEL}<SMALL><I>(%s)</I></SMALL></FONT>

where {LABEL} is what you set std_label to and %s is substituted with
the error message. This option can not be used with the text= option.

97.25.2.8. required=1
---------------------

Specifies that this is a required field for formatting purposes. In
the std_label format, it means the field will be bolded. If you
specify your own label string, it will insert HTML anywhere you have
{REQUIRED: HTML}, but only when the field is required.

97.25.2.9. name
---------------

97.26. export
-------------

Exports a database to a delimited text file (see also import).

97.26.1. Summary
----------------

    [export table other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
base          Alias for table                           DEFAULT_VALUE
database      Alias for table                           DEFAULT_VALUE
delete        If 'verify' attribute also set, deletes   DEFAULT_VALUE
              column specified by 'field' attribute
              rather than adding a column.
field         The column to add (or delete if delete    DEFAULT_VALUE
              and verify are true)
file          Filename to export to. Note that the      DEFAULT_VALUE
              NoAbsolute directive and other conditions
              may affect actual location of the output
              file.
sort          Output sorted rows (usage:                DEFAULT_VALUE
              sort="sort_field:sort_option") (see
              search/form variable 'mv_sort_option' for
              sort options)
table         The table to export                       DEFAULT_VALUE
type          Specifies the [line, record] delimiter    DEFAULT_VALUE
              types. Either NOTES or one of the
              following: my %Delimiter = ( 2 => ["\n",
              "\n\n"], 3 => ["\n%%\n", "\n%%%\n"], 4 =>
              ["CSV","\n"], 5 => ['|', "\n"], 6 =>
              ["\t", "\n"], 7 => ["\t", "\n"], 8 =>
              ["\t", "\n"], LINE => ["\n", "\n\n"],
              '%%%' => ["\n%%\n", "\n%%%\n"], '%%' =>
              ["\n%%\n", "\n%%%\n"], CSV =>
              ["CSV","\n"], PIPE => ['|', "\n"], TAB =>
              ["\t", "\n"], );If using
              NOTESnotes_separator (defaults to
              "\f")notes_field (defaults to
              "notes_field")
verify        must be true when deleting a column       DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [export table]
---
    1

ASP-like Perl call:

   $Tag->export(  { table => VALUE_table
}, $body  );

or similarly with positional parameters,

    $Tag->export(table, $attribute_hash_reference, $body);

97.26.2. Description
--------------------

Exports 'table' to a delimited text file. See also import tag which
imports files into databases.

97.26.2.1. delete
-----------------

If 'verify' attribute also set, deletes column specified by 'field'
attribute rather than adding a column.

97.26.2.2. field
----------------

The column to add (or delete if delete and verify are true)

97.26.2.3. file
---------------

Filename to export to. Note that the NoAbsolute directive and other
conditions may affect actual location of the output file.

97.26.2.4. sort
---------------

Output sorted rows (usage: sort="sort_field:sort_option") (see
search/form variable 'mv_sort_option' for sort options)

97.26.2.5. table
----------------

The table to export

97.26.2.6. type
---------------

Specifies the [line, record] delimiter types. Either NOTES or one of
the following:

  my %Delimiter = (
        2 => ["\n", "\n\n"],
        3 => ["\n%%\n", "\n%%%\n"],
        4 => ["CSV","\n"],
        5 => ['|', "\n"],
        6 => ["\t", "\n"],
        7 => ["\t", "\n"],
        8 => ["\t", "\n"],
        LINE => ["\n", "\n\n"],
        '%%%' => ["\n%%\n", "\n%%%\n"],
        '%%' => ["\n%%\n", "\n%%%\n"],
        CSV => ["CSV","\n"],
        PIPE => ['|', "\n"],
        TAB => ["\t", "\n"],
        );

o    If using NOTES

     o    notes_separator (defaults to "\f")

     o    notes_field (defaults to "notes_field")

97.26.2.7. verify
-----------------

must be true when deleting a column

97.27. field
------------

97.27.1. Summary
----------------

Parameters: name code

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->field(
        {
         name => VALUE,
         code => VALUE,
        }
    )

 OR

    $Tag->field($name, $code);

Attribute aliases

            col ==> name
            column ==> name
            field ==> name
            key ==> code
            row ==> code
    [field name code]

Parameters    Description                               Default
............. ......................................... ............. 
code                                                    DEFAULT_VALUE
col           Alias for name                            DEFAULT_VALUE
column        Alias for name                            DEFAULT_VALUE
field         Alias for name                            DEFAULT_VALUE
key           Alias for code                            DEFAULT_VALUE
name                                                    DEFAULT_VALUE
row           Alias for code                            DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [field name code]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->field(  { code => VALUE_code
                    name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->field(name,code, $attribute_hash_reference, $body);

97.27.2. Description
--------------------

Expands into the value of the field name for the product identified by
code as found by searching the products database. It will return the
first entry found in the series of Product Files. the products
database. If you want to constrain it to a particular database, use
the [data base name code] tag.

Note that if you only have one ProductFile products, which is the
default, [field column key] is the same as [data products column key].

97.27.2.1. code
---------------

97.27.2.2. name
---------------

97.28. file
-----------

97.28.1. Summary
----------------

Parameters: name type

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->file(
        {
         name => VALUE,
         type => VALUE,
        }
    )

 OR

    $Tag->file($name, $type);
    [file name type]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE
type                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [file name type]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->file(  { name => VALUE_name
                   type => VALUE_type
}, $body  );

or similarly with positional parameters,

    $Tag->file(name,type, $attribute_hash_reference, $body);

97.28.2. Description
--------------------

Inserts the contents of the named file. The file should normally be
relative to the catalog directory - file names beginning with / or ..
are not allowed if the Interchange server administrator has set
NoAbsolute to Yes.

The optional type parameter will do an appropriate ASCII translation
on the file before it is sent.

97.28.2.1. name
---------------

97.28.2.2. type
---------------

97.29. filter
-------------

97.29.1. Summary
----------------

Parameters: op

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [filter] FOO [/filter]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->filter(
        {
         op => VALUE,
        },
        BODY
    )

 OR

    $Tag->filter($op, $BODY);
    [filter op]

Parameters    Description                               Default
............. ......................................... ............. 
op                                                      DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [filter op]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->filter(  { op => VALUE_op
}, $body  );

or similarly with positional parameters,

    $Tag->filter(op, $attribute_hash_reference, $body);

97.29.2. Description
--------------------

Applies any of Interchange's standard filters to an arbitrary value,
or you may define your own. The filters are also available as
parameters to the cgi, data, and value tags.

Filters can be applied in sequence and as many as needed can be
applied.

Here is an example. If you store your author or artist names in the
database "LAST, First" so that they sort properly, you still might
want to display them normally as "First Last". This call

    [filter op="name namecase"]WOOD, Grant[/filter]

will display as

    Grant Wood

Another way to do this would be:

    [data table=products column=artist key=99-102 filter="name namecase"]

Filters available include:

97.29.2.1. Length filter
------------------------

If you pass just a numeric argument, filter will return only first N
characters.  For example:

[filter 5]Interchange[/filter]

results in:

"Inter"

By appending a ".", you can direct Interchange to append an ellipsis:

[filter 5.]Interchange[/filter]

results in:

"Inter..."

                if (/^(\d+)(\.?)$/) {
                        substr($value, $1) = $2 ? '...' : ''
                                if length($value) > $1;
                        next;
                }

97.29.2.2. cgi
--------------

Returns the value of the CGI variable. Useful for starting a filter
sequence with a seed value.

    'cgi' =>    sub {
                    return $CGI::values(shift);
                },

97.29.2.3. digits
-----------------

Returns only digits.

    'digits' => sub {
                    my $val = shift;
                    $val =~ s/\D+//g;
                    return $val;
                },

97.29.2.4. digits_dot
---------------------

Returns only digits and periods, i.e. [.0-9]. Useful for decommifying
numbers.

    'digits_dot' => sub {
                    my $val = shift;
                    $val =~ s/[^\d.]+//g;
                    return $val;
                },

97.29.2.5. dos
--------------

Turns linefeeds into carriage-return / linefeed pairs.

    'dos' =>    sub {
                    my $val = shift;
                    $val =~ s/\r?\n/\r\n/g;
                    return $val;
                },

97.29.2.6. entities
-------------------

Changes < to &lt;, " to &quot;, etc.

    'entities' => sub {
                    return HTML::Entities::encode(shift);
                },

97.29.2.7. gate
---------------

Performs a security screening by testing to make sure a corresponding
scratch variable has been set.

    'gate' =>   sub {
                    my ($val, $var) = @_;
                    return '' unless $::Scratch->{$var};
                    return $val;
                },

97.29.2.8. lc
-------------

Lowercases the text.

    'lc' =>     sub {
                    return lc(shift);
                },

97.29.2.9. lookup
-----------------

Looks up an item in a database based on the passed table and column.
Call would be:

    [filter op="uc lookup.country.name"]us[/filter]

This would be the equivalent of [data table=country column=name
key=US].

    'lookup' => sub {
                        my ($val, $tag, $table, $column) = @_;
                        return tag_data($table, $column, $val) || $val;
                },

97.29.2.10. mac
---------------

Changes newlines to carriage returns.

    'mac' =>    sub {
                    my $val = shift;
                    $val =~ s/\r?\n|\r\n?/\r/g;
                    return $val;
                },

97.29.2.11. name
----------------

Transposes a LAST, First name pair.

    'name' => sub {
                    my $val = shift;
                    return $val unless $val =~ /,/;
                    my($last, $first) = split /\s*,\s*/, $val, 2;
                    return "$first $last";
                },

97.29.2.12. namecase
--------------------

Namecases the text. Only works on values that are uppercase in the
first letter, i.e. [filter op=namecase]LEONARDO da Vinci[/filter] will
return "Leonardo da Vinci".

    'namecase' => sub {
                    my $val = shift;
                    $val =~ s/([A-Z]\w+)/\L\u$1/g;
                    return $val;
                },

97.29.2.13. no_white
--------------------

Strips all whitespace.

    'no_white' =>   sub {
                    my $val = shift;
                    $val =~ s/\s+//g;
                    return $val;
                },

97.29.2.14. pagefile
--------------------

Strips leading slashes and dots.

    'pagefile' => sub {
                    $_[0] =~ s:^[./]+::;
                    return $_[0];
                },

97.29.2.15. sql
---------------

Change single-quote characters into doubled versions, i.e. ' becomes
''.

    'sql'       => sub {
                    my $val = shift;
                    $val =~ s:':'':g; # '
                    return $val;
                },

97.29.2.16. strip
-----------------

Strips leading and trailing whitespace.

    'strip' =>  sub {
                    my $val = shift;
                    $val =~ s/^\s+//;
                    $val =~ s/\s+$//;
                    return $val;
                },

97.29.2.17. text2html
---------------------

Rudimentary HTMLizing of text.

    'text2html' => sub {
                    my $val = shift;
                    $val =~ s|\r?\n\r?\n|<P>|;
                    $val =~ s|\r?\n|<BR>|;
                    return $val;
                },

97.29.2.18. uc
--------------

Uppercases the text.

    'uc' =>     sub {
                    return uc(shift);
                },

97.29.2.19. unix
----------------

Removes those crufty carriage returns.

    'unix' =>   sub {
                    my $val = shift;
                    $val =~ s/\r?\n/\n/g;
                    return $val;
                },

97.29.2.20. urlencode
---------------------

Changes non-word characters (except colon) to %3c notation.

    'urlencode' => sub {
                    my $val = shift;
                    $val =~ s|[^\w:]|sprintf "%%%02x", ord $1|eg;
                    return $val;
                },

97.29.2.21. value
-----------------

Returns the value of the user session variable. Useful for starting a
filter sequence with a seed value.

    'value' =>  sub {
                    return $::Values->(shift);
                },

97.29.2.22. word
----------------

Only returns word characters. Locale does apply if collation is
properly set.

    'word' =>   sub {
                    my $val = shift;
                    $val =~ s/\W+//g;
                    return $val;
                },

You can define your own filters in a GlobalSub (or Sub or ActionMap):

    package Vend::Interpolate;

    $Filter{reverse} = sub { $val = shift; return scalar reverse $val  };

That filter will reverse the characters sent.

The arguments sent to the subroutine are the value to be filtered, any
associated variable or tag name, and any arguments appended to the
filter name with periods as the separator.

A [filter op=lookup.products.price]99-102[/filter] will send
('99-102', undef, 'products', 'price') as the parameters. Assuming the
value of the user variable foo is bar, the call [value name=foo
filter="lookup.products.price.extra"] will send ('bar', 'foo',
'products', 'price', 'extra').

97.29.2.23. op
--------------

97.30. flag
-----------

Controls Interchange flags. For example, flags affect database access
and transactions for those databases able to support these features.
See also the [tag] tag.

97.30.1. Summary
----------------

    [flag type]

Parameters    Description                               Default
............. ......................................... ............. 
build         Forces build of static Interchange page   DEFAULT_VALUE
              specified by the name attribute
checkhtml                                               DEFAULT_VALUE
commit        Attempts to commit transactions           DEFAULT_VALUE
flag          Alias for type                            DEFAULT_VALUE
name          Alias for type                            DEFAULT_VALUE
read          Flags the table read-only                 DEFAULT_VALUE
rollback      Attempts to rollback transactions         DEFAULT_VALUE
show          Normally, the [flag] tag returns nothing  DEFAULT_VALUE
              to the page. Setting 'show=1' causes the
              tag to return status, if any.
table         Alias for tables                          DEFAULT_VALUE
tables        The name of the table to flag'table' is   DEFAULT_VALUE
              an alias
transactions  Reopens the database in transactions mode DEFAULT_VALUE
              if Safe.pm is not active (e.g., in a
              global subroutine, usertag or [perl
              global=1] tag). The limitation exists
              because it is not possible to reopen a
              database within Safe.pm.
type                                                    DEFAULT_VALUE
value         The boolean value of the flag             DEFAULT_VALUE
write         Flags the table writable by default (or   DEFAULT_VALUE
              read-only if you also set the value=0
              attribute)

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [flag type]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->flag(  { type => VALUE_type
}, $body  );

or similarly with positional parameters,

    $Tag->flag(type, $attribute_hash_reference, $body);

97.30.2. Description
--------------------

The flag tag controls database access and transactions.

If a DBM-based database is to be modified, it must be flagged writable
on the page calling the write tag.

For example, you can call

    [flag type=write value=1 table=products]

to mark the products DBM database writable. This must be done before
ANY access to that table.

Note that SQL databases are always writable if allowed by the SQL
database itself, and in-memory databases will never be written.

Using [flag build] forces static build of a page, even if it contains
dynamic elements.

97.30.2.1. build
----------------

Forces build of static Interchange page specified by the name
attribute

97.30.2.2. checkhtml
--------------------

97.30.2.3. commit
-----------------

Attempts to commit transactions

97.30.2.4. read
---------------

Flags the table read-only

97.30.2.5. rollback
-------------------

Attempts to rollback transactions

97.30.2.6. show
---------------

Normally, the [flag] tag returns nothing to the page. Setting 'show=1'
causes the tag to return status, if any.

97.30.2.7. tables
-----------------

The name of the table to flag

o    'table' is an alias

97.30.2.8. transactions
-----------------------

Reopens the database in transactions mode if Safe.pm is not active
(e.g., in a global subroutine, usertag or [perl global=1] tag). The
limitation exists because it is not possible to reopen a database
within Safe.pm.

97.30.2.9. type
---------------

97.30.2.10. value
-----------------

The boolean value of the flag

97.30.2.11. write
-----------------

Flags the table writable by default (or read-only if you also set the
value=0 attribute)

97.31. fly-list
---------------

97.31.1. Summary
----------------

Parameters: code base

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [fly-list] FOO [/fly-list]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->fly_list(
        {
         code => VALUE,
         base => VALUE,
        },
        BODY
    )

 OR

    $Tag->fly_list($code, $base, $BODY);
    [fly-list code base]

Parameters    Description                               Default
............. ......................................... ............. 
base                                                    DEFAULT_VALUE
code                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [fly-list code base]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->fly_list(  { base => VALUE_base
                       code => VALUE_code
}, $body  );

or similarly with positional parameters,

    $Tag->fly_list(code,base, $attribute_hash_reference, $body);

97.31.2. Description
--------------------

Syntax: [fly-list prefix=tag_prefix* code=code*]

Defines an area in a random page which performs the flypage lookup
function, implementing the tags below.

   [fly-list]
    (contents of flypage.html)
   [/fly-list]

If you place the above around the contents of the demo flypage, in a
file named flypage2.html, it will make these two calls display
identical pages:

    [page 00-0011] One way to display the Mona Lisa </a>
    [page flypage2 00-0011] Another way to display the Mona Lisa </a>

If you place a [fly-list] tag alone at the top of the page, it will
cause any page to act as a flypage.

By default, the prefix is item, meaning the [item-code] tag will
display the code of the item, the [item-price] tag will display price,
etc. But if you use the prefix, i.e. [fly-list prefix=fly], then it
will be [fly-code]; prefix=foo would cause [foo-code], etc.

97.31.2.1. base
---------------

97.31.2.2. code
---------------

97.32. fly-tax
--------------

97.32.1. Summary
----------------

Parameters: area

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->fly_tax(
        {
         area => VALUE,
        }
    )

 OR

    $Tag->fly_tax($area);
    [fly-tax area]

Parameters    Description                               Default
............. ......................................... ............. 
area                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [fly-tax area]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->fly_tax(  { area => VALUE_area
}, $body  );

or similarly with positional parameters,

    $Tag->fly_tax(area, $attribute_hash_reference, $body);

97.32.2. Description
--------------------

Builds a tax rate from TAXAREA, TAXRATE, and TAXSHIPPING Variable
values, and the SalesTax directive value.

97.32.2.1. area
---------------

97.33. goto
-----------

Skips page content between [goto name] and [label name]. Note that the
goto tag is not interpreted in the standard way, and you cannot use
the '$Tag->goto()' Perl syntax. Note also that skipping endtags with
goto will probably break your page.

97.33.1. Summary
----------------

    [goto name=label_name if=condition]
        content to skip
    [label name=label_name]

or positionally,

    [goto name if]
        content to skip
    [label name]

Parameters    Description                               Default
............. ......................................... ............. 
name          The name set in the corresponding [label] none
              tag
if            Condition for goto. Should evaluate to    true
              truth value before tag is parsed.

Other_Characteristics
.................................. .................................. 
Container tag                      No, but you use it like this:[goto
                                   name=label_name if=condition]body
                                   text[label label_name]
Has Subtags                        [label] interpreted by goto

ASP-like Perl call:

No Perl call available (Note that this tag is not parsed in the
standard way).

97.33.2. Description
--------------------

Skips page content between [goto name] and [label name]. Note that the
goto tag is not interpreted in the standard way, and you cannot use
the '$Tag->goto()' Perl syntax. Note also that skipping endtags with
goto will probably break your page.

The correspondingly named [label] tag marks the end of the page
content the goto should skip. Note that the [label] tag is not an end
tag, but simply a marker for the end of the text to skip.

Technical note (Interchange 4.8): This tag may not work properly if
you have more than one goto/label pair on a page.



97.33.2.1. name
---------------

This should match the name set in a [label] tag after the goto tag in
the page (i.e., don't create loops).

97.33.2.2. if
-------------

Condition for goto. If the argument to 'if' is true, the tag will skip
the text between the goto and <label>.  Note that the tag itself does
not evaluate the condition. The condition must evaluate to a true or
false value before the goto tag processes it.

For example, this will not execute the goto:

    [set go]0[/set]
    [goto name="there" if="[scratch go]"]

97.34. handling
---------------

97.34.1. Summary
----------------

Parameters: mode

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->handling(
        {
         mode => VALUE,
        }
    )

 OR

    $Tag->handling($mode, $ATTRHASH);

Attribute aliases

            carts ==> cart
            modes ==> mode
            name ==> mode
            tables ==> table
    [handling mode other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
carts         Alias for cart                            DEFAULT_VALUE
mode                                                    DEFAULT_VALUE
modes         Alias for mode                            DEFAULT_VALUE
name          Alias for mode                            DEFAULT_VALUE
tables        Alias for table                           DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [handling mode]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->handling(  { mode => VALUE_mode
}, $body  );

or similarly with positional parameters,

    $Tag->handling(mode, $attribute_hash_reference, $body);

97.34.2. Description
--------------------

Calculates and inserts handling costs. Accepts the same noformat and
convert arguments as the shipping tag.

97.34.2.1. cart
---------------

97.34.2.2. mode
---------------

97.34.2.3. table
----------------

97.35. harness
--------------

Test harness block. Similar to try/catch. Interprets the body text and
checks the return value against expected and explicitly bad cases.

Returns DIED, OK, or NOT OK message along with your result if not the
expected value.

97.35.1. Summary
----------------

    [harness other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
expected      Tagname for delimiting your expected      DEFAULT_VALUE
              return value (default "OK")
name          This will appear in your output message   DEFAULT_VALUE
              (useful for distinguishing harness tags
              from one another) (default "testnnn")

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [harness]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->harness(  {
}, $body  );

or similarly with positional parameters,

    $Tag->harness(, $attribute_hash_reference, $body);

97.35.2. Description
--------------------

Test harness block. Similar to try/catch. Interprets the body text and
checks the return value against expected and explicitly bad cases.

Returns DIED, OK, or NOT OK message along with the harness name and
your result if not the expected value.

97.35.2.1. expected
-------------------

Tagname for delimiting your expected return value (default "OK")

97.35.2.2. name
---------------

This will appear in your output message (useful for distinguishing
harness tags from one another) (default "testnnn")

97.36. href
-----------

Alias for [area] tag.

97.37. html-table
-----------------

Builds an HTML table

97.37.1. Summary
----------------

    [html-table other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
columns       Whitespace-delimited list of columns      DEFAULT_VALUE
delimiter     Line delimiter to use if tag body is      DEFAULT_VALUE
              delimited text rather than an array
              reference (default "\t")
fc            HTML attributes for <TD> in the first     DEFAULT_VALUE
              cell
fr            HTML attributes for <TR> in the first row DEFAULT_VALUE
record_delim  Record delimiter to use if tag body is    DEFAULT_VALUE
              delimited text rather than an array
              reference (default "\n")
td            HTML attributes for <TD>                  DEFAULT_VALUE
th            HTML attributes for <TH>                  DEFAULT_VALUE
tr            HTML attributes for <TR>                  DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [html-table]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->html_table(  {
}, $body  );

or similarly with positional parameters,

    $Tag->html_table(, $attribute_hash_reference, $body);

97.37.2. Description
--------------------

Builds an HTML table

97.37.2.1. columns
------------------

Whitespace-delimited list of columns

97.37.2.2. delimiter
--------------------

Line delimiter to use if tag body is delimited text rather than an
array reference (default "\t")

97.37.2.3. fc
-------------

HTML attributes for <TD> in the first cell

97.37.2.4. fr
-------------

HTML attributes for <TR> in the first row

97.37.2.5. record_delim
-----------------------

Record delimiter to use if tag body is delimited text rather than an
array reference (default "\n")

97.37.2.6. td
-------------

HTML attributes for <TD>

97.37.2.7. th
-------------

HTML attributes for <TH>

97.37.2.8. tr
-------------

HTML attributes for <TR>

97.38. if
---------

97.38.1. Summary
----------------

Parameters: type term op compare

THIS TAG HAS SPECIAL POSITIONAL PARAMETER HANDLING.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [if] FOO [/if]. Nesting: NO

Invalidates cache: YES

Called Routine:

Called Routine for positional:

ASP-like Perl call:

Not applicable. Any [if ...] call can be better and more efficiently
done with Perl.

Attribute aliases

            base ==> type
            comp ==> compare
            condition ==> compare
            operator ==> op

Parameters    Description                               Default
............. ......................................... ............. 
base          Alias for type                            DEFAULT_VALUE
comp          Alias for compare                         DEFAULT_VALUE
compare                                                 DEFAULT_VALUE
condition     Alias for compare                         DEFAULT_VALUE
op                                                      DEFAULT_VALUE
operator      Alias for op                              DEFAULT_VALUE
term                                                    DEFAULT_VALUE
type                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [if type term op compare]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->if(  { compare => VALUE_compare
                 op => VALUE_op
                 term => VALUE_term
                 type => VALUE_type
}, $body  );

or similarly with positional parameters,

    $Tag->if(type,term,op,compare, $attribute_hash_reference, $body);

97.38.2. Description
--------------------

Named call example: [if type="type" term="field" op="op"
compare="compare"]

Positional call example: [if type field op compare]

negated: [if type="!type" term="field" op="op" compare="compare"]

Positional call example: [if !type field op compare]

Allows conditional building of HTML based on the setting of various
Interchange session and database values. The general form is:

    [if type term op compare]
    [then]
                                If true, this is printed on the document.
                                The [then] [/then] is optional in most
                                cases. If ! is prepended to the type
                                setting, the sense is reversed and
                                this will be output for a false condition.
    [/then]
    [elsif type term op compare]
                                Optional, tested when if fails
    [/elsif]
    [else]
                                Optional, printed when all above fail
    [/else]
    [/if]

The [if] tag can also have some variants:

    [if type=explicit compare=`$perl_code`]
        Displayed if valid Perl CODE returns a true value.
    [/if]

You can do some Perl-style regular expressions:

    [if value name =~ /^mike/]
                                This is the if with Mike.
    [elsif value name =~ /^sally/]
                                This is an elsif with Sally.
    [/elsif]
    [elsif value name =~ /^pat/]
                                This is an elsif with Pat.
    [/elsif]
    [else]
                                This is the else, no name I know.
    [/else]
    [/if]

While named parameter tag syntax works for [if ...], it is more
convenient to use positional calls in most cases. The only exception
is if you are planning on doing a test on the results of another tag
sequence:

    [if value name =~ /[value b_name]/]
        Shipping name matches billing name.
    [/if]

Oops!  This will not work. You must do instead

    [if base=value term=name op="=~" compare="/[value b_name]/"]
        Shipping name matches billing name.
    [/if]

or better yet

    [if type=explicit compare=`
                        $Values->{name} =~ /$Values->{b_name}/
                        `]
        Shipping name matches billing name.
    [/if]

Interchange also supports a limited [and ...] and [or ...] capability:

    [if value name =~ /Mike/]
    [or value name =~ /Jean/]
    Your name is Mike or Jean.
    [/if]

    [if value name =~ /Mike/]
    [and value state =~ /OH/]
    Your name is Mike and you live in Ohio.
    [/if]

If you wish to do very complex AND and OR operations, you will have to
use [if explicit] or better yet embedded Perl/ASP. This allows complex
testing and parsing of values.

There are many test targets available:

97.38.2.1. config Directive
---------------------------

The Interchange configuration variables. These are set by the
directives in your Interchange configuration file (or the defaults).

    [if config CreditCardAuto]
    Auto credit card validation is enabled.
    [/if]

97.38.2.2. data database::field::key
------------------------------------

The Interchange databases. Retrieves a field in the database and
returns true or false based on the value.

    [if data products::size::99-102]
    There is size information.
    [else]
    No size information.
    [/else]
    [/if]

    [if data products::size::99-102 =~ /small/i]
    There is a small size available.
    [else]
    No small size available.
    [/else]
    [/if]

97.38.2.3. discount
-------------------

Checks to see if a discount is present for an item.

    [if discount 99-102]
    Item is discounted.
    [/if]

97.38.2.4. explicit
-------------------

A test for an explicit value. If Perl code is placed between a
[condition] [/condition] tag pair, it will be used to make the
comparison. Arguments can be passed to import data from user space,
just as with the [perl] tag.

    [if explicit]
    [condition]
        $country = '[value country]';
        return 1 if $country =~ /u\.?s\.?a?/i;
        return 0;
    [/condition]
    You have indicated a US address.
    [else]
    You have indicated a non-US address.
    [/else]
    [/if]

This example is a bit contrived, as the same thing could be
accomplished with [if value country =~ /u\.?s\.?a?/i], but you will
run into many situations where it is useful.

This will work for Variable values:

    [if type=explicit compare="__MYVAR__"] .. [/if]

However, note that the 'compare' option is equivalent to the
[condition] block in that both evaluate as Perl code. That means you
need to watch out when you put in user-supplied values (so that users
can't inject Perl code on your server) and data from your own
variables or tables which may look different than you expected.

For example, say you're in a loop checking whether at least one of the
fields 'foo' and 'bar' has a value ("true" according to Perl):

    [if type=explicit compare="[loop-param foo][loop-param bar]"]

Most of the time this works fine. But if 'foo' contains a string
beginning with '0', such as '0009', Perl will try to interpret it as
an octal number, where the digit '9' is invalid, resulting in this
unexpected error in the catalog error log:

    Bad if 'explicit   0009': Illegal octal digit '9' at (eval 155) line 1, at end of line

A safer way to check is:

    [if type=explicit compare="q{[loop-param foo][loop-param bar]}"]

Although then your data should not contain a '}'. To be extra safe you
can surround your interpolated data with a [filter X] ... [/filter]
tag pair appropriate for the quoting method you've used.

97.38.2.5. file
---------------

Tests for existence of a file. Useful for placing image tags only if
the image is present.

    [if type=file term="/home/user/www/images/[item-code].gif"]
    <IMG SRC="[item-code].gif">
    [/if]

The file test requires that the SafeUntrap directive contains ftfile
(which is the default).

97.38.2.6. items
----------------

The Interchange shopping carts. If not specified, the cart used is the
main cart. Usually used as a litmus test to see if anything is in the
cart, for example:

  [if items]You have items in your shopping cart.[/if]

  [if items layaway]You have items on layaway.[/if]

97.38.2.7. ordered
------------------

Order status of individual items in the Interchange shopping carts. If
not specified, the cart used is the main cart. The following items
refer to a part number of 99-102.

  [if ordered 99-102] Item 99-102 is in your cart. [/if]
    Checks the status of an item on order, true if item
    99-102 is in the main cart.

  [if ordered 99-102 layaway] ... [/if]
    Checks the status of an item on order, true if item
    99-102 is in the layaway cart.

  [if ordered 99-102 main size] ... [/if]
    Checks the status of an item on order in the main cart,
    true if it has a size attribute.

  [if ordered 99-102 main size =~ /large/i] ... [/if]
    Checks the status of an item on order in the main cart,
    true if it has a size attribute containing 'large'.

    To make sure it is exactly large, you could use:

  [if ordered 99-102 main size eq 'large'] ... [/if]

97.38.2.8. pragma
-----------------

The Interchange Pragma settings, set with the the catalog.cfg manpage
directive Pragma or with [pragma name].

    [if pragma dynamic_variables]
    __THE_VARIABLE__
    [else]
    [data table=variable column=Variable key=THE_VARIABLE]
    [/else]
    [/if]

97.38.2.9. scratch
------------------

The Interchange scratchpad variables, which can be set with the [set
name]value[/set] element.

    [if scratch mv_separate_items]
    ordered items will be placed on a separate line.
    [else]
    ordered items will be placed on the same line.
    [/else]
    [/if]

97.38.2.10. session
-------------------

the Interchange session variables. of particular interest are login,
frames, secure, and browser.

97.38.2.11. validcc
-------------------

a special case, takes the form [if validcc no type exp_date].
evaluates to true if the supplied credit card number, type of card,
and expiration date pass a validity test. does a Luhn-10 calculation
to weed out typos or phony card numbers. Uses the standard
CreditCardAuto variables for targets if nothing else is passed.

97.38.2.12. value
-----------------

the Interchange user variables, typically set in search, control, or
order forms. Variables beginning with mv_ are Interchange special
values, and should be tested/used with caution.

The field term is the specifier for that area. For example, [if
session logged_in] would return true if the logged_in session
parameter was set.

As an example, consider buttonbars for frame-based setups. It would be
nice to display a different buttonbar (with no frame targets) for
sessions that are not using frames:

    [if scratch frames]
        __BUTTONBAR_FRAMES__
    [else]
        __BUTTONBAR__
    [/else]
    [/if]

Another example might be the when search matches are displayed. If you
use the string '[value mv_match_count] titles found', it will display
a plural for only one match. Use:

    [if value mv_match_count != 1]
        [value mv_match_count] matches found.
    [else]
        Only one match was found.
    [/else]
    [/if]

The op term is the compare operation to be used. Compare operations
are as in Perl:

    ==  numeric equivalence
    eq  string equivalence
    >   numeric greater-than
    gt  string greater-than
    <   numeric less-than
    lt  string less-than
    !=  numeric non-equivalence
    ne  string non-equivalence

Any simple perl test can be used, including some limited regex
matching. More complex tests are best done with [if explicit].

97.38.2.13. [then] text [/then]
-------------------------------

This is optional if you are not nesting if conditions, as the text
immediately following the [if ..] tag is used as the conditionally
substituted text. If nesting [if ...] tags you should use a
[then][/then] on any outside conditions to ensure proper
interpolation.

97.38.2.14. [elsif type field op* compare*]
-------------------------------------------

named attributes: [elsif type="type" term="field" op="op"
compare="compare"]

Additional conditions for test, applied if the initial [if ..] test
fails.

97.38.2.15. [else] text [/else]
-------------------------------

The optional else-text for an if or [if-field] conditional.

97.38.2.16. [condition] text [/condition]
-----------------------------------------

Only used with the [if explicit] tag. Allows an arbitrary expression
in Perl to be placed inside, with its return value interpreted as the
result of the test. If arguments are added to [if explicit args],
those will be passed as arguments are in the [perl] construct.

97.38.2.17. compare
-------------------

97.38.2.18. op
--------------

97.38.2.19. term
----------------

97.38.2.20. type
----------------

97.39. import
-------------

97.39.1. Summary
----------------

Parameters: table type

Positional parameters in same order.

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Interpolates container text by default.

This is a container tag, i.e. [import] FOO [/import]. Nesting: NO

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->import(
        {
         table => VALUE,
         type => VALUE,
        },
        BODY
    )

 OR

    $Tag->import($table, $type, $ATTRHASH, $BODY);

Attribute aliases

            base ==> table
            database ==> table
    [import table type other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
base          Alias for table                           DEFAULT_VALUE
database      Alias for table                           DEFAULT_VALUE
table                                                   DEFAULT_VALUE
type                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [import table type]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->import(  { table => VALUE_table
                     type => VALUE_type
}, $body  );

or similarly with positional parameters,

    $Tag->import(table,type, $attribute_hash_reference, $body);

97.39.2. Description
--------------------

Named attributes:

    [import table=table_name
            type=(TAB|PIPE|CSV|%%|LINE)
            continue=(NOTES|UNIX|DITTO)
            separator=c]

Import one or more records into a database. The type is any of the
valid Interchange delimiter types, with the default being defined by
the setting of the database DELIMITER. The table must already be a
defined Interchange database table; it cannot be created on the fly.
(If you need that, it is time to use SQL.)

The type of LINE and continue setting of NOTES is particularly useful,
for it allows you to name your fields and not have to remember the
order in which they appear in the database. The following two imports
are identical in effect:

    [import table=orders]
    code: [value mv_order_number]
    shipping_mode: [shipping-description]
    status: pending
    [/import]

    [import table=orders]
    shipping_mode: [shipping-description]
    status: pending
    code: [value mv_order_number]
    [/import]

The code or key must always be present, and is always named code.

If you do not use NOTES mode, you must import the fields in the same
order as they appear in the ASCII source file.

The [import ....] TEXT [/import] region may contain multiple records.
If using NOTES mode, you must use a separator, which by default is a
form-feed character (^L).

97.39.2.1. table
----------------

97.39.2.2. type
---------------

97.40. include
--------------

97.40.1. Summary
----------------

Parameters: file locale

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

Not applicable.

    [include file locale]

Parameters    Description                               Default
............. ......................................... ............. 
file                                                    DEFAULT_VALUE
locale                                                  DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [include file locale]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->include(  { file => VALUE_file
                      locale => VALUE_locale
}, $body  );

or similarly with positional parameters,

    $Tag->include(file,locale, $attribute_hash_reference, $body);

97.40.2. Description
--------------------

Same as [file name] except interpolates for all Interchange tags and
variables. Does NOT do locale translations.

97.40.2.1. file
---------------

97.40.2.2. locale
-----------------

97.41. index
------------

Creates an index for the specified table.

97.41.1. Summary
----------------

    [index table other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
base          Alias for table                           DEFAULT_VALUE
basefile      Database filename. Exports the table to   DEFAULT_VALUE
              this filename if old or missing before
              indexing. See also the export tag for
              additional relevant attributes such as
              delimiter type, etc.
col           alias for fields                          DEFAULT_VALUE
columns       alias for fields                          DEFAULT_VALUE
database      Alias for table                           DEFAULT_VALUE
export_only   Just do the export if necessary (not the  DEFAULT_VALUE
              index).
extension     Index file extension (default "idx")      DEFAULT_VALUE
fields        field(s) to index                         DEFAULT_VALUE
fn            alias for fields                          DEFAULT_VALUE
show_status   Return '1' to the page if successful      DEFAULT_VALUE
spec          The index specification                   DEFAULT_VALUE
table                                                   DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [index table]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->index(  { table => VALUE_table
}, $body  );

or similarly with positional parameters,

    $Tag->index(table, $attribute_hash_reference, $body);

97.41.2. Description
--------------------

Creates an index for the specified table.

97.41.2.1. basefile
-------------------

Database filename. Exports the table to this filename if old or
missing before indexing. See also the export tag for additional
relevant attributes such as delimiter type, etc.

97.41.2.2. col
--------------

alias for fields

97.41.2.3. columns
------------------

alias for fields

97.41.2.4. export_only
----------------------

Just do the export if necessary (not the index).

97.41.2.5. extension
--------------------

Index file extension (default "idx")

97.41.2.6. fields
-----------------

field(s) to index

97.41.2.7. fn
-------------

alias for fields

97.41.2.8. show_status
----------------------

Return '1' to the page if successful

97.41.2.9. spec
---------------

The index specification

97.41.2.10. table
-----------------

97.42. item-list
----------------

97.42.1. Summary
----------------

Parameters: name

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [item-list] FOO [/item-list]. Nesting:
NO

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    NOTE: This would not usually be used with embedded Perl -- a better
    choice would normally be:

                 for(@$Items) { CODE }

    $Tag->item_list(
        {
         name => VALUE,
        },
        BODY
    )

 OR

    $Tag->item_list($name, $ATTRHASH, $BODY);

Attribute aliases

            cart ==> name
    [item-list name other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
cart          Alias for name                            DEFAULT_VALUE
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [item-list name]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->item_list(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->item_list(name, $attribute_hash_reference, $body);

97.42.2. Description
--------------------

Within any page, the [item-list cart*] element shows a list of all the
items ordered by the customer so far. It works by repeating the source
between [item-list] and [/item-list] once for each item ordered.

NOTE: The special tags that reference item within the list are not
normal Interchange tags, do not take named attributes, and cannot be
contained in an HTML tag (other than to substitute for one of its
values or provide a conditional container). They are interpreted only
inside their corresponding list container. Normal Interchange tags can
be interspersed, though they will be interpreted after all of the
list-specific tags.

Between the [item-list] markers the following elements will return
information for the current item:

97.42.2.1. [if-data table column]
---------------------------------

If the database field column in table table is non-blank, the
following text up to the [/if-data] tag is substituted. This can be
used to substitute IMG or other tags only if the corresponding source
item is present. Also accepts an [else]else text[/else] pair for the
opposite condition.

97.42.2.2. [if-data ! table column]
-----------------------------------

Reverses sense for [if-data].

97.42.2.3. [/if-data]
---------------------

Terminates an [if-data table column] element.

97.42.2.4. [if-field fieldname]
-------------------------------

If the products database field fieldname is non-blank, the following
text up to the [/if-field] tag is substituted. If you have more than
one products database table (see ProductFiles), it will check them in
order until a matching key is found. This can be used to substitute
IMG or other tags only if the corresponding source item is present.
Also accepts an [else]else text[/else] pair for the opposite
condition.

97.42.2.5. [if-field ! fieldname]
---------------------------------

Reverses sense for [if-field].

97.42.2.6. [/if-field]
----------------------

Terminates an [if-field fieldname] element.

97.42.2.7. [item-accessories attribute*, type*, field*, database*, name*]
-------------------------------------------------------------------------

Evaluates to the value of the Accessories database entry for the item.
If passed any of the optional arguments, initiates special processing
of item attributes based on entries in the product database.

97.42.2.8. [item-code]
----------------------

Evaluates to the product code for the current item.

97.42.2.9. [item-data database fieldname]
-----------------------------------------

Evaluates to the field name fieldname in the arbitrary database table
database, for the current item.

97.42.2.10. [item-description]
------------------------------

Evaluates to the product description (from the products file) for the
current item.

In support of OnFly, if the description field is not found in the
database, the description setting in the shopping cart will be used
instead.

97.42.2.11. [item-field fieldname]
----------------------------------

Evaluates to the field name fieldname in the products database, for
the current item. If the item is not found in the first of the
ProductFiles, all will be searched in sequence.

97.42.2.12. [item-increment]
----------------------------

Evaluates to the number of the item in the match list. Used for
numbering search matches or order items in the list.

97.42.2.13. [item-last]tags[/item-last]
---------------------------------------

Evaluates the output of the Interchange tags encased inside the tags,
and if it evaluates to a numerical non-zero number (i.e. 1, 23, or -1)
then the list iteration will terminate. If the evaluated number is
negative, then the item itself will be skipped. If the evaluated
number is positive, then the item itself will be shown but will be
last on the list.

      [item-last][calc]
        return -1 if '[item-field weight]' eq '';
        return 1 if '[item-field weight]' < 1;
        return 0;
        [/calc][/item-last]

If this is contained in your [item-list] (or [search-list] or flypage)
and the weight field is empty, then a numerical -1 will be output from
the [calc][/calc] tags; the list will end and the item will not be
shown. If the product's weight field is less than 1, a numerical 1 is
output. The item will be shown, but will be the last item shown. (If
it is an [item-list], any price for the item will still be added to
the subtotal.)

97.42.2.14. [item-modifier attribute]
-------------------------------------

Evaluates to the modifier value of attribute for the current item.

97.42.2.15. [item-next]tags[/item_next]
---------------------------------------

Evaluates the output of the Interchange tags encased inside, and if it
evaluates to a numerical non-zero number (i.e. 1, 23, or -1) then the
item will be skipped with no output. Example:

      [item-next][calc][item-field weight] < 1[/calc][/item-next]

If this is contained in your [item-list] (or [search-list] or flypage)
and the product's weight field is less than 1, then a numerical 1 will
be output from the [calc][/calc] operation. The item will not be
shown. (If it is an [item-list], any price for the item will still be
added to the subtotal.)

97.42.2.16. [item-price n* noformat*]
-------------------------------------

Evaluates to the price for quantity n (from the products file) of the
current item, with currency formatting. If the optional "noformat" is
set, then currency formatting will not be applied.

97.42.2.17. [item-discount-price n* noformat*]
----------------------------------------------

Evaluates to the discount price for quantity n (from the products
file) of the current item, with currency formatting. If the optional
"noformat" is set, then currency formatting will not be applied.
Returns regular price if not discounted.

97.42.2.18. [item-discount]
---------------------------

Returns the difference between the regular price and the discounted
price.

97.42.2.19. [item-discount_subtotal]
------------------------------------

Inserts the discounted subtotal of the ordered items.

97.42.2.20. [item-quantity]
---------------------------

Evaluates to the quantity ordered for the current item.

97.42.2.21. [item-subtotal]
---------------------------

Evaluates to the subtotal (quantity * price) for the current item.
Quantity price breaks are taken into account.

97.42.2.22. [item-modifier-name attribute]
------------------------------------------

Evaluates to the name to give an input box in which the customer can
specify the modifier to the ordered item.

97.42.2.23. [quantity-name]
---------------------------

Evaluates to the name to give an input box in which the customer can
enter the quantity to order.

97.42.2.24. name
----------------

97.43. label
------------

The page label for goto. See [goto] tag for description.  Note that
this is not a standard tag, but is simply a marker used by goto.

Parameter: name

    [goto name=label_name if=condition]
        content to skip
    [label name=label_name]

97.43.1. Summary
----------------

NO SUMMARY SECTION

    [label]

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [label]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->label(  {
}, $body  );

or similarly with positional parameters,

    $Tag->label(, $attribute_hash_reference, $body);

97.43.2. Description
--------------------

NO DESCRIPTION SECTION

97.44. log
----------

Log contained text to specified file.

97.44.1. Summary
----------------

    [log file other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
arg           Alias for file                            DEFAULT_VALUE
create        Set create=1 to create the file if not    DEFAULT_VALUE
              present
delim         Line delimiter                            DEFAULT_VALUE
file          name of file to log to.                   DEFAULT_VALUE
              'file=">filename"' also sets 'create'
              attribute.
hide          Suppress status otherwise returned by tag DEFAULT_VALUE
              to the page.
process       Processing (if any) to apply to the       DEFAULT_VALUE
              content while loggingnostrip (don't strip
              leading/trailing whitespace and convert
              "\r\n" to "\n"
record_delim  Record delimiter                          DEFAULT_VALUE
type          Log typetext (ordinary text file)quot     DEFAULT_VALUE
              (delimited entries)error (add Interchange
              error formatting and time/location
              stamps)

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [log file]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->log(  { file => VALUE_file
}, $body  );

or similarly with positional parameters,

    $Tag->log(file, $attribute_hash_reference, $body);

97.44.2. Description
--------------------

Log contained text to specified file.

97.44.2.1. create
-----------------

Set create=1 to create the file if not present

97.44.2.2. delim
----------------

Line delimiter

97.44.2.3. file
---------------

name of file to log to. 'file=">filename"' also sets 'create'
attribute.

97.44.2.4. hide
---------------

Suppress status otherwise returned by tag to the page.

97.44.2.5. process
------------------

Processing (if any) to apply to the content while logging

o    nostrip (don't strip leading/trailing whitespace and convert
     "\r\n" to "\n"

97.44.2.6. record_delim
-----------------------

Record delimiter

97.44.2.7. type
---------------

Log type

o    text (ordinary text file)

o    quot (delimited entries)

o    error (add Interchange error formatting and time/location stamps)

97.45. loop
-----------

97.45.1. Summary
----------------

Parameters: list

Positional parameters in same order.

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [loop] FOO [/loop]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    NOTE: This would not usually be used with embedded Perl -- a better
    choice would normally be:

                 for(@list) { CODE }

    $Tag->loop(
        {
         list => VALUE,
        },
        BODY
    )

 OR

    $Tag->loop($list, $ATTRHASH, $BODY);

Attribute aliases

            arg ==> list
            args ==> list
    [loop list other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
arg           Alias for list                            DEFAULT_VALUE
args          Alias for list                            DEFAULT_VALUE
list                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [loop list]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->loop(  { list => VALUE_list
}, $body  );

or similarly with positional parameters,

    $Tag->loop(list, $attribute_hash_reference, $body);

97.45.2. Description
--------------------

Returns a string consisting of the LIST, repeated for every item in a
comma-separated or space-separated list. Operates in the same fashion
as the [item-list] tag, except for order-item-specific values.
Intended to pull multiple attributes from an item modifier - but can
be useful for other things, like building a pre-ordained product list
on a page.

Loop lists can be nested reliably in Interchange by using the
prefix="tag" parameter. New syntax:

    [loop list="A B C"]
        [loop prefix=mid list="[loop-code]1 [loop-code]2 [loop-code]3"]
            [loop prefix=inner list="X Y Z"]
                [mid-code]-[inner-code]
            [/loop]
        [/loop]
    [/loop]

You can do an arbitrary search with the search="args" parameter, just
as in a one-click search:

    [loop search="se=Americana/sf=category"]
        [loop-code] [loop-field title]
    [/loop]

The above will show all items with a category containing the whole
world "Americana", and will work the same in both old and new syntax.

Ranges are accepted when you pass a list if you set the ranges option:

    [loop list="A..Z" ranges=1][loop-code] [/loop]

The above lists all of the characters from A to Z. Any Perl
incrementing variable list will work, but most commonly a range would
be something like 1..100. You can mix regular sets -- 1..5 10 20 would
produce the list 1 2 3 4 5 10 20.

If you surround the repeating text section with a [list] [/list]
anchor, the more-list, ml=N, and on-match / no-match processing is
done just as in [query] and [search-region].

Using the acclist option will parse Interchange option lists, as used
in product options. The value is available with [loop-code], the label
with [loop-param label]. If the size data for SKU TS-007 was set to
the string S=Small, M=Medium, L=Large, XL=Extra Large then you could
produce a select list of options this way:

    [loop list="[data products size TS-007]" acclist=1]
            [on-match]<SELECT NAME=mv_order_size>[/on-match]
                [list]<OPTION VALUE="[loop-code]"> [loop-param label]</OPTION>[/list]
        [on-match]</SELECT>[/on-match]
    [/loop]

Of course the above is probably more easily produced with [accessories
code=TS-007 attribute=size], but there will be other uses for the
capability. For instance:

         <SELECT NAME=Season>
    [loop acclist=1
                list="
                        Q1=Winter,
                        Q2=Spring,
                        Q3=Summer,
                        Q4=Fall
                "]> <OPTION VALUE="[loop-code]"> [loop-param label]</OPTION>
    [/loop]

If your parameter list needs to have spaces in the parameters,
surround them with double or single quotes and set the quoted=1
option: in product options. If the size data for SKU TS-007 was set to
the string S=Small, M=Medium, L=Large, XL=Extra Large then you could
produce a select list of options this way:

    [loop list="[data products size TS-007]" acclist=1]
            [on-match]<SELECT NAME=mv_order_size>[/on-match]
                [list]<OPTION VALUE="[loop-code]"> [loop-param label]</OPTION>[/list]
        [on-match]</SELECT>[/on-match]
    [/loop]

A nice shortcut is available when using [loop] to generate <OPTION>
lists inside HTML <SELECT>...</SELECT> blocks, when you want the
user's last selection to be chosen by default on subsequent page
views. Interchange simplifies this with functions that output
"SELECTED" (surrounded by appropriate whitespace) for an <OPTION> if a
certain value is set to the <OPTION VALUE="...">. (It sounds more
complicated than it really is.)

For example, consider:

<select name=search_cat>
[loop
        search="
                fi=cat
                st=db
                ra=yes
                rf=name
                tf=name
                un=1
        "
]
<option[selected search_cat [loop-code]>[loop-code]
[/loop]
</select>

When the user returns to the page, their last selection will be chosen
as the default. (Assuming the value search_cat was set after the
search, which is normally is with standard searches.)

[loop] offers the option attribute, which can give loops that parse
faster and are easier to write. The following example is equivalent to
the one above:

<select name=search_cat>
[loop
        option=search_cat
        search="
                fi=cat
                st=db
                ra=yes
                rf=name
                tf=name
                un=1
        "
]
<option>[loop-code]
[/loop]
</select>

It works equally well when option values are explicitly specified:

<option value="[loop-code]">So-called "[loop-code]"

See also the ictemplates documentation in the section "Checks and
Selections."

97.45.2.1. [if-loop-data table column] IF [else] ELSE [/else][/if-loop-field]
-----------------------------------------------------------------------------

Outputs the IF if the column in table is non-empty, and the ELSE (if
any) otherwise.

See [if-PREFIX-data].

97.45.2.2. [if-loop-field column] IF [else] ELSE [/else][/if-loop-field]
------------------------------------------------------------------------

Outputs the IF if the column in the products table is non-empty, and
the ELSE (if any) otherwise. Will fall through to the first non-empty
field if there are multiple ProductFiles.

See [if-PREFIX-field].

97.45.2.3. [if-loop-param param] IF [else] ELSE [/else][/if-loop-param]
-----------------------------------------------------------------------

Only works if you have named return fields from a search (or from a
passed list with the lr=1 parameter).

Outputs the IF if the returned param is non-empty, and the ELSE (if
any) otherwise.

See [if-PREFIX-param].

97.45.2.4. [if-loop-pos N] IF [else] ELSE [/else][/if-loop-pos]
---------------------------------------------------------------

Only works if you have multiple return fields from a search (or from a
passed list with the lr=1 parameter).

Parameters are numbered from ordinal 0, with [loop-pos 0] being the
equivalent of [loop-code].

Outputs the IF if the returned positional parameter N is non-empty,
and the ELSE (if any) otherwise.

See [if-PREFIX-pos].

97.45.2.5. [loop-accessories]
-----------------------------

Outputs an [accessories ...] item.

See [PREFIX-accessories].

97.45.2.6. [loop-change marker]
-------------------------------

See [PREFIX-change].

97.45.2.7. [loop-code]
----------------------

Evaluates to the code for the current item.

See [PREFIX-code].

97.45.2.8. [loop-data database fieldname]
-----------------------------------------

Evaluates to the field name fieldname in the arbitrary database table
database, for the current item.

See [PREFIX-data].

97.45.2.9. [loop-description]
-----------------------------

Evaluates to the product description (from the products file, passed
description in on-fly item, or description attribute in cart) for the
current item.

See [PREFIX-description].

97.45.2.10. [loop-field fieldname]
----------------------------------

Evaluates to the field name fieldname in the database,  for the
current item.

See [PREFIX-field].

97.45.2.11. [loop-increment]
----------------------------

Evaluates to the number of the item in the list. Used for numbering
items in the list.

Starts from integer 1.

See [PREFIX-increment].

97.45.2.12. [loop-last]tags[/loop-last]
---------------------------------------

Evaluates the output of the Interchange tags encased inside, and if it
evaluates to a numerical non-zero number (i.e. 1, 23, or -1) then the
loop iteration will terminate. If the evaluated number is negative,
then the item itself will be skipped. If the evaluated number is
positive, then the item itself will be shown but will be last on the
list.

      [loop-last][calc]
        return -1 if '[loop-field weight]' eq '';
        return 1 if '[loop-field weight]' < 1;
        return 0;
        [/calc][/loop-last]

If this is contained in your [loop list] and the weight field is
empty, then a numerical -1 will be output from the [calc][/calc] tags;
the list will end and the item will not be shown. If the product's
weight field is less than 1, a numerical 1 is output. The item will be
shown, but will be the last item shown.

97.45.2.13. [loop-next]tags[/loop-next]
---------------------------------------

Evaluates the output of the Interchange tags encased inside, and if it
evaluates to a numerical non-zero number (i.e. 1, 23, or -1) then the
loop will be skipped with no output. Example:

      [loop-next][calc][loop-field weight] < 1[/calc][/loop-next]

If this is contained in your [loop list] and the product's weight
field is less than 1, then a numerical 1 will be output from the
[calc][/calc] operation. The item will not be shown.

97.45.2.14. [loop-price n* noformat*]
-------------------------------------

Evaluates to the price for optional quantity n (from the products
file) of the current item, with currency formatting. If the optional
"noformat" is set, then currency formatting will not be applied.

97.45.2.15. list
----------------

97.46. mail
-----------

Mail contained text to recipient specified by 'to' using the program
specified with the SendMailProgram catalog directive.

97.46.1. Summary
----------------

    [mail to other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
extra         Additional headers (these will also be    DEFAULT_VALUE
              added to 'raw' messages)
hide          Suppress tag return value. This would     DEFAULT_VALUE
              otherwise be the 'success' attribute
              setting.
raw           Send it raw without creating headers and  DEFAULT_VALUE
              checking content, recipient, subject,
              etc.
show          The tag will return the final message     DEFAULT_VALUE
              with headers in the page
success       Tag return value if successful (default   DEFAULT_VALUE
              is 1).
to                                                      DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [mail to]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->mail(  { to => VALUE_to
}, $body  );

or similarly with positional parameters,

    $Tag->mail(to, $attribute_hash_reference, $body);

97.46.2. Description
--------------------

Mail contained text to recipient specified by 'to' using the program
specified with the SendMailProgram catalog directive.

97.46.2.1. extra
----------------

Additional headers (these will also be added to 'raw' messages)

97.46.2.2. hide
---------------

Suppress tag return value. This would otherwise be the 'success'
attribute setting.

97.46.2.3. raw
--------------

Send it raw without creating headers and checking content, recipient,
subject, etc.

97.46.2.4. show
---------------

The tag will return the final message with headers in the page

97.46.2.5. success
------------------

Tag return value if successful (default is 1).

97.46.2.6. to
-------------

97.47. mvasp
------------

Executes the ASP-style perl code contained by the tag. The code will
run under the restrictions of the Safe module. This is very similar to
the [perl] tag, except that the standard '<%' and '%>' ASP delimiters
allow you to mix HTML and perl code.

97.47.1. Summary
----------------

    [mvasp tables] ASP here [/mvasp]
    [mvasp tables="db1 db2 ..." other_named_attributes] ASP here [/mvasp]

Parameters    Description                               Default
............. ......................................... ............. 
tables        Database tables to be made available to   none
              ASP Perl code
table         Alias for tables                          none

Attributes                         Default
.................................. .................................. 
failure                            none
no_return                          Always true
subs                               No
arg="subs"                         Same as subs
global                             No
file                               none
interpolate                        No
reparse                            No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes
Has Subtags                        <% and %>
Container tag                      Yes
Nests                              No

Tag expansion example:

    [mvasp tables="products" failure="ASP Broke <BR>"]
        <P>This is HTML</p>
        <% my $sku = $Values->{code}; %>
        <P>More HTML</p>
        <% my $result = "Looked up SKU $sku. It is a ";
            $result .= $Tag->data('products', 'description', $sku );
            $Document->write( "$result <br>\n" ); %>
        <P>Still more HTML</p>
    [/mvasp]
---
    <P>This is HTML</p>

    <P>More HTML</p>
    Looked up SKU os28044. It is a Framing Hammer <br>

    <P>Still more HTML</p>

97.47.1.1. See Also
-------------------

perl, Interchange Programming

97.47.2. Description
--------------------

Executes the ASP-style perl code contained by the tag. The code will
run under the restrictions of the Safe module. This is very similar to
the [perl no_return=1] tag, except that the standard '<%' and '%>' ASP
delimiters allow you to mix HTML and perl code.

See the perl tag and ASP-Like Perl sections for more detail.

97.47.2.1. tables
-----------------

Whitespace-separated list of database tables to make available within
the ASP-Perl code. See perl tag.

97.47.2.2. failure
------------------

The value the tag should return in case the perl code fails the eval.
See perl tag.

97.47.2.3. no_return
--------------------

The return value of the perl code is always suppressed. If you want
output from the ASP code sections, you must explicitly write it with
the &HTML or $Document->write() functions.

You can also retrieve the return value of the perl code from the
session hash via [data session mv_perl_result]. See perl tag.

97.47.2.4. subs
---------------

Enable GlobalSub routines (requires catalog directive AllowGlobal).
See perl tag.

97.47.2.5. global
-----------------

Turn off Safe protection (requires catalog directive AllowGlobal). See
perl tag.

97.47.2.6. file
---------------

Prepend the contents of the specified file or FileDatabase entry to
the perl code before eval'ing it. See perl tag.

97.47.2.7. Examples
-------------------

See the ASP-Like Perl section of Interchange Programming.

97.48. nitems
-------------

Returns the total number of items ordered.  Uses the current cart if
none specified.

97.48.1. Summary
----------------

    [nitems name]

Parameters    Description                               Default
............. ......................................... ............. 
compare       Regular expression the specified          DEFAULT_VALUE
              qualifier attribute's value must match to
              be counted. This replaces the truth value
              comparison.Default: None (uses truth
              value of the specified qualifier
              attribute)
name          Cart nameDefault: current cart            DEFAULT_VALUE
qualifier     An item attribute that must be true in    DEFAULT_VALUE
              order to count the item.Default: None

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [nitems name]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->nitems(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->nitems(name, $attribute_hash_reference, $body);

97.48.2. Description
--------------------

Expands into the total number of items ordered so far. Takes an
optional cart name as a parameter.

97.48.2.1. compare
------------------

Regular expression the specified qualifier attribute's value must
match to be counted. This replaces the truth value comparison.

o    Default: None (uses truth value of the specified qualifier
     attribute)

97.48.2.2. name
---------------

Cart name

o    Default: current cart

97.48.2.3. qualifier
--------------------

An item attribute that must be true in order to count the item.

o    Default: None

97.49. options
--------------

Builds HTML widgets as defined in the options table for selecting
options associated with a given product. This tag handles simple,
matrix or modular options.  See also the accessories tag.

Here is an illustrative example from the 'tools' sample data set of
the foundation catalog:

===
    [options code=os28005]
---
    <input type=hidden name=mv_item_option value="logo">
        <SELECT NAME="mv_order_logo">
        <OPTION VALUE="c">Construct Something
        <OPTION VALUE="y" SELECTED>Your Logo</SELECT><BR>
    <input type=hidden name=mv_item_option value="color">
        <INPUT TYPE="radio" NAME="mv_order_color" VALUE="BLK" >&nbsp;Black
        <INPUT TYPE="radio" NAME="mv_order_color" VALUE="BEIGE" >&nbsp;Beige
        <INPUT TYPE="radio" NAME="mv_order_color" VALUE="WHITE" >&nbsp;White<BR>
    <input type=hidden name=mv_item_option value="bristle">
        <SELECT NAME="mv_order_bristle">
        <OPTION VALUE="synthetic">Synthetic
        <OPTION VALUE="camel">Camel Hair</SELECT>
===

97.49.1. Summary
----------------

    [options code]

Parameters    Description                               Default
............. ......................................... ............. 
bold          Boldfaces the labels if the 'label'       DEFAULT_VALUE
              option is set.Default: False
code          Product key (usually sku).No default      DEFAULT_VALUE
joiner        The joiner for the widgets.Default: <BR>  DEFAULT_VALUE
label         Shows labels for the options with the     DEFAULT_VALUE
              widgets.The following example (using
              another item from the 'tools' data)
              illustrates the price and label
              attributes:=== [options code=os28011
              label=1 price=1]--- Handle<BR> <input
              type=hidden name=mv_item_option
              value="handle"> <SELECT
              NAME="mv_order_handle"> <OPTION
              VALUE="W">Wood handle <OPTION
              VALUE="E">Ebony handle
              ($20.00)</SELECT><BR> Blade material<BR>
              <input type=hidden name=mv_item_option
              value="blade"> <SELECT
              NAME="mv_order_blade"> <OPTION
              VALUE="P">Plastic blade ($-1.22) <OPTION
              VALUE="S" SELECTED>Steel blade <OPTION
              VALUE="T">Titanium blade
              ($100.00)</SELECT>===(again, the output
              has been reformatted to fit the
              page).Default: False
price         Boolean. If set and the options have      False
              prices, the HTML widget(s) will show the
              prices. This is like the price attribute
              of the accessories tag.Note that the
              price_data setting comes from the 'price'
              column of the options table.Technical
              note-- If your options table has
              different mappings, you can control this
              with $::Variable->{MV_OPTION_TABLE_MAP}
table         Table to use for option                   DEFAULT_VALUE
              attributes.Default: 'options'
td            Results as table rows. For example,       DEFAULT_VALUE
              compare the following example from the
              'tools' sample data set with the earlier
              example:=== [options code=os28005
              td=1]--- <td><input type=hidden
              name=mv_item_option value="logo"> <SELECT
              NAME="mv_order_logo"> <OPTION
              VALUE="c">Construct Something <OPTION
              VALUE="y" SELECTED>Your
              Logo</SELECT></td> <td><input type=hidden
              name=mv_item_option value="color"> <INPUT
              TYPE="radio" NAME="mv_order_color"
              VALUE="BLK" >&nbsp;Black <INPUT
              TYPE="radio" NAME="mv_order_color"
              VALUE="BEIGE" >&nbsp;Beige <INPUT
              TYPE="radio" NAME="mv_order_color"
              VALUE="WHITE" >&nbsp;White</td>
              <td><input type=hidden
              name=mv_item_option value="bristle">
              <SELECT NAME="mv_order_bristle"> <OPTION
              VALUE="synthetic">Synthetic <OPTION
              VALUE="camel">Camel
              Hair</SELECT></td>===(Note that the
              output was reformatted to fit this page)

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [options code]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->options(  { code => VALUE_code
}, $body  );

or similarly with positional parameters,

    $Tag->options(code, $attribute_hash_reference, $body);

97.49.2. Description
--------------------

NO DESCRIPTION SECTION

97.49.2.1. bold
---------------

Boldfaces the labels if the 'label' option is set.

o    Default: False

97.49.2.2. code
---------------

Product key (usually sku).

o    No default

97.49.2.3. joiner
-----------------

The joiner for the widgets.

o    Default: <BR>

97.49.2.4. label
----------------

Shows labels for the options with the widgets.

The following example (using another item from the 'tools' data)
illustrates the price and label attributes:

===
   [options code=os28011 label=1 price=1]
---
   Handle<BR>
     <input type=hidden name=mv_item_option value="handle">
       <SELECT NAME="mv_order_handle">
       <OPTION VALUE="W">Wood handle
       <OPTION VALUE="E">Ebony handle ($20.00)</SELECT><BR>
   Blade material<BR>
     <input type=hidden name=mv_item_option value="blade">
       <SELECT NAME="mv_order_blade">
       <OPTION VALUE="P">Plastic blade ($-1.22)
       <OPTION VALUE="S" SELECTED>Steel blade
       <OPTION VALUE="T">Titanium blade ($100.00)</SELECT>
===

(again, the output has been reformatted to fit the page).

o    Default: False

97.49.2.5. price
----------------

Boolean. If set and the options have prices, the HTML widget(s) will
show the prices. This is like the price attribute of the accessories
tag.

     Note that the price_data setting comes from the 'price' column of
     the options table.

     Technical note-- If your options table has different mappings,
     you can control this with $::Variable->{MV_OPTION_TABLE_MAP}

o    Default: False

97.49.2.6. table
----------------

Table to use for option attributes.

o    Default: 'options'

97.49.2.7. td
-------------

Results as table rows. For example, compare the following example from
the 'tools' sample data set with the earlier example:

===
   [options code=os28005 td=1]
---
   <td><input type=hidden name=mv_item_option value="logo">
      <SELECT NAME="mv_order_logo">
      <OPTION VALUE="c">Construct Something
      <OPTION VALUE="y" SELECTED>Your Logo</SELECT></td>
   <td><input type=hidden name=mv_item_option value="color">
      <INPUT TYPE="radio" NAME="mv_order_color" VALUE="BLK" >&nbsp;Black
      <INPUT TYPE="radio" NAME="mv_order_color" VALUE="BEIGE" >&nbsp;Beige
      <INPUT TYPE="radio" NAME="mv_order_color" VALUE="WHITE" >&nbsp;White</td>
   <td><input type=hidden name=mv_item_option value="bristle">
      <SELECT NAME="mv_order_bristle">
      <OPTION VALUE="synthetic">Synthetic
      <OPTION VALUE="camel">Camel Hair</SELECT></td>
===

(Note that the output was reformatted to fit this page)

97.50. or
---------

97.50.1. Summary
----------------

Parameters: type term op compare

THIS TAG HAS SPECIAL POSITIONAL PARAMETER HANDLING.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

Called Routine for positional:

ASP-like Perl call:

    $Tag->or(
        {
         type => VALUE,
         term => VALUE,
         op => VALUE,
         compare => VALUE,
        }
    )

 OR

    $Tag->or($type, $term, $op, $compare);

Attribute aliases

            base ==> type
            comp ==> compare
            operator ==> op
    [or type term op compare]

Parameters    Description                               Default
............. ......................................... ............. 
base          Alias for type                            DEFAULT_VALUE
comp          Alias for compare                         DEFAULT_VALUE
compare                                                 DEFAULT_VALUE
op                                                      DEFAULT_VALUE
operator      Alias for op                              DEFAULT_VALUE
term                                                    DEFAULT_VALUE
type                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [or type term op compare]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->or(  { compare => VALUE_compare
                 op => VALUE_op
                 term => VALUE_term
                 type => VALUE_type
}, $body  );

or similarly with positional parameters,

    $Tag->or(type,term,op,compare, $attribute_hash_reference, $body);

97.50.2. Description
--------------------

NO Description

97.50.2.1. compare
------------------

97.50.2.2. op
-------------

97.50.2.3. term
---------------

97.50.2.4. type
---------------

97.51. order
------------

Expands into a hypertext link which will include the specified item in
the list of products to order and display the order page.

97.51.1. Summary
----------------

    [order code quantity]Link Text</A>
    [order code=os28044 quantity=2]Link Text</A>

Parameters    Description                               Default
............. ......................................... ............. 
code          This is the unique identifier for the     none
              item, typically the SKU in the products
              table
quantity      Quantity to order                         1

Attributes                         Default
.................................. .................................. 
code                               No
page                               SpecialPage order
cart                               main cart
base                               ProductFiles array
area                               off
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      No
Has end tag                        No ([/order] is a macro for </A>)

Tag expansion example:

    [order os28044 2]Buy Framing Hammer[/order]
---
    <A HREF="http://localhost.localdomain/cgi-bin/tag72/ord/basket?\
    mv_session_id=6CZ2whqo&mv_pc=1&mv_action=refresh&\
    mv_order_item=os28044&mv_order_quantity=3">Buy Framing Hammer</A>

ASP-like Perl call:

    $Tag->order($code, $quantity);

97.51.2. Description
--------------------

Expands into a hypertext link which will include the specified code in
the list of products to order and display the order page.

code should be a product code listed in one of the "products"
databases. The optional argument base constrains the order to a
particular products file. If not specified, all tables defined as
ProductFiles will be searched in sequence for the item.

The optional argument cart selects the shopping cart where the item
will be placed.

page allows you to specify a different order page than the default one
specified by SpecialPage order.

97.51.3. How to Order an Item
-----------------------------

Interchange can either use a form-based order or a link-based order to
place an item in the shopping cart. The order tag creates a link-based
order.

You can use the area tag with form variables if you need more control,
for example, to change frames for the order:

   <A HREF="[area href=ord/basket
                  form="mv_order_item=os28044
                        mv_order_quantity=2
                        mv_action=refresh"]"
    TARGET=newframe> Order Framing Hammer</A>

This can also be done more easily with the area option to the order
tag:

    <A HREF="[order code=os28044 quantity=2 area=1]"
         TARGET=newframe> Order Framing Hammer</A>

To order with a form, you set the form variable mv_order_item to the
item-code/SKU and use the refresh action:

   <FORM ACTION="[process]" METHOD=POST>
   <INPUT TYPE=hidden  NAME="mv_todo"        VALUE="refresh">
   <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="os28044">

   Order <INPUT NAME="mv_order_quantity" SIZE=3 VALUE=1> Framing Hammer

   <INPUT TYPE=submit VALUE="Order!">
   </FORM>

Groups of items may be batched:

   <FORM ACTION="[process]" METHOD=POST>
   <INPUT TYPE=hidden  NAME="mv_todo"        VALUE="refresh">

   <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="TK112">
   <INPUT NAME="mv_order_quantity" SIZE=3> Standard Toaster

   <INPUT TYPE=hidden  NAME="mv_order_item"  VALUE="TK200">
   <INPUT NAME="mv_order_quantity" SIZE=3> Super Toaster

   <INPUT TYPE=submit VALUE="Order!">
   </FORM>

Items that have a quantity of zero (or blank) will be skipped. Only
items with a positive quantity will be placed in the basket.

Attributes like size or color may be specified at time of order. See
the accessories tag for detail.

97.52. page
-----------

Expands to a hyperlink to an Interchange page or action, including
surrounding <A HREF ...>. The URL within the link includes the
Interchange session ID and supplied arguments. The optional [/page] is
simply a macro for </A>.

If you do not want the <A HREF ...>, use the area tag instead - these
are equivalent:

    [page href=dir/page arg=mv_arg]TargetName</A>
    <A HREF="[area href=dir/page arg=mv_arg]">TargetName</A>

97.52.1. Summary
----------------

    [page href arg]
    [page href=dir/page arg=page_arguments other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
href          Path to Interchange page or actionSpecial process
              arguments'scan' treats arg as a search
              argument'http://...' external link
              (requires form attribute)
arg           Interchange arguments to page or action   none
base          alias for arg                             none

Attributes                         Default
.................................. .................................. 
extra                              none
form                               none
search                             No
secure                             No
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        No ([/page] is a macro for </A>)

Tag expansion example:

    [page href=dir/page.html arg="arg1=AA/arg2=BB"]

    <a href="www.here.com/cgi-bin/mycatalog/page.html?mv_session_id=6CZ2whqo&\
    mv_pc=1&mv_arg=arg1%3dAA/arg2%3dBB">

ASP-like Perl call:

    $Tag->page(  { href => "dir/page",
                   arg  => "arguments", }  );

or similarly with positional parameters,

    $Tag->page($href, $arg, $attribute_hash_reference);

Using arrayref for joined search (see also Attribute Arrays and
Hashes)

    my $searchref = [ "se=hammer/fi=products/sf=description",
                      "se=plutonium/fi=products/sf=description", ];

    $Tag->page( { href   => 'scan',
                  search => $searchref, } );

97.52.1.1. See Also
-------------------

area

97.52.2. Description
--------------------

The page tag inserts a hyperlink to the specified Interchange page or
action. For example, [page shirts] will expand into

   <a href="http://www.here.com/cgi-bin/mycatalog/shirts?mv_session_id=6CZ2whqo&mv_pc=1">

The catalog page displayed will come from "shirts.html" in the pages
directory.

The additional argument will be passed to Interchange and placed in
the {arg} session parameter. This allows programming of a conditional
page display based on where the link came from. The argument is then
available with the tag [data session arg], or the embedded Perl
session variable $Session->{arg}. Spaces and some other characters
will be escaped with the %NN HTTP-style notation and unescaped when
the argument is read back into the session.

For better performance, Interchange can prebuild and cache pages that
would otherwise be generated dynamically. If Interchange has built
such a static page for the target, the page tag produces a link to the
cached page whenever the user has accepted and sent back a cookie with
the session ID. If the user did not accept the cookie, Interchange
cannot use the cache, since the link must then include the
mv_session_id argument in order to preserve session.

97.52.2.1. extra
----------------

97.52.2.2. form
---------------

The optional form argument allows you to encode a form in the link.

        [page form="mv_order_item=os28044
                    mv_order_size=15oz
                    mv_order_quantity=1
                    mv_separate_items=1
                    mv_todo=refresh"] Order 15oz Framing Hammer</A>

The two form values mv_session_id and mv_arg are automatically added
when appropriate. The form value mv_arg receives the value of the
tag's arg parameter.

This would generate a form that ordered quantity one of item number
os28044 with size 15oz. The item would appear on a separate line in
the shopping cart, since mv_separate_items is set. Since the href is
not set, you will go to the default shopping cart page -
alternatively, you could have set mv_orderpage=yourpage to go to
yourpage.

All normal Interchange form caveats apply - you must have an action,
you must supply a page if you don't want to go to the default, etc.

You can theoretically submit any form with this, though none of the
included values can have newlines or trailing whitespace. If you want
to do something like that you will have to write a UserTag.

If the parameter href is not supplied, process is used, causing normal
Interchange form processing.

If the href points to an http:// link, then no Interchange URL
processing will be done, but the URL will include mv_session_id,
mv_pc, and any arguments supplied with the arg attribute:

       [page  href="http://www.elsewhere.net/cgi/script"
              form="cgi_1=ONE
                    cgi_2=TWO"
               arg="Interchange argument"]External link</A>

       <A HREF="http://www.elsewhere.net/cgi/script?\
        mv_session_id=6CZ2whqo&mv_pc=1&mv_arg=Interchange%20argument&\
        cgi_1=ONE&cgi_2=TWO">External link</A>

97.52.2.3. search
-----------------

Interchange allows you to pass a search in a URL. There are two ways
to do this:

1.   Place the search specification in the named search attribute.

     o    Interchange will ignore the href parameter (the link will be
          set to 'scan'.

     o    If you give the arg parameter a value, that value will be
          available as [value mv_arg] within the search display page.

2.   Set the href parameter to 'scan' and set arg to the search
     specification.

     o    Note that you can use this form positionally - the values go
          into href and arg, so you do not have to name parameters.

These are identical:

    [page scan
          se=Impressionists
          sf=category]
        Impressionist Paintings
    </a>

    [page href=scan
          arg="se=Impressionists
               sf=category"]
        Impressionist Paintings
    </A>

    [page search="se=Impressionists
                  sf=category"]
        Impressionist Paintings
    </a>

Here is the same thing from a non-Interchange page (e.g., a home
page), assuming '/cgi-bin/mycatalog' is the CGI path to Interchange's
vlink):

     <A HREF="/cgi-bin/mycatalog/scan/se=Impressionists/sf=category">
        Impressionist Paintings
     </A>

Sometimes, you will find that you need to pass characters that will
not be interpreted positionally. In that case, you should quote the
arguments:

    [page href=scan
          arg=|
                se="Something with spaces"
          |]

See the Search and Form Variables appendix for a listing of the form
variables along with two-letter abbreviations and descriptions.

They can be treated just the same as form variables on the page,
except that they can't contain spaces, '/' in a file name, or quote
marks. These characters can be used in URL hex encoding, i.e. %20 is a
space, %2F is a /, etc. - &sp; or &#32; will not be recognized. If you
use one of the methods below to escape these "unsafe" characters, you
won't have to worry about this.

You may specify a one-click search in three different ways. The first
is as used in previous versions, with the scan URL being specified
completely as the page name. The second two use the "argument"
parameter to the [page ...] or [area ...]> tags to specify the search
(an argument to a scan is never valid anyway).

97.52.2.4. secure
-----------------

97.52.2.5. Original syntax
--------------------------

If you wish to do an OR search on the fields category and artist for
the strings "Surreal" and "Gogh", while matching substrings, you would
do:

 [page scan se=Surreal/se=Gogh/os=yes/su=yes/sf=artist/sf=category]
    Van Gogh -- compare to surrealists
 </a>

In this method of specification, to replace a / (slash) in a file name
(for the sp, bd, or fi parameter) you must use the shorthand of ::,
i.e. sp=results::standard. (This may not work for some browsers, so
you should probably either put the page in the main pages directory or
define the page in a search profile.)

97.52.2.6. Ampersand syntax
---------------------------

You can substitute & for / in the specification and be able to use /
and quotes and spaces in the specification.

 [page scan se="Van Gogh"&sp=lists/surreal&os=yes&su=yes&sf=artist&sf=category]
    Van Gogh -- compare to surrealists
 </a>

Any "unsafe" characters will be escaped.

97.52.2.7. Multi-line syntax
----------------------------

You can specify parameters one to a line, as well.

    [page scan
        se="Van Gogh"
        sp=lists/surreal
        os=yes
        su=yes
        sf=artist
        sf=category
    ] Van Gogh -- compare to surrealists </a>

Any "unsafe" characters will be escaped. You may not search for
trailing spaces in this method; it is allowed in the other notations.

97.52.2.8. Joined searches
--------------------------

You can also specify a joined search using an attribute array (see
Attribute Arrays and Hashes):

    [page href=scan
      search.0="se=fragrant
                fi=products
                sf=smell"
      search.1="se=purple
                sf=color"
      search.2="se=perennial
                sf=type"]

The search routine called by the page tag automatically adds the other
relevant search specification elements, including the 'co=yes' to
indicate a combined search (joined searches are described in the
Interchange database documentation).

97.52.2.9. [/page]
------------------

This is not an actual end tag, but simply a macro that expands to
</A>. The following two lines are equivalent:

  [page shirts]Our shirt collection[/page]
  [page shirts]Our shirt collection</A>

Tip: In large pages, just use the </A> tag for a small performance
improvement.

97.53. perl
-----------

Executes the perl code contained by the tag. The code will run under
the restrictions of Perl's Safe module by default. The tag expands to
the value returned by the enclosed code (i.e., printing to STDOUT or
STDERR is useless).

See also Interchange Programming.

97.53.1. Summary
----------------

    [perl tables] Code here [/perl]
    [perl tables="db1 db2 ..." other_named_attributes] Code here [/perl]

Parameters    Description                               Default
............. ......................................... ............. 
tables        Database tables to be made available to   none
              ASP Perl code
table         Alias for tables                          none

Attributes                         Default
.................................. .................................. 
failure                            none
no_return                          No
subs                               No
arg="subs"                         Same as subs
global                             No
file                               none
number_errors                      none
eval_label                         none
short_errors                       none
trim_errors                        none
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes
Has Subtags                        No
Container tag                      Yes

Tag expansion example:

    [perl tables="products" failure="Perl code error <BR>"]
     my $result = "Looked up SKU $Values->{code}. It is a ";
     $result .= $Tag->data('products', 'description', $Values->{code} );
     return ("$result <br>\n");
    [/perl]
---
    Looked up SKU os28044. It is a Framing Hammer <br>

ASP-like Perl call: (e.g., to use it like a runtime eval() within your
code)

    $Tag->perl(  { tables  => "products", },
                 $code  );

or similarly with positional parameters,

    $Tag->perl( $tables, $attribute_hash_reference );

97.53.1.1. See Also
-------------------

See also Interchange Programming, [calc], and [mvasp].

97.53.2. Description
--------------------

This tag allows you to embed perl code within an Interchange page. The
code will run under the restrictions of Perl's Safe module by default.
Perl's 'warnings' and 'strict' pragmas are both turned off, and Safe
will block you from turning them on, since it blocks Perl's 'use'
command. (This is not usually a problem, since you should probably use
an alternative such as a usertag if your code is complex enough to
need strict.)

The tag expands to the value returned by the enclosed code (i.e.,
printing to STDOUT or STDERR is useless).

    [perl]
        $name    = $Values->{name};
        $browser = $Session->{browser};
        return "Hi, $name! How do you like your $browser?
    [/perl]

Object references are available for most Interchange tags and
functions, as well as direct references to Interchange session and
configuration values.

Object                             Description
.................................. .................................. 
$CGI->{key}                        Hash reference to raw submitted
                                   values
$CGI_array->{key}                  Arrays of submitted values
$Carts->{cartname}                 Direct reference to shopping carts
$Config->{key}                     Direct reference to $Vend::Cfg
$DbSearch->array(@args)            Do a DB search and get results
$Document->header()                Writes header lines
$Document->send()                  Writes to output
$Document->write()                 Writes to page
$Scratch->{key}                    Direct reference to scratch area
$Session->{key}                    Direct reference to session area
$Tag->tagname(@args)               Call a tag as a routine (UserTag
                                   too!)
$TextSearch->array(@args)          Do a text search and get results
$Values->{key}                     Direct reference to user form
                                   values
$Variable->{key}                   Config variables (same as
                                   $Config->{Variable});
&HTML($html)                       Same as $Document->write($html);
&Log($msg)                         Log to the error log

For full descriptions of these objects, see Interchange Perl Objects.

97.53.2.1. tables
-----------------

This should be a whitespace-separated list of database tables you want
to make available within the Perl code.

If you wish to use database values in your Perl code, the tag must
pre-open the table(s) you will be using. Here is an example using the
products table:

    [perl tables=products]
        my $cost = $Tag->data('products', 'our_cost', $Values->{code});
        $min_price = $cost * ( 1 + $min_margin );
        return ($min_price > $sale_price) ? $min_price : $sale_price;
    [/perl]

If you do not do this, your code will fail with a runtime Safe error
when it tries to look up 'our_cost' in the products database with the
data tag.

Even if you properly specify the tables to pre-open, some database
operations will still be restricted because Safe mode prohibits
creation of new objects. For SQL, most operations can be performed if
the Safe::Hole module is installed. Otherwise, you may have to set the
global=1 attribute to use data from SQL tables.

Interchange databases can always be accessed as long as they are
pre-opened by using an item first.

Technical note:

Safe objects (including database handles) may persist within a page,
and the perl tag does not necessarily destroy objects created earlier
in the page. As a result, your code may work even though you did not
set 'tables' properly, only to break later when you change something
elsewhere on the page.

For example, this will work because the first call to [accessories
...] opens the (default) products table:

    [accessories code=os28044 attribute=size]

    [perl]
        return $Tag->accessories( { attribute => 'size',
                                    code      => 'os28085' } );
    [/perl]

If you remove the first [accessories ...] tag, then the
$Tag->accessories call will fail with a Safe error unless you also set
'tables=products' in the perl tag.

The moral of this story is to ensure that you pass all necessary
tables in the perl tag.

97.53.2.2. failure
------------------

If your code contains a compile or runtime error and fails to evaluate
(i.e., eval($code) would set $@), the tag will return the value set
for the failure attribute. The error will be logged as usual.

For example,

    [perl failure="It Broke"]
        my $cost = $Tag->data('products', 'our_cost', $Values->{code});
        $min_price = $cost * ( 1 + $min_margin );
        return ($min_price > $sale_price) ? $min_price : $sale_price;
    [/perl]

will return 'It Broke' because the $Tag->Data(...) call will fail
under the Safe module (see tables above).

97.53.2.3. no_return
--------------------

If no_return=1, this attribute suppresses the return value of the perl
code.

You can retrieve the return value from the session hash via [data
session mv_perl_result] until it gets overwritten by another perl tag.

If no_return is set, the perl tag will return any output explicitly
written with the &HTML or $Document->write() functions.

Note:

If no_return is not set, then the $Document->write() buffer is not
returned (unless you use $Document->hot(1) or $Document->send(), in
which case the contents of the write buffer will probably appear
before anything else on the page). See Interchange Perl Objects for
more detail.



Here is an example:

    [perl tables=products no_return=1]
        my $cost = $Tag->data('products', 'our_cost', $Values->{code});
        $min_price = $cost * ( 1 + $min_margin );
        &HTML( ($min_price > $sale_price) ? $min_price : $sale_price );
        return ($min_price > $sale_price) ? 'too low' : 'ok';
    [/perl]

This will put the same price on the page as our earlier example, but

$Session->{mv_perl_result} will be either 'too low' or 'ok'.

The [mvasp] tag is very similar to [perl no_return=1].

97.53.2.4. subs
---------------

If you have set the AllowGlobal catalog directive, setting subs=1 will
enable you to call GlobalSub routines within the enclosed perl code.
Note that this can compromise security.

97.53.2.5. global
-----------------

If you have set the AllowGlobal catalog directive, setting global=1
will turn off Safe protection within the tag.

The code within the tag will then be able to do anything the user ID
running Interchange can. This seriously compromises security, and you
should know what you are doing before using it in a public site. It is
especially dangerous if a single Interchange server is shared by
multiple companies or user IDs.

Also, full 'use strict' checking is turned on by default when in
global mode. You can turn it off by using 'no strict;' within your
code. Note that any strict errors will go to the Interchange error
logs, and the tag itself will fail silently within the page.

97.53.2.6. file
---------------

This prepends the contents of the specified file or FileDatabase entry
to the enclosed perl code (if any), then executes as usual.

For example,

    [perl file="my_script.pl"][/perl]

would execute myscript.pl and expand to its return value.

Absolute filenames (or filenames containing '../') are prohibited by
the NoAbsolute catalog directive.

If the filename is not absolute, Interchange first looks for a file in
the current directory, then in the list set with the TemplateDir
catalog directive. If it fails to find a file by that name, it then
looks for an entry by that name in the database specified with the
FileDatabase catalog directive.

97.53.2.7. file
---------------

Add line numbers to the source code displayed in the error.log,
amazingly useful if some of the perl is being generated elsewhere and
interpolated.

97.53.2.8. eval_label
---------------------

Set to a string, will replace the (eval ###) in the error message with
this label, handy to quickly track down bugs when you have more than
one perl block in the page, especially if you are using short_errors.

97.53.2.9. short_errors
-----------------------

If set to a true value, syntax errors and the like in perl tags will
log just the error, not the whole source code of the block in
question, handy when you have the code open in an editor anyway and
don't want the error itself to get scrolled away when running 'tail -f
error.log'.

97.53.2.10. trim_errors
-----------------------

If set to a number, and the error produced includes a line number,
then only that number of lines before and after the broken line itself
will be displayed, instead of the whole block.

97.54. price
------------

97.54.1. Summary
----------------

Parameters: code

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->price(
        {
         code => VALUE,
        }
    )

 OR

    $Tag->price($code, $ATTRHASH);

Attribute aliases

            base ==> mv_ib
    [price code other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
base          Alias for mv_ib                           DEFAULT_VALUE
code                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [price code]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->price(  { code => VALUE_code
}, $body  );

or similarly with positional parameters,

    $Tag->price(code, $attribute_hash_reference, $body);

97.54.2. Description
--------------------

Arguments:

        code       Product code/SKU
        base       Only search in product table *base*
        quantity   Price for a quantity
        discount   If true(1), check discount coupons and apply
        noformat   If true(1), don't apply currency formatting

Expands into the price of the product identified by code as found in
the products database. If there is more than one products file
defined, they will be searched in order unless constrained by the
optional argument base. The optional argument quantity selects an
entry from the quantity price list. To receive a raw number, with no
currency formatting, use the option noformat=1.

Interchange maintains a price in its database for every product. The
price field is the one required field in the product database - it is
necessary to build the price routines.

For speed, Interchange builds the code that is used to determine a
product's price at catalog configuration time. If you choose to change
a directive that affects product pricing you must reconfigure the
catalog.

Quantity price breaks are configured by means of the CommonAdjust
directive. There are a number of CommonAdjust recipes which can be
used; the standard example in the demo calls for a separate pricing
table called pricing. Observe the following:

   CommonAdjust  pricing:q2,q5,q10,q25, ;products:price, ==size:pricing

This says to check quantity and find the applicable column in the
pricing database and apply it. In this case, it would be:

    2-4      Column *q2*
    5-9      Column *q5*
    10-24    Column *q10*
    25 up    Column *q25*

What happens if quantity is one? It "falls back" to the price that is
in the table products, column price.

After that, if there is a size attribute for the product, the column
in the pricing database corresponding to that column is checked for
additions or subtractions (or even percentage changes).

If you use this tag in the demo:

    [price code=99-102 quantity=10 size=XL]

the price will be according to the q10 column, adjusted by what is in
the XL column. (The row is of course 99-102.) The following entry in
pricing:

  code    q2   q5   q10  q25  XL
  99-102  10   9    8    7    .50

Would yield 8.50 for the price. Quantity of 10 in the q10 column, with
50 cents added for extra large (XL).

Following are several examples based on the above entry as well as
this the entry in the products table:

  code    description   price    size
  99-102  T-Shirt       10.00    S=Small, M=Medium, L=Large*, XL=Extra Large

NOTE: The examples below assume a US locale with 2 decimal places, use
of commas to separate, and a dollar sign ($) as the currency
formatting.

  TAG                                          DISPLAYS
  ----------------------------------------     --------
  [price 99-102]                               $10.00
  [price code="99-102"]                        $10.00
  [price code="99-102" quantity=1]             $10.00
  [price code="99-102" noformat=1]             10
  [price code="99-102" quantity=5]             $9.00
  [price code="99-102" quantity=5 size=XL]     $9.50
  [price code="99-102" size=XL]                $10.50
  [price code="99-102" size=XL noformat=1]     10.5

Product discounts for specific products, all products, or the entire
order can be configured with the [discount ...] tag. Discounts are
applied on a per-user basis - you can gate the discount based on
membership in a club or other arbitrary means.

Adding [discount 99-102] $s * .9[/discount] deducts 10% from the price
at checkout, but the price tag will not show that unless you add the
discount=1 parameter.

    [price code="99-102"]            -->   $10.00
    [price code="99-102" discount=1] -->   $9.00

See Product Discounts.

97.54.2.1. base
---------------

97.54.2.2. code
---------------

97.55. process
--------------

This is a shortcut for the 'process' action, expanding to your catalog
URL and session ID. It is analogous to the area tag for the 'process'
page, but is more limited. The following expansion is illustrative:

    [process target=targetframe]
---
    http://www.here.com/cgi-bin/mycatalog/process.html?\
    id=6CZ2whqo" TARGET="targetframe

(the trailing backslash indicates continuation, i.e., the result
should be only one line)

Note the mismatched quotes in the expansion.  Your surrounding HTML
should supply the containing quotes, like this:

   <A HREF="[process target=targetframe]">...

Aliases:  process_target, process_order

97.55.1. Summary
----------------

    [process target secure]
    [process target=targetframe secure=1 other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
target        The target frame or window                None
secure        Boolean. If true (secure=1), the URL will No
              link to your secure server.

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      No

Tag expansion example:

    [process targetframe 1]
---
    http://secure.here.com/cgi-bin/mycatalog/process.html?\
    id=6CZ2whqo" TARGET="targetframe

ASP-like Perl call:

    $Tag->process(  { target => 'frametarget',
                      secure => 1, } );

or similarly with positional parameters,

    $Tag->process($target, $secure, $attribute_hash_reference);

97.56. process-search
---------------------

This is an exact alias for [area<C search>].

97.57. query
------------

Passes SQL statements through to SQL databases, or allows SQL queries
via Interchange's database abstraction into non-SQL databases and text
files. The latter requires the Perl SQL Statement module (included
with Bundle::Interchange from CPAN).

97.57.1. Summary
----------------

    [query sql]
    [query sql="SQL_query_text" other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
sql           The SQL statement.Passed directly through none
              to an SQL database.For a non-SQL table,
              the tag interprets your SQL first. See
              the SQL Statement module for limitations
              and detail.
query         Alias for sql                             none

Attributes                         Default
.................................. .................................. 
table                              products
base (alias for table)             products
type (row_count, html, list,       none: uses arrayref="" if no type
textref)
arrayref                           arrayref="" if no type given
hashref                            none
more (type=list)                   No
xx form var. abbrev. (type=list)   see form variable
 (type=list)                       sql
list_prefix (type=list)            list
random (type=list)                 No
safe_data (type=list)              No
label (type=list)                  current
form (type=list)                   none
wantarray                          No
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      Yes
Has subtags                        Yes
Nests                              No

Tag usage example:

This will list sku, description and price for ten products per page,
followed by hyperlinks to the other pages of the list. Note that you
may interpolate Interchange tags in the usual way if you double-quote
the SQL statement.

    [query sql="select sku, description, price from products where price < [value mv_arg]"
         type=list
         more=1
           ml=10]

      [on_match]Matched<br>[/on_match]
      [no_match]Not Found<br>[/no_match]

      [list]
        [sql-code] [sql-param description] [sql-price]
      [/list]

      [more_list]
        [more]
      [/more_list]
    [/query]

ASP-like Perl call:

   my $sql = "select * from products order by price";
   my $result_array = $Tag->query( { sql => $sql,  },
                                   $body );
   my ($same_results, $col_name_hash, $col_name_array) =
                      $Tag->query( { sql => $sql,  },
                                   $body );

   my $result_hasharray = $Tag->query( { sql     => $sql,
                                         hashref => 'my_results',  },
                                       $body );

or similarly with positional parameters,

    $Tag->query( $sql, $attribute_hash_reference, $body);

97.57.2. Description
--------------------

The query tag allows you to make SQL queries. If you are using an SQL
database table, the tag will pass your SQL statement directly to the
database and return the result.

If your table is not in an SQL database (for example, GDBM, text,
LDAP, and in-memory tables), Interchange will internally convert it to
an Interchange search specification with the Perl SQL Statement module
(included with Bundle::Interchange from CPAN). This means that you can
use simple SQL queries regardless of the underlying database
implementation.

97.57.2.1. Subtags
------------------

For list queries (type=list), the following subtags are available:

Subtag                             Usage
.................................. .................................. 
on_match                            [on_match] do this if something
                                   matched [/on_match]
no_match                            [no_match] do this if nothing
                                   matched [/no_match]
list                                [list_prefix] do this for each
                                   matched item [/list_prefix]The
                                   'list' subtag defines a region
                                   where you can use any of the
                                   looping subtags that work in
                                   array-list context (see Looping
                                   tags and Sub-tags).The default
                                   looping tag prefix will be 'sql'.
                                   Note however that you can override
                                   this by setting the prefix
                                   attribute in the enclosing query
                                   tag.Similarly, the list_prefix
                                   attribute renames the [list]
                                   subtag itself to the value you set
                                   (see list_prefix below).
more_list                           [more_list] [more]
                                   [/more_list]The 'more_list' and
                                   'more' subtags are used when
                                   paginating the query results (see
                                   'more' attribute). The [more]
                                   subtag will expand to a list of
                                   links to the other pages of the
                                   query results.

See also the example at the end of the Summary section above.

97.57.2.2. Perl and ASP usage
-----------------------------

If you are calling $Tag->query within a perl tag (or whenever the code
is secured by the Safe.pm module), you must be sure to set the tables
attribute properly in the enclosing perl tag (see the perl tag
documentation for detail).

The types that return text to a page (i.e., row_count, html, and
textref) work as usual, returning an appropriate string. Note that you
may also have access to the results as an array reference in
$Vend::Interpolate::Tmp->{''} for the life of the page.

If you do not set a type, the tag will return a reference to an array
of array references, since the default with no type is arrayref="".

If you call $Tag->query in scalar context and set arrayref or hashref,
it will return your results as a reference to an array of either
arrayrefs or hashrefs, respectively (i.e., the same data structures
you would get from Perl's DBI.pm module with fetchall_arrayref).

In list context, the first returned element is the aforementioned
reference to your results. The second element is a hash reference to
your column names, and the third element is an an array reference to
the list of column names.

The following examples should be illustrative:

  [perl tables=products]
    my $sql = "select sku, price, description from products
               where price < 10 order by price";

    my $results = $Tag->query( { sql => $sql, } );
    my ( $same_results, $col_name_hashref, $col_name_arrayref)
        = $Tag->query( { sql => $sql, } );

    my $hash_results = $Tag->query( {     sql => $sql,
                                      hashref => 'my_results' } );

    # $Vend::Interpolate::Tmp->{my_results} == $hash_results
    # $Vend::Interpolate::Tmp->{''} == $results == $same_results

    return $Tag->uneval( $results );
  [/perl]

Technical Note: The $Tag->query() call works a bit differently in
GlobalSubs and UserTags than within a perl tag.  Specifically, in a
GlobalSub or global UserTag, if you call query() in list context and
want the three references (i.e., results, column hash and column
array), then you need to set the 'wantarray=1' attribute in the
query() call.  See the wantarray attribute.



97.57.2.3. sql
--------------

This is the text of your SQL statement. The standard Interchange
quoting rules apply. For example, use double quotes (") if you want to
interpolate Interchange tags within your SQL statement, backticks (`)
to calculate a value, etc.

    [query sql="select description, price from products
               where price < [value mv_arg]" ...]
        ...
    [/query]

97.57.2.4. table
----------------

The table attribute sets the database to use for the query. The
default will typically be the database containing the 'products' table
(unless you have changed the first entry in
$Vend::Cfg->{ProductFiles}).

97.57.2.5. type
---------------

If you are not setting the 'arrayref' or 'hashref' attributes, then
the type attribute defines the way the query will return its results.
The type should be one of the following:

Type                               Returns
.................................. .................................. 
html                               The html type returns the results
                                   in an html table. You will need to
                                   supply the enclosing <TABLE ...>
                                   and </TABLE> html tags. The
                                   following is an example of typical
                                   usage: <TABLE> [query sql="select
                                   * from products where price > 12
                                   order by price" type=html]
                                   [/query] </TABLE>
list                               This allows you to use subtags to
                                   control the query output and
                                   pagination. See the Subtags
                                   section above for detail.
row_count                          This causes the tag to return the
                                   number of rows in the query
                                   result.
textref                            This causes the tag to return a
                                   the query results as a serialized
                                   array of arrays that Perl can
                                   evaluate with its eval() function.
                                   Here is an illustrative example:
                                   my $rows = eval( $Tag->query( {
                                   sql => "select * from products"
                                   type => "textref" } ) ); my $r3_c0
                                   = $rows->[3]->[0];

If you do not specify a type, the tag will create an arrayref as if
you had set 'arrayref=""'.

97.57.2.6. arrayref and hashref
-------------------------------

If you set 'arrayref=keyname' or 'hashref=keyname', the query will not
return results to the page. Instead, it will place the results of your
query in the $Vend::Interpolate::Tmp hash. Using 'arrayref=my_query'
sets $Vend::Interpolate::Tmp->{my_query} to refer to an array of array
references, while 'hashref=my_query' creates an array of hash
references.

Note that this is useful only if you intend to access the results
within Perl code (for example, within a [perl] tag), since there is no
direct output to the returned page.

The $Vend::Interpolate::Tmp hash persists only for the life of the
template page being processed. If you need the query results array
reference to outlive the page, you will have to save the reference
somewhere more persistent such as the $Session hash:

   $Session->{my_query} = $Vend::Interpolate::Tmp->{my_query};

Beware the impact on performance if you do this with large result
sets.

Technical note - the string returned by the 'textref' type will eval()
to the 'arrayref' data structure.

97.57.2.7. more
---------------

Requires 'type=list'.

You must set more=1 to properly paginate your results from list
queries (see 'type=list' above. If you do not set more=1, then the
links to later pages will merely redisplay the first page of your
results.

97.57.2.8. form variable abbreviations
--------------------------------------

Requires 'type=list'.

See the Search and Form Variables appendix for a list of form
variables. Note that you must use the two-letter abbreviation rather
than the full form variable name.

A few deserve special mention:

Abbr                   Name                    Description
...................... ....................... ...................... 
ml                     mv_matchlimit           Sets number of rows to
                                               return. If paginating
                                               (more=1), sets rows
                                               returned per page.
fm                     mv_first_match          Start displaying
                                               search at specified
                                               match
sp                     mv_search_page          Sets the page for
                                               search display
st                     mv_searchtype           Forces a specific
                                               search type (text,
                                               glimpse, db or sql),
                                               overriding the default
                                               determined from your
                                               database
                                               implementation.

97.57.2.9. 
-----------

Requires 'type=list'.

Setting 'prefix=foo' overrides the default prefix of 'sql' for loop
subtags within a list region (see Looping tags and Sub-tags).

See the list_prefix attribute below for an illustrative example.

97.57.2.10. list_prefix
-----------------------

Requires 'type=list'.

Setting 'list_prefix=bar' overrides the default region tagname of
'list'. The best way to show this is by example. Compare the following
two examples of list queries, the first using the defaults and the
second with explicitly set prefix and list_prefix.

    [query sql="select sku, description, price from products
               where price < 20"
         type=list
         more=1
           ml=10]

      [on_match]Matched<br>[/on_match]
      [no_match]Not Found<br>[/no_match]

      [list]
        [sql-code] [sql-param description] [sql-price]
      [/list]

      [more_list]
        [more]
      [/more_list]
    [/query]
---
    [query  sql="select sku, description, price from products
                where price < 20"
           type=list
         prefix=foo
    list_prefix=bar
           more=1
             ml=10]

      [on_match]Matched<br>[/on_match]
      [no_match]Not Found<br>[/no_match]

      [bar]
        [foo-code] [foo-param description] [foo-price]
      [/bar]

      [more_list]
        [more]
      [/more_list]
    [/query]

97.57.2.11. random
------------------

Requires 'type=list'.

You can use the 'random' attribute to randomly select a set of rows
from the whole result set of your query. In other words, setting
'random=n', where n > 0, causes the [list] region to loop over n
randomly chosen rows rather than the full query result set.

The example below would display three randomly chosen products priced
under 20.

    [query sql="select * from products
               where price < 20"
         type=list
       random=3]

      [list]
        [sql-code] [sql-param description] [sql-price]
      [/list]

    [/query]

97.57.2.12. safe_data
---------------------

Requires 'type=list'.

Note - you should not set this unless you need it and know what you
are doing.

Setting 'safe_data=1' allows the [sql-data] tag to return values
containing the '[' character. See also Looping tags and Sub-tags.

Beware of reparsing issues.

97.57.2.13. label
-----------------

Requires 'type=list'.

If you are setting up multiple simultaneously active search objects
within a page, this allows you to distinguish them. The default label
is 'current'. Most people will not need this.

97.57.2.14. form
----------------

Requires 'type=list'.

You can use this to pass one CGI form variable in the pagination links
of a [more-list]. For example, 'form="foo=bar"' to include '&foo=bar'
in the URL of each of the pagination links.

Note that the variable will not be available in the initial result set
since the query returns the first page directly (i.e., you did not
follow a pagination link).

97.57.2.15. wantarray
---------------------

This is relevant only when calling $Tag->query( ... ) within global
Perl code such as a globalsub or global usertag where $MVSAFE::Safe is
not defined. In these cases, setting 'wantarray=1' allows the call to

  $Tag->query( { wantarray => 1, ... }, ... );

to return references as it would if called within an ordinary [perl]
tag. Note that it does not force list context if you call $Tag->query
in scalar context.

Technical note - the ordinary [query ...] ... [/query] usage forces
scalar context on the query call and suppresses the return value for
those types that would return references if $Tag->query were called
within a [perl] tag. The wantarray option is needed because global
subs and usertags are also affected by this unless you set wantarray.

97.58. read-cookie
------------------

Returns the value of the named cookie. Returns nothing if the cookie
does not exist.

97.58.1. Summary
----------------

    [read-cookie name]
    [read-cookie name=mycookie]

Attributes    Description                               Default
............. ......................................... ............. 
name          The name of the cookie whose value you    none
              want

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes
Container tag                      No

Usage example:

    [read-cookie name=MV_SESSION_ID]
---
    6CZ2whqo

ASP-like Perl call:

    $Tag->read_cookie(  { name => $name, }  );

or similarly with positional parameters,

    $Tag->read_cookie( $name );

97.58.2. Description
--------------------

This tag expands to the value of the named cookie (or nothing if the
cookie does not exist).

See the Netscape specification at
http://www.netscape.com/newsref/std/cookie_spec.html if you need more
cookie-specific detail.

97.58.2.1. name
---------------

This is the name of the cookie whose value you want to retrieve.

97.58.2.2. Parsing an HTTP_COOKIE string
----------------------------------------

If you pass this tag a second parameter within a Perl call, it will
use your value as the HTTP_COOKIE string (ignoring the real one). This
only applies if you pass the values positionally within a perl call
since there is no name for the HTTP_COOKIE string input:

  $Tag->read_cookie('MV_SESSION_ID', "MV_SESSION_ID=UnHyaDQj:127.0.0.1; ...");

97.59. restrict
---------------

Restrict tag execution in a region. If a restricted tag is
encountered, it is simply output.

97.59.1. Summary
----------------

    [restrict tag1 tag2]
    [restrict policy=deny enable="page area value"]

Attributes    Description                               Default
............. ......................................... ............. 
policy        Whether to allow or deny by default.      deny
enable        Tags to enable when default policy is     none
              deny.
disable       Tags to disable. Overrides enable.        none

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes
Container tag                      No

Usage example:

    [read-cookie name=MV_SESSION_ID]
---
    6CZ2whqo

ASP-like Perl call:

    N/A. Cannot be called effectively.

97.59.2. Description
--------------------

Restrict tag execution in a region. If a restricted tag is
encountered, it is simply output. It can be used to allow certain tags
in a user-editable region, while denying dangerous tags. Or it can be
used to restrict all tag execution in a region.

97.59.2.1. policy
-----------------

Default is deny, which makes most sense. You then specifically enable
certain ITL tags. If you set allow by default, you must be very
careful that you really are disabling all of what you consider to be
dangerous tags.

97.59.2.2. enable
-----------------

A space-separated or comma-separated list of tags to disable when the
default policy is deny. Has no effect when the default policy is
allow, and any tags passed in the disable parameter override the
enable.

97.59.2.3. disable
------------------

A space-separated or comma-separated list of tags to disable when the
default policy is allow. If you have a list of tags that are enabled,
perhaps stored in a scratch variable, you can disable some of those
tags since this takes precedence over the enable.

97.60. row
----------

97.60.1. Summary
----------------

Parameters: width

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Interpolates container text by default.

This is a container tag, i.e. [row] FOO [/row]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->row(
        {
         width => VALUE,
        },
        BODY
    )

 OR

    $Tag->row($width, $BODY);
    [row width]

Parameters    Description                               Default
............. ......................................... ............. 
width                                                   DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [row width]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->row(  { width => VALUE_width
}, $body  );

or similarly with positional parameters,

    $Tag->row(width, $attribute_hash_reference, $body);

97.60.2. Description
--------------------

Formats text in tables. Intended for use in emailed reports or
<PRE></PRE> HTML areas. The parameter nn gives the number of columns
to use. Inside the row tag, [col param=value ...] tags may be used.

97.60.2.1. [col width=nn wrap=yes|no gutter=n align=left|right|input spacing=n]
-------------------------------------------------------------------------------

Sets up a column for use in a [row]. This parameter can only be
contained inside a [row nn] [/row] tag pair. Any number of columns
(that fit within the size of the row) can be defined.

The parameters are:

    width=nn        The column width, I<including the gutter>. Must be
                    supplied, there is no default. A shorthand method
                    is to just supply the number as the I<first> parameter,
                    as in [col 20].

    gutter=n        The number of spaces used to separate the column (on
                    the right-hand side) from the next. Default is 2.

    spacing=n       The line spacing used for wrapped text. Default is 1,
                    or single-spaced.

    wrap=(yes|no)   Determines whether text that is greater in length than
                    the column width will be wrapped to the next line. Default
                    is I<yes>.

    align=(L|R|I)   Determines whether text is aligned to the left (the default),
                    the right, or in a way that might display an HTML text
                    input field correctly.

97.60.2.2. [/col]
-----------------

Terminates the column field.

97.60.2.3. width
----------------

97.61. salestax
---------------

97.61.1. Summary
----------------

Parameters: name noformat

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->salestax(
        {
         name => VALUE,
         noformat => VALUE,
        }
    )

 OR

    $Tag->salestax($name, $noformat);

Attribute aliases

            cart ==> name
    [salestax name noformat]

Parameters    Description                               Default
............. ......................................... ............. 
cart          Alias for name                            DEFAULT_VALUE
name                                                    DEFAULT_VALUE
noformat                                                DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [salestax name noformat]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->salestax(  { name => VALUE_name
                       noformat => VALUE_noformat
}, $body  );

or similarly with positional parameters,

    $Tag->salestax(name,noformat, $attribute_hash_reference, $body);

97.61.2. Description
--------------------

Expands into the sales tax on the subtotal of all the items ordered so
far for the cart, default cart is main. If there is no key field to
derive the proper percentage, such as state or zip code, it is set to
0. If the noformat tag is present and non-zero, the raw number with no
currency formatting will be given.

97.61.2.1. name
---------------

97.61.2.2. noformat
-------------------

97.62. scratch
--------------

97.62.1. Summary
----------------

Parameters: name

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->scratch(
        {
         name => VALUE,
        }
    )

 OR

    $Tag->scratch($name);
    [scratch name]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [scratch name]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->scratch(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->scratch(name, $attribute_hash_reference, $body);

97.62.2. Description
--------------------

Returns the contents of a scratch variable to the page. (A scratch
variable is set with a [set] value [/set] container pair.)

97.62.2.1. name
---------------

97.63. scratchd
---------------

Deletes the named scratch variable and returns its value before the
deletion. For example,

    [scratchd varname_to_delete]

deletes the scratch variable varname_to_delete.

See also the scratch and set tags.

97.63.1. Summary
----------------

    [scratchd P_PARAM]
    [scratchd N_PARAM other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
name          Name of scratch variable to delete        None

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes
Container tag                      No

Tag expansion example:

    [set myvar]This is myvar[/set]
    .
    .
    .
    [scratchd myvar]
---
    This is myvar

ASP-like Perl call:

    $Tag->scratchd($name, $attribute_hash_reference);

97.63.2. Description
--------------------

Deletes the named scratch variable and returns its value before the
deletion.

97.64. search-list
------------------

Formats results returned by a search. Must be enclosed within a
search-region. Has sub-tags (see Looping tags and Sub-tags).

97.65. search-region
--------------------

97.65.1. Summary
----------------

Parameters: arg

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [search-region] FOO [/search-region].
Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->search_region(
        {
         arg => VALUE,
        },
        BODY
    )

 OR

    $Tag->search_region($arg, $ATTRHASH, $BODY);

Attribute aliases

            args ==> arg
            params ==> arg
            search ==> arg
    [search-region arg other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
arg                                                     DEFAULT_VALUE
args          Alias for arg                             DEFAULT_VALUE
params        Alias for arg                             DEFAULT_VALUE
search        Alias for arg                             DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [search-region arg]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->search_region(  { arg => VALUE_arg
}, $body  );

or similarly with positional parameters,

    $Tag->search_region(arg, $attribute_hash_reference, $body);

97.65.2. Description
--------------------

NO Description

97.65.2.1. arg
--------------

97.66. selected
---------------

97.66.1. Summary
----------------

Parameters: name value

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->selected(
        {
         name => VALUE,
         value => VALUE,
        }
    )

 OR

    $Tag->selected($name, $value, $ATTRHASH);
    [selected name value other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
case                                                    DEFAULT_VALUE
cgi                                                     DEFAULT_VALUE
default                                                 DEFAULT_VALUE
name                                                    DEFAULT_VALUE
multiple                                                DEFAULT_VALUE
value                                                   DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [value name=example set=neato]
    <OPTION[selected example neato]>Neato
    <OPTION[selected example silly]>Silly
---
    <OPTION SELECTED>Neato
    <OPTION>Silly

97.66.2. Description
--------------------

You can provide a "memory" for drop-down menus, radio buttons, and
checkboxes with the [checked] and [selected] tags.

This will output SELECTED if the variable var_name is equal to value.
If the optional MULTIPLE argument is present, it will look for any of
a variety of values. Not case sensitive unless the optional case=1
parameter is used.

Here is a drop-down menu that remembers an item-modifier color
selection:

    <SELECT NAME="color">
    <OPTION [selected color blue]> Blue
    <OPTION [selected color green]> Green
    <OPTION [selected color red]> Red
    </SELECT>

Here is the same thing, but for a shopping-basket color selection:

    <SELECT NAME="[item-modifier-name color]">
    <OPTION [selected [item-modifier-name color] blue]> Blue
    <OPTION [selected [item-modifier-name color] green]> Green
    <OPTION [selected [item-modifier-name color] red]> Red
    </SELECT>

By default, the Values space (i.e. [value foo]) is checked - if you
want to use the volatile CGI space (i.e. [cgi foo]) use the parameter
cgi=1.

Use the parameter default=1 to specify the option that should be
marked SELECTED if the value/CGI variable has never been set.

If the parameter multiple=1 is set, the value parameter can contain
multiple (stacked) values that should be selected, separated by ASCII
null characters ("\0" in Perl).

97.66.2.1. case
---------------

97.66.2.2. cgi
--------------

97.66.2.3. default
------------------

97.66.2.4. name
---------------

97.66.2.5. multiple
-------------------

97.66.2.6. value
----------------

97.67. set
----------

97.67.1. Summary
----------------

Parameters: name

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [set] FOO [/set]. Nesting: NO

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->set(
        {
         name => VALUE,
        },
        BODY
    )

 OR

    $Tag->set($name, $BODY);
    [set name]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

ASP-like Perl call:

   $Tag->set(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->set(name, $attribute_hash_reference, $body);

97.67.2. Description
--------------------

Sets a scratch variable to value.

Most of the mv_* variables that are used for search and order
conditionals are in another namespace - they can be set by means of
hidden fields in a form.

You can set an order profile with:

  [set checkout]
  name=required
  address=required
  [/set]
  <INPUT TYPE=hidden NAME=mv_order_profile VALUE="checkout">

A search profile would be set with:

  [set substring_case]
  mv_substring_match=yes
  mv_case=yes
  [/set]
  <INPUT TYPE=hidden NAME=mv_profile VALUE="substring_case">

Any of these profile values can be set in the OrderProfile files as
well.

97.67.2.1. name
---------------

97.68. set-cookie
-----------------

Sets browser cookie(s) with the specified attributes.

97.68.1. Summary
----------------

    [set-cookie named_attributes]

Parameters must be named (no positional usage except in Perl call)

Attributes    Description                               Default
............. ......................................... ............. 
name          The name you give the cookie              none
value         The value (automatically html-escaped by  none
              Interchange)
expire        Expiration date as"Wdy, DD-Mon-YYYY       none
              HH:MM:SS GMT"
domain        Overrides the domain(s) set in            Domain(s), if
              CookieDomain                              any, defined
                                                        in the
                                                        CookieDomain
                                                        directive
path          legal URL paths for the cookie            URL path(s)
                                                        to your
                                                        catalog,
                                                        including
                                                        aliases

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes
Container tag                      No

Usage example:

    [set-cookie name=mycookie
               value="the value"
              expire="Tue, 03-Apr-2001 17:00:00 GMT"]
---
    This tag returns no value in the page

ASP-like Perl call:

    $Tag->set_cookie(  { name   => $name,
                         value  => $value,
                         expire => $expire,
                         domain => $domain,
                         path   => $path, }  );

or similarly with positional parameters,

    $Tag->set_cookie( $name, $value, $expire, $domain, $path );

97.68.2. Description
--------------------

This tag sets one or more browser cookies with your specified name,
value, and expiration. (Interchange will set more than one cookie if
needed to ensure that the cookie is visible from all Catalog URL path
aliases and CookieDomains.)

See the Netscape specification at
http://www.netscape.com/newsref/std/cookie_spec.html for more
cookie-specific detail.

If you need access to the cookie from outside of your Interchange
catalog, you can also set the domain and URL paths for which the
cookie will be valid. If you need the cookie only within your catalog
and the domains specified by the CookieDomain directive, you probably
should not override the Interchange domain and path defaults.

97.68.2.1. name
---------------

This is the name of the cookie. This is the key you will use when
reading the cookie later.

97.68.2.2. value
----------------

This is the value to store in the cookie.

97.68.2.3. expire
-----------------

Persistent cookies (that outlive a browser session) require an
expiration date. The date must be a string of the form:

     "Wdy, DD-Mon-YYYY HH:MM:SS GMT"

and the timezone must be GMT.

If you do not supply a date, the cookie will disappear when the user
closes the browser.

97.68.2.4. domain
-----------------

The value you set will override the Interchange default domain(s). You
might set this if you need access to the cookie from outside the
Interchange catalog, but it is usually better to set the CookieDomain
directive in your catalog.

The default is to use your catalog's domain or all CookieDomain
values.

97.68.2.5. path
---------------

The value you set will override the Interchange default URL path(s).

The default is to set a cookie with a path for each catalog alias (see
the Catalog directive). This ensures that the cookie will be visible
regardless of how the end user returns to your catalog.

97.69. seti
-----------

97.69.1. Summary
----------------

Parameters: name

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Interpolates container text by default.

This is a container tag, i.e. [seti] FOO [/seti]. Nesting: NO

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->seti(
        {
         name => VALUE,
        },
        BODY
    )

 OR

    $Tag->seti($name, $BODY);
    [seti name]value[/seti]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [seti name]value[/seti]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->seti(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->seti(name, $attribute_hash_reference, $body);

97.69.2. Description
--------------------

Equivalent to the [set] tag, except that it interpolates by default.

97.69.2.1. name
---------------

97.70. setlocale
----------------

Sets locale and/or currency for the current page. Can be made
persistent for the user with the 'persist' option. Resets default
locale if called without arguments.  See also Setting the Locale in
the template documentation.

97.70.1. Summary
----------------

    [setlocale]

Parameters    Description                               Default
............. ......................................... ............. 
currency      The currency format to use.Default:       DEFAULT_VALUE
              [scratch mv_currency] (see also 'persist'
              attribute)
locale        The locale to use.Default: [scratch       DEFAULT_VALUE
              mv_locale] (see also 'persist' attribute)
persist       Setting 'persist=1' also sets the scratch DEFAULT_VALUE
              variables, mv_locale and mv_currency to
              specified locale and currency. This makes
              the locale settings persistent for the
              user's session. Otherwise (persist=0),
              the setlocale tag affects the remainder
              of the current page only.

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [setlocale]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->setlocale(  {
}, $body  );

or similarly with positional parameters,

    $Tag->setlocale(, $attribute_hash_reference, $body);

97.70.2. Description
--------------------

Immediately sets the locale to locale, and will cause it to persist in
future user pages if the persist is set to a non-zero, non-blank
value. If the currency attribute is set, the pricing and
currency-specific locale keys and Interchange configuration directives
are modified to that locale. If there are no arguments, it sets it
back to the user's default locale as defined in the scratch variables
mv_locale and mv_currency.

This allows:

    Dollar Pricing:

    [setlocale en_US]
    [item-list]
    [item-code]: [item-price]<BR>
    [/item-list]

    Franc Pricing:

    [setlocale fr_FR]
    [item-list]
    [item-code]: [item-price]<BR>
    [/item-list]

    [comment] Return to the user's default locale [/comment]
    [setlocale]

97.70.2.1. currency
-------------------

The currency format to use.

o    Default: [scratch mv_currency] (see also 'persist' attribute)

97.70.2.2. locale
-----------------

The locale to use.

o    Default: [scratch mv_locale] (see also 'persist' attribute)

97.70.2.3. persist
------------------

Setting 'persist=1' also sets the scratch variables, mv_locale and
mv_currency to specified locale and currency. This makes the locale
settings persistent for the user's session. Otherwise (persist=0), the
setlocale tag affects the remainder of the current page only.

97.71. shipping
---------------

Returns the cost of shipping the items in the cart via the shipping
mode set with the mode parameter. See also the Shipping section of the
Database documentation.

97.71.1. Summary
----------------

    [shipping mode]

Parameters    Description                               Default
............. ......................................... ............. 
add           Adds the argument to add as data for a    DEFAULT_VALUE
              shipping.asc file (in
              $Vend::Cfg->{ScratchDir}/) and sets it.
cart          Alias: carts Comma-delimited list of      DEFAULT_VALUE
              names of carts to calculate shipping cost
              for.Default: current cart
carts         Alias for cart                            DEFAULT_VALUE
convert       Applies the conversion (if any) set with  DEFAULT_VALUE
              the PriceDivide catalog configuration
              directive.Default: True
default       Resets shipping mode to default of [value DEFAULT_VALUE
              mv_shipmode]
file          Filename to read shipping from (default   DEFAULT_VALUE
              is usual shipping database, e.g.,
              shipping.asc)
format        Format for results with label             DEFAULT_VALUE
              attribute.Default: '<OPTION
              VALUE="%M"%S>%D (%F)'For example,
              [shipping mode="FLAT" label=1 format="My
              Format Desc %D Price %F"]
handling      Boolean-- use [value mv_handling] rather  DEFAULT_VALUE
              than [value mv_shipping] as first default
              for mode. Note that this attribute
              matters only if you do not specify the
              mode in the tag.Note that this is set by
              the [handling tag (which calls the
              shipping tag internally). You should
              probably use the handling tag rather than
              setting this directly.Default: False
hide          Suppresses output                         DEFAULT_VALUE
label         By default, returns HTML <OPTION ...>     DEFAULT_VALUE
              widget for shipping mode(s), including
              description and cost. You can override
              the widget with the format attribute.
              Note that label overrides noformat.Here
              is an example from the foundation
              checkout.html page: [shipping label=1
              mode=|[data table=country key='[default
              country US]' col=shipmodes]| ]
mode          Aliases: name, modes Whitespace, null or  DEFAULT_VALUE
              comma delimited list of modes for which
              to calculate shipping cost. See also
              mv_shipmode.Default: [value mv_handling]
              if handling=1 or [value mv_shipmode] or
              'default'
modes         Alias for mode                            DEFAULT_VALUE
name          Alias for mode                            DEFAULT_VALUE
noformat      Returns result as a number rather than a  DEFAULT_VALUE
              string formatted for the current locale's
              currency.Default: True
reset_message Boolean. Blanks the session's current     DEFAULT_VALUE
              shipping message (i.e.,
              $Session->{ship_message}).
reset_modes   Clears list of modes in                   DEFAULT_VALUE
              $Vend::Cfg->{Shipping_line}Default: False
table         Alias: tables Whitespace-delimited list   DEFAULT_VALUE
              of tables containing shipping data
              required for perl or query calculations
              (e.g., in the 'PERL' field of your
              shipping database - see Shipping). You
              must specify the tables to get past the
              Perl 'Safe.pm' protection. For example,
              you will get 'Safe' errors if you refer
              to an SQL table without specifying it
              here.Default: None
tables        Alias for table                           DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [shipping mode]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->shipping(  { mode => VALUE_mode
}, $body  );

or similarly with positional parameters,

    $Tag->shipping(mode, $attribute_hash_reference, $body);

97.71.2. Description
--------------------

This tag calculates the shipping cost for items in the current cart
via the specified shipping mode (usually set in the mv_shipmode
variable).  See the Shipping section of the Database documentation for
detail.

97.71.2.1. Rounding
-------------------

Note that the tag rounds the calculated shipping cost to a
locale-specific number of fractional digits (e.g., to the nearest
penny, or 2 digits after the decimal point in the USA).

97.71.2.2. add
--------------

Adds the argument to add as data for a shipping.asc file (in
$Vend::Cfg->{ScratchDir}/) and sets it.

97.71.2.3. cart
---------------

o    Alias: carts Comma-delimited list of names of carts to calculate
     shipping cost for.

o    Default: current cart

97.71.2.4. convert
------------------

Applies the conversion (if any) set with the PriceDivide catalog
configuration directive.

o    Default: True

97.71.2.5. default
------------------

Resets shipping mode to default of [value mv_shipmode]

97.71.2.6. file
---------------

Filename to read shipping from (default is usual shipping database,
e.g., shipping.asc)

97.71.2.7. format
-----------------

Format for results with label attribute.

o    Default: '<OPTION VALUE="%M"%S>%D (%F)'

o    For example,

    [shipping mode="FLAT"
             label=1
            format="My Format Desc %D Price %F"]

97.71.2.8. handling
-------------------

Boolean-- use [value mv_handling] rather than [value mv_shipping] as
first default for mode. Note that this attribute matters only if you
do not specify the mode in the tag.

o    Note that this is set by the [handling tag (which calls the
     shipping tag internally).  You should probably use the handling
     tag rather than setting this directly.

o    Default: False

97.71.2.9. hide
---------------

Suppresses output

97.71.2.10. label
-----------------

By default, returns HTML <OPTION ...> widget for shipping mode(s),
including description and cost. You can override the widget with the
format attribute.  Note that label overrides noformat.

o    Here is an example from the foundation checkout.html page:

    [shipping
        label=1
        mode=|[data table=country key='[default country US]' col=shipmodes]|
    ]

97.71.2.11. mode
----------------

o    Aliases: name, modes Whitespace, null or comma delimited list of
     modes for which to calculate shipping cost.  See also
     mv_shipmode.

o    Default: [value mv_handling] if handling=1 or [value mv_shipmode]
     or 'default'

97.71.2.12. noformat
--------------------

Returns result as a number rather than a string formatted for the
current locale's currency.

o    Default: True

97.71.2.13. reset_message
-------------------------

Boolean. Blanks the session's current shipping message (i.e.,
$Session->{ship_message}).

97.71.2.14. reset_modes
-----------------------

Clears list of modes in $Vend::Cfg->{Shipping_line}

o    Default: False

97.71.2.15. table
-----------------

o    Alias: tables Whitespace-delimited list of tables containing
     shipping data required for perl or query calculations (e.g., in
     the 'PERL' field of your shipping database - see Shipping). You
     must specify the tables to get past the Perl 'Safe.pm'
     protection. For example, you will get 'Safe' errors if you refer
     to an SQL table without specifying it here.

o    Default: None

97.72. shipping-desc
--------------------

Returns the shipping description for the specified shipping mode.  See
the Shipping section of the Database documentation.  See also
shipping.asc database for shipping modes.

Alias: shipping-description

The two tags below are identical in operation:

   [shipping-desc mode]
   [shipping-description mode]

97.72.1. Summary
----------------

    [shipping-desc mode]
    [shipping-desc mode=shipping_mode]

Parameters    Description                 Default
............. ........................... ........................... 
mode          Shipping mode. This is a    mv_shipmode, or 'default'
              key into the shipping.asc   if mv_shipmode not set
              database. See Shipping
              documentation.

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes, but only if no mode given
Container tag                      No

Tag expansion example:

    [shipping-desc 1DM]
---
    UPS Next Day Air Early AM

ASP-like Perl call:

    $Tag->shipping_desc( $mode );

97.73. soap
-----------

97.73.1. Summary
----------------

Parameters: call uri proxy

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->soap(
        {
         call => VALUE,
         uri => VALUE,
         proxy => VALUE,
        }
    )

 OR

    $Tag->soap($call, $uri, $proxy, $ATTRHASH);
    [soap call uri proxy other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
call                                                    DEFAULT_VALUE
proxy                                                   DEFAULT_VALUE
uri                                                     DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [soap call uri proxy]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->soap(  { call => VALUE_call
                   proxy => VALUE_proxy
                   uri => VALUE_uri
}, $body  );

or similarly with positional parameters,

    $Tag->soap(call,uri,proxy, $attribute_hash_reference, $body);

97.73.2. Description
--------------------

NO Description

97.73.2.1. call
---------------

97.73.2.2. proxy
----------------

97.73.2.3. uri
--------------

97.74. strip
------------

Strips leading and trailing whitespace from the contained body text.

97.74.1. Summary
----------------

    [strip]
       Body text to strip
    [/strip]

No parameters.

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      Yes
Has Subtags                        No

ASP-like Perl call:

   $Tag->strip($BODY);

or even better, just do it directly like this

   $BODY =~ s/^\s+//;
   $BODY =~ s/\s+$//;

97.75. subtotal
---------------

97.75.1. Summary
----------------

Parameters: name noformat

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->subtotal(
        {
         name => VALUE,
         noformat => VALUE,
        }
    )

 OR

    $Tag->subtotal($name, $noformat);

Attribute aliases

            cart ==> name
    [subtotal name noformat]

Parameters    Description                               Default
............. ......................................... ............. 
cart          Alias for name                            DEFAULT_VALUE
name                                                    DEFAULT_VALUE
noformat                                                DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [subtotal name noformat]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->subtotal(  { name => VALUE_name
                       noformat => VALUE_noformat
}, $body  );

or similarly with positional parameters,

    $Tag->subtotal(name,noformat, $attribute_hash_reference, $body);

97.75.2. Description
--------------------

Positional: [subtotal cart* noformat*]

mandatory: NONE

optional: cart noformat

Expands into the subtotal cost, exclusive of sales tax, of all the
items ordered so far for the optional cart. If the noformat tag is
present and non-zero, the raw number with no currency formatting will
be given.

97.75.2.1. name
---------------

97.75.2.2. noformat
-------------------

97.76. tag
----------

97.76.1. Summary
----------------

Parameters: op arg

Positional parameters in same order.

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [tag] FOO [/tag]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->tag(
        {
         op => VALUE,
         arg => VALUE,
        },
        BODY
    )

 OR

    $Tag->tag($op, $arg, $ATTRHASH, $BODY);

Attribute aliases

            description ==> arg
    [tag op arg other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
arg                                                     DEFAULT_VALUE
description   Alias for arg                             DEFAULT_VALUE
op                                                      DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [tag op arg]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->tag(  { arg => VALUE_arg
                  op => VALUE_op
}, $body  );

or similarly with positional parameters,

    $Tag->tag(op,arg, $attribute_hash_reference, $body);

97.76.2. Description
--------------------

Performs any of a number of operations, based on the presence of arg.
The arguments that may be given are:

97.76.2.1. export database file* type*
--------------------------------------

Exports a complete Interchange database to its text source file (or
any specified file). The integer n, if specified, will select export
in one of the enumerated Interchange export formats. The following tag
will export the products database to products.txt (or whatever you
have defined its source file as), in the format specified by the
Database directive:

    [tag export products][/tag]

Same thing, except to the file products/new_products.txt:

    [tag export products products/newproducts.txt][/tag]

Same thing, except the export is done with a PIPE delimiter:

    [tag export products products/newproducts.txt 5][/tag]

The file is relative to the catalog directory, and only may be an
absolute path name if NoAbsolute is set to No.

97.76.2.2. flag arg
-------------------

Sets an Interchange condition.

The following enables writes on the products and sizes databases held
in Interchange internal DBM format:

    [tag flag write]products sizes[/tag]

SQL databases are always writable if allowed by the SQL database
itself - in-memory databases will never be written.

The [tag flag build][/tag] combination forces static build of a page,
even if dynamic elements are contained. Similarly, the [tag flag
cache][/tag] forces search or page caching (not usually wise).

97.76.2.3. log dir/file
-----------------------

Logs a message to a file, fully interpolated for Interchange tags. The
following tag will send every item code and description in the user's
shopping cart to the file logs/transactions.txt:

    [tag log logs/transactions.txt]
    [item-list][item-code]  [item-description]
    [/item-list][/tag]

The file is relative to the catalog directory, and only may be an
absolute path name if NoAbsolute is set to No.

97.76.2.4. mime description_string
----------------------------------

Returns a MIME-encapsulated message with the boundary as employed in
the other mime tags, and the description_string used as the
Content-Description. For example

   [tag mime My Plain Text]Your message here.[/tag]

will return

  Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
  Content-ID: [sequential, lead as in mime boundary]
  Content-Description: My Plain Text

  Your message here.

When used in concert with [tag mime boundary], [tag mime header], and
[tag mime id], allows MIME attachments to be included - typically with
PGP-encrypted credit card numbers. See the demo page ord/report.html
for an example.

97.76.2.5. mime boundary
------------------------

Returns a MIME message boundary with unique string keyed on session
ID, page count, and time.

97.76.2.6. mime header
----------------------

Returns a MIME message header with the proper boundary for that
session ID, page count, and time.

97.76.2.7. mime id
------------------

Returns a MIME message id with the proper boundary for that session
ID, page count, and time.

97.76.2.8. show_tags
--------------------

The encased text will not be substituted for with Interchange tags,
with < and [ characters changed to &#lt; and &#91; respectively.

    [tag show_tags][value whatever][/tag]

97.76.2.9. time
---------------

Formats the current time according to POSIX strftime arguments. The
following is the string for Thursday, April 30, 1997.

    [tag time]%A, %B %d, %Y[/tag]

97.76.2.10. touch
-----------------

Touches a database to allow use of the tag_data() routine in
user-defined subroutines. If this is not done, the routine will error
out if the database has not previously been accessed on the page.

    [tag touch products][/tag]

97.76.2.11. arg
---------------

97.76.2.12. op
--------------

97.77. time
-----------

97.77.1. Summary
----------------

Parameters: locale

Positional parameters in same order.

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [time] FOO [/time]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->time(
        {
         locale => VALUE,
        },
        BODY
    )

 OR

    $Tag->time($locale, $ATTRHASH, $BODY);
    [time locale other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
adjust        Temporarily adjust the time for display   none
              purposes.
gmt           Display time as GMT.                      none
locale        Format the time according to the named    none
              locale.
tz            Use the passed timezone to display the    none
              time.
zerofix       Strips leading zeroes from numbers.       none

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [time locale]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->time(  { locale => VALUE_locale
}, $body  );

or similarly with positional parameters,

    $Tag->time(locale, $attribute_hash_reference, $body);

97.77.2. Description
--------------------

Formats the current time according to POSIX strftime arguments. The
following is the string for Monday, January 1, 2001.

    [time]%A, %B %d, %Y[/tag]

See the strftime man page for information on the arguments (which are
the same as modern UNIX date commands).

Accepts the following options:

97.77.2.1. adjust
-----------------

If you wish to temporarily adjust the time for display purposes, you
can pass an adjust parameter with the number of hours (plus or minus).

        [time]%c[/time]
        [time adjust="-3"]%c[/time]

Will display:

 Mon 01 Jan 2001 11:29:03 AM EST
 Mon 01 Jan 2001 08:29:03 AM EST

If the number ends in zero and has 3 digits or more, it is assumed
that the number is in timezone format (i.e +500) the local time or
from GMT:

        [time]%c[/time]
        [time adjust="-330"]%c[/time]
        [time adjust="-300"]%c[/time]

Will display:

 Mon 01 Jan 2001 11:29:03 AM EST
 Mon 01 Jan 2001 07:59:03 AM EST
 Mon 01 Jan 2001 08:29:03 AM EST

If you want to force the number to be just a number of hours, add the
hours parameter:

        [time]%c[/time]
        [time adjust="100" hours=1]%c[/time]

Will display:

 Mon 01 Jan 2001 11:29:03 AM EST
 Fri 05 Jan 2001 15:29:03 PM EST

If adjust is an Interchange time duration with a suffix of sec, min,
hrs, days, or weeks, that will be used.

        [time]%c[/time]
        [time adjust="2 days"]%c[/time]

Will display:

 Mon 01 Jan 2001 11:29:03 AM EST
 Wed 03 Jan 2001 11:29:03 AM EST

Note that the time zone does not change - you should either pick a
format which doesn't display zone, use the tz parameter, or manage it
yourself.

NOTE: You can adjust time globally for an Interchange installation by
setting the $ENV{TZ} variable on many systems. Set TZ in your
environment and then restart Interchange:

        ## bash/ksh/sh
        TZ=PST7PDT; export TZ
        interchange -restart

        ## csh/tcsh
        setenv TZ PST7PDT
        interchange -restart

On most modern UNIX systems, all times will now be in the PST zone.

97.77.2.2. gmt
--------------

If you want to display time as GMT, use the gmt parameter:

        [time]%c[/time]
        [time gmt=1]%c[/time]

will display:

        Mon 01 Jan 2001 11:33:26 AM EST
        Mon 01 Jan 2001 04:33:26 PM EST

Once again, the zone will not be set to GMT, so you should pick a
format string which doesn't use zone, use the tz parameter, or manage
it yourself.

97.77.2.3. locale
-----------------

Format the time according to the named locale, assuming that locale is
available on your operating system. For example, the following:

        [time locale=en_US]%B %d, %Y[/time]
        [time locale=fr_FR]%B %d, %Y[/time]

should display:

        January 01, 2001
        janvier 01, 2001

97.77.2.4. tz
-------------

Use the passed timezone to display the time. Will adjust for hours
difference.

Example:

        [time tz=GMT0]
        [time tz=CST6CDT]
        [time tz=PST8PDT]

will display:

        Mon 01 Jan 2001 04:43:02 PM GMT
        Mon 01 Jan 2001 10:43:02 AM CST
        Mon 01 Jan 2001 08:43:02 AM PST

Note that the first alphabetical string is the zone name when not
under daylight savings time, the digit is the number of hours
displacement from GMT, and the second alphabetical string is the zone
name when in daylight savings time. NOTE: This may not work on all
operating systems.

97.77.2.5. zerofix
------------------

Strips leading zeroes from numbers.

97.78. timed-build
------------------

97.78.1. Summary
----------------

Parameters: file

Positional parameters in same order.

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [timed-build] FOO [/timed-build].
Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->timed_build(
        {
         file => VALUE,
        },
        BODY
    )

 OR

    $Tag->timed_build($file, $ATTRHASH, $BODY);
    [timed-build file other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
auto          Turn on automatic region processing.      none
file          Name of the cache file.                   none
if            Conditional display of the cached region. none
minutes       Number of minutes after which the timed   60
              build should be repeated.
period        Alternative way of expressing time.       none

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [timed-build file]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->timed_build(  { file => VALUE_file
}, $body  );

or similarly with positional parameters,

    $Tag->timed_build(file, $attribute_hash_reference, $body);

97.78.2. Description
--------------------

Allows you to build CPU-intensive regions of ITL tags on a timed
basis.

In the simplest case, surround a region of ITL with [timed-build] and
[/timed-build]:

        [timed-build]
                Built at [time]%c[/time].
        [/timed-build]

If a file parameter is not passed, saves to the directory timed in
catalog root, with the file name of the current page. If the minutes
parameter is not passed specifying how often the page should be
rebuilt, then it will not be rebuilt until the output file is removed.

Accepts the following parameters:

97.78.2.1. auto
---------------

Turns on automatic region processing. The text of the timed-build
region is processed to determine a unique checksum or digest (using
MD5), and that file name is checked in the directory tmp/auto-timed
(assuming ScratchDir is set to tmp). If no number of minutes is
supplied, 60 is assumed.

This is designed to automatically build regions of commonly used areas
without having to manage the file name yourself.

Implies login=1, but will still abort if no session ID cookie has been
sent. Use force=1 to ignore cookie status.

97.78.2.2. file
---------------

Name of the file to save the results in. Relative to catalog root. The
directory must exist.

97.78.2.3. if
-------------

Allows you to to only display the cached region when the if parameter
is true. For example, you can do:

        [timed-build if="[value timed]"]
        ITL tags....
        [/timed-build]

The cached region will only be displayed if the variable timed is set
to a non-zero, non-blank value. Otherwise, the ITL tags will be
re-interpreted every time.

97.78.2.4. minutes
------------------

The number of minutes after which the timed build should be repeated.
If set to 0, it will be built once and then not rebuilt until the
output file is removed.

97.78.2.5. period
-----------------

Alternative way of expressing time. You can pass a string describing
the rebuild time period:

        [timed-build period="4 hours"]
        ITL tags....
        [/timed-build]

This is really the same as minutes=240. Useful for passing seconds:

        [timed-build period="5 seconds"]
        ITL tags....
        [/timed-build]

The region will be rebuilt every 5 seconds.

Performance Tip: use minutes of .08 instead; avoids having to parse
the period string.

If you have the StaticDir catalog.cfg parameter set to a writable
path, you can build a cached static version of your catalog over time.
Simply place a [timed-build] tag at the top of pages you wish to build
statically. Assuming the catalog is not busy and write lock can be
obtained, the StaticDBM database will be updated to mark the page as
static and the next time a link is made for that page the static
version will be presented.

97.79. tmp
----------

97.79.1. Summary
----------------

Parameters: name

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Interpolates container text by default.

This is a container tag, i.e. [tmp] FOO [/tmp]. Nesting: NO

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->tmp(
        {
         name => VALUE,
        },
        BODY
    )

 OR

    $Tag->tmp($name, $BODY);

    [tmp name]value[/tmp]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        Yes
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [tmp name]value[/tmp]

ASP-like Perl call:

   $Tag->tmp(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->tmp(name, $attribute_hash_reference, $body);

97.79.2. Description
--------------------

Sets a Scratch variable to the value specified in the tag body. This
is just as the [seti] tag would do it, except that the name is added
to the list of Scratch keys that are to be deleted immediately after
the current page has been processed and served. This saves session
write time in many cases.

This tag interpolates automatically. (Interpolation can be turned off
with interpolate=0.) See also: [tmpn].

IMPORTANT NOTE: the [tmp ...][/tmp] tag is not appropriate for setting
order profiles or mv_click actions. If you want to avoid that, use a
profile stored via the catalog.cfg directive OrderProfile.

97.79.2.1. name
---------------

97.80. tmpn
-----------

97.80.1. Summary
----------------

Parameters: name

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [tmpn] FOO [/tmpn]. Nesting: NO

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->tmpn(
        {
         name => VALUE,
        },
        BODY
    )

 OR

    $Tag->tmpn($name, $BODY);

    [tmpn name]value[/tmp]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      Yes
Has Subtags                        No
Nests                              No

ASP-like Perl call:

   $Tag->tmpn(  { name => VALUE_name
}, $body  );

or similarly with positional parameters,

    $Tag->tmpn(name, $attribute_hash_reference, $body);

97.80.2. Description
--------------------

Equivalent to the [tmp] tag, except that it does not interpolate by
default.

NOTE: This tag was introduced in Interchange 4.9 and is therefore not
available in earlier versions.

97.80.2.1. name
---------------

97.81. total-cost
-----------------

97.81.1. Summary
----------------

Parameters: name noformat

Positional parameters in same order.

Pass attribute hash as last to subroutine: no

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->total_cost(
        {
         name => VALUE,
         noformat => VALUE,
        }
    )

 OR

    $Tag->total_cost($name, $noformat);

Attribute aliases

            cart ==> name
    [total-cost name noformat]

Parameters    Description                               Default
............. ......................................... ............. 
cart          Alias for name                            DEFAULT_VALUE
name                                                    DEFAULT_VALUE
noformat                                                DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [total-cost name noformat]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->total_cost(  { name => VALUE_name
                         noformat => VALUE_noformat
}, $body  );

or similarly with positional parameters,

    $Tag->total_cost(name,noformat, $attribute_hash_reference, $body);

97.81.2. Description
--------------------

Expands into the total cost of all the items in the current shopping
cart, including sales tax (if any).

97.81.2.1. name
---------------

97.81.2.2. noformat
-------------------

97.82. tree
-----------

97.82.1. Summary
----------------

Parameters: table master subordinate start

The attribute hash reference is passed after the parameters but before
the container text argument. This may mean that there are parameters
not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

This is a container tag, i.e. [tree] FOO [/tree]. Nesting: NO

Invalidates cache: no

Called Routine:

ASP-like Perl call:

    $Tag->tree(
        {
         table => VALUE,
         master => VALUE,
         subordinate => VALUE,
         start => VALUE,
        },
        BODY
    )

 OR

    $Tag->tree($table, $master, $subordinate, $start, $ATTRHASH, $BODY);

Attribute aliases

            sub ==> subordinate
    [tree table master subordinate start other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
master                                                  DEFAULT_VALUE
start                                                   DEFAULT_VALUE
sub           Alias for subordinate                     DEFAULT_VALUE
subordinate                                             DEFAULT_VALUE
table                                                   DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate                        No
reparse                            Yes

Other_Characteristics
.................................. .................................. 
Invalidates cache                  no
Container tag                      Yes
Has Subtags                        No
Nests                              No

Tag expansion example:

    [tree table master subordinate start]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->tree(  { master => VALUE_master
                   start => VALUE_start
                   subordinate => VALUE_subordinate
                   table => VALUE_table
}, $body  );

or similarly with positional parameters,

    $Tag->tree(table,master,subordinate,start, $attribute_hash_reference, $body);

97.82.2. Description
--------------------

Provides iterative list capability for binary trees. It produces
hash-based rows use the same tags as [item-list]; sets some additional
hash key entries to describe the tree and provide display control.

Works on a data set with the structure:

    parent  child
    99      a
    a       b
    a       c
    a       d
    a       x
    x       y
    x       z
    99      m
    99      n
    99      o
    o       e
    o       f
    o       g

Sets several keys which assist in walking and displaying the tree.

97.82.2.1. mv_level
-------------------

Level of the item. If it is in the first level, it is 0. Sublevels are
infinite (except for performance).

97.82.2.2. mv_increment
-----------------------

Increment label for the item. Normally goes from 1...n, but can be
changed to A...Z or a...z in outline mode.

97.82.2.3. mv_children
----------------------

If in autodetect mode, set to the number of children this branch has.
If a leaf, set to 0.

97.82.2.4. mv_spacing
---------------------

A multiple of level times the spacing option. Useful for setting width
of spacer images.

The above sample data placed in a table named "tree" would produce:

    a           mv_level=0, mv_increment=1, mv_children=4
        b       mv_level=1, mv_increment=1, mv_children=0
        c       mv_level=1, mv_increment=2, mv_children=0
        d       mv_level=1, mv_increment=3, mv_children=0
        x       mv_level=1, mv_increment=4, mv_children=2
            y   mv_level=2, mv_increment=1, mv_children=0
            z   mv_level=2, mv_increment=2, mv_children=0
    m           mv_level=0, mv_increment=1, mv_children=0
    n           mv_level=0, mv_increment=2, mv_children=0
    o           mv_level=0, mv_increment=3, mv_children=3
        e       mv_level=1, mv_increment=1, mv_children=0
        f       mv_level=1, mv_increment=2, mv_children=0
        g       mv_level=1, mv_increment=3, mv_children=0

from the tag call:

        <table>
    [tree   start=99
            table=tree
            master=parent
            subordinate=child
            autodetect=1
            spacing=4
            full=1]
        <tr>
        <td>
        [if-item-param mv_level]
                [item-calc]
                        return '&nbsp' x [item-param mv_spacing];
                [/item-calc]
        [/if-item-param]
        [item-param child]
        </td>
        <td>
                mv_level=[item-param mv_level],
                mv_increment=[item-param mv_increment],
                mv_children=[item-param mv_children]
        </td>
        </tr>
        [/tree]
        </table>

Accepts the following parameters:

97.82.2.5. table
----------------

Database table which contains the tree. Must be a valid Interchange
table identifier.

97.82.2.6. master
-----------------

The column which is used to determine the parent of the item.

97.82.2.7. subordinate
----------------------

The child column, which determines which items are sub-items of the
current one. Used to re-query for items with its value in master.

97.82.2.8. start_item
---------------------

The first item to be followed, i.e. the master value of all the
top-level items.

97.82.2.9. autodetect
---------------------

Specifies that the next level should be followed to detect the number
of child items contained. Not recursive; only follows far enough to
determine the children of the current item.

97.82.2.10. full
----------------

Specifies that all items should be followed. Essentially the same as
specifying memo and passing the explode variable, but not dependent on
them. Useful for building lists for inclusion in embedded Perl, among
other things.

97.82.2.11. stop
----------------

An optional stop field which, when the value is true, can stop the
following of the branch.

97.82.2.12. continue
--------------------

An optional continue field which, when the value is true, can force
the branch to be followed.

97.82.2.13. sort
----------------

The column which should be used for ordering the items - determines
the order in which they will be displayed under the current parent.

97.82.2.14. outline
-------------------

Sets outline mode, where mv_increment will be displayed with letter
values or numeral values. If set to specifically 1, will produced
outline increments like:

    1
        A
        B
            1
            2
        C
            1
            2
                a
                b
                    1
                    2
                        a
                        b
    2

97.82.2.15. memo
----------------

Indicates that the collapse/explode/toggle features are to be used,
and names a Scratch variable where the values should be stored.

97.82.2.16. collapse
--------------------

The name of a variable in the user's session which will determine that
the tree should be "collapsed". When collapsed, the child items will
not be followed unless they are set to be followed with toggle. Zeros
all toggles.

Requires memo to be set if values are to be retained.

97.82.2.17. toggle
------------------

The name of a variable in the user's session which will determine that
the current item should be either followed or not followed. The first
time the toggle variable corresponding to its primary key is passed,
the item will be expanded. The next call will "collapse" the item.

Requires memo to be set if values are to be retained.

97.82.2.18. explode
-------------------

The name of a variable in the user's session which will determine that
the tree should be "exploded". When exploded, all child items are
followed and the full tree can be displayed.

Requires memo to be set if values are to be retained.

97.82.2.19. pedantic
--------------------

When set to a true value, and an endless tree is detected (i.e. the
child branch contains a parent) then the error will be logged to the
catalog error log and the tree call will return with an error.

If pedantic is not set (the default), the current leaf will be shown
but never followed. This allows partial display of the tree.

97.82.2.20. log_error
---------------------

When set to a true value, and an endless tree is detected (i.e. the
child branch contains a parent) then the error will be logged to the
catalog error log. No logging done by default.

97.82.2.21. show_error
----------------------

When set to a true value, and an endless tree is detected (i.e. the
child branch contains a parent) then the error will be returned in the
page. Errors are NOT shown by default.

In addition to the above values, all valid options for a list tag are
in force. For example, you can set a "SELECTED" value on an option
list with option=1, set the tag prefix with prefix, etc.

97.82.2.22. master
------------------

97.82.2.23. start
-----------------

97.82.2.24. subordinate
-----------------------

97.82.2.25. table
-----------------

97.83. try
----------

Allows you to trap errors. Interchange processes the body text of the
[try][/try] block and returns it normally if it does not generate an
error. If it does generate an error, Interchange executes the
[catch][/catch] block.

See also 'catch'.

97.83.1. Summary
----------------

    [try label=my_label other_named_attributes]
        Body text to return if no error
    [/try]
    .
    .
    .
    [catch my_label]
        Body text to return if try block caused an error
    [/catch]

Parameters    Description                               Default
............. ......................................... ............. 
label         The label shared by the paired try and    'default'
              catch blocks

Attributes             Description             Default
...................... ....................... ...................... 
status                 Returns 0 (failed) or 1 none
                       (succeeded) instead of
                       page output
hide                   Suppresses page output  No
clean                  Suppress try block      No
                       output if it has an
                       error
interpolate            See Interpolating       No
                       Parameters
reparse                See Interpolating       Yes
                       Parameters

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Container tag                      Yes

Tag expansion example:

    [set divisor]0[/set]
    [try label=div]
        [calc] 1 / [scratch divisor] [/calc]
    [/try]
    [catch div]Division error[/catch]
---
    Division Error

ASP-like Perl call:

    $Tag->try(    { label  => I<'try_catch_label'>,
                    status => 1, },
                  $try_body  );

    $Tag->catch(  { label  => I<'try_catch_label'>, },
                  $catch_body )

or similarly with positional parameters,

    $Tag->try($label, $attribute_hash_reference, $try_body);
    $Tag->catch($label, $attribute_hash_reference, $catch_body);

97.83.1.1. See Also
-------------------

catch

97.83.2. Description
--------------------

Allows you to trap errors. Interchange processes the body text of the
[try][/try] block and returns it normally if it does not generate an
error. If it does generate an error, interchange executes the
[catch][/catch] block. The catch block executes where it is on the
page (i.e., it does not replace the output of the try block).

Note that the catch block must occur after the [try] block in the
document.

97.83.2.1. label
----------------

The try and catch blocks are matched by this label.

Technical note:

The try tag will also place a result in the $Session object.  For
example, the following returns the 'Illegal division by zero...' error
message if it occurs:

    [try label=divide][calc] 1 / [scratch divisor] [/calc][/try]

    [catch divide]
        [calc]$Session->{try}{divide}[/calc]
    [/catch]

The $Session->{try}{divide} object will be set to the empty string
('') if there was no error, or it will contain the error message if
there was an error.

The [perl] and [calc] tags also set $Session->{try}->{active_label} on
errors.

97.83.2.2. status
-----------------

Suppresses try block output and returns 1 if no error or 0 if an error
occurred instead.  Executes the catch block as usual in case of an
error.

97.83.2.3. hide
---------------

Suppresses try block output (regardless of success or failure). 
Executes the catch block as usual in case of an error.

97.83.2.4. clean
----------------

Setting 'clean=1' will cause the try block to suppress its output only
if it has an error. Otherwise (clean=0 or not set), the try block will
return whatever partial output it has completed before the error.  The
catch block will work as usual.

97.84. update
-------------

Forces an update of the specified interchange function. Function may
be one of the following:

o    cart (updates current or named cart)

o    process (updates order or search)

o    values (updates user-entered fields)

o    data (updates database, using current mv_ CGI form variables)

97.84.1. Summary
----------------

    [update function]

Parameters    Description                               Default
............. ......................................... ............. 
function      cartUpdates current or named cart (see    DEFAULT_VALUE
              name attribute)processUpdates an order or
              a search pagevaluesUpdates user-entered
              fieldsdataUpdates database, using current
              mv_ CGI form variables, for
              example:mv_data_table Table to
              updatemv_data_key Key into
              tablemv_data_fields Fields to update
              (space or null delimited)mv_data_function
              One of the
              following:deleteupdateinsertdeleteetc.
name          Cart name to update (if                   DEFAULT_VALUE
              'function=cart')Default: current cart

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [update function]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->update(  { function => VALUE_function
}, $body  );

or similarly with positional parameters,

    $Tag->update(function, $attribute_hash_reference, $body);

97.84.2. Description
--------------------

Forces an update of the specified interchange function. Function may
be one of the following:

o    cart (updates current or named cart)

o    process (updates order or search)

o    values (updates user-entered fields)

o    data (updates database, using current mv_ CGI form variables)

97.84.2.1. function
-------------------

o    cart

     o    Updates current or named cart (see name attribute)

o    process

     o    Updates an order or a search page

o    values

     o    Updates user-entered fields

o    data

     o    Updates database, using current mv_ CGI form variables, for
          example:

          o    mv_data_table Table to update

          o    mv_data_key Key into table

          o    mv_data_fields Fields to update (space or null
               delimited)

          o    mv_data_function One of the following:

               o    delete

               o    update

               o    insert

               o    delete

          o    etc.

97.84.2.2. name
---------------

Cart name to update (if 'function=cart')

o    Default: current cart

97.85. userdb
-------------

97.85.1. Summary
----------------

Parameters: function

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Invalidates cache: YES

Attribute aliases

            name ==> nickname
            table ==> db
    [userdb function other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
function                                                DEFAULT_VALUE
name          Alias for nickname                        DEFAULT_VALUE
table         Alias for db                              DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [userdb function]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->userdb({
       function => VALUE
   });

or similarly with positional parameters,

    $Tag->userdb(function, $attribute_hash_reference);

97.85.2. Description
--------------------

Interchange provides a [userdb ...] tag to access the UserDB
functions.

    [userdb
        function=function_name
        username="username"*
        password="password"*
        verify="password"*
        oldpass="old password"*
        shipping="fields for shipping save"
        billing="fields for billing save"
        preferences="fields for preferences save"
        force_lower=1
        param1=value*
        param2=value*
        hide=1
        show=1
        ...
    ]

* Optional

It is normally called in an mv_click or mv_check setting, as in:

    [set Login]
    mv_todo=return
    mv_nextpage=welcome
    [userdb function=login]
    [/set]

    <FORM ACTION="[process]" METHOD=POST>
    <INPUT TYPE=hidden NAME=mv_click VALUE=Login>
    Username <INPUT NAME=mv_username SIZE=10>
    Password <INPUT NAME=mv_password SIZE=10>
    </FORM>

There are several global parameters that apply to any use of the
userdb functions. Most importantly, by default the database table is
set to be userdb. If you must use another table name, then you should
include a database=table parameter with any call to userdb. The global
parameters (default in parentheses):

    database     Sets user database table (userdb)
    hide         Hide the return value of certain functions
                 (including login, new_account, save, load)
    show         Show the return value of certain functions
                 or the error message, if any (0)
    force_lower  Force possibly upper-case database fields
                 to lower case session variable names (0)
    billing      Set the billing fields (see Accounts)
    shipping     Set the shipping fields (see Address Book)
    preferences  Set the preferences fields (see Preferences)
    bill_field   Set field name for accounts (accounts)
    addr_field   Set field name for address book (address_book)
    pref_field   Set field name for preferences (preferences)
    cart_field   Set field name for cart storage (carts)
    pass_field   Set field name for password (password)
    time_field   Set field for storing last login time (time)
    expire_field Set field for expiration date (expire_date)
    acl          Set field for simple access control storage (acl)
    file_acl     Set field for file access control storage (file_acl)
    db_acl       Set field for database access control storage (db_acl)

97.85.2.1. function
-------------------

97.85.2.2. name
---------------

97.85.2.3. table
----------------

97.86. value
------------

Returns the the current value of the named form input field.
HTML-escapes Interchange tags in the result for security.

Can also set a new value within the current page.

97.86.1. Summary
----------------

    [value name]
    [value name=form_var_name other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
name          This is the name of the form variable     None
              whose value you want.

Attributes                         Default
.................................. .................................. 
set                                none
hide                               No
filter                             none
keep (with filter)                 No
scratch                            No
default                            none
enable_html                        No
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  Yes

Tag expansion example:

Assuming form variable 'foo' = 'bar',

    [value foo]
---
    bar

ASP-like Perl call:

    $Tag->value( { name => var_name } );

    # or if you simply want the value:
    $Values->{var_name};

or similarly with positional parameters,

    $Tag->value($name, $attribute_hash_reference);

97.86.2. Description
--------------------

Usage example:

   <INPUT TYPE="text" NAME="name" VALUE="[value name]">
   <INPUT TYPE="text" NAME="name" VALUE="[value name=name]">

Expands into the current value of the named customer/form input field.
When the value is returned, any Interchange tags present in the value
will be escaped. This prevents users from entering Interchange tags in
form values, which would be a serious security risk.

97.86.2.1. name
---------------

This is the name of the form variable whose value you want.

97.86.2.2. set
--------------

You can change a value with 'set=new_value'. The tag will return the
value you set unless you also set the hide=1 attribute.

Use this to "uncheck" a checkbox or set other form variable values to
defaults. If you simply want a place to store your own data, use the
set and scratch tags instead.

Note that this is only available in new-style tags, for safety
reasons.

97.86.2.3. hide
---------------

Setting hide=1 suppresses the tag's return value, which can be useful
with the set attribute.

97.86.2.4. filter
-----------------

See the filter tag for a list of filters.

Setting 'filter="filter"' modifies the named value with the specified
filter.

97.86.2.5. keep (with filter)
-----------------------------

Set keep=1 if you want the tag to return a filtered result but do not
want the filter to modify the form value itself in the $::Values hash.

97.86.2.6. scratch
------------------

Setting 'scratch=1' places a copy of the value in the $::Scratch hash.
An illustrative example:

   foo is [value name=foo scratch=1] in the Values hash
   foo is now also [scratch foo] in the Scratch hash

97.86.2.7. default
------------------

This sets a return value in case the named value is missing or
otherwise false. The following will expand to "Using default":

    [value name=myname set=0 hide=1]
    [value name=myname default="Using default"]

97.86.2.8. enable_html
----------------------

Any '<' characters will normally be converted into '&lt;' for safety
reasons. This conversion can be disabled using 'enable_html=1'.

97.87. value-extended
---------------------

97.87.1. Summary
----------------

Parameters: name

Positional parameters in same order.

The attribute hash reference is passed to the subroutine after the
parameters as the last argument. This may mean that there are
parameters not shown here.

Must pass named parameter interpolate=1 to cause interpolation.

Invalidates cache: YES

Called Routine:

ASP-like Perl call:

    $Tag->value_extended(
        {
         name => VALUE,
        }
    )

 OR

    $Tag->value_extended($name, $ATTRHASH);
    [value-extended name other_named_attributes]

Parameters    Description                               Default
............. ......................................... ............. 
name                                                    DEFAULT_VALUE

Attributes                         Default
.................................. .................................. 
umask                              none
interpolate (reparse)              No

Other_Characteristics
.................................. .................................. 
Invalidates cache                  YES
Container tag                      No
Has Subtags                        No
Nests                              Yes

Tag expansion example:

    [value-extended name]
---
    TODO: (tag result)

ASP-like Perl call:

   $Tag->value_extended( { name => VALUE_name }, $body );

or similarly with positional parameters,

    $Tag->value_extended(name, $attribute_hash_reference, $body);

97.87.2. Description
--------------------

Named call example:

   [value-extended
            name=formfield
            outfile=filename*
            umask=octal*
            ascii=1*
            yes="Yes"*
            no="No"*
            joiner="char|string"*
            test="isfile|length|defined"*
            index="N|N..N|*"
            file_contents=1*
            maxsize=length*
            elements=1*
   ]

Expands into the current value of the customer/form input field named
by field. If there are multiple elements of that variable, it will
return the value at index; by default all joined together with a
space.

If the variable is a file variable coming from a multipart/form-data
file upload, then the contents of that upload can be returned to the
page or optionally written to the outfile.

97.87.2.1. name
---------------

Specify which value variable to deal with. If no other parameters are
present, then the value of the variable will be returned. If there are
multiple elements, then by default they will all be returned joined by
a space. If joiner is present, then they will be joined by its value.

In the special case of a file upload, the value returned is the name
of the file as passed for upload.

97.87.2.2. joiner
-----------------

The character or string that will join the elements of the array. Will
accept string literals such as "\n" or "\r".

97.87.2.3. test
---------------

Three tests: isfile returns true if the variable is a file upload.
length returns the length. defined returns whether the value has ever
been set at all on a form.

97.87.2.4. index
----------------

The index of the element to return if not all are wanted. This is
useful especially for pre-setting multiple search variables. If set to
*, will return all (joined by joiner). If a range, such as 0 .. 2,
will return multiple elements.

97.87.2.5. file_contents
------------------------

Returns the contents of a file upload if set to a non-blank, non-zero
value. If the variable is not a file, returns nothing.

97.87.2.6. maxsize
------------------

The maximum file size allowed, in bytes. If a file of greater size
than maxsize is uploaded, the tag will return false and an error will
be logged.

97.87.2.7. outfile
------------------

Names a file to write the contents of a file upload to. It will not
accept an absolute file name; the name must be relative to the catalog
directory. If you wish to write images or other files that would go to
HTML space, you must use the HTTP server's Alias facilities or make a
symbolic link.

97.87.2.8. umask
----------------

Permission mask (in octal) to apply to the uploaded file's permission
bits. You may want to set this to make a file world-readable, or to
keep it from being group-readable. See the UNIX chmod(1) manpage for
details.

97.87.2.9. ascii
----------------

To do an auto-ASCII translation before writing the outfile, set the
ascii parameter to a non-blank, non-zero value. Default is no
translation.

97.87.2.10. yes
---------------

The value that will be returned if a test is true or a file is written
successfully. Defaults to 1 for tests and the empty string for
uploads.

97.87.2.11. no
--------------

The value that will be returned if a test is false or a file write
fails. Defaults to the empty string.

98. User-defined Tags
=====================

To define a tag that is catalog-specific, place UserTag directives in
your catalog.cfg file. For server-wide tags, define them in
interchange.cfg. Catalog-specific tags take precedence if both are
defined - in fact, you can override the base Interchange tag set with
them. The directive takes the form:

   UserTag  tagname  property  value

where tagname is the name of the tag, property is the attribute
(described below), and value is the value of the property for that
tagname.

The user tags can either be based on Perl subroutines or just be
aliases for existing tags. Some quick examples are below.

An alias:

    UserTag product_name Alias     data products title

This will change [product_name 99-102] into [data products title
99-102], which will output the title database field for product code
99-102. Don't use this with [item-data ...] and [item-field ...], as
they are parsed separately. You can do [product-name [item-code]],
though.

A simple subroutine:

    UserTag company_name Routine   sub { "Your company name" }

When you place a [company-name] tag in an Interchange page, the text
Your company name will be substituted.

A subroutine with a passed text as an argument:

    UserTag caps   Routine   sub { return "\U@_" }
    UserTag caps   HasEndTag

The tag [caps]This text should be all upper case[/caps] will become
THIS TEXT SHOULD BE ALL UPPER CASE.

Here is a useful one you might wish to use:

    UserTag quick_table HasEndTag
    UserTag quick_table Interpolate
    UserTag quick_table Order   border
    UserTag quick_table Routine <<EOF
    sub {
        my ($border,$input) = @_;
        $border = " BORDER=$border" if $border;
        my $out = "<TABLE ALIGN=LEFT$border>";
        my @rows = split /\n+/, $input;
        my ($left, $right);
        for(@rows) {
            $out .= '<TR><TD ALIGN=RIGHT VALIGN=TOP>';
            ($left, $right) = split /\s*:\s*/, $_, 2;
            $out .= '<B>' unless $left =~ /</;
            $out .= $left;
            $out .= '</B>' unless $left =~ /</;
            $out .= '</TD><TD VALIGN=TOP>';
            $out .= $right;
            $out .= '</TD></TR>';
            $out .= "\n";
        }
        $out .= '</TABLE>';
    }
    EOF

Called with:

    [quick-table border=2]
    Name: [value name]
    City: [value city][if value state], [value state][/if] [value country]
    [/quick_table]

As is the case with [perl] tag, user tags run under the Perl Safe.pm
module with warnings disabled. Unlike [perl] tags, however, user tags
use Perl's 'strict' pragma.

The properties for UserTag are:

98.1. Alias
-----------

An alias for an existing (or other user-defined) tag. It takes the
form:

    UserTag tagname Alias    tag to insert

An Alias is the only property that does not require a Routine to
process the tag.

98.2. attrAlias
---------------

An alias for an existing attribute for defined tag. It takes the form:

    UserTag tagname attrAlias   alias attr

As an example, the standard Interchange value tag takes a named
attribute of name for the variable name, meaning that [value name=var]
will display the value of form field var. If you put this line in
catalog.cfg:

    UserTag value attrAlias   identifier name

then [value identifier=var] will be an equivalent tag.

98.3. CanNest
-------------

Notifies Interchange that this tag must be checked for nesting. Only
applies to tags that have HasEndTag defined, of course. NOTE: Your
routine must handle the subtleties of nesting, so don't use this
unless you are quite conversant with parsing routines. See the
routines tag_loop_list and tag_if in lib/Vend/Interpolate.pm for an
example of a nesting tag.

    UserTag tagname CanNest

98.4. HasEndTag
---------------

Defines an ending [/tag] to encapsulate your text - the text in
between the beginning [tagname] and ending [/tagname] will be the last
argument sent to the defined subroutine.

    UserTag tagname HasEndTag

98.5. Implicit
--------------

This defines a tag as implicit, meaning it can just be an attribute
instead of an attribute=value pair. It must be a recognized attribute
in the tag definition, or there will be big problems. Use this with
caution!

    UserTag tagname Implicit attribute value

If you want to set a standard include file to a fixed value by
default, but don't want to have to specify [include
file="/long/path/to/file"] every time, you can just put:

    UserTag include Implicit file file=/long/path/to/file

and [include file] will be the equivalent. You can still specify
another value with [include file="/another/path/to/file"].

98.6. Interpolate
-----------------

The behavior for this attribute depends on whether the tag is a
container (i.e. HasEndTag is defined). If it is not a container, the
Interpolate attribute causes the the resulting HTML from the UserTag
to be re-parsed for more Interchange tags. If it is a container,
Interpolate causes the contents of the tag to be parsed before the tag
routine is run.

    UserTag tagname Interpolate

98.7. InvalidateCache
---------------------

If this is defined, the presence of the tag on a page will prevent
search cache, page cache, and static builds from operating on the
page.

    UserTag tagname InvalidateCache

It does not override [tag flag build][/tag], though.

98.8. Order
-----------

The optional arguments that can be sent to the tag. This defines not
only the order in which they will be passed to Routine, but the name
of the tags. If encapsulated text is appropriate (HasEndTag is set),
it will be the last argument.

    UserTag tagname Order param1 param2

98.9. PosRoutine
----------------

Identical to the Routine argument - a subroutine that will be called
when the new syntax is not used for the call, i.e. [usertag argument]
instead of [usertag ARG=argument]. If not defined, Routine is used,
and Interchange will usually do the right thing.

98.10. Routine
--------------

An inline subroutine that will be used to process the arguments of the
tag. It must not be named, and will be allowed to access unsafe
elements only if the interchange.cfg parameter AllowGlobal is set for
the catalog.

    UserTag tagname Routine  sub { "your perl code here!" }

The routine may use a "here" document for readability:

    UserTag tagname Routine <<EOF
    sub {
        my ($param1, $param2, $text) = @_;
        return "Parameter 1 is $param1, Parameter 2 is $param2";
    }
    EOF

The usual here documents caveats apply.

Parameters defined with the Order property will be sent to the routine
first, followed by any encapsulated text (HasEndTag is set).

Note that the UserTag facility, combined with AllowGlobal, allows the
user to define tags just as powerful as the standard Interchange tags.
This is not recommended for the novice, though - keep it simple. 8-)

99. Standard Usertags
=====================

The distribution includes a number of prebuilt usertags in the usertag
directory in the Interchange software directory. Some of these are
used by the foundation catalog or its administrative interface.

99.1. bar_button
----------------

Displays content based on current page. Could be used for building
e.g. menu bars.

99.1.1. Summary
---------------

    [bar-button page current]...[selected]...[/selected][/bar-button]
    [bar-button page=page current=current-page]...[selected]...[/selected][/bar-button]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
page          Name of page for which this bar-button is none
              defined
current       Name of the current page                  Current page:
                                                        MV_PAGE

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        [/bar-button]

Tag expansion example:

To build a simple '3-button' menu bar one could put the following on
each of the pages. The results of this code for page2 are shown below.

        <table><tr>
        [bar-button page=page1]
        <TD><A HREF="[area page1]">PAGE-1</A></TD>
        [selected]
        <TD bgcolor="red"><A HREF="[area page1]"><B>PAGE-1-selected</B></A></TD>
        [/selected]
        [/bar-button]
        [bar-button page=page2]
        <TD><A HREF="[area page2]">PAGE-2</A></TD>
        [selected]
        <TD bgcolor="red"><A HREF="[area page2]"><B>PAGE-2-selected</B></A></TD>
        [/selected]
        [/bar-button]
        [bar-button page=page3]
        <TD><A HREF="[area page3]">PAGE-3</A></TD>
        [selected]
        <TD bgcolor="red"><A HREF="[area page3]"><B>PAGE-3-selected</B></A></TD>
        [/selected]
        [/bar-button]
        </tr></table>
---
        PAGE-1    PAGE-2-selected    PAGE-3

ASP-like Perl call:

    $Tag->button_bar(  { page => $page,
                     current  => $current,
                         body => $body}  );

or similarly,

    $Tag->area($page, $current, $body);

99.1.1.1. See Also
------------------

bar_link routine

99.1.2. Description
-------------------

Displays content based on current page. The content between the
[selected][/selected] tags will be displayed only if the name of the
current page matches the name that was passed to the page parameter
(page=page-name). The default content will be displayed when there is
no match.

99.1.2.1. page
--------------

The name of the page for which this definition of the bar-button is
defined.

99.1.2.2. current
-----------------

The name of the current page. Defaults to current page MV_PAGE.

99.2. button
------------

99.3. convert_date
------------------

This tag converts a given date format into another format.

99.3.1. Summary
---------------

    [convert_date day* other_named_attributes[/convert_date]
    [convert_date day=n* other_named_attributes[/convert_date]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
days          The number of days from or before today   none

Attributes                         Default
.................................. .................................. 
format                             '%d-%b-%Y %I:%M%p' or '%d-%b-%Y'
fmt - Alias for format             none
raw                                none
zerofix                            none

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        [/convert_date]

Tag expansion example:

  a. [convert-date][/convert-date]
  b. [convert-date 1][/convert-date]
  c. [convert-date -1][/convert-date]
  d. [convert-date]2001-5-1[/convert-date]
  e. [convert-date]2001-05-01[/convert-date]
  f. [convert-date]20010515[/convert-date]
  g. [convert-date raw=1]2001-05-18[/convert-date]
  h. [convert-date fmt="%d-%m-%Y"]2001-05-18[/convert-date]
  i. [convert-date]200 1 -  --051 =9[/convert-date]
  j. [convert-date]2001 -  --05 -20 11 1 5[/convert-date]
  k. [convert-date raw=1]2001-05-21 11:15[/convert-date]
---
  a. 18-May-2001 03:15AM (todays day and time)
  b. 19-May-2001 03:15AM (today + 1 day)
  c. 17-May-2001 03:15AM (today - 1 day)
  d. 01-May-2001
  e. 01-May-2001
  f. 15-May-2001
  g. 20010518
  h. 18-05-2001
  i. 19-May-2001
  j. 20-May-2001 11:15AM
  k. 200105211115

ASP-like Perl call:

    $Tag->convert_date( { days => 1 } );

    $Tag->convert_date( { body => "2001-05-19 15:35",
                       format => "%d-%m-%Y %H:%M", } );

or similarly with positional parameters,

    $Tag->convert_date( 1 );

99.3.2. Description
-------------------

This tag converts almost any given date format into another, possibly
user defined, format.

99.3.2.1. days
--------------

Number of days from or before today's date and time. Will only be used
if nothing is supplied between the tags.

99.3.2.2. format
----------------

POSIX time format string of your choice. See Unix strftime(3) manpage
for complete details.

99.3.2.3. raw
-------------

If this option is set to true, will display given date in raw format,
e.g. yyyymmdd or yyyymmddHHMM.

99.3.2.4. zerofix
-----------------

Strips leading zeroes from numbers.

99.4. db_date
-------------

This tag returns the time of last access of the database source file.

99.4.1. Summary
---------------

    [db_date table* format*]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
table         Table name.                               products
format        POSIX time format string                  %A %d %b %Y

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        No

Tag expansion example:

    [db-date]
    [db-date cat]
    [db-date table=cat format="%d %b %Y"]
---
    Wednesday 02 May 2001 (products.txt)
    Wednesday 03 May 2001 (cat.txt)
    03 May 2001 (cat.txt)

ASP-like Perl call:

    $Tag->db_date( { table => cat,
                    format => "%d %b %Y", } );

or similarly with positional parameters,

    $Tag->db_date( "cat", "%d %b %Y" );

99.4.2. Description
-------------------

This tag returns the time of last access of the database source file.

99.4.2.1. table
---------------

Table name. Defaults to products if not specified.

99.4.2.2. format
----------------

POSIX time format string. See Unix strftime(3) manpage for details.
Defaults to '%A %d %b %Y' when not specified.

99.5. delete_cart
-----------------

This tag deletes a cart from the userdb.

99.5.1. Summary
---------------

    [delete_cart nickname]
    [delete_cart nickname="cart-name"]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
nickname      Must be an existing nickname              none

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        No

Tag expansion example:

    [delete_cart mycart]
    [delete_cart nickname="mycart"]

ASP-like Perl call:

    $Tag->delete_cart( { nickname => "mycart", } );

or similarly with positional parameters,

    $Tag->delete_cart( "mycart" );

99.5.1.1. See Also
------------------

userdb, load_cart, save_cart and pages
templates/components/saved_carts_list_small, pages/saved_carts.html
for more examples.

99.5.2. Description
-------------------

Deletes a cart with name nickname from the user database. Basically
the same as [userdb function=delete_cart nickname=mycart].

99.5.2.1. nickname
------------------

Nickname of cart to be deleted.

99.6. email
-----------

This tag takes a recipient address and a body text and uses the
SendmailProgram with -t option to send email.

99.6.1. Summary
---------------

    [email to subject* reply* from* extra*]Your message[/email]
    [email to=to_address subject=subject reply=reply_address
        from=from_address extra=extra_headers]Your message[/email]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
to            Email address of recipient                none
subject       Subject line                              String: <no
                                                        subject>
reply         Email address to be used for the reply-to none
              header
from          Senders email address                     First address
                                                        in
                                                        MailOrderTo
                                                        configuration
                                                        variable
extra         Additional headers to be included         none

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        [/email]

Tag expansion example:

    [email
           to="foo@bar.com"
      subject="Greetings"
         from="bar@foo.com"
    ]
    Hello World
    [/email]

ASP-like Perl call:

    $Tag->email(  { to => $to,
                  from => $from,
               subject => $subject,
                 reply => $reply,
                 extra => $extra,
                  body => $body }  );

or similarly,

    $Tag->email($to, $subject, $reply, $from, $extra, $body);

99.6.1.1. See Also
------------------

email_raw and etc/mail_receipt, pages/process_return.html,
pages/stock-alert-added.html for examples.

99.6.2. Description
-------------------

Will send the content between the [email][/email] tags as an email to
the recipient (to) using the SendmailProgram with -t option.

99.6.2.1. extra
---------------

Extra headers to be included. Example: Errors-To:
errors@yourdomain.com

99.6.2.2. from
--------------

Email address identifying the sender of the message. Will use the
first email address of the MailOrderTo configuration variable if it is
not supplied.

99.6.2.3. reply
---------------

Email address to be used for the Reply-to header. No Reply-to header
will be present if this parameter is omitted.

99.6.2.4. subject
-----------------

Short text describing the content of the message. The Subject line of
an email message. The string <no subject> will be substituted if this
parameter is omitted.

99.6.2.5. to
------------

Valid email address(es) of the recipient(s). This parameter is
required.

99.7. email_raw
---------------

This tag takes a raw email message, including headers, and uses the
SendmailProgram with -t option.

99.7.1. Summary
---------------

    [email_raw]Your message including headers[/email_raw]

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        [/email_raw]

Tag expansion example:

    [email_raw]
From: foo@bar.com
To: bar@foo.com
Subject: baz

The text of the message.
    [/email_raw]

The headers must be at the beginning of the line, and the header must
have a valid To: or it will not be delivered.

ASP-like Perl call:

    $Tag->email_raw(  { body => $body }  );

or similarly,

    $Tag->email_raw($body);

99.7.1.1. See Also
------------------

email

99.7.2. Description
-------------------

Will send the content between the [email_raw][/email_raw] tags as a
raw email message to the recipient specified in the supplied headers
using the SendmailProgram with -t option.

99.8. fedex_query
-----------------

99.9. formel
------------

99.10. fortune
--------------

This tag uses the fortune(1) command to display a random saying.

Options:

        short=yes|no* Select only short (< 160 chars) fortunes
        a=1           Select from all fortunes, even potentially offensive ones.
        o=1           Select only from potentially offensive fortunes.
        raw=1         Don't do any HTML formatting

Example:

        [fortune short=yes]


99.11. get-url
--------------

Fetch a URL and return the contents.

99.11.1. Summary
----------------

    [get-url url]
    [get-url url="valid-url" strip=1*]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
url           Must be a valid URL. Meaning, you have to none
              supply the
              protocol.Examplehttp://demo.akopia.com/ftp://ftp.akopia.com/

Attributes                         Default
.................................. .................................. 
strip                              none

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        No

Tag expansion example:

    [get-url http://demo.akopia.com/]
    [get-url url="http://demo.akopia.com/" strip=1]

ASP-like Perl call:

    $Tag->get_url( { url => "http://demo.akopia.com/", } );

    $Tag->get_url( { url => "http://demo.akopia.com/",
                   strip => 1, } );

or similarly with positional parameters,

    $Tag->get_url( "http://demo.akopia.com/" );

99.11.2. Description
--------------------

Uses the LWP libraries (LWP::Simple) to fetch a URL and returns the
contents.

99.11.2.1. strip
----------------

If the strip option is set, strips everything up to <body> and
everything after </body>.

99.11.2.2. url
--------------

Must be a valid URL (including protocol).

99.12. load_cart
----------------

This tag loads a cart by name from the userdb.

99.12.1. Summary
----------------

    [load_cart nickname]
    [load_cart nickname="cart-name"]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
nickname      Must be an existing nickname.Nickname is  none
              constructed from:a name parttime modified
              (time the cart was saved by save_cart
              tag)type (c for cart, r for recurring)

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        No

Tag expansion example:

    [load_cart mycart:990102732:c]
    [load_cart nickname="mycart:990102732:c"]

ASP-like Perl call:

    $Tag->load_cart( { nickname => "mycart:990102732:c", } );

or similarly with positional parameters,

    $Tag->load_cart( "mycart:990102732:c" );

99.12.1.1. See Also
-------------------

userdb, delete_cart, save_cart and pages
templates/components/saved_carts_list_small, pages/saved_carts.html
for more examples.

99.12.2. Description
--------------------

Loads a cart with name nickname from the user database. It will be
merged with the current cart. Basically the same as [userdb
function=get_cart nickname=cartname merge=1].

99.12.2.1. nickname
-------------------

Nickname of cart to be loaded. See above.

99.13. loc
----------

99.14. rand
-----------

99.15. reconfig
---------------

99.16. reconfig_time
--------------------

99.17. reconfig_wait
--------------------

99.18. save_cart
----------------

This tag saves the current cart or recurring order in the userdb under
a given name.

99.18.1. Summary
----------------

    [save_cart nickname recurring]
    [save_cart nickname="cart-name" recurring=1]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
nickname      Label for the cart.                       none
recurring     Set to true if recurring. Set to false,   none
              or omit if cart.

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        No

Tag expansion example:

    [save_cart mycart]
    [save_cart nickname=mycart recurring=1]

ASP-like Perl call:

    $Tag->save_cart( { nickname => mycart,
                      recurring => 1, } );

or similarly with positional parameters,

    $Tag->save_cart( "mycart", "1" );

99.18.1.1. See Also
-------------------

userdb, delete_cart, load_cart and pages
templates/components/saved_carts_list_small, pages/saved_carts.html
for more examples.

99.18.2. Description
--------------------

Saves the current cart with name nickname in the user database.
Basically the same as [userdb function=set_cart nickname=cartname]

99.18.2.1. nickname
-------------------

Nickname for the current cart to be saved. You can use same nickname
for different carts. An index will be added if there are more carts
with the same nickname.

99.18.2.2. recurring
--------------------

Set to true if recurring. Set to false, or simply omit it, if it is a
cart.

99.19. summary
--------------

This tag calculates column totals.

99.19.1. Summary
----------------

    [summary amount]
    [summary amount=n.nn other_named_attributes]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
amount        Numerical value to be added to previous   none
              total

Attributes                         Default
.................................. .................................. 
currency                           none
format                             none
hide                               none, no hiding
name                               ONLY0000, internal use only
reset                              none
total                              none

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        No

Tag expansion example:

    [loop list="10 20 30.5"]
        [summary amount="[loop-code]" hide=1]
    [/loop]
    [summary total=1 format="%.3f"]
    [summary total=1 currency=1]
---
    60.500
    $60.50

ASP-like Perl call:

    $Tag->summary( { amount => 10.5,
                       hide => 1, } );

    $Tag->summary( { amount => 25,
                       name => mytotal,
                   currency => 1, } );

or similarly with positional parameters,

    $Tag->summary( 10.5, $attribute_hash_reference );

99.19.1.1. See Also
-------------------

templates/components/cart, pages/ord/checkout.html for more examples.

99.19.2. Description
--------------------

The summary tag provides you with an easy way to calculate and display
totals. The display of the amounts is fully customizable. You can hide
display, or you can show the amounts with the proper currency
formatting according to the locale, or you can define your own
formatting. Any number of summaries can be kept on a page.

99.19.2.1. currency
-------------------

The amount or total will be displayed according to the currency
formatting of the current locale if this attribute is set to true (non
blank or zero).

99.19.2.2. format
-----------------

You can choose any formatting of the amount you like. Just set the
format attribute to the desired formatting string (%s, %.2f etc.).
When both, currency and format attributes are set, the format
attribute will take precedence. So it doesn't make much sense to set
them both at the same time.

99.19.2.3. hide
---------------

Will suppress the display of amount when set to true.

99.19.2.4. name
---------------

You can calculate as many totals as you like on the same page. Just
supply a different label for each summary.

99.19.2.5. reset
----------------

Will erase the total(s) if set to true. Be careful tough. It will
reset ALL totals when you have no name attribute supplied. If you have
provided a label for the name attribute then it will only reset the
total for that particular label. All others won't be touched.

99.19.2.6. total
----------------

Will show the total instead of the amount if set to true.

99.20. table_organize
---------------------

Takes an unorganized set of table cells and organizes them into rows
based on the number of columns.

99.20.1. Summary
----------------

    [table-organize cols* other_named_attributes]
             [loop ....] <td> [loop-tags] </td> [/loop]
        [/table-organize]

    [table-organize cols=n* other_named_attributes]
             [loop ....] <td> [loop-tags] </td> [/loop]
        [/table-organize]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
cols          Number of columns.                        2
columns       Alias for cols.                           2

Attributes                         Default
.................................. .................................. 
caption                            none
columnize                          none
embed                              none
filler                             &nbsp;
limit                              none
pretty                             none
rows                               none
table                              none
td                                 none
tr                                 none

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        [/table-organize]

Tag expansion example:

This example produces a table that (1) alternates rows with background
colors "#EEEEEE" and "#FFFFFF", and (2) aligns the columns right,
center, left:

        [table-organize
            cols=3
            pretty=1
            tr.0='bgcolor="#EEEEEE"'
            tr.1='bgcolor="#FFFFFF"'
            td.0='align=right'
            td.1='align=center'
            td.2='align=left'
        ]
            [loop list="1 2 3 1a 2a 3a 1b"] <td> [loop-code] </td> [/loop]
        [/table-organize]
---
        <tr bgcolor="#EEEEEE">
                <td align=right>1</td>
                <td align=center>2</td>
                <td align=left>3</td>
        </tr>
        <tr bgcolor="#FFFFFF">
                <td align=right>1a</td>
                <td align=center>2a</td>
                <td align=left>3a</td>
        </tr>
        <tr bgcolor="#EEEEEE">
                <td align=right>1b</td>
                <td align=center>&nbsp;</td>
                <td align=left>&nbsp;</td>
        </tr>

If the attribute columnize=1 is present, the result will look like:

            <tr bgcolor="#EEEEEE">
                    <td align=right>1</td>
                    <td align=center>1a</td>
                    <td align=left>1b</td>
            </tr>
            <tr bgcolor="#FFFFFF">
                    <td align=right>2</td>
                    <td align=center>2a</td>
                    <td align=left>&nbsp;</td>
            </tr>
            <tr bgcolor="#EEEEEE">
                    <td align=right>3</td>
                    <td align=center>3a</td>
                    <td align=left>&nbsp;</td>
            </tr>

See the source for more ideas on how to extend this tag.

ASP-like Perl call:

    $Tag->table_organize( { cols => 3,
                            pretty => 1, }, $BODY );

or similarly with positional parameters:

    $Tag->table_organize( $cols, $attribute_hash_reference, $BODY );

99.20.1.1. See Also
-------------------

pages/flypage.html, pages/quantity.html,
templates/components/best_horizontal, templates/components/cart,
templates/components/cross_horizontal, templates/components/random,
templates/components/random_vertical, templates/components/upsell

99.20.2. Description
--------------------

Takes an unorganized set of table cells and organizes them into rows
based on the number of columns; it will also break them into separate
tables.

If the number of cells are not on an even modulus of the number of
columns, then "filler" cells are pushed on.

99.20.2.1. cols (or columns)
----------------------------

Number of columns. This argument defaults to 2 if not present.

99.20.2.2. rows
---------------

Optional number of rows. Implies "table" parameter.

99.20.2.3. table
----------------

If present, will cause a surrounding <TABLE> </TABLE> pair with the
attributes specified in this option.

99.20.2.4. caption
------------------

Table <CAPTION> container text, if any. Can be an array.

99.20.2.5. td
-------------

Attributes for table cells. Can be an array.

99.20.2.6. tr
-------------

Attributes for table rows. Can be an array.

99.20.2.7. columnize
--------------------

Will display cells in (newspaper) column order, i.e. rotated.

99.20.2.8. pretty
-----------------

Adds newline and tab characters to provide some reasonable indenting.

99.20.2.9. filler
-----------------

Contents to place in empty cells put on as filler. Defaults to
"&nbsp;".

99.20.2.10. limit
-----------------

Maximum number of cells to use. Truncates extra cells silently.

99.20.2.11. embed
-----------------

If you want to embed other tables inside, make sure they are called
with lower case <td> elements, then set the embed tag and make the
cells you wish to organize be <TD> elements. To switch that sense, and
make the upper-case or mixed case be the ignored cells, set the embed
parameter to "lc".

    [table-organize embed=lc]
                <td>
                        <TABLE>
                                <TR>
                                <TD> something
                                </TD>
                                </TR>
                        </TABLE>
                </td>
    [/table-organize]

or

    [table-organize embed=uc]
                <TD>
                        <table>
                                <tr>
                                <td> something
                                </td>
                                </tr>
                        </table>
                </TD>
    [/table-organize]

The "tr", "td", and "caption" attributes can be specified with
indexes; if they are, then they will alternate according to the
modulus.

The "td" option array size should probably always equal the number of
columns; if it is bigger, then trailing elements are ignored. If it is
smaller, no attribute is used.

99.21. title_bar
----------------

Creates a quick title bar.

99.21.1. Summary
----------------

    [title-bar width size color]My title[/title-bar]
    [title-bar width=600 size=5 color="#ff0000"]My title[/title-bar]

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
color         Background color the bar.Defaults         HEADERBG or
              tovariable HEADERBG or#444444             #444444
size          Font size                                 6
width         Width of the title bar                    500

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        [/title-bar]

Tag expansion example:

    [title-bar 600 5 red]My title[/title-bar]
    [title-bar width=600 size=5 color="#ff0000"]My title[/title-bar]

ASP-like Perl call:

    $Tag->title_bar( { body => "My Title", } );

    $Tag->title_bar( { width => 400,
                       color => "#0000ff",
                        body => "My title", } );

or similarly with positional parameters,

    $Tag->title_bar( 600, 5, "red", "My title" );

99.21.2. Description
--------------------

Quickly adds a title bar to your pages without having to type the html
each time. Background color, width of the bar and size of the text can
be customized by setting the appropriate parameter. The text color
defaults to variable HEADERTEXT or when its not present to white.

99.21.2.1. color
----------------

Sets the background color of the bar. You can set the color as 'red',
'#ff0000', or 'bgcolor="#ff0000"'.

99.21.2.2. size
---------------

Determines the size of the text. Parameter should be set to a value
accepted by the HTML <font> tag size attribute.

99.21.2.3. width
----------------

Sets the width of the bar.

99.22. ups_query
----------------

99.23. usertrack
----------------

99.24. var
----------

99.25. xml-generator
--------------------

This is a quick and dirty tag that generates XML tags based upon one
of two types of data (delimited and session).

99.25.1. Summary
----------------

    [xml-generator type* other_named_attributes][/xml-generator]
    [xml-generator type=value* other_named_attributes][/xml-generator]
    [xml-generator type=value* other_named_attributes][][/xml-generator]

*Optional

Positional parameters: The first line shows the usage with positional
parameters (given in order). The second line shows usage with named
parameters.



Parameters    Description                               Default
............. ......................................... ............. 
type          Data type. Delimited or session           delimited

Attributes                         Default
.................................. .................................. 
attributes                         none
dbdump                             none
delimiter                          \t
field_names                        &nbsp;
separator                          \n
toplevel_tag                       'table' for delimited type and
                                   'session' for other type
record_tag                         record
field_tag                          field
key_name                           none
spacer                             [\s,]+
no_second                          none
skip_empty                         none

Other_Characteristics
.................................. .................................. 
Invalidates cache                  No
Macro                              No
Has end tag                        [/xml-generator]

Tag expansion example:

    [xml-generator type=delimited
             attributes="date"
                   date="[tag time]%d-%b-%Y[/tag]"
           toplevel_tag=products
    ]code       description     price
        [query list=1 sql="select sku, description, price from products" prefix=xml][xml-code]  [xml-param description] [xml-param price]
        [/query]
    [/xml-generator]
---
    <products date="18-May-2001">
            <record key="os28113">
                    <code>os28113</code>
                    <description>The Claw Hand Rake</description>
                    <price>14.99</price>
            </record>
            <record key="os28006">
                    <code>os28006</code>
                    <description>Painters Brush Set</description>
                    <price>29.99</price>
            </record>
            ...
    </products>

ASP-like Perl call:

    $Tag->xml_generator( {type => delimited,
                      toplevel_tag => apex,  }, $BODY );


or similarly with positional parameters,

    $Tag->xml_generator( $type, $attribute_hash_reference, $BODY );

99.25.2. Description
--------------------

99.25.2.1. type
---------------

delimited

Accepts a delimited and separated (default is TAB delimiter and
newline separator) list of records such as that generated by an
'[item-list]', '[sql]', or '[loop search=""]' ITL tag.

session

When the type is not delimited, it can contain any hash reference into
the Interchange session. Examples are:

        values       The form values
        scratch      Scratch values
        errors       Error values
        other        Any other Session key, for example "source" for
                     [data session source]

If the value is a hash, then it will be sent as an XML record with the
top level equal to "session", and a second_level tag equal to the hash
name, and keys as separate XML container tags. If the parameter "that
is equal to the type" is given, only those fields will be shown.
Otherwise the entire hash will be shown. For example, this tag:

        [xml-generator type="values" values="fname lname"][/xml-generator]

will generate:

        <session>
                <values>
                        <fname>First</fname>
                        <lname>Last</lname>
                </values>
        </session>

if it is a scalar, then only the second level will be done:

        [xml-generator type="cybercash_id"][/xml-generator]

will do the equivalent of:

        <session>
                <cybercash_id>[data session cybercash_id]</cybercash_id>
        </session>

So bringing it all together, the following:

        [xml-generator type="values scratch source"
                       values="fname lname"
                       scratch="downloads"][/xml-generator]
will generate:

        <session>
                <values>
                        <fname>First</fname>
                        <lname>Last</lname>
                </values>
                <scratch>
                        <downloads>0</downloads>
                </scratch>
                <source>Partner1</source>
        </session>

99.25.2.2. no_second
--------------------

Prevents the second-level tags from being generated. Extending the
last example in the "session" type above, this

        [xml-generator  type="values scratch source"
                        no_second=1
                        values="fname lname"
                        scratch="downloads"][/xml-generator]
will generate:

        <session>
                <fname>First</fname>
                <lname>Last</lname>
                <downloads>0</downloads>
                <source>Partner1</source>
        </session>

99.25.2.3. attributes
---------------------

The attributes (if any) to pass on to the top level tag. For instance,

    [xml-generator
          attributes="date"
                date="[tag time]%d-%b-%Y[/tag]"
        toplevel_tag=order
    ][/xml-generator]

will generate a toplevel tag pair of:

        <order date="18-Mar-2001">
        </order>

99.25.2.4. dbdump
-----------------

Will dump all tables in the catalog when this attribute is set true.
Used attributes are "toplevel_tag", "record_tag", "field_tag", and
"skip_empty" or default values ('table', 'record', 'field'
respectively).

Output format:
    <database name="catalogname">
        <toplevel_tag name="tablename1">
            <record_tag key="value of first field-1">
                <field_tag name="fieldname1">fieldvalue1</field_tag>
                <field_tag name="fieldname2">fieldvalue2</field_tag>
                        </record_tag>
            <record_tag key="value of first field-2">
                <field_tag name="fieldname1">fieldvalue1</field_tag>
                <field_tag name="fieldname2">fieldvalue2</field_tag>
                        </record_tag>
                </toplevel_tag>
        <toplevel_tag name="tablename2">
            <record_tag key="value of first field-1">
                <field_tag name="fieldname1">fieldvalue1</field_tag>
                <field_tag name="fieldname2">fieldvalue2</field_tag>
                        </record_tag>
                </toplevel_tag>
        </database>

Important note: All tables are read into memory. So be warned, this
could be a real memory hog.

Ton Verhagen's proposal:

1.   Add option to select tables. E.g. dump_tables="products cat area"
     and/or

2.   Add option to select an output file. E.g.
     dump_file="tabledump.XML". Send output to file line by line.

99.25.2.5. delimiter
--------------------

Character used as delimiter of fields in delimited data type. Defaults
to a tab character.

99.25.2.6. field_names
----------------------

Space or comma-delimited list of field names to be used for delimited
data type. Should be in the same order as in the data list provided
(between the tags).

Another way of providing the field names would be:

    [xml-generator .....]fieldname-1    fieldname-2     fieldname-3
        [field value list
         delimited by option delimiter and
         separated by option separator][/xml-generator]

Note: Field name list must be tab delimited.

Ton Verhagen's humble opinion: This should change in future versions!
Use option delimiter instead.

99.25.2.7. separator
--------------------

Character used as line separator in list between
[xml-separator][xml-separator] tags and in output 'session' data type.
Defaults to a newline, "\n".

99.25.2.8. toplevel_tag
-----------------------

The toplevel tag name to use. Defaults to "table" for the 'dbdump
mode' and delimited type, and "session" for the other.

99.25.2.9. record_tag
---------------------

Defines the tag name for the record tag. Defaults to 'record'. Used
for 'dbdump mode' and delimited type.

99.25.2.10. field_tag
---------------------

Defines the tag name for the field tag. Defaults to 'field'. Only used
in 'dbdump mode'.

99.25.2.11. key_name
--------------------

Only used in delimited data type. Defines fieldname to determine key
value in "record_tag".

    <record_tag key="value of field with name defined by key_name"> ....

99.25.2.12. spacer
------------------

Character used as delimiter in type parameter definition and
corresponding attributes. Defaults to '[\s,]+' (one or more whitespace
or comma).

    [xml-generator type="values|scratch"
                 values="value1|value2"
                scratch="scratch1|scratch2"
                 spacer="|"
    ][/xml-generator]

99.25.2.13. skip_empty
----------------------

Only used in dbdump mode (dbdump=1). Will skip empty fields if this
attribute is set true.

I. Template Parsing Order
=========================

I.1. Standard Parsing
---------------------

Under normal circumstances, the template page containing tags and HTML
is parsed in the following order:

1.   Any content in MV_AUTOLOAD is prepended to the template page.





2.   Any [pragma] tags anywhere in the text are processed, and the
     specified pragmas are set.

     o    Since [pragma] tags are preprocessed before any other
          content, reparse will not catch them, nor will they work if
          included in variables. Also, the specified pragma will apply
          to the entire template (not just the section after the tag).

     o    If you want to apply a pragma with a variable or only to
          part of a document, you must use [tag pragma="..."] instead.



3.   Variables (macros) are processed in the following order:

     25.  @@VARNAME@@ global variables

     26.  @_VARNAME_@ local or global variables

     27.  __VARNAME__ local variables



4.   Interchange comments are stripped.





5.   False-endtag macros are expanded (e.g., [/page] and [/order]).





6.   '<!--[tagname]-->' escapes are converted to [tagname]

     o    This can be a convenience for your HTML editor if it has
          trouble with tags using the standard [tagname] syntax.

     o    However, if you want to HTML-comment out an Interchange tag
          in content that will be fed raw to a browser, you must
          include whitespace between the HTML comment delimiters and
          the tag, like this, '<!--  [tagname]  -->'.



7.   The main tag parser is called.

     o    Some tags parse recursively (depending upon reparse and
          interpolate settings, of course).

     o    Some tags (e.g., [loop]) process PREFIX-tags in their
          contained body text. Hence, the PREFIX-tags are not handled
          recursively.

     o    Some tags are interpreted in the lib/Vend/Parse.pm:start
          routine. You cannot call them with the '$Tag->tagname()'
          syntax. They are:

          o    The [goto] tag. Note also that the [goto] tag handles
               the [label] tag.

          o    The [bounce] tag.



8.   Image paths substitution on the HTML output occurs.





I.2. Nonstandard parsing within the admin interface
---------------------------------------------------

Parsing of content via the specialized [regenerate] usertag included
with the administrative interface does not obey the above order. The
MV_AUTOLOAD and '<!--[tagname]-->' escapes are skipped. There are some
other more subtle differences as well; in the very unlikely event that
you need to check this in the source code, compare the
'interpolate_html' and 'cache_html' routines in Interpolate.pm.

I.3. Nonstandard parsing of Subtags
-----------------------------------

Subtags are parsed within the containing array-list or hash-list
context created by the containing tag (see Looping tags and Sub-tags).

o    All subtags at an earlier precedence level are treated before any
     in the next level.

o    Within the same level, tags are processed in the order the appear
     on the page.

o    Any standard tags are processed during 'interpolate' (before) or
     'reparse' (after) phases of processing the containing tag.

Technical note

Processing within a hash- or array-list is actually done as a series
of global regular expression substitutions on the page. Each
substitution replaces one tag with the output of the subroutine(s)
associated with it.



In array-list context, subtags are processed in the following order:

1.   Check for PREFIX-line and prepare for it if present (does not
     process PREFIX-line at this time)

2.   PREFIX-sub definitions processed

3.   if-PREFIX-* nesting resolved

4.   PREFIX-alternate processed

5.   if-PREFIX-param  processed

6.   if-PREFIX-pos  processed

7.   PREFIX-pos  processed

8.   if-PREFIX-field  processed

9.   PREFIX-line  processed

10.  PREFIX-increment  processed

11.  PREFIX-accessories  processed

12.  PREFIX-options  processed

13.  PREFIX-code  processed

14.  PREFIX-description  processed

15.  PREFIX-field  processed

16.  PREFIX-price  processed

17.  PREFIX-change  processed

18.  PREFIX-calc  processed

19.  PREFIX-exec  processed

20.  PREFIX-filter  processed

21.  PREFIX-last  processed

22.  PREFIX-next  processed

23.  User's previous HTML widget SELECTED settings restored

24.  Reparse standard tags in output of above (if reparse enabled for
     the containing tag)

In hash-list context, subtags are processed in the following order:

1.   PREFIX-sub definitions processed

2.   if-PREFIX-* nesting resolved

3.   PREFIX-alternate processed

4.   PREFIX-line  processed

5.   if-PREFIX-param  processed

6.   if-PREFIX-field  processed

7.   if-PREFIX-modifier  processed (if-PREFIX-param and
     if-PREFIX-modifier are functionally identical except for parse
     order)

8.   PREFIX-increment  processed

9.   PREFIX-accessories  processed

10.  PREFIX-options  processed

11.  PREFIX-sku  processed

12.  PREFIX-code  processed

13.  PREFIX-quantity  processed

14.  PREFIX-modifier  processed

15.  PREFIX-param  processed

16.  PREFIX-quantity-name  processed

17.  PREFIX-modifier-name  processed

18.  PREFIX-subtotal  processed

19.  PREFIX-discount-subtotal  processed

20.  PREFIX-code  processed again differently (operating on new
     instances of PREFIX-code in output of above?)

21.  PREFIX-field  processed

22.  PREFIX-description  processed

23.  PREFIX-price  processed

24.  PREFIX-discount-price  processed

25.  PREFIX-difference  processed

26.  PREFIX-discount  processed

27.  PREFIX-change  processed

28.  PREFIX-tag  processed (*** CHECK THIS TAG NAME ***)

29.  PREFIX-calc  processed

30.  PREFIX-exec  processed

31.  PREFIX-filter  processed

32.  PREFIX-last  processed

33.  PREFIX-next  processed

34.  User's previous HTML widget SELECTED settings restored

35.  Reparse standard tags in output of above (if reparse enabled for
     the containing tag)

J. Search and Form Variables
============================

J.1. Variable Names
-------------------

J.1..1. other
-------------

Name                 scan   Type   Description
.................... ...... ...... .................................. 
mv_all_chars         ac     S      Turns on punctuation matching
mv_arg[0-9]+                A      Parameters for mv_subroutine
                                   (mv_arg0,mv_arg1,...)
mv_base_directory    bd     S      Sets base directory for search
                                   file names
mv_begin_string      bs     S      Pattern must match beginning of
                                   field
mv_case              cs     S      Turns on case sensitivity
mv_cartname                 O      Sets the shopping cart name
mv_check                    A      Any form, sets multiple user
                                   variables after update
mv_click                    A      Any form, sets multiple form
                                   variables before update
mv_click                    XA     Default mv_click routine, click is
                                   mv_click_arg
mv_click name               XA     Routine for a click name, sends
                                   click as arg
mv_click_arg                XA     Argument name in scratch space
mv_coordinate        co     S      Enables field/spec matching
                                   coordination
mv_column_op         op     S      Operation for coordinated search
mv_credit_card*             O      Discussed in order security (some
                                   are read-only)
mv_dict_end          de     S      Upper bound for binary search
mv_dict_fold         df     S      Non-case sensitive binary search
mv_dict_limit        di     S      Sets upper bound based on
                                   character position
mv_dict_look         dl     S      Search specification for binary
                                   search
mv_dict_order        do     S      Sets dictionary order mode
mv_doit                     A      Sets default action
mv_email                    O      Reply-to address for orders
mv_exact_match       em     S      Sets word-matching mode
mv_failpage          fp     O,S    Sets page to display on failed
                                   order check/search
mv_field_file        ff     S      Sets file to find field names for
                                   Glimpse
mv_field_names       fn     S      Sets field names for search,
                                   starting at 1
mv_first_match       fm     S      Start displaying search at
                                   specified match
mv_head_skip         hs     S      Sets skipping of header line(s) in
                                   index
mv_index_delim       id     S      Delimiter for search fields (TAB
                                   default)
mv_matchlimit        ml     S      Sets match page size
mv_max_matches       mm     S      Sets maximum match return
mv_min_string        ms     S      Sets minimum search spec size
mv_negate            ne     S      Records NOT matching will be found
mv_nextpage          np     A      Sets next page user will go to
mv_numeric           nu     S      Comparison numeric in coordinated
                                   search
mv_order_group              O      Allows grouping of master item/sub
                                   item
mv_order_item               O      Causes the order of an item
mv_order_number             O      Order number of the last order
                                   (read-only)
mv_order_quantity           O      Sets the quantity of an ordered
                                   item
mv_order_profile            O      Selects the order check profile
mv_order_receipt            O      Sets the receipt displayed
mv_order_report             O      Sets the order report sent
mv_order_subject            O      Sets the subject line of order
                                   email
mv_orsearch          os     S      Selects AND/OR of search words
mv_profile           mp     S      Selects search profile
mv_record_delim      dr     S      Search index record delimiter
mv_return_all        ra     S      Return all lines found (subject to
                                   range search)
mv_return_delim      rd     S      Return record delimiter
mv_return_fields     rf     S      Fields to return on a search
mv_return_file_name  rn     S      Set return of file name for
                                   searches
mv_return_spec       rs     S      Return the search string as the
                                   only result
mv_save_session             C      Set to non-zero to prevent
                                   expiration of user session
mv_search_field      sf     S      Sets the fields to be searched
mv_search_file       fi     S      Sets the file(s) to be searched
mv_search_line_return lr    S      Each line is a return code (loop
                                   search)
mv_search_match_count       S      Returns the number of matches
                                   found (read-only)
mv_search_page       sp     S      Sets the page for search display
mv_searchspec        se     S      Search specification
mv_searchtype        st     S      Sets search type (text, glimpse,
                                   db or sql)
mv_separate_items           O      Sets separate order lines (one per
                                   item ordered)
mv_session_id        id     A      Suggests user session id
                                   (overridden by cookie)
mv_shipmode                 O      Sets shipping mode for custom
                                   shipping
mv_sort_field        tf     S      Field(s) to sort on
mv_sort_option       to     S      Options for sort
mv_spelling_errors   er     S      Number of spelling errors for
                                   Glimpse
mv_substring_match   su     S      Turns off word-matching mode
mv_successpage              O      Page to display on successful
                                   order check
mv_todo                     A      Common to all forms, sets form
                                   action
mv_todo.map                 A      Contains form imagemap
mv_todo.checkout.x          O      Causes checkout action on click of
                                   image
mv_todo.return.x            O      Causes return action on click of
                                   image
mv_todo.submit.x            O      Causes submit action on click of
                                   image
mv_todo.x                   A      Set by form imagemap
mv_todo.y                   A      Set by form imagemap
mv_unique            un     S      Return unique search results only
mv_value             va     S      Sets value on one-click search
                                   (va=var=value)

J.2. Abbreviations
------------------

The two-letter abbreviations are mapped with these letters:

Abbr   Long name
...... .............................................................. 
DL     mv_raw_dict_look
MM     mv_more_matches
ac     mv_all_chars
ar     mv_arg
bd     mv_base_directory
bs     mv_begin_string
ck     mv_cache_key
co     mv_coordinate
cs     mv_case
cv     mv_verbatim_columns
de     mv_dict_end
df     mv_dict_fold
di     mv_dict_limit
dl     mv_dict_look
do     mv_dict_order
dr     mv_record_delim
em     mv_exact_match
er     mv_spelling_errors
fi     mv_search_file
fm     mv_first_match
fn     mv_field_names
hs     mv_head_skip
id     mv_session_id
il     mv_index_delim
ix     mv_index_delim
lb     mv_search_label
lo     mv_list_only
lr     mv_line_return
lr     mv_search_line_return
ml     mv_matchlimit
mm     mv_max_matches
mp     mv_profile
ms     mv_min_string
ne     mv_negate
np     mv_nextpage
nu     mv_numeric
op     mv_column_op
os     mv_orsearch
pc     mv_pc
ra     mv_return_all
rd     mv_return_delim
rf     mv_return_fields
rn     mv_return_file_name
rr     mv_return_reference
rs     mv_return_spec
se     mv_searchspec
sf     mv_search_field
si     mv_search_immediate
sp     mv_search_page
sq     mv_sql_query
st     mv_searchtype
su     mv_substring_match
tf     mv_sort_field
to     mv_sort_option
un     mv_unique
va     mv_value

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Template Guide
==============

100. Introduction
=================

Interchange is designed to build its pages based on templates from a
database. This document describes how to build templates using the
Interchange Tag Language (ITL) and explains the different options you
can use in a template.

100.1. Overview
---------------

The search builder can be used to generate very complex reports on the
database or to help in the construction of ITL templates. Select a
"Base table" that will be the foundation for the report. Specify the
maximum number of rows to be returned at one time, and whether to show
only unique entries.

The "Search filter" narrows down the list of rows returned by matching
table columns based on various criteria. Up to three separate
conditions can be specified. The returned rows must match all
criteria.

Finally, select any sorting options desired for displaying the results
and narrow down the list of columns returned if desired. Clicking
"Run" will run the search immediately and display the results.
"Generate definition" will display an ITL tag that can be placed in a
template and that will return the results when executed.

To build complex order forms and reports, Interchange has a complete
tag language with over 80 different functions called Interchange Tag
Language (ITL). It allows access to and control over any of an
unlimited number of database tables, multiple shopping carts, user
name/address information, discount, tax and shipping information,
search of files and databases, and much more.

There is some limited conditional capability with the [if] tag, but
when doing complex operations, use of embedded Perl/ASP should be
strongly considered. Most of the tests use Perl code, but Interchange
uses the Safe.pm module with its default restrictions to help ensure
that improper code will not crash the server or modify the wrong data.

Perl can also be embedded within the page and, if given the proper
permission by the system administrator, call upon resources from other
computers and networks.

101. About Variable Replacement
===============================

Variable substitution is a simple and often used feature of
Interchange templates. It allows you to set a variable to a particular
value in the catalog.cfg directory. Then, by placing that variable
name on a page, you invoke that value to be used. Before anything else
is done on a template, all variable tokens are replaced by variable
values. There are three types of variable tokens:

__VARIABLENAME__ is replaced by the catalog variable called
VARIABLENAME.

@@VARIABLENAME@@ is replaced by the global variable called
VARIABLENAME.

@_VARIABLENAME_@ is replaced by the catalog variable VARIABLENAME if
it exists; otherwise, it is replaced by the global variable
VARIABLENAME.

For more information on how to use the Variable configuration file
directive to set global variables in interchange.cfg and catalog
variables in catalog.cfg, see the Interchange Configuration Guide.

102. Using Interchange Template Tags
====================================

This section describes the different template specific tags and
functions that are used when building a your templates.

102.1. Understanding Tag Syntax
-------------------------------

Interchange uses a style similar to HTML, but with [square brackets]
replacing <chevrons>. The parameters that can be passed are similar,
where a parameter="parameter value" can be passed.

Summary:

    [tag parameter]             Tag called with positional parameter
    [tag parameter=value]       Tag called with named parameter
    [tag parameter="the value"] Tag called with space in parameter
    [tag 1 2 3]                 Tag called with multiple positional parameters
    [tag foo=1 bar=2 baz=3]     Tag called with multiple named parameters
    [tag foo=`2 + 2`]           Tag called with calculated parameter
    [tag foo="[value bar]"]     Tag called with tag inside parameter
    [tag foo="[value bar]"]
        Container text.         Container tag.
    [/tag]

Most tags can accept some positional parameters. This makes parsing
faster and is, in most cases, simpler to write.

The following is an example tag:

    [value name=city]

This tag causes Interchange to look in the user form value array and
return the value of the form parameter city, which might have been set
with:

    City: <INPUT TYPE=text NAME=city VALUE="[value city]">

Note: Keep in mind that the value was pre-set with the value of city
(if any). It uses the positional style, meaning name is the first
positional parameter for the [value ...] tag. Positional parameters
cannot be derived from other Interchange tags. For example, [value
[value formfield]] will not work. But, if the named parameter syntax
is used, parameters can contain other tags. For example:

    [value name="[value formfield]"]]

There are exceptions to the above rule when using list tags such as
[item-list], [loop], [query] and others. These tags, and their
exceptions, are explained in their corresponding sections.

Many Interchange tags are container tags. For example:

    [set Checkout]
        mv_nextpage=ord/checkout
        mv_todo=return
    [/set]

Tags and parameter names are not case sensitive, so [VALUE
NAME=something] and [value name=something] work the same. The
Interchange development convention is to type HTML tags in upper case
and Interchange tags in lower case. This makes pages and tags easier
to read.

Single quotes work the same as double quotes and can prevent
confusion. For example:

    [value name=b_city set='[value city]']

Backticks should be used with extreme caution since they cause the
parameter contents to be evaluated as Perl code using the [calc] tag.
For example:

    [value name=row_value set=`$row_value += 1`]

is the same as

    [value name=row_value set="[calc]$row_value += 1[/calc]"]

Vertical bars can also be used as quoting characters, but have the
unique behavior of stripping leading and trailing whitespace. For
example:

    [loop list="
        k1    A1    A2    A3
        k2    B1    B2    B3"]
        [loop-increment][loop-code]
    [/loop]

could be better expressed as:

    [loop list=|
            k1    A1    A2    A3
            k2    B1    B2    B3
    |]
        [loop-increment][loop-code]
    [/loop]

How the result of the tag is displayed depends on if it is a container
or a standalone tag. A container tag has a closing tag (for example,
[tag] stuff [/tag]). A standalone tag has no end tag (for example,
[area href=somepage]. Note that [page] and [order] are not container
tags. ([/page] and [/order] are simple macros.)

A container tag will have its output re-parsed for more Interchange
tags by default. To inhibit this behavior, set the attribute reparse
to 0.  However, it has been found that the default re-parsing is
almost always desirable. On the other hand, the output of a standalone
tag will not be re-interpreted for Interchange tag constructs (with
some exceptions, like [include file].

Most container tags will not have their contents interpreted
(Interchange tags parsed) before being passed the container text.
Exceptions include [calc], [currency] and [seti]. All tags accept the
interpolate=1 tag modifier, which causes the interpretation to take
place.

102.2. data and field
---------------------

The [data] and [field] tags access elements of Interchange databases.
They are the form used outside of the iterating lists, and are used to
do lookups when the table, column/field or key/row is conditional
based on a previous operation.

The following are equivalent for attribute names:

    table --> base
    col   --> field --> column
    key   --> code  --> row

The [field] tag looks in any tables defined as ProductFiles, in that
order, for the data and returns the first non-empty value. In most
catalogs, where ProductFiles is not defined, i.e., the demo, [field
title 00-0011] is equivalent to [data products title 00-0011]. For
example, [field col=foo key=bar] will not display something from the
table "category" because "category" is not in the directive
ProductFiles or there are multiple ProductFiles and an earlier one has
an entry for that key.

[data table column key]

     named attributes: [data base="database" field="field" key="key"
     value="value" op="increment]

     Returns the value of the field in any of the arbitrary databases
     or from the variable namespaces. If the option increment=1 is
     present, the field will be automatically incremented with the
     value in value.

     If a DBM-based database is to be modified, it must be flagged
     writable on the page calling the write tag. For example, use [tag
     flag write]products[/tag] to mark the products database writable.

     In addition, the [data ...] tag can access a number of elements
     in the Interchange session database:

              accesses      Accesses within the last 30 seconds
              arg           The argument passed in a [page ...] or [area ...] tag
              browser       The user browser string
              host          Interchange's idea of the host (modified by DomainTail)
              last_error    The last error from the error logging
              last_url      The current Interchange path_info
              logged_in     Whether the user is logged in via UserDB
              pageCount     Number of unique URLs generated
              prev_url      The previous path_info
              referer       HTTP_REFERER string
              ship_message  The last error messages from shipping
              source        Source of original entry to Interchange
              time          Time (seconds since Jan 1, 1970) of last access
              user          The REMOTE_USER string
              username      User name logged in as (UserDB)

     Databases will hide variables, so if a database is named
     "session," "scratch," or any of the other reserved names it won't
     be able to use the [data ...] tag to read them. Case is
     sensitive, so the database could be called "Session," but this is
     not recommended practice.

[field name code]

     named attributes: [field code="code" name="fieldname"]

     Expands into the value of the field name for the product as
     identified by code found by searching the products database. It
     will return the first entry found in the series of Product Files
     in the products database. If this needs to constrained to a
     particular table, use a [data table col key] call.

102.3. set, seti, tmp, tmpn scratch and scratchd
------------------------------------------------

Scratch variables are maintained in the user session, which is
separate from the form variable values set on HTML forms. Many things
can be controlled with scratch variables, particularly search and
order processing, the mv_click multiple variable setting facility and
key Interchange conditions session URL display.

There are four tags that are used to set the scratch space: [set
variable] value [/set], [seti variable] value [/seti], [tmp variable]
value [/tmp], [tmpn variable] value [/tmpn] and and two tags for
reading scratch space: [scratch variable] and [scratchd variable].

[set variable] value [/set]

     Sets a scratchpad variable to a value.

     Most of the mv_* variables that are used for search and order
     conditionals are in another namespace. They can be set through
     hidden fields in a form.

     An order profile would be set with:

            [set checkout]
            name=required Please enter your name.
            address=required No address entered.
            [/set]
            <INPUT TYPE=hidden NAME=mv_order_profile VALUE="checkout">

     A search profile would be set with:

            [set substring_case]
            mv_substring_match=yes
            mv_case=yes
            [/set]
            <INPUT TYPE=hidden NAME=mv_profile VALUE="substring_case">

     To do the same as [set foo]bar[/set] in embedded Perl:

              [calc]$Scratch->{foo} = 'bar'; return;[/calc]

[seti variable] value [/seti]

     The same as [set] except it interpolates the container text. The
     above is the same as:

              [set name=variable interpolate=1] [value something] [/set]

[tmp variable] value [/tmp]

     The same as [seti] except it does not persist.

[tmpn variable] value [/tmpn]

     The same as [set] except it does not persist.

[scratch variable]

     Returns the contents of a scratch variable to the page. [scratch
     foo] is the same as, but faster than:

              [perl] $Scratch->{foo} [/perl]

[scratchd variable]

     The same as [scratch variable] except it deletes the value after
     returning it. Same as [scratch foo] [set foo] [/set].

[if scratch name op* compare*] yes [else] no [/else][/if]

     Tests a scratch variable. See the [if] tag documentation for more
     information.

102.4. loop
-----------

Loop lists can be used to construct arbitrary lists based on the
contents of a database field, a search or other value (like a fixed
list). Loop accepts a search parameter that will do one-click searches
on a database table (or file).

To iterate over all keys in a table, use the idiom ([loop
search="ra=yes/ml=9999"] [/loop]. ra=yes sets mv_return_all, which
means "match everything". ml=9999 limits matches to that many records.
If the text file for searching an Interchange DBM database is not
used, set st=db (mv_searchtype).

When using st=db, returned keys may be affected by TableRestrict. Both
can be sorted with [sort table:field:mod -start +number] modifiers.
See sorting.

The Interchange Tags Reference has more information on the [loop] tag.

[loop item item item] LIST [/loop]

     named attributes: [loop prefix=label* list="item item item"*
     search="se=whatever"*]

     Returns a string consisting of the LIST, repeated for every item
     in a comma-separated or space-separated list. This tag works the
     same way as the [item-list] tag, except for order-item-specific
     values. It is intended to pull multiple attributes from an item
     modifier, but can be useful for other things, like building a
     pre-ordained product list on a page.

     Loop lists can be nested by using different prefixes:

              [loop prefix=size list="Small Medium Large"]
                  [loop prefix=color list="Red White Blue"]
                      [color-code]-[size-code]<BR>
                  [/loop]
                  <P>
              [/loop]

     This will output:

              Red-Small
              White-Small
              Blue-Small
          
              Red-Medium
              White-Medium
              Blue-Medium
          
              Red-Large
              White-Large
              Blue-Large

     The search="args" parameter will return an arbitrary search, just
     as in a one-click search:

              [loop search="se=Americana/sf=category"]
                  [loop-code] [loop-field title]
              [/loop]

     The above will show all items with a category containing the
     whole world "Americana."

[if-loop-data table field] IF [else] ELSE [/else][/if-loop-data]

     Outputs the IF if the field in the table is not empty or the ELSE
     (if any) otherwise.

Note: This tag does not nest with other if-loop-data tags.

[if-loop-field] IF [else] ELSE [/else][/if-loop-field]

     Outputs the IF if the field in the products table is not empty or
     the ELSE (if any) otherwise.

Note: This tag does not nest with other if-loop-field tags.

[loop-alternate N] DIVISIBLE [else] NOT DIVISIBLE
[/else][/loop-alternate]

     Set up an alternation sequence. If the loop-increment is
     divisible by N, the text will be displayed. If [else]NOT
     DIVISIBLE TEXT [/else] is present, then the NOT DIVISIBLE TEXT
     will be displayed. For example:

              [loop-alternate 2]EVEN[else]ODD[/else][/loop-alternate]
              [loop-alternate 3]BY 3[else]NOT by 3[/else][/loop-alternate]

[/loop-alternate]

     Terminates the alternation area.

[loop-change marker]

     Same as [item-change], but within loop lists.

[loop-code]

     Evaluates to the first returned parameter for the current
     returned record.

[loop-data database fieldname]

     Evaluates to the field name fieldname in the arbitrary database
     table database for the current item.

[loop-description]

     Evaluates to the product description for the current item.
     Returns the <Description Field> from the first products database
     where that item exists.

[loop-field fieldname]

     The [loop-field]

     The [loop-field] tag is special in that it looks in any of the
     tables defined as ProductFiles, in that order, for the data and
     returns the value only if that key is defined. In most catalogs,
     where ProductFiles is not defined [loop-field title] is
     equivalent to [loop-field products title].

     Evaluates to the field name fieldname in the database for the
     current item.

[loop-increment]

     Evaluates to the number of the item in the list. Used for
     numbering items in the list. Starts from one (1).

[loop-last]tags[/loop-last]

     Evaluates the output of the ITL tags encased in the [loop-last]
     tags. If it evaluates to a numerical non-zero number (for
     example, 1, 23, -10 etc.), the loop iteration will terminate. If
     the evaluated number is negative, the item itself will be
     skipped. If the evaluated number is positive, the item itself
     will be shown, but will be last on the list.

                [loop-last][calc]
                  return -1 if '[loop-field weight]' eq '';
                  return 1 if '[loop-field weight]' < 1;
                  return 0;
                  [/calc][/loop-last]

     If this is contained in your [loop list] and the weight field is
     empty, a numerical -1 will be output from the [calc][/calc] tags;
     the list will end and the item will not be shown. If the
     product's weight field is less than 1, a numerical 1 is output.
     The item will be shown, but it will be the last item on the list.

[loop-next]tags[/loop-next]

     Evaluates the output of the ITL tags encased in the [loop-next]
     tags. If it evaluates to a numerical non-zero number (for
     example, 1, 23, -10 etc.), the loop will be skipped with no
     output. Example:

                [loop-next][calc][loop-field weight] < 1[/calc][/loop-next]

     If this is contained in your [loop list] and the product's weight
     field is less than 1, a numerical 1 will be output from the
     [calc][/calc] operation. The item will not be shown.

[loop-price n* noformat*]

     Evaluates to the price for the optional quantity n (from the
     products file) of the current item, with currency formatting. If
     the optional "noformat" is set, then currency formatting will not
     be applied.

[loop-calc] PERL [/loop-calc]

     Calls embedded Perl with the code in the container. All [loop-*]
     tags can be placed inside except for [loop-filter
     ...][/loop-filter], [loop-exec routine][/loop-exec],
     [loop-last][/loop-last] and [loop-next][/loop-next].

Note: All normal embedded Perl operations can be used, but be careful
to pre-open any database tables with a [perl tables="tables you
need"][/perl] tag prior to the opening of the [loop].

[loop-exec routine]argument[/loop-exec]

     Calls a subroutine predefined either in catalog.cfg with Sub or
     in a [loop] with [loop-sub routine] PERL [/loop-sub]. The
     container text is passed as $_[0] and the array (or hash) value
     of the current row is $_[1].

[loop-sub routine]PERL[/loop-sub]

     Defines a subroutine that is available to the current (and
     subsequent) [loop-*] tags within the same page. See Interchange
     Programming.

102.5. if
---------

[if type field op* compare*]

The Interchange Tags Reference has more information on the [if] tag.

     named attributes: [if type="type" term="field" op="op"
     compare="compare"]

[if !type field op* compare*]

     named attributes: [if type="!type" term="field" op="op"
     compare="compare"]

Allows the conditional building of HTML based on the setting of
various Interchange session and database values. The general form is:

         [if type term op compare]
         [then]
                                     If true, this text is printed on the document.
                                     The [then] [/then] is optional in most
                                     cases. If ! is prepended to the type
                                     setting, the sense is reversed and
                                     this text will be output for a false condition.
         [/then]
         [elsif type term op compare]
                                     Optional, tested when if fails.
         [/elsif]
         [else]
                                     Optional, printed on the document when all above fail.
         [/else]
         [/if]

The [if] tag can also have some variants:

         [if explicit]
         [condition] CODE [/condition]
                                     Displayed if valid Perl CODE returns a true value.
         [/if]

Some Perl-style regular expressions can be written:

         [if value name =~ /^mike/i]
                                     This is the if with Mike.
         [elsif value name =~ /^sally/i]
                                     This is an elsif with Sally.
         [/elsif]
         [elsif value name =~ /^barb/i]
         [or value name =~ /^mary/i]
                                     This is an elsif with Barb or Mary.
         [elsif value name =~ /^pat/i]
         [and value othername =~ /^mike/i]
                                     This is an elsif with Pat and Mike.
         [/elsif]
         [else]
                                     This is the else, no name I know.
         [/else]
         [/if]

While the named parameter tag syntax works for [if ...], it is more
convenient to use the positional syntax in most cases. The only
exception is when you are planning to do a test on the results of
another tag sequence:

This will not work:

   [if value name =~ /[value b_name]/]
       Shipping name matches billing name.
   [/if]

Do this instead:

   [if type=value term=name op="=~" compare="/[value b_name]/"]
       Shipping name matches billing name.
   [/if]

As an alternative:

   [if type=value term=high_water op="<" compare="[shipping noformat=1]"]
       The shipping cost is too high, charter a truck.
   [/if]

There are many test targets available. The following is a list of some
of the available test targets.

config Directive

     The Interchange configuration variables. These are set by the
     directives in the Interchange configuration file.

              [if config CreditCardAuto]
              Auto credit card validation is enabled.
              [/if]

data  database::field::key

     The Interchange databases. Retrieves a field in the database and
     returns true or false based on the value.

              [if data products::size::99-102]
              There is size information.
              [else]
              No size information.
              [/else]
              [/if]
          
              [if data products::size::99-102 =~ /small/i]
              There is a small size available.
              [else]
              No small size available.
              [/else]
              [/if]

     If another tag is needed to select the key, and it is not a
     looping tag construct, named parameters must be used:

              [set code]99-102[/set]
              [if type=data term="products::size::[scratch code]"]
              There is size information.
              [else]
              No size information.
              [/else]
              [/if]

discount

     Checks to see if a discount is present for an item.

              [if discount 99-102]
              This item is discounted.
              [/if]

explicit

     A test for an explicit value. If Perl code is placed between a
     [condition] [/condition] tag pair, it will be used to make the
     comparison. Arguments can be passed to import data from user
     space, just as with the [perl] tag.

              [if explicit]
              [condition]
                  $country = $ values =~{country};
                  return 1 if $country =~ /u\.?s\.?a?/i;
                  return 0;
              [/condition]
              You have indicated a US address.
              [else]
              You have indicated a non-US address.
              [/else]
              [/if]

     The same thing could be accomplished with [if value country =~
     /u\.?s\.?a?/i], but there are many situations where this example
     could be useful.

file

     Tests for the existence of a file. This is useful for placing
     image tags only if the image is present.

              [if file /home/user/www/images/[item-code].gif]
              <IMG SRC="[item-code].gif">
              [/if]
          
              or
          
              [if type=file term="/home/user/www/images/[item-code].gif"]
              <IMG SRC="[item-code].gif">
              [/if]

     The file test requires that the SafeUntrap directive contain
     ftfile (which is the default).

items

     The Interchange shopping carts. If not specified, the cart used
     is the main cart. This is usually used to test to see if anything
     is in the cart. For example:

            [if items]You have items in your shopping cart.[/if]
          
            [if items layaway]You have items on layaway.[/if]

ordered

     Order status of individual items in the Interchange shopping
     carts. Unless otherwise specified, the cart used is the main
     cart. The following items refer to a part number of 99-102.

            [if ordered 99-102] ... [/if]
              Checks the status of an item on order, true if item
              99-102 is in the main cart.
          
            [if ordered 99-102 layaway] ... [/if]
              Checks the status of an item on order, true if item
              99-102 is in the layaway cart.
          
            [if ordered 99-102 main size] ... [/if]
              Checks the status of an item on order in the main cart,
              true if it has a size attribute.
          
            [if ordered 99-102 main size =~ /large/i] ... [/if]
              Checks the status of an item on order in the main cart,
              true if it has a size attribute containing 'large'.
              THE CART NAME IS REQUIRED IN THE OLD SYNTAX. The new
              syntax for that one would be:
          
              [if type=ordered term="99-102" compare="size =~ /large/i"]
          
              To make sure it is the size that is large and not another attribute, you could use:
          
              [if ordered 99-102 main size eq 'large'] ... [/if]
          
            [if ordered 99-102 main lines] ... [/if]
                Special case -- counts the lines that the item code is
                present on. (Only useful, of course, when mv_separate_items
                or SeparateItems is defined.)

scratch

     The Interchange scratchpad variables, which can be set with the
     [set name] value [/set] element.

              [if scratch mv_separate_items]
              Ordered items will be placed on a separate line.
              [else]
              Ordered items will be placed on the same line.
              [/else]
              [/if]

session

     The Interchange session variables. Of particular interest are
     logged_in, source, browser and username.

validcc

     A special case, it takes the form [if validcc no type exp_date].
     Evaluates to true if the supplied credit card number, type of
     card and expiration date pass a validity test. It performs a
     LUHN-10 calculation to weed out typos or phony card numbers.

value

     The Interchange user variables, typically set in search, control
     or order forms. Variables beginning with mv_ are Interchange
     special values and should be tested and used with caution.

variable

     See Interchange Variable values.

The field term is the specifier for that area. For example, [if
session frames] would return true if the frames session parameter was
set.

As an example, consider buttonbars for frame-based setups. You might
decide to display a different buttonbar with no frame targets for
sessions that are not using frames:

   [if session frames]
       [buttonbar 1]
   [else]
       [buttonbar 2]
   [/else]
   [/if]

Another example might be the when search matches are displayed. If
using the string [value mv_match_count] titles found, it will display
a plural result even if there is only one match. Use:

   [if value mv_match_count != 1]
       [value mv_match_count] matches found.
   [else]
       Only one match was found.
   [/else]
   [/if]

The op term is the compare operation to be used. Compare operations
are the same as they are in Perl:

   ==  numeric equivalence
   eq  string equivalence
   >   numeric greater-than
   gt  string greater-than
   <   numeric less-than
   lt  string less-than
   !=  numeric non-equivalence
   ne  string equivalence

Any simple Perl test can be used, including some limited regex
matching. More complex tests should be done with [if explicit].

[then] text [/then]

     This is optional if not nesting "if" conditions. The text
     immediately following the [if ..] tag is used as the
     conditionally substituted text. If nesting [if ...] tags, use
     [then][/then] on any outside conditions to ensure proper
     interpolation.

[elsif type field op* compare*]

     named attributes: [elsif type="type" term="field" op="op"
     compare="compare"]

     Additional conditions for test, applied if the initial [if ..]
     test fails.

[else] text [/else]

     The optional else-text for an if or if-item-field conditional.

[condition] text [/condition]

     Only used with the [if explicit] tag. Allows an arbitrary
     expression in Perl to be placed inside, with its return value
     interpreted as the result of the test. If arguments are added to
     [if explicit args], those will be passed as arguments in the
     [perl] construct.

[/if]

     Terminates an if conditional.

103. Programming
================

Interchange has a powerful paradigm for extending and enhancing its
functionality. It uses two mechanisms, user-defined tags and user
subroutines on two different security levels, global and catalog. In
addition, embedded Perl code can be used to build functionality into
pages.

User-defined tags are defined with the UserTag directive in either
interchange.cfg or catalog.cfg. The tags in interchange.cfg are global
and they are not constrained by the Safe Perl module as to which
opcodes and routines they may use. The user-defined tags in
catalog.cfg are constrained by Safe. However, if the AllowGlobal
global directive is set for the particular catalog in use, its UserTag
and Sub definitions will have global capability.

103.1. Overriding Interchange Routines
--------------------------------------

Many of the internal Interchange routines can be accessed by
programmers who can read the source and find entry points. Also, many
internal Interchange routines can be overridden:

   GlobalSub <<EOS
   sub just_for_overriding {
       package Vend::Module;
       use MyModule;
       sub to_override {
           &MyModule::do_something_funky($Values->{my_variable});
       }
   }
   EOS

The effect of the above code is to override the to_override routine in
the module Vend::Module. This is preferable to hacking the code for
functionality changes that are not expected to change frequently. In
most cases, updating the Interchange code will not affect the
overridden code.

Note: Internal entry points are not guaranteed to exist in future
versions of Interchange.

103.2. Embedding Perl Code
--------------------------

Perl code can be directly embedded in Interchange pages. The code is
specified as:

   [perl]
       $name    = $Values->{name};
       $browser = $Session->{browser};
       return "Hi, $name! How do you like your $browser?";
   [/perl]

ASP syntax can be used with:

   [mvasp]
       <%
       $name    = $Values->{name};
       $browser = $Session->{browser};
       %>
       Hi, <%= $name %>!
       <%
           HTML "How do you like your $browser?";
       %>
   [/mvasp]

The two examples above are essentially equivalent.  See the perl and 
mvasp tags for usage details.

The [perl] tag enforces Safe.pm checking, so many standard Perl
operators are not available. This prevents user access to all files
and programs on the system without the Interchange daemon's
permissions. See GlobalSub and User-defined Tags for ways to make
external files and programs available to Interchange.

     Named parameters:

     See the perl tag for a description of the tag parameters and
     attributes.  These include:

       [perl tables="tables-to-open"*
               subs=1*
             global=1*
          no_return=1*
            failure="Return value in case of compile or runtime error"*
               file="include_file"*]

     Required parameters: none

Any Interchange tag (except ones using SQL) can be accessed using the
$Tag object. If using SQL queries inside a Perl element, AllowGlobal
permissions are required and and the global=1 parameter must be set.
Installing the module Safe::Hole along with sharing the database table
with <tables=tablename> will enable SQL use.

     For example:

             # If the item might contain a single quote
             [perl]
             $comments = $Values->{comments};
             [/perl]

Important Note: Global subroutines are not subject to the stringent
security check from the Safe module. This means that the subroutine
will be able to modify any variable in Interchange and will be able to
write to read and write any file that the Interchange daemon has
permission to write. Because of this, the subroutines should be used
with caution. They are defined in the main interchange.cfg file and
can't be reached by from individual users in a multi-catalog system.

Global subroutines are defined in interchange.cfg with the GlobalSub
directive or in user catalogs which have been enabled through
AllowGlobal. Catalog subroutines are defined in catalog.cfg, with the
Sub directive and are subject to the stringent Safe.pm security
restrictions that are controlled by the global directive SafeUntrap.

The code can be as complex as you want them to be, but cannot be used
by operators that modify the file system or use unsafe operations like
"system," "exec," or backticks. These constraints are enforced with
the default permissions of the standard Perl module Safe. Operations
may be untrapped on a system-wide basis with the SafeUntrap directive.

The result of this tag will be the result of the last expression
evaluated, just as in a subroutine. If there is a syntax error or
other problem with the code, there will be no output.

Here is a simple one which does the equivalent of the classic hello.pl
program:

   [perl] my $tmp = "Hello, world!"; $tmp; [/perl]

There is no need to set the variable. It is there only to show the
capability.

To echo the user's browser, but within some HTML tags:

   [perl]
   my $html = '<H5>';
   $html .= $Session->{browser};
   $html .= '</H5>';
   $html;
   [/perl]

To show the user their name and the current time:

   [perl]

   my $string = "Hi, " . $Values->{name} ". The time is now ";
   $string .= $Tag->time();
   $string;

   [/perl]

103.3. ASP-Like Perl
--------------------

Interchange supports an ASP-like syntax using the [mvasp] tag.

   [mvasp]
   <HTML><BODY>
       This is HTML.<BR>

   <% HTML "This is code<BR>"; %>
       More HTML.<BR>
   <% $Document->write("Code again.<BR>") %>
   [/mvasp]

If no closing [/mvasp] tag is present, the remainder of the page will
also be seen as ASP.

ASP is simple. Anything between <% and %> is code, and the string %>
can not occur anywhere inside. Anything not between those anchors is
plain HTML that is placed unchanged on the page. Interchange
variables, [L][/L] and [LC][/LC] areas will still be inserted, but any
Interchange tags will not.

There is a shorthand <% = $foo %>, which is equivalent to <%
$Document->write($foo); %> or <% HTML $foo; %>

   [mvasp]
   <HTML><BODY>
       This is HTML.<BR>
       [value name] will show up as &#91;value name].<BR>

       &#95_VARIABLE__ value is equal to: __VARIABLE__

   <% = "This is code<BR>" %>

The __VARIABLE__ will be replaced by the value of Variable VARIABLE,
but [value name] will be shown unchanged.

Important Note: If using the SQL::Statement module, the catalog must
be set to AllowGlobal in interchange.cfg. It will not work in "Safe"
mode due to the limitations of object creation in Safe. Also, the
Safe::Hole module must be installed to have SQL databases work in Safe
mode.



103.4. Error Reporting
----------------------

If your Perl code fails with a compile or runtime error, Interchange
writes the error message from the Perl interpreter into the catalog's
error log. This is usually 'catalog_root/error.log'. Error messages do
not appear on your web page as the return value of the Perl tag or
routine.

You will not have direct access to the 'strict' and 'warnings' pragmas
where Interchange runs your perl code under Safe (for example, within
a [perl] or [mvasp] tag).

104. Interchange Perl Objects
=============================

     Interchange gives you access to the power of Perl with the
     [perl], [calc] and

     [mvasp] tags. They all support the same set of Perl objects and
     variables.

104.1. A note about Safe
------------------------

You can access all objects associated with the catalog and the user
settings with opcode restrictions based on the standard Perl module
Safe.pm. There are some unique things to know about programming with
Interchange.

Under Safe, certain things cannot be used. For instance, the following
can not be used when running Safe:

   $variable = `cat file/contents`;

The backtick operator violates a number of the default Safe opcode
restrictions. Also, direct file opens can not be used. For example:

   open(SOMETHING, "something.txt")
       or die;

This will also cause a trap, and the code will fail to compile.
However, equivalent Interchange routines can be used:

   # This will work if your administrator doesn't have NoAbsolute set
   $users = $Tag->file('/home/you/list');

   # This will always work, file names are based in the catalog directory
   $users = $Tag->file('userlist');

104.2. Standard objects and variables
-------------------------------------

The following is a list of Interchange Perl standard objects are:

$CGI

     This is a hash reference to %CGI::values, the value of user
     variables as submitted in the current page/form. To get the value
     of a variable submitted as

              <INPUT TYPE=hidden NAME=foo VALUE=bar>

     use

              [perl]
                          return "Value of foo is $CGI->{foo}";
                  [/perl]

Actually, you should not do that -- if someone sends you a value you
should not output it willy-nilly for security reasons. Filter it first
with the [filter] tag as accessed by the $Tag object:

              [perl]
                          my $val = $Tag->filter('encode_entities', $CGI->{foo});
                          return "Value of foo is $val";
                  [/perl]

     Remember, multiple settings of the same variable are separated by
     a NULL character. To get the array value, use $CGI_array.

$CGI_array

     This is a hash reference to %CGI::values_array, arrays containing
     the value or values of user variables as submitted in the current
     page/form. To get the value of a variable submitted as

              <INPUT TYPE=hidden NAME=foo VALUE='bar'>
              <INPUT TYPE=hidden NAME=foo VALUE='baz'>

     use

              <% = "The values of foo are", join (' and ', @{$CGI_array->{'foo'}}) %>

     Remember, multiple settings of the same variable are separated by
     a NULL character. To get the array value, use $CGI_array.

$Carts

     A reference to the shopping cart hash $Vend::Session->{carts}.
     The normal default cart is "main". A typical alias is $Items.

     Shopping carts are an array of hash references. Here is an
     example of a session cart array containing a main and a layaway
     cart.

              {
                  'main' => [
                              {
                                  'code' => '00-0011',
                                  'mv_ib' => 'products',
                                  'quantity' => 1,
                                  'size' => undef,
                                  'color' => undef
                              },
                              {
                                  'code' => '99-102',
                                  'mv_ib' => 'products',
                                  'quantity' => 2,
                                  'size' => 'L',
                                  'color' => 'BLUE'
                              }
                          ],
                  'layaway' => [
                              {
                                  'code' => '00-341',
                                  'mv_ib' => 'products',
                                  'quantity' => 1,
                                  'size' => undef,
                                  'color' => undef
                              }
                          ]
              }

     In this cart array, $Carts->{main}[1]{code} is equal to 99-102.
     Normally, it would be equivalent to $Items->[1]{code}.

$Config

     A reference to the $Vend::Cfg array. This is normally used with a
     large amount of the Interchange source code, but for simple
     things use something like:

    # Allow searching the User database this page only
    $Config->{NoSearch} =~ s/\buserdb\b//;

     Changes are not persistent -- they are reset upon the next page
     access.

%Db

     A hash of databases shared with the tables="foo" parameter to the
     [perl] resp. [mvasp] tag calls. Once the database is shared, it
     is open and can be accessed by any of its methods. This will not
     work with SQL unless the Safe::Hole module is installed or
     AllowGlobal is set for the catalog.

NOTE: This object is not present and the below will not work with
[calc].

     To get a reference to a particular table, specify its hash
     element:

              my $db = $Db{products};

     The available methods are:

              # access an element of the table
              $field = $db->field($key, $column);
          
              # set an element of the table
              $db->set_field($key, $column_name, $value);
          
              # atomic increment of an element of the table
              $db->inc_field($key, $column_name, 1);
          
              # Return a complete hash of the database row (minus the key)
              $hashref = $db->row_hash($key);
          
              # Return some fields from a row
              my @fields = qw/sku price description/;
              $array_ref = $db->get_slice($key, \@fields);
          
              # Set some fields in a row (slice)
              my $key = 'os28004';
              my @fields = qw/price description/;
              my @values = (5.95, "Ergo Roller");
              $array_ref = $db->set_slice($key, \@fields, \@values);
          
              # Alternate way to set slice
              my $key = 'os28004';
              my %fields = ( price => 5.95, description => "Ergo Roller");
              $array_ref = $db->set_slice($key, \%fields);
          
              # Perform a SQL query, returning an array of arrays
              # (the equivalent of DBI $sth->fetchall_arrayref)
              $ary = $db->query($sql);
          
              # Same as above, except receive
              # hash reference of pointers to field positions and
              # array reference containing list of fields
              my $sql = 'select * from products';
              ($ary, $index_hash, $name_ary) = $db->query($sql);
              $fields_returned = join ",", @$name_ary;
              $pointer_to_price = $index_hash->{price};
          
              # Perform a SQL query, returning an array of hashes
              $ary = $db->query({ sql => $sql, hashref => 1 });
          
              # see if element of the table is numeric
              $is_numeric = $db->numeric($column_name);
          
              # Quote for SQL query purposes
              $quoted = $db->quote($value, $column_name);
          
              # Check configuration of the database
              $delimiter = $db->config('DELIMITER');
          
              # Find the names of the columns (not including the key)
              @columns = $db->columns();
              # Insert the key column name
              unshift @columns, $db->config('KEY');
          
              # See if a column is in the table
              $is_a_column = defined $db->test_column($column_name);
          
              # See if a row is in the table
              $is_present = $db->record_exists($key);
          
              # Create a subroutine to return a single column from the table
              $sub = $db->field_accessor($column);
              for (@keys) {
                  push @values, $sub->($key);
              }
          
              # Create a subroutine to set a single column in the database
              $sub = $db->field_settor($column);
              for (@keys) {
                  $sub->($key, $value);
              }
          
              # Create a subroutine to set a slice of the database
              $sub = $db->row_settor(@columns);
              for (@keys) {
                  $sub->($key, @values);
              }
          
              # Return a complete array of the database (minus the key)
              @values = $db->row($key);
          
              # Delete a record/row from the table
              $db->delete_record($key);

%Sql

     A hash of SQL databases that you shared with the [perl
     tables="foo"] parameter to the tag call. It returns the DBI
     database handle, so operations like the following can be
     performed:

NOTE: This object is not present and the below will not work with
[calc].

            [perl products]
              my $dbh = $Sql{products}
                  or return "Database not shared.";
              my $sth = $dbh->prepare('select * from products')
                  or return "Couldn't open database.";
              $sth->execute();
              my @record;
              while(@record = $sth->fetchrow()) {
                  foo();
              }
              $sth = $dbh->prepare('select * from othertable')
                  or return "Couldn't open database.";
              $sth->execute();
              while(@record = $sth->fetchrow()) {
                  bar();
              }
            [/perl]

$DbSearch

     A search object that will search a database without using the
     text file. It is the same as Interchange's db searchtype. Options
     are specified in a hash and passed to the object. All
     multiple-field options should be passed as array references.
     Before using the $DbSearch object, it must be told which table to
     search. For example, to use the table foo, it must have been
     shared with [mvasp foo].

     There are three search methods: array, hash and list.

              array    Returns a reference to an array of arrays (best)
              hash     Returns a reference to an array of hashes (slower)
              list     Returns a reference to an array of tab-delimited lines

     \Example:

              $DbSearch->{table} = $Db{foo};
          
              $search = {
          
                      mv_searchspec => 'Mona Lisa',
                      mv_search_field => [ 'title', 'artist', 'price' ],
                      mv_return_fields    => [ 'title' ]
          
                  };
          
              my $ary = $DbSearch->array($search);
          
              if(! scalar @$ary) {
                  return HTML "No match.\n";
              }
          
              for(@$ary) {

$Document

This is an object which will allow you to write and manipulate the
output of your embedded Perl. For instance, you can emulate a
non-parsed-header program with:

          [perl]
                  $Document->hot(1);
                  for(1 .. 20) {
                          $Document->write("Counting to $_...<br>");
                          $Document->write( " " x 4096);
                          $Tag->sleep(1);
                  }
                  $Document->write("Finished counting!");
                  return;
          [/perl]

Note the write of 4096 spaces. Because Interchange's link program is
parsed by default and your web server (and the link program) have
buffers, you need to fill up the buffer to cause a write. You can do
it without the extra padding if you set the link up as a
non-parsed-header program -- see your web server documentation on how
to do that.

There are several methods associated with $Document:

           HTML $foo;                     # Append $foo to the write buffer array
           $Document->write($foo);        # object call to append $foo to the write
                                          # buffer array
           $Document->insert($foo);       # Insert $foo to front of write buffer array
           $Document->header($foo, $opt); # Append $foo to page header
           $Document->send();             # Send write buffer array to output, done
                                          # automatically upon end of ASP, clears buffer
                                          # and invalidates $Document->header()
           $Document->hot(1);             # Cause writes to send immediately
           $Document->hot(0);             # Stop immediate send
           @ary = $Document->review();    # Place contents of write buffer in @ary
           $Document->replace(@ary)       # Replace contents of write buffer with @ary
           $ary_ref = $Document->ref();   # Return ref to output buffer

$Document->write($foo)

     Write $foo to the page in a buffered fashion. The buffer is an
     array containing the results of all previous $Document->write()
     operations. If $Document->hot(1) has been set, the output
     immediately goes to the user.

$Document->insert($foo)

     Insert $foo to the page buffer. The following example will output
     "123"

              $Document->write("23");
              $Document->insert("1");
              $Document->send();

     while this example will output "231"

              $Document->write("23");
              $Document->write("1");
              $Document->send();

     will output "231".

$Document->header($foo, $opt)

     Add the header line $foo to the HTTP header. This is used to
     change the page content type, cache options or other attributes.
     The code below changes the content type (MIME type) to
     text/plain:

              $Document->header("Content-type: text/plain");

     There is an optional hash that can be sent with the only valid
     value being "replace." The code below scrubs all previous header
     lines:

              $Document->header("Content-type: text/plain", { replace => 1 } );

     Once output has been sent with $Document->send(), this can no
     longer be done.

$Document->hot($foo)

     If the value of $foo is true (in a Perl sense), then all
     $Document->write() operations will be immediately sent until a
     $Document->hot(0) is executed.

$Document->send()

     Causes the document write buffer to be sent to the browser and
     empties the buffer. Any further $Document->header() calls will be
     ignored. Can be used to implement non-parsed-header operation.

$Document->review()

     Returns the value of the write buffer.

              @ary = $Document->review();

$Document->replace(@new)

     Completely replaces the write buffer with the arguments.

$Document->ref()

     Returns a reference to the write buffer.

              # Remove the first item in the write buffer
              my $ary_ref = $Document->ref();
              shift @$ary_ref;

HTML

     Writes a string (or list of strings) to the write buffer array.
     The call

              HTML $foo, $bar;

     is exactly equivalent to

              $Document->write($foo, $bar);

     Honors the $Document->hot() setting.

$Items

     A reference to the current shopping cart. Unless an Interchange
     [cart ...] tag is used, it is normally the same as
     $Carts->{main}.

$Scratch

     A reference to the scratch values ala [scratch foo].

             <% $Scratch->{foo} = 'bar'; %>

     is equivalent to:

              [set foo]bar[/set]

$Session

     A reference to the session values ala [data session username].

              <%
                  my $out = $Session->{browser};
                  $Document->write($out);
              %>

     is equivalent to:

              [data session browser]

     Values can also be set. If the value of [data session source]
     needed to be changed, for example, set:

              <%
                  $Session->{source} = 'New_partner';
              %>

$Tag

     Using the $Tag object, any Interchange tag including user-defined
     tags can be accessed.

IMPORTANT NOTE: If the tag will access a database that has not been
previously opened, the table name must be passed in the ITL call. For
example:

     Named parameters:

              [perl tables="products pricing"]

     or

     Positional parameters:

              [perl products pricing]

     Any tag can be called.

              [perl]
                  my $user = $Session->{username};
                  return $Tag->data('userdb', 'name', $user );
              [/perl]

     is the same as:

              [data table=userdb column=name key="[data session username]"]

     If the tag has a dash (-) in it, use an underscore instead:

              # WRONG!!!
              $Tag->shipping-desc('upsg');
              # Right
              $Tag->shipping_desc('upsg');

     There are two ways of specifying parameters. Either use the
     positional parameters as documented (for an authoritative look at
     the parameters, see the %Routine value in Vend::Parse) or specify
     it all with an option hash parameter names as in any named
     parameters as specified in an Interchange tag. The calls

              $Tag->data('products', 'title', '00-0011');

     and

              my $opt = {
                              table   => 'products',
                              column  => 'title',
                              key     => '00-0011',
                          };
          
              $Tag->data( $opt );

     are equivalent for the data tag.

     If using the option hash method, and the tag has container text,
     either specify it in the hash parameter body or add it as the
     next argument. The two calls:

              $Tag->item_list( {
                                  'body' => "[item-code] [item-field title]",
                              });

     and

              $Tag->item_list( { }, "[item-code] [item-field title]")

     are equivalent.

     Parameter names are ALWAYS lower case.

$Values

     A reference to the user form values ala [value foo].

              <% $Document->write($Values->{foo}); %>

     is equivalent to:

              [value foo]

&Log

     Send a message to the error log (same as ::logError in GlobalSub
     or global UserTag).

              <%
                  Log("error log entry");
              %>

     It prepends the normal timestamp with user and page information.
     To suppress that information, begin the message with a backslash
     (\).

              <%
                  Log("\\error log entry without timestamp");
                  Log('\another error log entry without timestamp');
                  Log("error log entry with timestamp");
              %>

105. Debugging
==============

No debug output is provided by default. The source files contain
commented-out '::logDebug(SOMETHING)' statements which can be edited
to activate them. Set the value of DebugFile to a file that will be
written to:

   DebugFile /tmp/icdebug

105.1. Export
-------------

     Named Parameters: [export table="dbtable"]

     Positional Parameters: [export db_table]

     The attribute hash reference is passed to the subroutine after
     the parameters as the last argument. This may mean that there are
     parameters not shown here. Must pass named parameter
     interpolate=1 to cause interpolation.

     Invalidates cache: YES

     Called Routine:

     ASP/perl tag calls:

              $Tag->export(
                  {
                   table => VALUE,
                  }
              )

     OR

              $Tag->export($table, $ATTRHASH);

     Attribute aliases:

                  base ==> table
                  database ==> table

105.2. Time
-----------

     Named Parameters: [time locale="loc"]

     Positional Parameters: [time loc]

     The attribute hash reference is passed after the parameters but
     before the container text argument. This may mean that there are
     parameters not shown here. Must pass named parameter
     interpolate=1 to cause interpolation.

     This is a container tag, i.e., [time] FOO [/time].

     Nesting: NO.

     Invalidates cache: NO.

     Called Routine:

     ASP/perl tag calls:

              $Tag->time(
                  {
                   locale => VALUE,
                  },
                  BODY
              )

     OR

              $Tag->time($locale, $ATTRHASH, $BODY);

105.3. Import
-------------

     Named Parameters: [import table=table_name
     type=(TAB|PIPE|CSV|%%|LINE) continue=(NOTES|UNIX|DITTO)
     separator=c]

     Positional Parameters: [import table_name TAB]

     The attribute hash reference is passed after the parameters but
     before the container text argument. This may mean that there are
     parameters not shown here. Interpolates container text by
     default>.

     This is a container tag, i.e., [import] FOO [/import].

     Nesting: NO

     Invalidates cache: YES.

     Called Routine:

     ASP/perl tag calls:

              $Tag->import(
                  {
                   table => VALUE,
                   type => VALUE,
                  },
                  BODY
              )

     OR

              $Tag->import($table, $type, $ATTRHASH, $BODY);

     Attribute aliases:

                  base ==> table
                  database ==> table

     Description:

     Import one or more records into a database. The type is any of
     the valid Interchange delimiter types, with the default being
     defined by the setting of the database DELIMITER. The table must
     already be a defined Interchange database table; it cannot be
     created on-the-fly. (Use SQL for on-the-fly tables.)

     The type of LINE and continue setting of NOTES is particularly
     useful, for it allows the naming of fields so that the order in
     which they appear in the database will not have to be remembered.
     The following two imports are identical in effect:

              [import table=orders type=LINE continue=NOTES]
              code: [value mv_order_number]
              shipping_mode: [shipping-description]
              status: pending
              [/import]
          
              [import table=orders type=LINE continue=NOTES]
              shipping_mode: [shipping-description]
              status: pending
              code: [value mv_order_number]
              [/import]

     The code or key must always be present, and is always named code.
     If NOTES mode is not used, import the fields in the same order as
     they appear in the ASCII source file. The [import ....] TEXT
     [/import] region may contain multiple records. If using NOTES
     mode, use a separator, which by default is a form-feed character
     (^L).

105.4. Log
----------

     Named Parameters: [log file=file_name]

     Positional Parameters: [log file_name]

     The attribute hash reference is passed after the parameters but
     before the container text argument. This may mean that there are
     parameters not shown here. Must pass named parameter
     interpolate=1 to cause interpolation. This is a container tag,
     i.e., [log] FOO [/log].

     Nesting: NO.

     Invalidates cache: NO.

     Called Routine:

     ASP/perl tag calls:

              $Tag->log(
                  {
                   file => VALUE,
                  },
                  BODY
              )

     OR

              $Tag->log($file, $ATTRHASH, $BODY);

     Attribute aliases:

                  arg ==> file

105.5. Header
-------------

105.6. price, description, accessories
--------------------------------------

[price code quantity* database* noformat*]

     named attributes: [price code="code" quantity="N" base="database"
     noformat=1* optionX="value"]

     Expands into the price of the product identified by code as found
     in the products database. If there is more than one products file
     defined, they will be searched in order unless constrained by the
     optional argument base. The optional argument quantity selects an
     entry from the quantity price list. To receive a raw number, with
     no currency formatting, use the option noformat=1.

     If an named attribute corresponding to a product option is
     passed, and that option would cause a change in the price, the
     appropriate price will be displayed.

     Demo example: The T-Shirt (product code 99-102), with a base
     price of $10.00, can vary in price depending on size and color.
     S, the small size, is 50 cents less; XL, the extra large size, is
     $1.00 more and the color RED is 0.75 extra. There are also
     quantity pricing breaks (see the demo pricing database. So the
     following will be true:

              [price  code=99-102
                      size=L]              is $10.00
          
              [price  code=99-102
                      size=XL]             is $11.00
          
              [price  code=99-102
                      color=RED
                      size=XL]             is $11.75
          
              [price  code=99-102
                      size=XL
                      quantity=10]         is $10.00
          
              [price  code=99-102
                      size=S]              is $9.50

     An illustration of this is on the simple flypage template when
     passed that item code.

[description code table*]

     named attributes: [description code="code" base="database"]

     Expands into the description of the product identified by code as
     found in the products database. If there is more than one
     products file defined, they will be searched in order unless
     constrained by the optional argument table.

[accessories code attribute*, type*, field*, database*, name*,
outboard*]

     named attributes: [accessories code="code" arg="attribute*,
     type*, field*, database*, name*, outboard*"]

     Initiates special processing of item attributes based on entries
     in the product database. See Item Attributes for a complete
     description of the arguments.

     When called with an attribute, the database is consulted and
     looks for a comma-separated list of attribute options. They take
     the form:

              name=Label Text, name=Label Text*

     The label text is optional. If none is given, the name will be
     used.

     If an asterisk is the last character of the label text, the item
     is the default selection. If no default is specified, the first
     will be the default. An example:

              [accessories TK112 color]

     This will search the product database for a field named "color."
     If an entry "beige=Almond, gold=Harvest Gold, White*,
     green=Avocado" is found, a select box like this will be built:

              <SELECT NAME="mv_order_color">
              <OPTION VALUE="beige">Almond
              <OPTION VALUE="gold">Harvest Gold
              <OPTION SELECTED>White
              <OPTION VALUE="green">Avocado
              </SELECT>

     In combination with the mv_order_item and mv_order_quantity
     variables, this can be used to allow entry of an attribute at
     time of order.

105.7. FILE and INCLUDE
-----------------------

These elements read a file from the disk and insert the contents in
the location of the tag. [include ...] will allow insertion of
Interchange variables and ITL tags.

[file ...]

     named: [file name="name" type="dos|mac|unix"*]

     positional: [file name]

     Inserts the contents of the named file. The file should normally
     be relative to the catalog directory. File names beginning with /
     or .. are only allowed if the Interchange server administrator
     has disabled NoAbsolute. The optional type parameter will do an
     appropriate ASCII translation on the file before it is sent.

[include file]

     named attributes: [include file="name"]

     Same as [file name] except interpolates for all Interchange tags
     and variables.

105.8. Banner/Ad rotation
-------------------------

Interchange has a built-in banner rotation system designed to show ads
or other messages according to category and an optional weighting.

The [banner ...] ITL tag is used to implement it.

The weighting system pre-builds banners in the directory 'Banners,'
under the temporary directory. It will build one copy of the banner
for every one weight. If one banner is weighted 7, one 2 and one 1,
then a total of 10 pre-built banners will be made. The first will be
displayed 70 percent of the time, the second 20 percent and the third
10 percent, in random fashion. If all banners need to be equal, give
each a weight of 1.

Each category may have separate weighting. If the above is placed in
category tech, then it will behave as above when placed in [banner
category=tech] in the page. A separate category, say art, would have
its own rotation and weighting.

The [banner ...] tag is based on a database table, named banners by
default. It expects a total of five (5) fields in the table:

code

     This is the key for the item. If the banners are not weighted,
     this should be a category specific code.

category

     To choose to categorize weighted ads, this contains the category
     to select. If empty, it will be placed in the default (or blank)
     category.

weight

     Must be an integer number 1 or greater to include this ad in the
     weighting. If 0 or blank, the ad will be ignored when weighted
     ads are built.

rotate

     If the weighted banners are not used, this must contain some
     value. If the field is empty, the banner will not be displayed.
     If the value is specifically 0 (zero), then the entire contents
     of the banner field will be displayed when this category is used.
     If it is non-zero, then the contents of the banner field will be
     split into segments (by the separator {or}). For each segment,
     the banners will rotate in sequence for that user only.
     Obviously, the first banner in the sequence is more likely to be
     displayed than the last.

     Summary of values of rotate field:

              non-zero, non-blank: Rotating ads
              blank:               Ad not displayed
              0:                   Ad is entire contents of banner field

banner

     This contains the banner text. If more than one banner is in the
     field, they should be separated by the text {or} (which will not
     be displayed).

Interchange expects the banner field to contains the banner text. It
can contain more than one banner, separated by the string '{or}.' To
activate the ad, place any string in the field rotate.

The special key "default" is the banner that is displayed if no
banners are found. (Doesn't apply to weighted banners.)

Weighted banners are built the first time they are accessed after
catalog reconfiguration. They will not be rebuilt until the catalog is
reconfigured or the file tmp/Banners/total_weight and
tmp/Banners/<category>/total_weight is removed.

If the option once is passed (i.e., [banner once=1 weighted=1], then
the banners will not be rebuilt until the total_weight file is
removed.

The database specification should make the weight field numeric so
that the proper query can be made. Here is the example from
Interchange's demo:

   Database   banner   banner.txt   TAB
   Database   banner   NUMERIC      weight

Examples:

weighted, categorized

     To select categorized and weighted banners:

     The banner table would look like this:

              code    category   weight   rotate   banner
              t1      tech       1                 Click here for a 10% banner
              t2      tech       2                 Click here for a 20% banner
              t3      tech       7                 Click here for a 70% banner
              a1      art        1                 Click here for a 10% banner
              a2      art        2                 Click here for a 20% banner
              a3      art        7                 Click here for a 70% banner

     Tag would be:

              [banner weighted=1 category="tech"]

     This will find *all* banners with a weight >= 1 where the
     category field is equal to tech. The files will be made into the
     director tmp/Banners/tech.

weighted

     To select weighted banners:

              [banner weighted=1]

     This will find *all* banners with a weight >= 1. (Remember,
     integers only.) The files will be made into the director
     tmp/Banners.

              code    category   weight   rotate   banner
              t1      tech       1                 Tech banner 1
              t2      tech       2                 Tech banner 2
              t3      tech       7                 Tech banner 3
              a1      art        1                 Art banner 1
              a2      art        2                 Art banner 2
              a3      art        7                 Art banner 3

     Each of the above with a weight of 7 will actually be displayed
     35 percent of the time.

categorized, not rotating

              [banner category="tech"]

     This is equivalent to:

              [data table=banner col=banner key=tech

     The differences are that it is not selected if "rotate" field is
     blank; if not selected, the default banner is displayed.

     The banner table would look like this:

              code    category   weight   rotate   banner
              tech               0        0        Tech banner

     Interchange tags can be inserted in the category parameter, if
     desired:

              [banner category="[value interest]"]

categorized and rotating

              [banner category="tech"]

     The difference between this and above is the database.

     The banner table would look like this:

              code    category   weight   rotate   banner
              tech               0        1        Tech banner 1{or}Tech banner 2
              art                0        1        Art banner 1{or}Art banner 2

     This would rotate between banner 1 and 2 for the category tech
     for each user. Banner 1 is always displayed first. The art banner
     would never be displayed unless the tag [banner category=art] was
     used, of course.

     Interchange tags can be inserted in the category parameter, if
     desired:

              [banner category="[value interest]"]

multi-level categorized

              [banner category="tech:hw"] or [banner category="tech:sw"]

     If have a colon-separated category, Interchange will select the
     most specific ad available. If the banner table looks like this:

              code    category   weight   rotate   banner
              tech               0        1        Tech banner 1{or}Tech banner 2
              tech:hw            0        1        Hardware banner 1{or}HW banner 2
              tech:sw            0        1        Software banner 1{or}SW banner 2

     This works the same as single-level categories, except that the
     category tech:hw will select that banner. The category tech:sw
     will select its own. But, the category tech:html would just get
     the "tech" banner. Otherwise, it works just as in other
     categorized ads. Rotation will work if set non-zero/non-blank and
     it will be inactive if the rotate field is blank. Each category
     rotates on its own.

Advanced

     All parameters are optional since they are marked with an
     asterisk (*).

     Tag syntax:

              [banner
                  weighted=1*
                  category=category*
                  once=1*
                  separator=sep*
                  delimiter=delim*
                  table=banner_table*
                  a_field=banner_field*
                  w_field=weight_field*
                  r_field=rotate_field*
              ]

     Defaults are blank except:

              table       banner    selects table used
              a_field     banner    selects field for banner text
              delimiter   {or}      delimiter for rotating ads
              r_field     rotate    rotate field
              separator   :         separator for multi-level categories
              w_field     weight    rotate field

105.9. Tags for Summarizing Shopping Basket/Cart
------------------------------------------------

The following elements are used to access common items which need to
be displayed on baskets and checkout pages.

* marks an optional parameter

[item-list cart*]

     named attributes: [item-list name="cart"]

     Places an iterative list of the items in the specified shopping
     cart, the main cart by default. See Item Lists for a description.

[/item-list]

     Terminates the [item-list] tag.

[nitems cart*]

     Expands into the total number of items ordered so far. Takes an
     optional cart name as a parameter.

[subtotal]

     Expands into the subtotal cost, exclusive of sales tax, of all
     the items ordered so far.

[salestax cart*]

     Expands into the sales tax on the subtotal of all the items
     ordered so far. If there is no key field to derive the proper
     percentage, such as state or zip code, it is set to 0. See SALES
     TAX for more information.

[shipping-description mode*]

     named attributes: [shipping-description name="mode"]

     The text description of mode. The default is the shipping mode
     currently selected.

[shipping mode*]

     named attributes: [shipping name="mode"]

     The shipping cost of the items in the basket via mode. The
     default mode is the shipping mode currently selected in the
     mv_shipmode variable. See SHIPPING.

[total-cost cart*]

     Expands into the total cost of all the items in the current
     shopping cart, including sales tax, if any.

[currency convert*]

     named attributes: [currency convert=1*]

     When passed a value of a single number, formats it according to
     the currency specification. For instance:

              [currency]4[/currency]

     will display:

              4.00

     Uses the Locale and PriceCommas settings as appropriate, and can
     contain a [calc] region. If the optional "convert" parameter is
     set, it will convert according to PriceDivide> for the current
     locale. If Locale is set to fr_FR, and PriceDivide for fr_FR is
     0.167, using the following sequence:

              [currency convert=1] [calc] 500.00 + 1000.00 [/calc] [/currency]

     will cause the number 8.982,04 to be displayed.

[/currency]

     Terminates the currency region.

[cart name]

     named attributes: [cart name="name"]

     Sets the name of the current shopping cart for display of
     [shipping], [price], [total], [subtotal] and [nitems] tags. If a
     different price is used for the cart, all of the above except
     [shipping] will reflect the normal price field. Those operations
     must be emulated with embedded Perl or the [item-list], [calc]
     and [currency] tags, or use the PriceAdjustment feature to set
     it.

[row nn]

     named attributes: [row width="nn"]

     Formats text in tables. Intended for use in emailed reports or
     <PRE></PRE> HTML areas. The parameter nn gives the number of
     columns to use. Inside the row tag, [col param=value ...] tags
     may be used.

[/row]

     Terminates a [row nn] element.

[col width=nn wrap=yes|no gutter=n align=left|right|input spacing=n]

     Sets up a column for use in a [row]. This parameter can only be
     contained inside a [row nn] [/row] tag pair. Any number of
     columns (that fit within the size of the row) can be defined.

     The parameters are:

              width=nn        The column width, including the gutter. Must be
                              supplied, there is no default. A shorthand method
                              is to just supply the number as the first parameter,
                              as in [col 20].
          
              gutter=n        The number of spaces used to separate the column (on
                              the right-hand side) from the next. Default is 2.
          
              spacing=n       The line spacing used for wrapped text. Default is 1,
                              or single-spaced.
          
              wrap=(yes|no)   Determines whether text that is greater in length than
                              the column width will be wrapped to the next line. Default
                              is yes.
          
              align=(L|R|I)   Determines whether text is aligned to the left (the default),
                              the right or in a way that might display an HTML text
                              input field correctly.

[/col]

     Terminates the column field.

105.10. Item Lists
------------------

Within any page, the [item-list cart*] element shows a list of all the
items ordered by the customer so far. It works by repeating the source
between [item-list] and [/item-list] once for each item ordered.

Note: The special tags that reference item within the list are not
normal Interchange tags, do not take named attributes and cannot be
contained in an HTML tag (other than to substitute for one of its
values or provide a conditional container). They are interpreted only
inside their corresponding list container. Normal Interchange tags can
be interspersed, though they will be interpreted after all of the
list-specific tags.

Between the item_list markers the following elements will return
information for the current item:

[if-item-data table column]

     If the database field column in table table is non-blank, the
     following text up to the [/if-item-data] tag is substituted. This
     can be used to substitute IMG or other tags only if the
     corresponding source item is present. Also accepts a [else]else
     text[/else] pair for the opposite condition.

Note: This tag does not nest with other [if-item-data ...] tags.

[if-item-data table column]

     Reverses sense for [if-item-data].

[/if-item-data]

     Terminates an [if-item-data table column] element.

[if-item-field fieldname]

     If the products database field fieldname is non-blank, the
     following text up to the [/if-item-field] tag is substituted. If
     there are more than one products database table (see
     ProductFiles), it will check them in order until a matching key
     is found. This can be used to substitute IMG or other tags only
     if the corresponding source item is present. Also accepts a
     [else]else text[/else] pair for the opposite condition.

Note: This tag does not nest with other [if-item-field ...] tags.

[if-item-field fieldname]

     Reverses sense for [if-item-field].

[/if-item-field]

     Terminates an [if-item-field fieldname] element.

[item-accessories attribute*, type*, field*, database*, name*]

     Evaluates to the value of the Accessories database entry for the
     item. If passed any of the optional arguments, initiates special
     processing of item attributes based on entries in the product
     database.

[item-alternate N] DIVISIBLE [else] NOT DIVISIBLE
[/else][/item-alternate]

     Sets up an alternation sequence. If the item-increment is
     divisible by N, the text will be displayed. If an [else]NOT
     DIVISIBLE TEXT[/else] is present, the NOT DIVISIBLE TEXT will be
     displayed.

     For example:

              [item-alternate 2]EVEN[else]ODD[/else][/item-alternate]
              [item-alternate 3]BY 3[else]NOT by 3[/else][/item-alternate]

[/item-alternate]

     Terminates the alternation area.

[item-code]

     Evaluates to the product code for the current item.

[item-data database fieldname]

     Evaluates to the field name fieldname in the arbitrary database
     table database for the current item.

[item-description]

     Evaluates to the product description (from the products file) for
     the current item.

[item-field fieldname]

     The [item-field ...] tag is special in that it looks in any of
     the tables defined as ProductFiles, in that order, for the data,
     returning the value only if that key is defined. In most
     catalogs, where ProductFiles is not defined (i.e., the demo),
     [item-field title] is equivalent to [item-data products title].

     Evaluates to the field name fieldname in the products database
     for the current item. If the item is not found in the first of
     the ProductFiles, all will be searched in sequence.

[item-increment]

     Evaluates to the number of the item in the match list. Used for
     numbering search matches or order items in the list.

[item-last]tags[/item-last]

     Evaluates the output of the Interchange tags encased inside the
     tags. If it evaluates to a numerical non-zero number (i.e., 1,
     23, or -1), the list iteration will terminate. If the evaluated
     number is negative, the item itself will be skipped. If the
     evaluated number is positive, the item itself will be shown but
     will be last on the list.

                [item-last][calc]
                  return -1 if '[item-field weight]' eq '';
                  return 1 if '[item-field weight]' < 1;
                  return 0;
                  [/calc][/item-last]

     If this is contained in the [item-list] (or [search-list] or
     flypage) and the weight field is empty, a numerical -1 will be
     output from the [calc][/calc] tags; the list will end and the
     item will not be shown. If the product's weight field is less
     than 1, a numerical 1 is output. The item will be shown, but will
     be the last item shown. (If it is an [item-list], any price for
     the item will still be added to the subtotal.) NOTE: there is no
     equivalent HTML style.

[item-modifier attribute]

     Evaluates to the modifier value of attribute for the current
     item.

[item-next]tags[/item_next]

     Evaluates the output of the Interchange tags encased inside. If
     it evaluates to a numerical non-zero number (i.e., 1, 23, or -1),
     the item will be skipped with no output. Example:

                [item-next][calc][item-field weight] < 1[/calc][/item-next]

     If this is contained in the [item-list] (or [search-list] or
     flypage) and the product's weight field is less than 1, a
     numerical 1 will be output from the [calc][/calc] operation. The
     item will not be shown. (If it is an [item-list], any price for
     the item will still be added to the subtotal.)

[item-price n* noformat*]

     Evaluates to the price for quantity n (from the products file) of
     the current item, with currency formatting. If the optional
     "noformat" is set, currency formatting will not be applied.

[item-discount-price n* noformat*]

     Evaluates to the discount price for quantity n (from the products
     file) of the current item, with currency formatting. If the
     optional "noformat" is set, currency formatting will not be
     applied. Returns regular price if not discounted.

[item-discount]

     Returns the difference between the regular price and the
     discounted price.

[item-quantity]

     Evaluates to the quantity ordered for the current item.

[item-subtotal]

     Evaluates to the subtotal (quantity * price) for the current
     item. Quantity price breaks are taken into account.

[item-modifier-name attribute]

     Evaluates to the name to give an input box in which the customer
     can specify the modifier to the ordered item.

[quantity-name]

     Evaluates to the name to give an input box in which the customer
     can enter the quantity to order.

106. Interchange Page Display
=============================

Interchange has several methods for displaying pages:

o    Display page by name

     If a page with [page some_page] or <A HREF="[area some_page]"> is
     called and that some_page.html exists in the pages directory
     (PageDir), it will be displayed.

o    On-the-fly page

     If a page with [page 00-0011] or <A HREF="[area 00-0011]"> is
     called and 00-0011 exists as a product in one of the products
     databases (ProductFiles), Interchange will use the special page
     descriptor flypage as a template and build based on that part
     number. This is partly for convenience; the same thing can be
     accomplished by calling [page your_template 00-0011] and using
     the [data session arg] to perform the templating. But there is
     special logic associated with the PageSelectField configuration
     attribute to allow pages to be built with varying templates.

o    Determine page via form action and variables

     If a form action, in almost all cases the page to display will be
     determined by the mv_nextpage form value. Example:

              <FORM ACTION="[process]">
              <INPUT TYPE=hidden NAME=mv_todo VALUE=return>
              <SELECT NAME=mv_nextpage>
              <OPTION VALUE=index>Main page
              <OPTION VALUE=browse>Product listing
              <OPTION VALUE="ord/basket">Shopping cart
              </SELECT>
              <INPUT TYPE=submit VALUE=Go>
              </FORM>

     The mv_nextpage dropdown will determine the page the user goes
     to.

106.1. On-the-fly Catalog Pages
-------------------------------

If an item is displayed on the search list (or order list) and there
is a link to a special page keyed on the item, Interchange will
attempt to build the page "on the fly." It will look for the special
page flypage.html, which is used as a template for building the page.
If [item-field fieldname], [item-price] and similar elements are used
on the page, complex and information-packed pages can be built. The
[if-item-field fieldname] HTML [/if-item-field] pair can be used to
insert HTML only if there is a non-blank value in a particular field.

Important note: Because the tags are substituted globally on the page,
[item-*] tags cannot be used on the default on-the-fly page. To use a
[search-region] or [item-list] tag, change the default with the prefix
parameter. Example:

   [item-list prefix=cart]
   [cart-code] -- title=[cart-data products title]
   [/item-list]

To have an on-the-fly page mixed in reliably, use the idiom [fly-list
prefix=fly code="[data session arg]"] [/flylist] pair.

[fly-list code="product_code" base="table"] ... [/fly-list]

     Other parameters:

              prefix=label     Allows [label-code], [label-description]

     Defines an area in a random page which performs the flypage
     lookup function, implementing the tags below:

             [fly-list code="[data session arg]"]
              (contents of flypage.html)
             [/fly-list]

     If placed around the contents of the demo flypage, in a file
     named <flypage2.html>, it will make these two calls display
     identical pages:

              [page 00-0011] One way to display the Mona Lisa </a>
              [page flypage2 00-0011] Another way to display the Mona Lisa </a>

If the directive PageSelectField is set to a valid product database
field which contains a valid Interchange page name (relative to the
catalog pages directory, without the .html suffix), it will be used to
build the on-the-fly page.

Active tags in their order of interpolation:

[if-item-field field]    Tests for a non-empty, non-zero value in field
[if-item-data db field]  Tests for a non-empty, non-zero field in db
[item-code]              Product code of the displayed item
[item-accessories args]  Accessory information (see accessories)
[item-description]       Description field information
[item-price quantity*]   Product price (at quantity)
[item-field field]       Product database field
[item-data db field]     Database db entry for field

106.2. Special Pages
--------------------

A number of HTML pages are special for Interchange operation.
Typically, they are used to transmit error messages, status of search
or order operations and other out of boundary conditions.

Note: The distributed demo does not use all of the default values.

The names of these pages can be set with the SpecialPage directive.
The standard pages and their default locations:

canceled (special_pages/canceled.html)

     The page displayed by Interchange when an order has been canceled
     by the user.

catalog (special_pages/catalog.html)

     The main catalog page presented by Interchange when another page
     is not specified.

failed (special_pages/failed.html)

     If the sendmail program could not be invoked to email the
     completed order, the failed.html page is displayed.

flypage (special_pages/flypage.html)

     If the catalog page for an item was not found when its
     [item-link] is clicked, this page is used as a template to build
     an on-the-fly page. See On-the-fly Catalog Pages.

interact (special_pages/interact.html)

     Displayed if an unexpected response was received from the
     browser, such as not getting expected fields from submitting a
     form. This would probably happen from typos in the html pages,
     but could be a browser bug.

missing (special_pages/missing.html)

     This page is displayed if the URL from the browser specifies a
     page that does not have a matching .html file in the pages
     directory. This can happen if the customer saved a bookmark to a
     page that was later removed from the database, for example, or if
     there is a defect in the code.

     Essentially this is the same as a 404 error in HTTP. To
     deliberately display a 404 error, just put this in
     special_pages/missing.html:

              [tag op=header]Status: 404 missing[/tag]

noproduct (special_pages/noproduct.html)

     This page is displayed if the URL from the browser specifies the
     ordering of a product code which is not in the products file.

order (ord/basket.html)

     This page is displayed when the customer orders an item. It can
     contain any or all of the customer-entered values, but is
     commonly used as a status display (or "shopping basket").

search (results.html)

     Contains the default output page for the search engine results.
     Also required is an input page, which can be the same as
     search.html or an additional page. By convention Interchange
     defines this as the page results.

              SpecialPage   search   results

violation (special pages/violation.html)

     Displayed if a security violation is noted, such as an attempt to
     access a page denied by an access_gate. See UserDB.

106.3. Checking Page HTML
-------------------------

Interchange allows debugging of page HTML with an external page
checking program.  Because leaving this enabled on a production system
is potentially a very bad performance degradation, the program is set
in a the global configuration file with the CheckHTML directive. To
check a page for validity, set the global directive CheckHTML to the
name of the program (don't do any output redirection). A good choice
is the freely available program Weblint. It would be set in
interchange.cfg with:

   CheckHTML  /usr/local/bin/weblint -s -

Of course, the server must be restarted for it to be recognized. The
full path to the program should be used. If having trouble, check it
from the command line (as with all external programs called by
Interchange).

Insert [flag type=checkhtml][/tag] at the top or bottom of pages to
check and the output of the checker should be appended to the browser
output as a comment, visible if the page or frame source are viewed.
To do this occasionally, use a Variable setting:

   Variable  CHECK_HTML    [flag type=checkhtml]

and place __CHECK_HTML__ in the pages.  Then set the Variable to the
empty string to disable it.

107. Forms and Interchange
==========================

Interchange uses HTML forms for many of its functions, including
ordering, searching, updating account information and maintaining
databases. Order operations possibly include ordering an item,
selecting item size or other attributes and reading user information
for payment and shipment. Search operations may also be triggered by a
form.

Interchange supports file upload with the multipart/form-data type.
The file is placed in memory and discarded if not accessed with the
[value-extended name=filevar file_contents=1] tag or written with
[value-extended name=filevar outfile=your_file_name]. See Extended
Value Access and File Upload.

Interchange passes variables from page to page automatically. Every
user session that is started by Interchange automatically creates a
variable set for the user. As long as the user session is maintained,
and does not expire, any variables you set on a form will be
"remembered" in future sessions.

Don't use the prefix mv_ for your own variables. Interchange treats
these specially and they may not behave as you wish. Use the mv_
variables only as they are documented.

Interchange does not unset variables it does not find on the current
form. That means you can't expect a checkbox to become unchecked
unless you explicitly reset it.

107.1. Special Form Fields
--------------------------

Interchange treats some form fields specially, to link to the search
engine and provide more control over user presentation. It has a
number of predefined variables, most of whose names are prefixed with
mv_ to prevent name clashes with your variables. It also uses a few
variables which are post-fixed with integer digits; those are used to
provide control in its iterating lists.

Most of these special fields begin with mv_, and include:

(O = order, S = search, C = control, A = all, X in scratch space)

Name              scan             Type              Description
................. ................ ................. ................ 
mv_all_chars      ac               S                 Turns on
                                                     punctuation
                                                     matching
mv_arg[0-9]+                       A                 Parameters for
                                                     mv_subroutine
                                                     (mv_arg0,mv_arg1,...)
mv_base_directory bd               S                 Sets base
                                                     directory for
                                                     search file
                                                     names
mv_begin_string   bs               S                 Pattern must
                                                     match beginning
                                                     of field
mv_case           cs               S                 Turns on case
                                                     sensitivity
mv_cartname                        O                 Sets the
                                                     shopping cart
                                                     name
mv_check                           A                 Any form, sets
                                                     multiple user
                                                     variables after
                                                     update
mv_click                           A                 Any form, sets
                                                     multiple form
                                                     variables before
                                                     update
mv_click                           XA                Default mv_click
                                                     routine, click
                                                     is mv_click_arg
mv_click <name>                    XA                Routine for a
                                                     click <name>,
                                                     sends click as
                                                     arg
mv_click_arg                       XA                Argument name in
                                                     scratch space
mv_coordinate     co               S                 Enables
                                                     field/spec
                                                     matching
                                                     coordination
mv_column_op      op               S                 Operation for
                                                     coordinated
                                                     search
mv_credit_card*                    O                 Discussed in
                                                     order security
                                                     (some are
                                                     read-only)
mv_dict_end       de               S                 Upper bound for
                                                     binary search
mv_dict_fold      df               S                 Non-case
                                                     sensitive binary
                                                     search
mv_dict_limit     di               S                 Sets upper bound
                                                     based on
                                                     character
                                                     position
mv_dict_look      dl               S                 Search
                                                     specification
                                                     for binary
                                                     search
mv_dict_order     do               S                 Sets dictionary
                                                     order mode
mv_doit                            A                 Sets default
                                                     action
mv_email                           O                 Reply-to address
                                                     for orders
mv_exact_match    em               S                 Sets
                                                     word-matching
                                                     mode
mv_failpage       fp               O,S               Sets page to
                                                     display on
                                                     failed order
                                                     check/search
mv_field_file     ff               S                 Sets file to
                                                     find field names
                                                     for Glimpse
mv_field_names    fn               S                 Sets field names
                                                     for search,
                                                     starting at 1
mv_first_match    fm               S                 Start displaying
                                                     search at
                                                     specified match
mv_head_skip      hs               S                 Sets skipping of
                                                     header line(s)
                                                     in index
mv_index_delim    id               S                 Delimiter for
                                                     search fields
                                                     (TAB default)
mv_matchlimit     ml               S                 Sets match page
                                                     size
mv_max_matches    mm               S                 Sets maximum
                                                     match return
mv_min_string     ms               S                 Sets minimum
                                                     search spec size
mv_negate         ne               S                 Records NOT
                                                     matching will be
                                                     found
mv_nextpage       np               A                 Sets next page
                                                     user will go to
mv_numeric        nu               S                 Comparison
                                                     numeric in
                                                     coordinated
                                                     search
mv_order_group                     O                 Allows grouping
                                                     of master
                                                     item/sub item
mv_order_item                      O                 Causes the order
                                                     of an item
mv_order_number                    O                 Order number of
                                                     the last order
                                                     (read-only)
mv_order_quantity                  O                 Sets the
                                                     quantity of an
                                                     ordered item
mv_order_profile                   O                 Selects the
                                                     order check
                                                     profile
mv_order_receipt                   O                 Sets the receipt
                                                     displayed
mv_order_report                    O                 Sets the order
                                                     report sent
mv_order_subject                   O                 Sets the subject
                                                     line of order
                                                     email
mv_orsearch       os               S                 Selects AND/OR
                                                     of search words
mv_profile        mp               S                 Selects search
                                                     profile
mv_record_delim   dr               S                 Search index
                                                     record delimiter
mv_return_all     ra               S                 Return all lines
                                                     found (subject
                                                     to range search)
mv_return_delim   rd               S                 Return record
                                                     delimiter
mv_return_fields  rf               S                 Fields to return
                                                     on a search
mv_return_file_name rn             S                 Set return of
                                                     file name for
                                                     searches
mv_return_spec    rs               S                 Return the
                                                     search string as
                                                     the only result
mv_save_session                    C                 Set to non-zero
                                                     to prevent
                                                     expiration of
                                                     user session
mv_search_field   sf               S                 Sets the fields
                                                     to be searched
mv_search_file    fi               S                 Sets the file(s)
                                                     to be searched
mv_search_line_return lr           S                 Each line is a
                                                     return code
                                                     (loop search)
mv_search_match_count              S                 Returns the
                                                     number of
                                                     matches found
                                                     (read-only)
mv_search_page    sp               S                 Sets the page
                                                     for search
                                                     display
mv_searchspec     se               S                 Search
                                                     specification
mv_searchtype     st               S                 Sets search type
                                                     (text, glimpse,
                                                     db or sql)
mv_separate_items                  O                 Sets separate
                                                     order lines (one
                                                     per item
                                                     ordered)
mv_session_id     id               A                 Suggests user
                                                     session id
                                                     (overridden by
                                                     cookie)
mv_shipmode                        O                 Sets shipping
                                                     mode for custom
                                                     shipping
mv_sort_field     tf               S                 Field(s) to sort
                                                     on
mv_sort_option    to               S                 Options for sort
mv_spelling_errors er              S                 Number of
                                                     spelling errors
                                                     for Glimpse
mv_substring_match su              S                 Turns off
                                                     word-matching
                                                     mode
mv_successpage                     O                 Page to display
                                                     on successful
                                                     order check
mv_todo                            A                 Common to all
                                                     forms, sets form
                                                     action
mv_todo.map                        A                 Contains form
                                                     imagemap
mv_todo.checkout.x                 O                 Causes checkout
                                                     action on click
                                                     of image
mv_todo.return.x                   O                 Causes return
                                                     action on click
                                                     of image
mv_todo.submit.x                   O                 Causes submit
                                                     action on click
                                                     of image
mv_todo.x                          A                 Set by form
                                                     imagemap
mv_todo.y                          A                 Set by form
                                                     imagemap
mv_unique         un               S                 Return unique
                                                     search results
                                                     only
mv_value          va               S                 Sets value on
                                                     one-click search
                                                     (va=var=value)

107.2. Form Actions
-------------------

Interchange form processing is based on an action and a todo. The
predefined actions at the first level are:

   process       process a todo
   search        form-based search
   scan          path-based search
   order         order an item

Any action can be defined with ActionMap.

The process action has a second todo level called with mv_todo or
mv_doit. The mv_todo takes preference over mv_doit, which can be used
to set a default if no mv_todo is set.

The action can be specified with any of:

page name

     Calling the page "search" will cause the search action. process
     will cause a form process action, etc. Examples:

              <FORM ACTION="/cgi-bin/simple/search" METHOD=POST>
              <INPUT NAME=mv_searchspec>
              </FORM>

     The above is a complete search in Interchange. It causes a simple
     text search of the default products database(s). Normally
     hard-coded paths are not used, but a Interchange tag can be used
     to specify it for portability:

              <FORM ACTION="[area search]" METHOD=POST>
              <INPUT NAME=mv_searchspec>
              </FORM>

     The tag [process] is often seen in Interchange forms. The above
     can be called equivalently with:

              <FORM ACTION="[process]" METHOD=POST>
              <INPUT TYPE=hidden NAME=mv_todo VALUE=search>
              <INPUT NAME=mv_searchspec>
              </FORM>

mv_action

     Setting the special variable mv_action causes the page name to be
     ignored as the action source. The above forms can use this as a
     synonym:

              <FORM ACTION="[area foo]" METHOD=post>
              <INPUT TYPE=hidden NAME=mv_action VALUE=search>
              <INPUT NAME=mv_searchspec>
              </FORM>

     The page name will be used to set mv_nextpage, if it is not
     otherwise defined. If mv_nextpage is present in the form, it will
     be ignored.

The second level todo for the process action has these defined by
default:

   back         Go to mv_nextpage, don't update variables
   search   Trigger a search
   submit   Submit a form for validation (and possibly a final order)
   go       Go to mv_nextpage (same as return)
   return   Go to mv_nextpage, update variables
   set      Update a database table
   refresh  Go to mv_orderpage|mv_nextpage and check for
            ordered items
   cancel   Erase the user session

If a page name is defined as an action with ActionMap or use of
Interchange's predefined action process, it will cause form
processing. First level is setting the special page name process, or
mv_action set to do a form process, the Interchange form can be used
for any number of actions. The actions are mapped by the ActionMap
directive in the catalog configuration file, and are selected on the
form with either the mv_todo or mv_doit variables.

To set a default action for a process form, set the variable mv_doit
as a hidden variable:

   <INPUT TYPE=hidden NAME=mv_doit VALUE=refresh>

When the mv_todo value is not found, the refresh action defined in
mv_doit will be used instead.

More on the defined actions:

back

     Goes to the page in mv_nextpage. No user variable update.

cancel

     All user information is erased, and the shopping cart is emptied.
     The user is then sent to mv_nextpage.

refresh

     Checks for newly-ordered items in mv_order_item, looking for
     on-the-fly items if that is defined, then updates the shopping
     cart with any changed quantities or options. Finally updates the
     user variables and returns to the page defined in mv_orderpage or
     mv_nextpage (in that order of preference).

return

     Updates the user variables and returns to the page defined in
     mv_nextpage.

search

     The shopping cart and user variables are updated, then the form
     variables are interpreted and the search specification contained
     therein is dispatched to the search engine. Results are returned
     on the defined search page (set by mv_search_page or the search
     page directives).

submit

     Submits the form for order processing. If no order profile is
     defined with the mv_order_profile variable, the order is checked
     to see if the current cart contains any items and the order is
     submitted.

     If there is an order profile defined, the form will be checked
     against the definition in the order profile and submitted if the
     pragma &final is set to yes. If &final is set to no (the default)
     and the check succeeds, the user will be routed to the
     Interchange page defined in mv_successpage or mv_nextpage. If the
     check fails, the user will be routed to mv_failpage or
     mv_nextpage in that order.

107.3. One-click Multiple Variables
-----------------------------------

Interchange can set multiple variables with a single button or form
control. First define the variable set (or profile, as in search and
order profiles) inside a scratch variable:

 [set Search by Category]
 mv_search_field=category
 mv_search_file=categories
 mv_todo=search
 [/set]

The special variable mv_click sets variables just as if they were put
in on the form. It is controlled by a single button, as in:

   <INPUT TYPE=submit NAME=mv_click VALUE="Search by Category">

When the user clicks the submit button, all three variables will take
on the values defined in the "Search by Category" scratch variable.
Set the scratch variable on the same form as the button is on. This is
recommended for clarity. The mv_click variable will not be carried
from form to form, it must be set on the form being submitted.

The special variable mv_check sets variables for the form actions
<checkout, control, refresh, return, search,> and <submit>. This
function operates after the values are set from the form, including
the ones set by mv_click, and can be used to condition input to search
routines or orders.

The variable sets can contain and be generated by most Interchange
tags. The profile is interpolated for Interchange tags before being
used. This may not always operate as expected. For instance, if the
following was set:

   [set check]
   [cgi name=mv_todo set=bar hide=1]
   mv_todo=search
   [if cgi mv_todo eq 'search']
   do something
   [/if]
   [/set]

The if condition is guaranteed to be false, because the tag
interpretation takes place before the evaluation of the variable
setting.

Any setting of variables already containing a value will overwrite the
variable. To build sets of fields (as in mv_search_field and
mv_return_fields), comma separation if that is supported for the field
must be used.

It is very convenient to use mv_click as a trigger for embedded Perl:

   <FORM ...
   <INPUT TYPE=hidden NAME=mv_check VALUE="Invalid Input">
   ...
   </FORM>

   [set Invalid Input]
   [perl]
   my $type        = $CGI->{mv_searchtype};
   my $spell_check = $CGI->{mv_spelling_errors};
   my $out = '';
   if($spell_check and $type eq 'text') {
       $CGI->{mv_todo}     = 'return';
       $CGI->{mv_nextpage} = 'special/cannot_spell_check';
   }
   return;
   [/perl]
   [/set]

107.4. Checks and Selections
----------------------------

A "memory" for drop-down menus, radio buttons and checkboxes can be
provided with the [checked] and [selected] tags.

[checked var_name value]

     named attributes: [checked name="var_name" value="value" cgi=0|1
     multiple=0|1 default=0|1 case=0|1]

     This will output CHECKED if the variable var_name is equal to
     value. Set the cgi attribute to use cgi instead of values data.
     Not case sensitive unless case is set.

     If the multiple attribute is defined and set to a non-zero value
     (1 is implicit) and if the value matches on a word/non-word
     boundary, it will be CHECKED. If the default attribute is set to
     a non-zero value, the box will be checked if the variable
     var_name is empty or zero.

[selected var_name value]

     named attributes: [selected name="var_name" value="value" cgi=0|1
     multiple=0|1 default=0|1 case=0|1]

     This will output SELECTED if the variable var_name is equal to
     value. Set the cgi attribute to use cgi instead of values data.
     Not case sensitive unless case is set.

     If the multiple argument is present, it will look for any of a
     variety of values. If the default attribute is set, SELECT will
     be output if the variable is empty or zero. Not case sensitive
     unless case is set.

     Here is a drop-down menu that remembers an item-modifier color
     selection:

              <SELECT NAME="color">
              <OPTION [selected name=color value=blue]> Blue
              <OPTION [selected name=color value=green]> Green
              <OPTION [selected name=color value=red]> Red
              </SELECT>

     For databases or large lists of items, sometimes it is easier to
     use [loop list="foo bar"] and its option parameter. The above can
     be achieved with:

              <SELECT NAME=color>
              [loop list="Blue Green Red" option=color]
              <OPTION> [loop-code]
              [/loop]
              </SELECT>

See also the ictags documentation on the [loop] tag.

107.5. Integrated Image Maps
----------------------------

Imagemaps can also be defined on forms, with the special form variable
mv_todo.map. A series of map actions can be defined. The action
specified in the default entry will be applied if none of the other
coordinates match. The image is specified with a standard HTML 2.0
form field of type IMAGE. Here is an example:

<INPUT TYPE=hidden NAME="mv_todo.map" VALUE="rect submit 0,0 100,20">
<INPUT TYPE=hidden NAME="mv_todo.map" VALUE="rect cancel 290,2 342,18">
<INPUT TYPE=hidden NAME="mv_todo.map" VALUE="default refresh">
<INPUT TYPE=image  NAME="mv_todo" SRC="url_of_image">

All of the actions will be combined together into one image map with
NCSA-style functionality (see the NCSA imagemap documentation for
details), except that Interchange form actions are defined instead of
URLs.

107.6. Setting Form Security
----------------------------

You can cause a form to be submitted securely (to the base URL in the
SecureURL directive, that is) by specifying your form input to be
ACTION="[process secure=1]".

To submit a form to the regular non-secure server, just omit the
secure modifier.

107.7. Stacking Variables on the Form
-------------------------------------

Many Interchange variables can be "stacked," meaning they can have
multiple values for the same variable name. As an example, to allow
the user to order multiple items with one click, set up a form like
this:

<FORM METHOD=POST ACTION="[process]">
<input type=checkbox name="mv_order_item" value="M3243"> Item M3243
<input type=checkbox name="mv_order_item" value="M3244"> Item M3244
<input type=checkbox name="mv_order_item" value="M3245"> Item M3245
<input type=hidden name="mv_doit" value="refresh">
<input type=submit name="mv_junk" value="Order Checked Items">
</FORM>

The stackable mv_order_item variable with be decoded with multiple
values, causing the order of any items that are checked.

To place a "delete" checkbox on the shopping basket display:

<FORM METHOD=POST ACTION="[process]">
[item-list]
  <input type=checkbox name="[quantity-name]" value="0"> Delete
  Part number: [item-code]
  Quantity: <input type=text name="[quantity-name]" value="[item-quantity]">
  Description: [item-description]
[/item-list]
<input type=hidden name="mv_doit" value="refresh">
<input type=submit name="mv_junk" value="Order Checked Items">
</FORM>

In this case, first instance of the variable name set by
[quantity-name] will be used as the order quantity, deleting the item
from the form.

Of course, not all variables are stackable. Check the documentation
for which ones can be stacked or experiment.

107.8. Extended Value Access and File Upload
--------------------------------------------

Interchange has a facility for greater control over the display of
form variables; it also can parse multipart/form-data forms for file
upload.

File upload is simple. Define a form like:

   <FORM ACTION="[process-target] METHOD=POST ENCTYPE="multipart/form-data">
   <INPUT TYPE=hidden NAME=mv_todo     VALUE=return>
   <INPUT TYPE=hidden NAME=mv_nextpage VALUE=test>
   <INPUT TYPE=file NAME=newfile>
   <INPUT TYPE=submit VALUE="Go!">
   </FORM>

The [value-extended ...] tag performs the fetch and storage of the
file. If the following is on the test.html page (as specified with
mv_nextpage and used with the above form, it will write the file
specified:

   <PRE>
   Uploaded file name: [value-extended name=newfile]
   Is newfile a file? [value-extended name=newfile yes=Yes no=No test=isfile]

   Write the file. [value-extended name=newfile outfile=junk.upload]
   Write again with
    indication: [value-extended name=newfile
                               outfile=junk.upload
                               yes="Written."]
                               no=FAILED]

   And the file contents:
   [value-extended name=newfile file_contents=1]
   </PRE>

The [value-extended] tag also allows access to the array values of
stacked variables. Use the following form:

   <FORM ACTION="[process-target] METHOD=POST ENCTYPE="multipart/form-data">
   <INPUT TYPE=hidden NAME=testvar VALUE="value0">
   <INPUT TYPE=hidden NAME=testvar VALUE="value1">
   <INPUT TYPE=hidden NAME=testvar VALUE="value2">
   <INPUT TYPE=submit VALUE="Go!">
   </FORM>

and page:

   testvar element 0: [value-extended name=testvar index=0]
   testvar element 1: [value-extended name=testvar index=1]
   testvar elements:
    joined with a space:   |[value-extended name=testvar]|
    joined with a newline: |[value-extended
                               joiner="\n"
                               name=testvar
                               index="*"]|
    first two only:    |[value-extended
                               name=testvar
                               index="0..1"]|
    first and last:    |[value-extended
                               name=testvar
                               index="0,2"]|

to observe this in action.

The syntax for [value-extended ...] is:

named: [value-extended
           name=formfield
           outfile=filename*
           ascii=1*
           yes="Yes"*
           no="No"*
           joiner="char|string"*
           test="isfile|length|defined"*
           index="N|N..N|*"
           file_contents=1*
           elements=1*]

positional: [value-extended name]

Expands into the current value of the customer/form input field named
by field. If there are multiple elements of that variable, it will
return the value at index; by default all joined together with a
space.

If the variable is a file variable coming from a multipart/form-data
file upload, then the contents of that upload can be returned to the
page or optionally written to the outfile.

name

     The form variable NAME. If no other parameters are present, the
     value of the variable will be returned. If there are multiple
     elements, by default they will all be returned joined by a space.
     If joiner is present, they will be joined by its value.

     In the special case of a file upload, the value returned is the
     name of the file as passed for upload.

joiner

     The character or string that will join the elements of the array.
     It will accept string literals such as "\n" or "\r".

test

     There are three tests. isfile returns true if the variable is a
     file upload. length returns the length. defined returns whether
     the value has ever been set at all on a form.

index

     The index of the element to return if not all are wanted. This is
     useful especially for pre-setting multiple search variables. If
     set to *, it will return all (joined by joiner). If a range, such
     as 0 .. 2, it will return multiple elements.

file_contents

     Returns the contents of a file upload if set to a non-blank,
     non-zero value. If the variable is not a file, it returns
     nothing.

outfile

     Names a file to write the contents of a file upload to. It will
     not accept an absolute file name; the name must be relative to
     the catalog directory. If images or other files are to be written
     to go to HTML space, use the HTTP server's Alias facilities or
     make a symbolic link.

ascii

     To do an auto-ASCII translation before writing the outfile, set
     the ascii parameter to a non-blank, non-zero value. The default
     is no translation.

yes

     The value that will be returned if a test is true or a file is
     written successfully. It defaults to 1 for tests and the empty
     string for uploads.

no

     The value that will be returned if a test is false or a file
     write fails. It defaults to the empty string.

107.9. Updating Interchange Database Tables with a Form
-------------------------------------------------------

Any Interchange database can be updated with a form using the
following method. The Interchange user interface uses this facility
extensively.

Note: All operations are performed on the database, not the ASCII
source file. An [export table_name] operation will have to be
performed for the ASCII source file to reflect the results of the
update. Records in any  database may be inserted or updated with the
[query] tag, but form-based updates or inserts may also be performed.

In an update form, special Interchange variables are used to select
the database parameters:

mv_data_enable (scratch)

     \IMPORTANT: This must be set to a non-zero, non-blank value in
     the scratch space to allow data set functions. Usually it is put
     in an mv_click that precedes the data set function. For example:

              [set update_database]
              [if type=data term="userdb::trusted::[data session username]"]
                  [set mv_data_enable]1[/set]
              [else]
                  [set mv_data_enable]0[/set]
              [/else]
              [/if]
              [/set]
              <INPUT TYPE=hidden NAME=mv_click VALUE=update_database>

mv_data_table

     The table to update.

mv_data_key

     The field that is the primary key in the table. It must match the
     existing database definition.

mv_data_function

     UPDATE, INSERT or DELETE. The variable mv_data_verify must be set
     true on the form for a DELETE to occur.

mv_data_verify

     Confirms a DELETE.

mv_data_fields

     Fields from the form which should be inserted or updated. Must be
     existing columns in the table in question.

mv_update_empty

     Normally a variable that is blank will not replace the field. If
     mv_update_empty is set to true, a blank value will erase the
     field in the database.

mv_data_filter_(field)

     Instantiates a filter for (field), using any of the defined
     Interchange filters. For example, if mv_data_filter_foo is set to
     digits, only digits will be passed into the database field during
     the set operation. A common value might be "entities", which
     protects any HTML by translating < into &lt;, " into &quot;, etc.

The Interchange action set causes the update. Here are a pair of
example forms. One is used to set the key to access the record
(careful with the name, this one goes into the user session values).
The second actually performs the update. It uses the [loop] tag with
only one value to place default/existing values in the form based on
the input from the first form:

   <FORM METHOD=POST ACTION="[process]">
    <INPUT TYPE=HIDDEN name="mv_doit" value="return">
    <INPUT TYPE=HIDDEN name="mv_nextpage" value="update_proj">
    Sales Order Number <INPUT TYPE=TEXT SIZE=8
                            NAME="update_code"
                            VALUE="[value update_code]">
    <INPUT TYPE=SUBMIT name="mv_submit"  Value="Select">
    </FORM>
<FORM METHOD=POST ACTION="[process]">
   <INPUT TYPE=HIDDEN NAME="mv_data_table"    VALUE="ship_status">
   <INPUT TYPE=HIDDEN NAME="mv_data_key"      VALUE="code">
   <INPUT TYPE=HIDDEN NAME="mv_data_function" VALUE="update">
   <INPUT TYPE=HIDDEN NAME="mv_nextpage"      VALUE="updated">
   <INPUT TYPE=HIDDEN NAME="mv_data_fields"
               VALUE="code,custid,comments,status">
   <PRE>

   [loop arg="[value update_code]"]
   Sales Order <INPUT TYPE=TEXT NAME="code    SIZE=10 VALUE="[loop-code]">
  Customer No. <INPUT TYPE=TEXT NAME="custid" SIZE=30
                   VALUE="[loop-field custid]">
      Comments <INPUT TYPE=TEXT NAME="comments"
                   SIZE=30 VALUE="[loop-field comments]">
        Status <INPUT TYPE=TEXT NAME="status"
                   SIZE=10 VALUE="[loop-field status]">
   [/loop]
   </PRE>

       <INPUT TYPE=hidden NAME="mv_todo" VALUE="set">
       <INPUT TYPE=submit VALUE="Update table">
   </FORM>

The variables in the form do not update the user's session values, so
they can correspond to database field names without fear of corrupting
the user session.

107.9.1. Can I use Interchange with my existing static catalog pages?
---------------------------------------------------------------------

Yes, but you probably won't want to in the long run. Interchange is
designed to build pages based on templates from a database. If all you
want is a shopping cart, you can mix standard static pages with
Interchange, but it is not as convenient and doesn't take advantage of
the many dynamic features Interchange offers.

That being said, all you usually have to do to place an order link on
a page is:

   <A HREF="/cgi-bin/construct/order?mv_order_item=SKU_OF_ITEM">Order!</A>

Replace /cgi-bin/construct with the path to your Interchange link.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License. line:

Interchange Upgrade Guide
=========================

108. Introduction
=================

This document contains, in rough form, notes on upgrading from
Minivend 3 to Minivend 4, and Minivend 4 to Interchange.

109. Interchange 4.8 Deprecated Features
========================================

This document describes features of Interchange 4.8 that have been
deprecated. Any use of these features should be discontinued. In most
cases we have provided an alternative mechanism to accomplish the same
results. These deprecated features may be removed at some point in the
future. You should change to the new mechanism to avoid breakage.

109.1. Deprecated Features Previous to Interchange 4
----------------------------------------------------

This section needs some serious work.

cart/page from path

     interchange.PL 308,313

             if($path =~ s:/(.*)::) {
                     $cart = $1;
                     if($cart =~ s:/(.*)::) {
                             $page = $1;
                     }
             }

mv_orderpage

     interchange.PL 321,323

             $CGI::values{mv_nextpage} = $CGI::values{mv_orderpage}
                                                                     || find_special_page('order')
                     if ! $CGI::values{mv_nextpage};

$decode

     interchange.PL 493

                             HTML::Entities::decode($value) if $decode;

mv_orderpage

     interchange.PL 854,855

                                             $CGI::values{mv_nextpage} = $CGI::values{mv_orderpage}
                                                     if $CGI::values{mv_orderpage};

ROUTINES and LANG

     interchange.PL 1552,1579

             ROUTINES: {
                     last ROUTINES unless index($Vend::FinalPath, '/process/') == 0;
                     while ($Vend::FinalPath =~ s:/process/(locale|language|currency)/([^/]*)/:/process/:) {
                             $::Scratch->{"mv_$1"} = $2;
                     }
                     $Vend::FinalPath =~ s:/process/page/:/:;
             }
             my $locale;
             if($locale = $::Scratch->{mv_language}) {
                     $Global::Variable->{LANG}
                             = $::Variable->{LANG} = $locale;
             }
     
             if ($Vend::Cfg->{Locale}                                                                and
                     $locale = $::Scratch->{mv_locale}       and
                     defined $Vend::Cfg->{Locale_repository}->{$locale}
                     )
             {
                     $Global::Variable->{LANG}
                                     = $::Variable->{LANG}
                                     = $::Scratch->{mv_language}
                                     = $locale
                              if ! $::Scratch->{mv_language};
                     Vend::Util::setlocale(  $locale,
                                                                     ($::Scratch->{mv_currency} || undef),
                                                                     { persist => 1 }                                                        );
             }

list_compat

     lib/Vend/Interpolate.pm 2808

             list_compat($opt->{prefix}, \$text);

     lib/Vend/Interpolate.pm 3538

             list_compat($opt->{prefix}, \$text);

     lib/Vend/Interpolate.pm 3874

             list_compat($opt->{prefix}, \$page);

find_sort

     lib/Vend/Interpolate.pm 3270,3271

             $text =~ /^\s*\[sort\s+.*/si
                     and $opt->{sort} = find_sort(\$text);

mv_order_report

     lib/Vend/Order.pm 867,868

         $body = readin($::Values->{mv_order_report})
                     if $::Values->{mv_order_report};

mv_error_$var

     lib/Vend/Order.pm 1030

                        $::Values->{"mv_error_$var"} = $message;

109.2. Interchange 4 Deprecated Features
----------------------------------------

Vend::Util::send_mail Vend::Order::send_mail send_mail

     The send_mail routine has been replaced by the Vend::Mail::send
     routine.

110. Upgrading from Minivend 4.0 to Interchange 4.6
===================================================

if [item-price] suddenly turns 0, check PriceField in the catalog.cfg

110.1. minivend.cfg
-------------------

o    Remove references to MiniMate.

o    Add this line to minivend.cfg:

     #include lib/UI/ui.cfg

Make sure the files catalog_before.cfg and catalog_after.cfg are
there, or add their contents to etc/your_cat_name.before and
etc/your_cat_name.after to it only for some catalogs.

110.2. Access Manager
---------------------

You need to get the minimate.asc file renamed to access.asc and add
the following fields to the first line:

groups
last_login
name
password

Remove these catalog.cfg lines:

        Variable            MINIMATE_META   mv_metadata
        Variable            MINIMATE_TABLE  minimate
        Database            minimate        minimate.asc      TAB

Add this one:

        Database            affiliate    affiliate.txt     TAB

Authentication for admin users is now done from a separate table than
customers, and passwords are encrypted.

110.3. Database Editing
-----------------------

Update the mv_metadata.asc file as appropriate.

110.4. Order Manager
--------------------

Some things that are needed for the order manager:

o    Add these fields to transactions:

    affiliate  approx. char(32)
    archived   char(1)
    campaign   approx. char(32)
    comments   blob/text
    complete   char(1)
    deleted    char(1)
    order_wday char(10)
    order_ymd  char(8)
    po_number  approx. char(32)

o    Add these fields to transactions:

    affiliate  approx. char(32)
    campaign   approx. char(32)

o    Remove this field from userdb:

mv_credit_card_info

o    Add these fields to userdb:

inactive     char(1)
credit_limit char(14) or decimal(12,2)
dealer       char(3)

o    Create the directory 'logs'.

o    Create the directory 'orders' if it doesn't already exist.

o    Update your order routes to those in the Interchange
     distribution. Note that the route log_entry is necessary if you
     want to enter orders from the Interchange UI.

o    Update the etc/log_transaction file.

o    Add the etc/log_entry file.

o    Add this to catalog.cfg:

    ## Don't want people setting their credit_limit directly
    UserDB default scratch "credit_limit dealer"

110.5. Affiliates
-----------------

Add a tab-delimited affiliate table:

affiliate name    campaigns   join_date   url timeout active  password

You can find a recommended database configuration in
foundation/dbconf/*/affiliate.*.

110.6. Page Editor
------------------

Add the directories 'templates' and 'backup'. Copy the contents of the
Interchange simple/templates to templates.

110.7. Item Editor
------------------

Add a merchandising table with the following fields:

Database  merchandising  merchandising.txt __SQLDSN__
Database  merchandising  DEFAULT_TYPE text

sku                 char(32)
featured            char(32)
banner_text
banner_image
blurb_begin
blurb_end
timed_promotion     char(16)
start_date          char(24)
finish_date         char(24)
upsell_to
cross_sell
cross_category      char(64)
others_bought
times_ordered

Index the fields with char(*) types. You can find the recommended
database configuration in foundation/dbconf/*/merchandising.*

110.8. Preferences Editor (KNAR)
--------------------------------

Create the tab-delimited file variable.txt with these fields:

code  Variable  pref_group

Add this as the *first* line of catalog.cfg:

VariableDatabase variable

110.9. Route Editor
-------------------

Create the file route.txt with these fields:

        code
        report
        receipt
        encrypt_program
        encrypt
        pgp_key
        pgp_cc_key
        cyber_mode
        credit_card
        profile
        inline_profile
        email
        attach
        counter
        increment
        continue
        partial
        supplant
        track
        errors_to

Add this line in catalog.cfg:

RouteDatabase route

110.10. Transactions database
-----------------------------

The back office UI should work fine for editing database tables.
Obviously the things which are specific to the order transaction setup
will break unless you have the right fields, but even these can be
controlled by configuring the UI.

Add a new field to transaction.txt called 'archived'.

111. Upgrading from Minivend 3 to Minivend 4
============================================

There were big changes from Minivend 3 to Minivend 4, some of which
were incompatible.

Many things were removed as redundant, deprecated, or just plain
crufty:

111.1. Nested [loop]s
---------------------

MV3 used a different scheme for creating nested loop lists:

[loop with="-a"* arg="item item item" search="se=whatever"]

allowed you to refer to the nested values with a [loop-code-a]
construct. In Minivend 4, the form is:

        [loop prefix=size list="Small Medium Large"]
                [loop prefix=color list="Red White Blue"]
                        [color-code]-[size-code]<BR>
                [/loop]
                <P>
        [/loop]

111.2. All frame features removed
---------------------------------

Frames are now managed by the user in HTML.

111.3. Tags removed
-------------------

111.3.1. buttonbar
------------------

Replace with Variable defined in catalog.cfg. buttonbar was previously
used as an SSI-like command for catalog-wide standardized features
like navigation bars. In the 3.x catalog.cfg the ButtonBars parameter
defines a list of html snippets, like

ButtonBars header.html footer.html copyright.html

So [buttonbar 0] substitutes 'header.html', [buttonbar 1] substitutes
'footer.html', etc.

In 4.x catalog.cfg, define variables, like

Variable HEADER    <pages/header
Variable FOOTER    <pages/footer
Variable COPYRIGHT <pages/copyright

Then replace all occurrences of [buttonbar 0] with __HEADER__,
[buttonbar 1] with __FOOTER__, etc.

Note that the old header.html, footer.html, etc. contained html code,
but were not actually html pages with <html><body> etc, tags. Thus the
current practice is to use filenames with no extension or perhaps
'.txt' to differentiate them from pages.

111.3.2. random
---------------

Replace with [ad random=1] or custom code. See the [ad] tag docs.
Random and rotate were used to place random or rotating regions on
pages, such as banner ads.

The Random directive in catalog.cfg defines the numbered HTML snippet
files, similar to buttonbars above.

111.3.3. rotate
---------------

Replace with [ad ...]. See [random] above.

111.3.4. help
-------------

No replacement. Use data functions or variables.

111.3.5. body
-------------

Replace with templates. Again the body tag [body 1] etc. defines
numbered body definitions that could be applied site-wide. However, in
this case minivend actually built up the <body ....> substitution
using the Mv_* directives in catalog.cfg.

111.3.6. finish_order
---------------------

[finish_order] was a conditional tag; if the basket contained anything
a 'checkout' graphic would be displayed. No replacement; use [if
items]Message[/if].

111.3.7. last_page
------------------

No replacement - this can be emulated by setting a scratch variable on
one page, then using it to build the return URL.

111.3.8. item-link
------------------

No replacement, just use [page [item-code]].

111.3.9. loop-link
------------------

No replacement, just use [page [loop-code]].

111.3.10. sql-link
------------------

No replacement, just use [page [sql-code]].

111.3.11. accessories
---------------------

Replace with normal data functions.

111.3.12. Compatibility routines
--------------------------------

Compatibility routines for many popular tags like [random], [rotate],
etc. are provided in the appendix of this document. To use one, copy
it to a file and put it in your usertag directory. (Tags in the
usertag directory are read in by interchange.cfg by default).

111.4. Directives removed
-------------------------

    ActionMap
    AdminDatabase
    AdminPage
    AsciiBackend
    BackendOrder
    ButtonBars
    CheckoutFrame
    CheckoutPage
    CollectData
    DataDir
    Delimiter
    DescriptionTrim
    FieldDelimiter
    FrameFlyPage
    FrameLinkDir
    FrameOrderPage
    FrameSearchPage
    ItemLinkDir
    ItemLinkValue
    MsqlDB
    MsqlProducts
    Mv_AlinkColor
    Mv_Background
    Mv_BgColor
    Mv_LinkColor
    Mv_TextColor
    Mv_VlinkColor
    NewReport
    NewTags
    OldShipping
    OrderFrame
    PageCache
    PriceDatabase
    Random
    ReceiptPage
    RecordDelimiter
    ReportIgnore
    Rotate
    SearchFrame
    SearchOverMsg
    SecureOrderMsg
    SpecialFile
    SubArgs
    Tracking

111.5. Minor operations removed
-------------------------------

o    auto-substitution of mp= on [loop search=profile], [search-region
     arg=profile]

o    [tag scan]...

o    [tag sql]...

Many of these are related to one of:

o    Removal of frames logic

o    Removed tags

o    Obsolete methods

o    Old routines for 2.0x compatibility

111.6. Search lists
-------------------

Search tags must now be surrounded by [search-region]
[/search-region]. This is because multiple searches can be done in a
page, with multiple [more-list] entries, multiple [no-match] areas,
etc. It was not really possible to avoid this and add the feature.

To find all files containing the search list, do:

find pages -type f | xargs grep -l '\[search.list'

That will yield a set of files that need to be updated. You should
surround all parts of the search area, i.e.:

    [search-region]

    [search-list]
        your search iteration stuff, [item-code], etc.
    [/search-list]

    [more-list]
        [more]
    [/more-list]

    [/search-region]

111.7. Search conditionals
--------------------------

Search conditionals should now say [if-item-field field]
[/if-item-field] and [if-item-data table column] [/if-item-data]. This
allows mixing and nesting of lists. You may find that the old works in
some situations, but it will not work in all situations.

111.8. Form data updates
------------------------

Added Scratch variable mv_data_enable to gate the update_data
function. You must set it before doing a form update. Prior to this it
was possible to update a SQL database willy-nilly.

A quick fix like this will allow the update on a single page:

    [set update_database]
    [set mv_data_enable]1[/set]
    [/set]
    <INPUT TYPE=hidden NAME=mv_click VALUE=update_database>

It will ensure at least that the user loads one form from you for each
update. For best security, gate with a userdb entry like this:

    [set update_database]
    [if type=data term="userdb::trusted::[data session username]"]
        [set mv_data_enable]1[/set]
    [else]
        [set mv_data_enable]0[/set]
    [/else]
    [/if]
    [/set]

111.9. Checkout changes
-----------------------

Minivend 4 uses in-page error-flagging on the checkout page. Simplest
way to convert is probably to use the checkout.html from the simple
demo as a start, and move in any customization from the existing
site's catalog.html (headers, footers, logos, etc.) A line-by-line
comparison of the data fields in the checkout page should be
performed, adding any custom fields as needed. Custom error checking
in etc/order.profiles may have to be re-worked, or can be added into
checkout.html using the in-page order profile capability. (Note that
etc/order.profiles is called etc/profiles.order in newly-built
Interchange catalogs.)

Remember to update receipt.html and report/report.html with any custom
fields, as well.

111.10. [if-field] etc.
-----------------------

The least-compatible things in the tag area are [if-field] (needs to
be [if-PREFIX-field], where prefix might be item|loop by default
depending on the tag. Likewise:

    [if-data table col]  --> [if-PREFIX-data table col]
    [on-change mark]     --> [PREFIX-change mark]
    [if-param param]     --> [if-PREFIX-param param]
    [PREFIX-param N]     --> [PREFIX-pos N] (where N is a digit)

111.11. [search-list]
---------------------

You must always surround [search-list] with [search-region]
[/search-region].

Embedded Perl changes quite a bit. While there are the $Safe{values}
and other variable settings, they are automatically shared (no
arg="values") and move to:

    $Safe{values}   -->  $Values
    $Safe{cgi}      -->  $CGI
    $Safe{carts}    -->  $Carts
    $Safe{items}    -->  $Items
    $Safe{config}   -->  $Config
    $Safe{scratch}  -->  $Scratch

There are a number of other objects, see the docs.

Most other issues have more to do with the catalog skeleton (i.e.
simple or barry or basic or art) than they do the core. For instance,
the "basic" catalog produced for MV3 ran unchanged except for the
issues discussed above.

111.12. Global subs
-------------------

Accessing globalsubs from [perl] tags is done slightly differently.

Minivend 3 method:

[perl sub]
myfunsub();
[/perl]

Minivend 4/IC method:

[perl subs=1]
myfunsub();
[/perl]

If you do this wrong, you'll get an error that looks like this:

115.202.115.237 H8gbq6oK:115.202.115.237 - [28/February/2001:18:58:50 -0500] testcat /cgi-bin/testcat.cgi Safe: Undefined subroutine &MVSAFE::myfunsub called at (eval 283) line 2.

K. Minivend 3 compatibility usertags and globalsubs
===================================================

These files were originally distributed with Minivend 4 in the compat/
directory. They replace Minivend 3 functionality that was removed or
greatly altered in Minivend 4.

K.1. body
---------

UserTag body PosNumber 2
UserTag body Order type extra
UserTag body Routine <<EOR
use vars qw($C);
sub parse_color {
    my ($var, $value) = @_;
    return '' unless $value;
    $var = lc $var;
    $C->{Color}->{$var} = [];
    @{$C->{'Color'}->{$var}} = split /\s+/, $value;
    return $value;
}

sub {
    my($scheme, $extra) = @_;
    my $r = '<BODY';
    my ($var,$tag);
    #return '<BODY>' unless (int($scheme) < 16 and int($scheme) > 1);

    my %color = qw( mv_bgcolor BGCOLOR mv_textcolor TEXT
                    mv_linkcolor LINK mv_vlinkcolor VLINK
                    mv_alinkcolor ALINK mv_background BACKGROUND );
    if (defined $::Values->{mv_resetcolors}
            and $::Values->{mv_resetcolors}) {
        delete $::Values->{mv_customcolors};
        undef $::Values->{mv_resetcolors};
    }
    if (defined $::Values->{mv_customcolors}) {
        foreach $var (keys %color) {
            $r .= qq| $color{$var}="| . $::Values->{$var} . '"'
                if $::Values->{$var};
        }
    }
    else {
        foreach $var (keys %color) {
            $r .= qq| $color{$var}="| . ${$Vend::Cfg->{Color}->{$var}}[$scheme] . '"'
                if defined ${$Vend::Cfg->{Color}->{$var}}[$scheme]
                    &&  ${$Vend::Cfg->{Color}->{$var}}[$scheme] !~ /\bnone\b/;
        }
    }
    $r =~ s#(BACKGROUND="(?!http:))([^/])#$1$Vend::Cfg->{ImageDir}$2#;
    $r .= " $extra" if defined $extra;
    $r .= '>';
}
EOR

AddDirective Mv_Background   color
AddDirective Mv_BgColor      color
AddDirective Mv_TextColor    color
AddDirective Mv_LinkColor    color
AddDirective Mv_AlinkColor   color
AddDirective Mv_VlinkColor   color

K.2. buttonbar
--------------

# Returns a buttonbar by number
UserTag buttonbar Order type
UserTag buttonbar PosNumber 1
UserTag buttonbar Interpolate 1
UserTag buttonbar Routine <<EOR
sub get_files {
    my($dir, @files) = @_;
    my(@out);
    my($file, $contents);
    foreach $file (@files) {
        config_error(
          "No leading ../.. allowed if NoAbsolute set. Contact administrator.\n")
        if $file =~ m#^\.\./.*\.\.# and $Global::NoAbsolute;
        push(@out,"\n") unless
            push(@out,readfile("$dir/$file.html"));
    }

    @out;
}

sub parse_buttonbar {
    my ($var, $value) = @_;
    return [] unless $value;
    my @c;
    my @vals = grep /\S/, split /\s+/, $value;
    for(@vals) {
        push @c, Vend::Util::readfile("pages/$_.html");
    }
    return \@c;
}

sub {
    my($buttonbar) = @_;
    if (defined $Vend::Cfg->{'ButtonBars'}->[$buttonbar]) {
        return $Vend::Cfg->{'ButtonBars'}->[$buttonbar];
    }
    else {
        return '';
    }
}
EOR

AddDirective ButtonBars  buttonbar

K.3. form_mail.cfg
------------------

GlobalSub <<EndOfSub
sub form_mail {
    my($to, $subject, $reply, $body) = @_;
    my($ok);

    $subject = '<no subject>' unless defined $subject && $subject;

    $reply = '' unless defined $reply;
    $reply = "Reply-to: $reply\n" if $reply;

    $ok = 0;
    SEND: {
        open(Vend::MAIL,"|$Vend::Cfg->{'SendMailProgram'} -t") or last SEND;
        print Vend::MAIL
            "To: $to\n",
            $reply,
            "Subject: $subject\n",
            "Errors-To: $Vend::Cfg->{MailOrderTo}\n\n",
            $body
            or last SEND;
        close Vend::MAIL or last SEND;
        $ok = ($? == 0);
    }

    if (!$ok) {
        logError("Unable to send mail using $Vend::Cfg->{'SendMailProgram'}\n" .
            "To '$to'\n" .
            "With subject '$subject'\n" .
            "With reply-to '$reply'\n" .
            "And body:\n$body");
    }
    $ok;
}
EndOfSub

K.4. help
---------

UserTag help PosNumber 1
UserTag help Order name
UserTag help Routine <<EOR
sub parse_help {
    my ($var, $value) = @_;
    my (@files);
    my (@items);
    my ($c, $chunk, $item, $help, $key);
    unless (defined $value && $value) {
        $c = {};
        return $c;
    }
    $c = $C->{'Help'};
    $var = lc $var;
    $C->{'Source'}->{'Help'} = $value;
    @files = get_files($C->{'PageDir'}, split /\s+/, $value);
    foreach $chunk (@files) {
        @items = split /\r?\n\r?\n/, $chunk;
        foreach $item (@items) {
            ($key,$help) = split /\s*\n/, $item, 2;
            if(defined $c->{$key}) {
                $c->{$key} .= $help;
            }
            else {
                $c->{$key} = $help;
            }

        }
    }
    return $c;
}

sub {
    my($help) = shift;
    # Move this to control section?
    if ($::Values->{mv_helpon}) {
        delete $::Values->{mv_helpoff};
        undef $::Values->{mv_helpon};
    }
    return '' if defined $::Values->{'mv_helpoff'};
    if (defined $Vend::Cfg->{'Help'}{$help}) {
        return $Vend::Cfg->{'Help'}{$help};
    }
    else {
        return '';
    }
}
EOR

AddDirective Help help

K.5. random_rotate
------------------

UserTag random PosNumber 0
UserTag random Interpolate 1
UserTag random Routine <<EOR
package Vend::Config;
sub parse_random {
    my ($var, $value) = @_;
    return '' unless (defined $value && $value);
    my $c = [];
    $var = lc $var;
    my @files = grep /\S/, split /\s+/, $value;
    local ($Vend::Cfg) = $C;
    for (@files) { push @$c, Vend::Util::readin($_) }
    return $c;
}

package Vend::Interpolate;
sub {
    my $random = int rand(scalar(@{$Vend::Cfg->{'Random'}}));
    if (defined $Vend::Cfg->{'Random'}->[$random]) {
        return $Vend::Cfg->{'Random'}->[$random];
    }
    else {
        return '';
    }
}
EOR

UserTag rotate PosNumber 2
UserTag rotate Order ceiling floor
UserTag rotate Interpolate 1
UserTag rotate Routine <<EOR
sub {
    return '' unless $Vend::Cfg->{Rotate};
    my $ceiling = $_[0] || @{$Vend::Cfg->{'Rotate'}} || return '';
    my $floor   = $_[1] || 1;

    $ceiling--;
    $floor--;

    my $marker = "rotate$floor$ceiling";

    if($ceiling < 0 or $floor < 0) {
        $floor = 0;
        $ceiling = scalar  @{$Vend::Cfg->{'Rotate'}} - 1;
        logError "Bad ceiling or floor for rotate";
    }

    my $rotate;
    $rotate = $Vend::Session->{$marker} || $floor;

    if($rotate > $ceiling or $rotate < $floor ) {
        $rotate = $floor;
    }

    $Vend::Session->{$marker} = $rotate + 1;
    return $Vend::Cfg->{'Rotate'}->[$rotate];
}
EOR

AddDirective Random random
AddDirective Rotate random

K.6. AsciiBackend
-----------------

GlobalSub <<EOS
sub AsciiBackend {
    package Vend::Order;
    $Vend::Order::override_track_order = \&track_order;
    sub track_order_backend {
        my ($order_no,$order_report) = @_;
        my ($c,$i);
        my (@backend);

        @backend = split /\s*,\s*/, $Vend::Cfg->{BackendOrder};

        if(@backend and $Vend::Cfg->{AsciiBackend}) {
            my(@ary);
            push @ary, $order_no;
            for(@backend) {
                push @ary, $::Values->{$_};
            }
            foreach $i (0 .. $#$Vend::Items) {
                push @ary, $Vend::Items->[$i]{'code'};
                push @ary, $Vend::Items->[$i]{'quantity'};
                if ($Vend::Cfg->{UseModifier}) {
                    foreach $j (@{$Vend::Cfg->{UseModifier}}) {
                        push @ary, $Vend::Items->[$i]->{$j}
                    }
                }
            }
            logData ($Vend::Cfg->{AsciiBackend}, @ary);
        }
        $Vend::Order::override_track_order->($order_no, $order_report);
    }
    *track_order = \&Vend::Order::override_track_order;
}
EOS

AddDirective BackendOrder
AddDirective AsciiBackend

112. History of Interchange
===========================

Interchange is a descendent of Vend, an e-commerce solution originally
developed by Andrew Wilcox in early 1995. Mike Heins took the first
publicly-released version, Vend 0.2, and added searching and DBM
catalog storage to create MiniVend. Mike released MiniVend 0.2m7 on
December 28, 1995. Subsequent versions of MiniVend took parts from
Vend 0.3, especially the vlink and Server.pm modules, which were
adapted to run with MiniVend. In the four years that followed, Mike
Heins expanded and enhanced MiniVend, creating a powerful and
versatile e-commerce development platform. MiniVend grew to support
thousands of businesses and their e-commerce sites, and sites running
on MiniVend versions 3 and 4 are still common today.

Separately, an experienced e-commerce development team founded Akopia.
Their goal was to create a sophisticated open source e-commerce
platform that was both feature-rich and easy to use. Their product,
Tallyman, was intuitive, and had great content-management features,
but lacked many of MiniVend's capabilities.

Akopia acquired MiniVend in June 2000. Mike Heins and the Tallyman
developers combined MiniVend 4 with Tallyman's features to create
Interchange. Interchange replaces both MiniVend and Tallyman. In order
to preserve compatibility, the name "minivend" and prefixes like "mv_"
and "MVC_" will still appear in source code and configuration files.
Interchange's first stable release was version 4.6.

In January 2001, Red Hat acquired Akopia and created its new
E-Business Solutions Division. Red Hat sponsored the development of
Interchange 4.8 and the Red Hat E-Commerce Suite.

In mid-2002, Red Hat decided to stop supporting Interchange
development, and a group of individuals formed the Interchange
Developer Group to coordinate Interchange development independent of
any company or person. Interchange continues to advance and the user
community is growing. Interchange 5.0 is planned for release in late
2002.

______________________________________________________________________

Copyright 2001-2002 Red Hat, Inc. Freely redistributable under terms
of the GNU General Public License.

Copyright 2002 ICDEVGROUP. Freely redistributable under terms of the
GNU General Public License.

