Summary of keywords | Customizable forms

The CMS addon for SREhttp/2

Abstract The CMS addon for the SREhttp/2 web server for OS/2 is a moderately powerful content management system (CMS). The power of CMS lies in it's ability to quickly create HTML documents that use stored data. In particular, with CMS it is easy to create "blogs", and other types of repetitive HTML documents.

Contents

  1. Introduction
  2. The database component
  3. The HTML generator
  4. Archives and Links
  5. Using "update archives" when invoking CMS
  6. Template files for archives
  7. Summary of CMS keywords and options (with links to detailed descriptions)
  8. Complete description of CMS keywords and options
  9. Appendices
  10. Meta Functions
  11. The DATE function
  12. The TIME function
  13. The STATUS function
  14. Description of the !SPECIAL information variables
  15. If-functions
  16. Controlling access to CMS dataseries
  17. Using the ARCHIVE element
  18. Using the COMMENT element
  19. Examples of the COMMENT element
  20. The CMS database files
  21. Creating blogs using predefined files
  22. CMS subdirectories and files
  23. CMS user-defined procedures & customizable forms
  24. The FileDir and UploadDIR
  25. SELECT and POLL CMS-variables
  26. Using POLL to implement a survey

I. Introduction

CMS consists of two components:
  1. a dataseries component
  2. an HTML file generator
Note that CMS is "multi-host" aware -- you can use a single installation of CMS to support CMS dataseries, and creation of output files, for many hosts on a single SREhttp/2 server.

CMS is multi-host aware. You can use CMS to create dataseries across different hosts on the same server machine -- a single installation of CMS will keep track of which dataseries belongs to which host.


I.a. The database component

The database component (which is based on SRE2003's built-in database engine) allows you to define and manage multiple CMS dataserieses. Using a web based interface, the user can define the names and types of variables in a dataseries, create new record and fill in the values of these variables, and modify and otherwise manage pre-existing records. Among the advantages offered by CMS is the ease of uploading files; CMS will handle all the complexities of requesting, retrieving, and storing uploaded files!
Technical
Notes:   
  • As a security measure, only users with either
  • a SREhttp/2 SUPERUSER privilege
  • a CMS_DEF privilege
  • are allowed to create dataseries!
  • The maximum size of a record is 10000 bytes (you can change this by editing the CMS_ADD.CMD, CMS_MOD.CMD, and other files).
Assuming the CMS was properly installed on your OS/2 computer that is running SREhttp/2, to access the database component simply fire up your web-browser, and request:
       /CMS/CMS? 
This will bring up a menu of choices. Create a new CMS dataseries

Use this to define a new CMS dataseries.
You will be asked to specify its name, the names and "types" of variables, and some descriptive information.

The several variable "types" are:

An Abstract A 50 character or less abstract, that is used for informational purposes (i.e.; when displaying lists of dataseries to choose from)
String A text string, without CRLFs.
Number an integer or real number (with '' treated as 0)
DateTime a date (day/month/year) and time (hour:minute)
Select List a selection list. See below for further details.
Poll a poll (running count of several choices). See below for further details.
Lines of Text Multiple lines of text
Checkbox A checkbox -- when checked, a value of 1 is stored. When not checked, a value of '' is stored
File or URL Allows the user to upload the contents of a file (assuming she is using a reasonably modern browser); or grab the contents of a URL.
If you specify any "File or URL types, you should also specify (in the field provided) the upload storage directory. This directory is where these uploaded files will be stored.
Note that when CMS generates output, it will use the contents of the file, not the file name.
Furthermore, this file (or URL) can be of any mimetype, it need not be a text file.
If you do not specify a "uploads storage directory", the UPLOADS subdirectory of the CMS directory is used.

You can also specify:

  • template files, and the output files they will generate.
  • The output files directory for these template and output files (used when you do not include a path when specifying output and template files).
  • A upload files directory (for storage of uploaded files).

  • Furthermore, you can limit access to this CMS dataseries by username --
    if you don't have one of the specified username, you won't be allowed to use the following actions. See the appendix for the details on controlling access.

  • Modify a CMS dataseries template definitions

    Remove template definitions, or add new "template definitions", to a dataseries. Note that when you define a dataseries, you can specify several "template definitions". These are stored in the .DEF file (in the CMS\INDEX) subdirectory for this dataseries. This option allows you to chanage these template definitions.
    Other variables in the .DEF file can be modified by the restructure a CMS dataseries option that is described below.

  • Generate output files from an existing CMS dataseries

    You'll be asked to select one of the currently defined CMS dataseries. Then, you will be asked to choose one (or several) output files to generate. This is done by selecting appropriate template and "output" files(from those you specified when when you defined the CMS dataseries). You can also choose to "sort" the documents in different orders. You can also choose to view only the most "recent" documents. Note that output files include the "current" listing of records, archives (singleton and subset), and comment files.

  • Add a record to an existing CMS dataseries

    You can add new records to one of the defined data series. When you add a record, you will be shown an HTML form listing the "types" of variables; with input fields suitable to the "type".

  • Remove a record from an existing CMS dataseries

    You can remove one, or several, records from a CMS dataseries. You can also view the records before removing them.

  • Modify a record in an existing CMS dataseries

    You can modify a record that currently exists in a CMS dataseries. For file types, you can change the original filename (as provided by the client), as well as the local file name (its name on the server machine, which will be relative to the file-storage directory). You can also view the uploaded file's contents.

  • Add a comment to a record in an existing CMS dataseries

    You can add comments to existing records at any time -- old comments (for this record) will be retained.

  • Remove a comment to a record in an existing CMS dataseries

    You can remove one or several comments on existing records at any time.

  • Modify a comment to a record in an existing CMS dataseries

    You can modify comments to existing records at any time.

  • Cleanup currently open CMS dataseries

    This will shutdown and reopen all currently open CMS dataseries. This is sometimes necessary when an error occurs.

  • Fix & Repair a CMS dataseries

    This will do maintainance and repair on a selected CMS dataseries.
    The selected dataseries will first be closed. Each record will then be examined, with deleted records removed, and bad records (that were somehow corrupted) are also removed.

    This should not need to be done, since CMS will do occassional cleanups of deleted records. Thus, the best use of this when you think CMS has been lax about removing deleted records, or , forcing a fix & repair if you think some records have been corrupted and need to be removed.

  • Delete a CMS dataseries

    You can delete a dataseries-- removing its several data and index files. You will be asked to verify this action!

  • Backup a CMS dataseries

    Backup up the main, comments, and definitions file of a CMS dataseries (dated filenames are written to the DATA\ARCHIVE subdirectory of CMS). You can also use this to restore a CMS dataseries from a backup.

  • Restructure a CMS dataseries

    Remove, add, and re-define the variables in a CMS dataseries. It's a good idea to backup the dataseries before restructuring it!

  • Replicate a CMS dataseries

    Create a new dataseries, that retains the attributes (such as the variables, directories, and template files) of an existing data-series. You can modify these attributes (for example, you can remove variables).

  • Install a pre-defined blog

    Create a blog using one of CMS's pre-defined templates.

  • Working with CMS's customizable forms

    Descriptions of CMS's customizable forms; with a simple tool for helping you get started using them.

  • Note: for details on the structure of CMS data files, see the appendix.

    I.b. The HTML file generator

    The HTML file generator is based on the use of template files. CMS will read a template file, and generate an output file. Typically, the output file will be an HTML document that you can then move to your web site (or save directly to the appropriate web-accessible directory).

    Templates are simply HTML documents that contain special CMS elements that contain CMS keywords. These give you access to a number of CMS functions. In particular, you can use these CMS "keywords" to output the values of variables stored in a CMS dataseries. And you can easily do this REPEATedly -- for each record in a dataseries.

    In addition, CMS templates allow for a limited amount of program control -- IF, ELSE, and GOTO statements are supported. For example, IF is used to selectively include blocks of HTML content, based on the values of user-defined variables or of variables from a CMS dataseries.

    For those who can work with REXX, the templates allow you to CALL (or INTERPRET) your own REXX procedures. These procedures will be given access to a number of the CMS variables (such as the values of the variables in the currently active record).

    The user-defined REXX procedure can return an arbitrarily long string for writing to the output file, and it can set the values of variables that will be available to other CMS elements.

    The general syntax of these CMS elements is:

      <? keyword  opt1 opt2 ... > 
    where the opts can sometimes take the form
    varname=value

    Some keywords take a special format, where options that are preceded by a ? are processed by CMS, and all other options are retained as is:
       <? keyword ?opt1 opt2 ..> 
    The next two sections describes the keywords, and their options.

    Notes

  • As of this writing, CMS does NOT provide a means of creating template files. You will have to write them yourself, using this documentation to instruct you into the proper usage of the many CMS elements.
  • By default (when path information is not included), output and template files are assumed to be in the output file directory.

  • I.c. Archives and Links

    Note: before reading this, you may want to read the Appendix section that discusses ARCHIVE

    When you generate an HTML document from a CMS template, there are several ways of storing the output: Each of these methods has advantages and disadvantages. As as compromise between the efficiency of the "subset" archives, and the ease of access of "singleton" archives, LINK elements can be used. LINK, which is used inside of REPEAT blocks, will generate a link to the "subset" archive document that contains the results for this record. More precisely, for each article a link will be included in this document. These links will point to the exact location, in the archive, of the article.

    Using LINK requires a bit of coordination: you need to create a "subset" ARCHIVE element with specifications that match what you use in the LINK element and you need to add a <?A ...> element to your ARCHIVE template with specifications that match LINK.

    In particular, for the LINK and ARCHIVE elements:

    See the description of LINK for further details.

    All in all, we recommend creating subset achives, and using LINK (and an A element in the archive's template file that has a matching ?NAME).

    Hint: you can use the link creator tool to semi-automate the construction of thes LINK and ARCHIVE elements.


    I.c.2. Selecting "update latest archives" when invoking CMS

    You can save processing time by selecting the
    update latest archives
    option when you
    generate output files from an existing CMS dataseries.

    This option effects how CMS creates "subset" archives. Basically, when checked, CMS will only create the "latest" archive file (the archive file covering the most recent records).

    More precisely, CMS will

    For example, if the subset archive type is MONTH, and the latest record was entered in Nov 2003, then only the archive document file for November 2003 will be recreated (say,ARC_November2003.HTML).

    Notes:


    I.c.3. Template files for archives

    The actual content of the archive files is determined by the template file you specify. These are exactly like the template files used to create the main output. That is, these files use all (with a few exceptions) of the CMS elements.

    There are a few considerations:

    1. You can use REPEAT blocks in BOTH singleton and subset archives.
      1. Subset: the REPEAT block will process all records in this subset
      2. Singleton: the REPEAT block will only process this record
      Note that many advanced CMS features (such as VAR and IF) only work within a REPEAT block.

      Therefore, using a REPEAT block within a singleton-archive template-file is often necessary and/or convenient.
      Even though only one record is being processed per singleton archive!

    2. You should not use the ARCHIVE element in template files that are meant to be used by other ARCHIVE elements!

    II. Summary of the CMS Keywords and Options

    KeywordDescription
    !-- & -- Insert start of HTML comment (a <!-- ) and end of an HTML comment (a --> )
    A Create a <A ..> element, with a variable value used as the HREF
    ARCHIVE Generate archive files
    CALL Call a file as a REXX procedure, output what it returns
    CASES, /CASES, CASE, and /CASE A case statement (a multiple block IF)
    COMMENT Create a link to a listing of a record's comments
    DEFINE and /DEFINE Define a subroutine
    ELSE and /ELSE Jump here if an IF condition is false
    GOSUB Insert contents of a subroutine
    GOTO Jump to a LABEL
    HTML Insert an HTML element, with substitutions
    IF and /IF Skip to the /IF if the IF condition is not met
    INC Increment a user-defined numeric variable
    ITER (and DROP) Stop processing this record (go to next record)
    INTERPRET Call a block of rexx code as a procedure, output what it returns
    LABEL Jump to here (using GOTO)
    LEAVE Stop processing all records
    LINK Create a link to this records "permanent" location
    POLL Display current poll results, or ask client to add a vote to the poll
    READFILE Read a file
    REPEAT and /REPEAT Repeat content, one time for each record in dataseries
    REM A comment, that will NOT be written to the output file
    SERIES Write some information on this CMS dataseries
    SET Set a user-defined variable
    SORT Sort the records on one of the "sortable" variables
    SHOW Show user-defined variables, and "system" variables (eg; time)
    SHRINK and /SHRINK Remove extra linefeeds, tabs, and spaces
    TEMPLATE Display information the CMS template being used
    TR, TH, and TD Write HTML table elements, with alternating colors
    VAR Lookup the value of a variable in the current CMS dataseries

    Note: Several keywords are typically used in a REPEAT block -- such as VAR, A, and TR.

    III. Full Description of the CMS Keywords and Options

    !-- and --
    Insert HTML comment delimiters This is useful for creating HTML comments that will contain the results of a CMS (a <? .. >) element.

    Example:

                    <? !-- Uncomment this to show attributes >
                    <UL>
                    <li><? var color >
                    <li><? Var weight >
                    </ul>
                    <? -- End of show attributes block > 
    Note that the Uncomment this to show attributes and the End of show attributes block will NOT be written to the output file.

    If you just want to include a comment in the template file, that will NOT be written to the output file, use the REM element.

    < and /<
    Insert HTML element delimiters This is sometimes useful when you want to use a CMS variable within an HTML element. Example:
                <? < >Input type="hidden" name="series" value="<? series name>" <? /< > 
    If you use "<" instead of "<? < >", the SERIES name CMS element will NOT be processed by CMS!

    A Create a <A href=... element Can only be used in a REPEAT block.

    options:
    ?URL=varname the varname variable will be used as the value of href= ("s will be added)

    Note: ?URL checks both the list of dataseries variables, and the list of user-defined variables.

    ?URL_FILE=varnameuse, as the value of href=, the local filename used to store a uploaded file type of variable.
    This is a convenient way to create a link to the locally stored version of an uploaded file (or of a downloaded web resource).
    Note that for other types of variables, URL_FILE and URL are the same
    ?BASE=url_base an optional "url" base, used if the ?URL does not contain path info (such as http://" or "foo.bar.net)
    ?BASE can also be used with ?NAME.

    Example:

    ?BASE=http://foo.bar.net/pictures/
         then, if the value of a ?URL varname is "hello.gif", a
           <A href="http://foo.bar.net/pictures/hello.gif"> 
         element will be created     
    
    Hint: to use ?URL to jump to an internal location (to a <A NAME="..">),
          use ?BASE="#"
    Hint: you can use ?BASE and ?NAME to create a 
        NAME target that has a common prefix and a variable
          suffix.
          Example (assuming the dataseries has a FAMILY variable): 
             <? A ?NAME=family ?BASE="F_NAME_">New family<? /a>
          Then, if FAMILY=Jones, the following will be output:
             <? A NAME="F_NAME_Jones"">New family</a>
    
    Hint: to force SREhttp/2 to return the file using a specific
          mimetype, use 
             ?BASE=/!SENDAS_type_subtype/dir1/dir2/
          For example:
             ?BASE=/!SENDAS_text_plain/mydir/textdocs/
          tells SREhttp/2 to return the document (the target of the A)
          as a plain-text mimetype.
    ?NAME=varname the varname variable (or the varname user-defined variable) will be used as the value of a name= option ("s will be added)

    Note: ?NAME checks both the list of dataseries variables, and the list of user-defined variables.

    &anopt=varname
    or
    anopt="a string"
    add an anopt option, set equal to the value of the varname variable.
    Or, if a multiple word string is used, anopt will equal the value of this string.

    As with the ?NAME and ?URL options, varname can be a dataseries or a user-defined variable.

    These options will be added at the end of the url, after a ?. You can specify many &optname options, they will be seperated by & characters (and will be properly URL-encoded).

    Notes:

    Examples:

    
        Example 1:
            <repeat>
               <? A ?url=sitename   target="info1"> <? var sitedesc></a><br>
            </repeat>
    
        could generate
               <a url="http://www.foo.net/hi.htm" target="info1">The foo hello</a><br>
               <a url="http://www.bar.net/bye.htm" target="info1">The bar goodbye</a><br>
        
        Example 2:
            <repeat>
               <? A ?url=pagename ?base="http://foo.bar.net/"   target="info1">Try this</a><br>
            </repeat>
        could generate
               <a url="http://foo.bar.net/intro.htm" target="info1">Try this</a><br>
               <a url="http://foo.bar.net/summary.htm" target="info1">Try this</a><br>
    
        Example 3:
            <repeat>
               <? A ?name=!ID"> Info for <? var username> </a><br>
                  ...
               <? A ?url="!ID" ?base="#">Top of entry</a> (for <? var username>)
        could generate
             <a  name="5243_625">Info for Joe</a><br>
                  ...
             <a href="#5243_625">Top of entry</a> (for Joe)
    
        Example 4:
             <? A target=apps ?name="/myaddon.cmd" &visitor=NAME &Entry=!ID "> Run my application? </a>
        could generate
             <a url="/myaddon.cmd?visitor=joe&Entry=2004>Run my application?</a>
    
        Example 5:
             <? if length(upfile) gt 1 >
                <? a ?url_file=descrip_file ?base=/calendar/files/>View attached file</a>
                (< ?a ?url_file=descrip_file ?base=/!sendas_text_plain/calendar/files/ >as text</a>)
             < ? /IF >
         could generate
             <a  href="/calendar/files/MY_party.DOC" >View attached file</a>
             (<a  href="/!sendas_text_plain/calendar/files/MY_party.DOC">as text</a>)
    
       
        

    ARCHIVE Generate archive files
    Archive files refer to documents that contain a subset of the records in your dataseries. Using ARCHIVE, you can easily create a variety of these files, with each document containing a logical subset of your records. For example, you can create a seperate document for each day, week, or month.

    Syntax.
    For subset archives:
    <? Archive option=value option=value ..>
    or, for singleton achives:
    <? Archive option=value option=value ..> link-string <? /ARCHIVE>
    The options are:
    FILE=template_file  
    TYPE=nnn|HOUR|DAY|WEEK|WEEK2|MONTH|MONTH2|YEAR|SORT 
    LIST=ul|ol|table|ulA|olA|tableA
    OUTPUT=output_file_pattern or $varname
    URL=base_url or $varname
    MESSAGE="a message"
    UPDATE=0|1|AUTO 
    #FIELD="field contents"
    Please see the appendix for a complete description of how to use ARCHIVE.

    Notes:


    CALL Call a file as a REXX procedure, and write returned results
    Syntax:
        CALL filename userarg
    where:
    filename A CMS-procedure. CMS-procedures are files containing a REXX procedure (i.e.; that contain REXX code and that return a value).
    If no path information, filename is assumed to be in the CMS\LIB directory.
    Otherwise, filename should either be a fully qualified file, or relative to the CMS directory.
    If no extension is given, an extension of .CMS is used.
    userarg A single (possibly multiple-word) argument to be sent to the procedure (that is contained in filename).
    In either case, the REXX code will be called as a procedure, and should "return" results. These results will be written to the output file.

    Notes:

    Examples:
            <? CALL $FILE example >
            <? CALL $FILE myprocs\foo  105.3 >
            <? CALL $FILE d:\mystuff\bar.int > 

    CASES, /CASES, CASE, /CASE Case statement. Can only be used in a REPEAT block.
    The CASES and CASE elements are used to choose one, from many possible, blocks of code to process. CASE is an alternative to lots of IF statements; it is somewhat faster to process, and in many cases it should be easier to write & read!

    Syntax:
    • < ? CASES varname >
      CASES defines the beginning of a case statement, where VARNAME list the variable whose value (for a record) will be compared to the conditions listed in each CASE element.
      VARNAME is one of the CMS variable variables (or !ID).

    • < ? /CASES >
      /CASES takes no conditions.

    • < ? /CASE condition-list >
      The condition list contains one, or more, conditions that must be satisfied. If these conditions are all true, then the code (between this CASE and the next /CASE) will be processed (after which CMS skips to the /CASES element that defines the end of this CASES block).

    • < ? /CASE varname >
      /CASE takes no conditions.
    The condition-list
    has the following
    possible formats:
    1. value
      If the current record's value (of the varname variable) equals value, the CASE is processed. Note that value can not contain any spaces (it must be one word).
    2. "value"
      If the current record's value (of the varname variable) equals value, the CASE is processed. Note that value can contain several words.
    3. cond1 "value1" , cond2 "value2", .. , condn "valuen"
      Several conditions, each seperated by a comma. The several values must in double quotes (").

      The valid conditions are: EQ NE LE LT GE GT IN INI.
      EQ, NE, LE, LT, GT, and GT are as described for the IF element.
      IN and INI refe to whether the record's value is "in" a list of words. IN is case-sensitve, INI is case-insensitive.
      Example: <? CASE IN "DOG CAT MOUSE" >

    Example:
    <? cases education >
    <? case eq "1" >
      Education is HS dropout 
    
      <?cases age>
         <?case  le "6"> Less then or equal to 6 years old   <? /case>
         <?case  lt "18"> Less then 18 years old   <? /case>
         <?case ge "18" , le "21"  > between 18 and 21 ? <?/case>
         <? case ini "NA DK " > age not reported <? /case> 
         <? case > Older than 21 <? /case>
       <? /cases (age) >
    <? /case (1)  >   
    
    <? case ge "2" , le "3" >
      Education is ge Some College  and le BA
    
    <? /case   >
    <? case ne "4"  >
      Education is not equal to Masters
    
    <? /case   >
    <? case >
      The default: other eduction
    
    <? /case (default education) > 
    
    <? /cases  (education) >
    

    COMMENT Make and point to comments. Can only be used in a REPEAT block.
    Syntax:
       <? COMMENT option=value option=value ..> link-string <? /COMMENT>
    or
       <? COMMENT option=value ?QUIET=1 option=value ..>

    The important options are:

                ?FILE=template_file
                ?OUTPUT=output_file_pattern 
                ?URL=base_url
                ?MODE=SHOW|UPDATE|CREATE|ADD|NAME|AUTO
                ?RETAIN=varname
                ?RESPFILE=response_file_name
                ?QUIET=0|1 

    Note that the following ?options are optional:
                    ?OUTPUT : default value is a modification of the current output name
                    ?URL :   default value is ""  (pathless links are created)
                    ?MODE: default value is SHOW
                    ?RETAIN: default is not to retain any variables
                    ?RESPFILE: default value is to use the generic response
                    ?QUIET: default value is 1
    However, ?FILE is not optional!

    Example:

                    #comments for this record: <? var status(cmt_cnt) >
                    <? comment  ?url=/blogs/comments/* target=vu2>View comments?<? /comment> 
    For further details on COMMENT, please see the appendix.

    DEFINE and /DEFINE Define a subroutine. Can not be used in a REPEAT block.
    Subroutines are blocks of text that will be inserted whenever a GOSUB is found.

    Syntax:
       <? DEFINE sub_name sub_arg >
          stuff
       <? /DEFINE >

    where:
    sub_namethe name of the subroutine
    sub_argan argument name
    stuffAn arbitrarily block of text, html elements, etc.. It may include any of the CMS elements (except for DEFINE).

    Notes
    • The sub_arg should be a unique string. All occurences of sub_arg in stuff will be replaced by the value of the gosub_value (that is specified within a GOSUB element.)
    • You can not DEFINE a subroutine in a REPEAT block, or inside of a subroutine.
    • You must DEFINE a subroutine before it is called in a GOSUB.
      Hint: DEFINE your subroutines in the HEAD section of your HTML document.
    Example:
    <? DEFINE sub2 $yibble >
      Welcome <? show $Yibble> .
      This is the sub2 definition. It calls sub1: <? gosub sub1 $yibble >
    <? /DEFINE>
    
    
    ELSE and /ELSE If a preceding IF condition is not met (is false), then process all code between the ELSE and /ELSE. Can only be used in a REPEAT block.
    An
       <?ELSE comment> various stuff <? ? /ELSE comment >
    can be used after a
       <
    ?IF var1 cond var2 > various stuff <? /IF comment >

    Basically,

  • if the IF condition is met, the stuff between the IF and /IF is processed, while the stuff between the ELSE and /ELSE is not processed.
  • if the IF condition is not met, the opposite occurs -- the stuff between the IF and /IF is not processed, while the stuff between the ELSE and /ELSE is processed.
  • Notes:
    • There should be nothing between a < ?/IF > and a following < ?ELSE >
    • You must end an ELSE block with a < ?/ELSE >.
    • Within an < ?ELSE > or a <? /ELSE >, you can include comments (they are ignored). For example:
          <? ELSE this takes care of males > ... < ? /ELSE end of males ELSE >
    • Along with IF blocks, ELSE blocks can be nested.
    • ELSE blocks require a preceding IF block.
    • However, IF blocks do not require a following ELSE block.
    • That is, you can use an IF by itself (without using an ELSE), but you can not use an ELSE by itself.
    Example:
    <? If male eq 1 >
      This record is for a man.
      <? if height gt 72>
          He is taller then 6 feet 
      <? /if>
      <? Else >
         He is shorter then 6 feet 
      <? /else >
    <? /if >
    <? else (a woman) >
      This record is for a woman.
      <? if height gt 66>
          She is taller then 5.5 feet 
      <? /if>
      <? Else >
         She is shorter then 5.5 feet 
      <? /else >
    <? /else (end of woman else)  >
    
    

    GOSUB Insert the contents of a subroutine.
    Replace this element with the contents of a subroutine (that was previously defined using the DEFINE CMS-element).
    This is a straight textual substitution. The substituted contents will then be processed by CMS.

    Syntax:
       <? GOSUB subname gosub_value >

    where:
    sub_namethe name of the subroutine whose contents are to be inserted
    gosub_valuea string
    The sub_arg string (specified when you DEFINEd the subroutine) will be replaced by the gosub_value.
    Example:
    <? gosub sub2 !count >
    <? gosub subs2 hello world >
    

    GOTO and LABEL. Goto a label. Can only be used in a REPEAT block.
    Example: <? Goto Section4 > , where Section4 is a Label.
    Labels are defined by: <? LABEL Label_Name>

    GOTO is an unconditional goto. Typically, it is used within a IF group. This can be convenient when you have large blocks of code that should be skipped.

    In addition, it can be used to implement a primitive loop.

    Example:
                    <UL>
                    <? Set II=0 >
                    <? Label LoopTop >
                      <? IF II le 10>
                         <? Inc ii>
                         <li> This is line <? Show ii >
                         <? goto looptop >                   
                      </if>
                    <? REM End of II loop >
                    </ul>
    Notes:
    • This sort of loop is "within" a record.
    • In contrast, REPEAT .. /REPEAT is a loop across records.

    HTML Insert an HTML element, with possible substitutions. Can only be used in a REPEAT block.
    HTML is used to insert any HTML element into the output file.
    In addition, HTML can lookup values of dataseries variables, or user-defined variables, as use them as the values of options defined within this HTML CMS-element.

    Syntax:
       <? HTML element opt1="a value" ?opt2=varname ... >
    Where:

    • element: any HTML element. For example: TABLE, A, FONT, and ul.
    • opt1: any option. For example, bgcolor (say, for use in TABLE. The a value will be written after the opt1 (enclosed in quotes).
    • ?opt2: any option, preceded by a question mark. For example, ?bgcolor. The varname can be a dataseries variable, or a user-defined variable. It's value will be used, along with opt2.
    Example:
      <? var name=datetime(edate) assign=tdate  nodisplay=1>
      <? html Hnew ?java1=tdate ?java1a=edate   java2="goodbye" >Hello!</a>
    might create
      <hnew  JAVA1="20040320"  JAVA1A="5174.140277778" JAVA2="goodbye">Hello!</a>
    
    Notes:
    • You can have as many opt1 and ?opt2 as desired.
    • HTML overlaps with several other CMS-elements (such as TR and A).

    ITER and DROP Skip this record. Can only be used in a REPEAT block.
    ITER is used to skip processing this record (for this record, do not write any more of the contents of the REPEAT block).

    DROP is used to drop the record -- skip processing and discard any of the output that may have been written for this record. Furthermore, the processed records count will not be incremented.

    Note that DROP is synonymous with ITER DROP.

    ITER and DROP are typically combined with an IF to suppress (further, or any) display of particular records (say, records older then a chosen date).

    Examples:    <? iter >
    <? drop >
    <? iter drop >
    <? if age gt 40 then {? drop} >

    IF and /IF Conditional execution: IF and /IF can ONLY be used in a REPEAT block
    Compare variable values, and then either retain or ignore content

    Long Syntax:     <? IF var1 cond var2 > .. <? /IF >,  or
        <? IF var1 cond > .. <? /IF > (for event tracking)
    Compressed Syntax:     <? IF var1 cond var2 then ... else ... >,  or
        <? IF var1 cond then ... else ... > (for event tracking)

    where:   var1 is usually a variable name. Or, it can be an if-function
    var2 is usually a value.
    cond is the condition
    then and else signify what to do if the cond is true or false

    Basically, if the condition
    (comparing var1 and var2)
    is met ...
    • Long syntax
      Retain all content between the <? IF ..> and the next <? /IF >.
    • Compressed syntax
      Retain the content between the then and the else. If there is no else, retain all content from the then to the >.
    If the condition
    is not met.
    • Long syntax:
      If you include an <? ELSE ..> immediately after a <? /IF >., then the contents within the ELSE and /ELSE will be retained. If you did not include an ELSE, just drop the stuff between the IF and the /IF.
    • Compressed syntax:
      The block of code following the ELSE will be retained. If ELSE was not specified, don't retain anything inside of this IF.

    Notes:

    • To reiterate... If you have an ELSE element after a /IF, then either the IF block will be processed (if the IF condition is true), or the ELSE block will be processed (if the condition was false).

    • The compressed syntax can be quite convenient. However, you can not include any < or > characters within a <? IF ... >.
      However, CMS will replace { and } with < and > (respectively). Thus, by using { and } you can included CMS-elements within a IF .. THEN ... ELSE .

    • Before comparing,the values of var1 and var2 are stripped of spaces, and converted to upper case.

    • If you want to display a { or a } within a THEN (or a ELSE), you can use &#123; and &#125;

    • /IF does not take any options.

    • var1 and var2 can be:
      1. A number
      2. When enclosed in " characters, a literal value.
      3. A variable in the current CMS dataseries
      4. An informational variable (described below)
      5. a user-defined variable that you set with a <? SET .. > or a <? CALL .. >. For example:
                            <? Set  local1 eq 3 >
                                ...
                            <? IF local1 eq 3> 
                                ...
                            <? /IF >
      6. If-function about the current record. This is entered using a FunctionName(opt) format;
        such as DATETIME(M) (the month the record was created).

    • Supported conditions are:
                      EQ   : equal
                      GT   : greater then
                      GE   : greater then or equal
                      LT   : less then
                      LE   : less then or equal
                      NE   : not equal
      Note: we use these FORTRAN style conditions due to the difficulties of using < and > characters inside of HTML elements!

    • Event tracking:

      If you do not specify var2, then the prior value (from the record processed before this one) of var1 is used. This allows you to process content conditional on whether a change occurs (or did not occur).
      Example:
         <? If datetime(M) NE >
      will be true, for record n, when the nth record's value of MONTH is different than MONTH value of the nth-1 record.

      Examples:   
        <? IF !ID EQ 5213.512431>
        <? If AUTHOR NE "JOE FLOE" >
        <? If DUE_DATE GT SUBMIT_DATE >
        <? IF DATETIME(W)  NE >
        <? IF DATETIME(Y,BIRTHDAY) GT 1945 >
      
        <? IF AUTHOR NE >
    The informational variables: Several "information and status" variables can be used by IF. All of them start with !.
      !SERIES  : the name of this CMS dataseries
      !ARG     : the  argument (entered by the client from the Generate output files form).
    Note: !MESSAGE is synonymous with !ARG. and several that only are used inside of REPEAT blocks !ID : the id of the current record !LOOP_S : record number of first record examined (by default, 1) !LOOP_E : record number of last record examined !CURRENT : current record number (between LOOP_S and LOOP_E) !NUMREC : total number of records (often the same as LOOP_E) !FILE_VARS : list of CMS dataseries variables that are of FILE type. !COUNT : number of records processed (and not DROPped) !COUNT_BLOCK : same as !COUNT, but just with the current repeat block
    Example:
        <? If !CURRENT eq !LOOP_E > This is the last record! </if>

    Note that these special variables can also be read in CALLed procedures.

    Example:    
      <? IF  NEED_EDIT_FLAG eq 1>
             The <? var filename=document> file needs to be edited
      <? /IF>
      <? If NEED_Edit_flag ne 1>
             Mr.<? var Editor> has completed editing
             <? var filename=document>
      <? /if >
    Example of
    embedded IF    
      <? If type eq "WILD" >
         <?IF species eq "LAND">
            <h3>Wild Land Animals</h3>
         <? /IF>
         <?IF species eq "AIR">
            <h3>Wild Birds</h3>
         <? /IF>
       <? /IF >
       <? If type ne "WILD" >
            <h3>Domesticated Animals </h3>
       <? /IF > 
    Example of
    compressed syntax  
      <? IF  NEED_EDIT_FLAG eq 1 then This needs editing else Editing not required >
      <? IF  species eq "LAND" then {? var animalname} is a land dweller 
                               else {? var animalname} is {b}not{/b} a land dweller >
      <? IF  datetime(Y,starttime) lt 2004 then {? iter drop } >
    
               
    

    INTERPRET Call a code-block as a REXX procedure, and write returned results
    Syntax:
        INTERPRET code-block
    where:
        code-block: A (possibly multiple line) REXX procedure

    The REXX code contained within the code-block will be called as a procedure. It should "return" results. These results will be written to the output file.

    Notes:

    • INTERPRET is very similar to the CALL element.
      INTERPRET works with code contained within the template, while CALL works with external files.
    • The code-block can NOT contain any < or > characters.
    • In comparison to the CALL element, the USERARG will equal ' '.
      The CALL_ID is an integer value which uniquely identifies a CALL or INTERPRET element.
      That is, each <? CALL ..> and <? INTERPRET > is assigned its own CALL_ID.

      Hence, when CALL (or INTERPRET) is used within a REPEAT block, the CALL_ID will remain the same across all records.

      Hint: you can use the CALL_ID to save variables (in the INFO. stem variable) for use in the next invocation of this same procedure.

      To read the CALL_ID, you can use the following REXX code:
          parse arg foo,kId
      where foo will always equal ''

    • A special stem variable, INFO., is available. See CALL for the details.
    • Example:
                      <? INTERPRET
                         t1=time('s')  
                         if t1>(86400/2) then do 
                              return 'Hello '||INFO.!FIRSTNAME||', it is the afternoon ' 
                         end
                         else do 
                              return 'It is the morning.'
                         end
                       >
      Notice that you can use temporary variables (t1 above). You can also set other INFO (say, INFO.!CTIME), providing the leaf (i.e.; CTIME) does not conflict with one of the CMS dataseries's variables.
    • Hint: If you want to do an INTERPRET that works with the values of a particular record, you can use:
        <? Repeat ID=ddd.ffff >
        <? INTERPRET ... )
        <? /REPEAT > 
      where ddd.ffff is the record you whose values you want to manipulate.

    INC Increment the value of a "user-defined" variable
    Syntax
       INC expression
    where expression should have the form:
       userdef_var anumber
  • userdef_var is one of the user-defined variables (defined by SET or within a CALL).
  • anumber must be a valid number. Or, leave it blank and 1 will be used.
  • Examples: <? INC II >
    <? INC JTH -1 >

    Notes:

    • To INC a user-defined variable, you must first SET it
    • if USERDEF_VAR or ANUMBER are not valid numbers, INC will do nothing.
    • you can not use INC with the "informational variables" (such as !ID, and !SERIES), or any of the CMS dataseries variables.
      See the IF keyword for a complete list of the informational variables.
    • for more complicated manipulations of user-defined variables, use CMS's CALL element.

    LABEL
    -- see the description under GOTO

    LEAVE Stop processing records. Can only be used in a REPEAT block.
    Stop processing this record, and do not process any more of the records in this dataseries.

    Typically, this is used with an IF .. /IF. For example, to suppress display of newer records.

    LEAVE can take one option: DROP. If drop is specified, output for the current record will NOT be written to the file, and the "processed records" count will not be incremented.

    Example:

        <? leave > 
        <? leave drop > 
    LINK Create a link to a record's permanent location Can only be used in a REPEAT block.

    Link is a combination of A and ARCHIVE -- it will create a "link" to a record's permanent location within an archive file.
    • By record, we mean the output created using information from this record.
    • By link, we mean an HTML statement of the form: <A href="url#locald">Link</a>
    Syntax:
        <? LINK option=value option=value ..> link-string&nbpsp;/ <? /LINK>
    The options are:
         ?TYPE = nnn|HOUR|DAY|WEEK|WEEK2|MONTH|MONTH2|YEAR|SORT 
       ?OUTPUT = output_file_pattern
          ?URL = base_url
         ?NAME = cms_var
    Except for the use of a ? prefix, the TYPE, OUTPUT, and URL options are similar to the similarly named ARCHIVE options (see the appendix for details).

    NAME is used to form locald in url#locald. We recommend that you use ?NAME=!ID (to use a special variant of the record's ID).

    Basically, LINK is meant to be used with an ARCHIVE element specified with the exact same values of TYPE, OUTPUT, and URL.
    Furthermore, the FILE (template file) referenced by this ARCHIVE should contain a <? A ?NAME=cms_var> element, where the cms_var is the same as the cms_var used in the NAME option of LINK.
    As noted above, we recommend using !ID in both places.

    Notes

    • as with A, you can include other options (that do not start with a ?) -- these will be included in the <A ..> portion of the link.
    • when using LINK and ARCHIVE, you should not use the ARCHIVE =0 option. -- LINK uses a file/url naming structure that mimics what ARCHIVE does when creating subset archives with UPDATE=1
    • The link-string can be any string -- it will be displayed by the browser.

    Example:
      <? link type=WEEK  output=f:\www\blogs\sports$A*.html 
                 url="/blogs/" name=!ID >permanent link<? /link>
    which could create statements of the form:
       <A href="/blogs/SPORTS$A_28Sep2003to4Oct2003.html#5030_53074074">permanent link</a>

    POLL and /POLL Display current poll results, or ask client to add a vote to the poll
    POLL is used to work with CMS poll variables.

    Syntax:    <? POLL option=value option=value ... >
    or..    <? POLL auto=ask option=value ... > a link <? /POLL >

    The case-insensitive options are:

    
      VAR = varname      : The Poll type CMS variable to ASK, UPDATE, or SHOW.
      ID = record_id     : The record containing this Poll. If ID is not
                           specified, then use the current record id.
                           If POLL is used outside of a REPEAT loop, then ID 
                           must be specified.
    
      AUTO=ask|show|update: CMS will automatically ...
                              ASK  = create a link, that when clicked, will
                                     bring up a questionaire for client to fill out,
                              SHOW = display current counts for this poll's choices
                              UPDATE = create a link, that when clicked,
                                       will display the current counts for this poll
      CNUMBER = a_number : The choice number. Several of the INFOoptions require that you
                           select a choice number. If you use AUTO, CNUMBER is ignored.
                      
    
      TARGET=window_name :  Used with AUTO=ask -- the link will contain a TARGET="window_name"
                            option.
                            Note: we highly recommend using TARGET with ASK=update 
    
      H3="a H3 string" :Used with AUTO=ask and AUTO=update -- a string to put in a <H3> 
                       (at the top of the questionaire).
    
      DESC="a B string" : Used with AUTO=ask and AUTO=update. A string to put in  <B> 
                       (at the top of the questionaire,underneath the H3).
    
      BGCOLOR="acolor"    : background color for document (only used with AUTO=ASK and AUTO=UPDATE)
    
      INFOoption[=uservar] : Information about this poll, or this response
                             INFOoption can be one of the following.
                            (general info)
                                CHOICES     : # of choices for this poll
                                RESPONSES : current total number of responses
                                HEADER    : the header (if one was defined)
                                FOOTER    : the footer (if one was defined)
                                COLOR     : the questionaire-table background color (if one was defined)
                            (choice specific info -- requires CNUMBER)                         
                                CT        : current number of responses (that chose this choice)
                                STORE     : the "stored" value for this choice
                                DISP      : the "displayed value" for this choice 
                            (statistics)
                                ALLSTAT   : do all the stats &  responses
                                WEIGHT    : used "stored value" when computing MEAN, SUM, and SD
                                MEAN      : mean
                                MEDIAN    : median (by choice #)
                                MAX       : max (by choice #)
                                SUM       : sum
                                SD        : standard deviation
                                CHART     : make a primitive bar chart
                                CHARTSPEC : what to output, width and height of bars, and list of colors
                        The equal sign, and the uservar, are optional. 
                        
                        If uservar is specified, the value of the option will
                        be saved to the uservar user-defined variable.
                        If uservar is not specified the value will be written to 
                        the output file.
    
                             Examples:
                                  CHOICES
                                  FOOTER=Save_footer
    
    
      FORM=survey_form  : Optional, and only used with AUTO=ASK.
                          A file containing specifications for constructing the questionaire.
                          In addition to the POLL variable, this file can specify other input fields.
                          These values will be written to the survey-output file (using the survey output 
                          format) that is specified in the poll-definition file.       
    
      #other="stuff"   : Optional, used only with AUTO=ASK  and AUTO=UPDATE.
                         Other fields to include in a link (you can specify zero, one,
                         or many "other" fields. 
                         The # is dropped, and the other="stuff" is included verbatim (including
                         the "s).
                           Example:  #onClick="window.alert('The test results'); return false; "
    
    

    Notes:

  • You can have many INFOoption options within a POLL CMS-element.
  • The INFOoption options are ignored if AUTO is specified.
  • If you specify one of the choice specific INFOoptions (such as count, stored, or displayed), you must specify the CNUMBER option.
  • The CNUMBER ranges from 1 to the total number of choices. It is not the values listed in the .POL file -- rather, it refers to the order of appearance (in the .POL file) of these values.
  • If you specify AUTO=ASK, you must follow the <? POLL .. > element with a link and a <? /poll>
  • The ALLSTATS statistical option is only used with AUTO=SHOW (don't bother specifying a =uservar with ALLSTATS).
  • The WEIGHT statistical option does not recognize a =uservar.

  • If you do not use WEIGHT, then the choice number is used when computing statistics (the first choice has a value of 1.0, the third choice a value of 3.0, etc.).
    Note that the choice number is determined by the order in which the choices are listed in the poll-definition file.
  • The CHARTSPEC uservar option should specify what to output, the maximum width and height of the bars used in the bar chart (in pixels), and a list of colors to use (all in a comma delimited list).

    For example: CHARTSPEC=1,100,10.
    or:CHARTSPEC=CR,100,10,RED,GREEN,BLUE,YELLOW.

    • The what to output should either be a 1, which means output the chart, the counts for each response, and the requested statistics.
      Or, it can be any combination of C, R, and S: the Chart, the Responses, and the Statistics (respectively).
    • If there are more choices then colors specified, the list of colors will be repeated.
    • The colors that are shipped with CMS are: Red, Green, Blue, Yellow, Magenta, Cyan, Grey, and Black.
    • If CHARTSPEC is not specified, the default is:CRS,250,20
      all items are output; chart bars have a a height of 20, and a maximum width of 250, and a default color order is used.
    • If S is not included in the what to output, then the statistics options (such as ALLSTATS) are ignored.

  • SHOW is static (it generates results that are written to your output file , but you need to re-generate the CMS output file to show current values)

    UPDATE is dynamic (no results are written to the output file, but a link can be pressed to generate the up-to-date results).

  • Special feature for DESC and H3:

    $VARNAME=avarname is replaced by the value of the avarname variable (avarname can be either a dataseries variable or a user-defined variable).

  • Details on using POLL to implmenet a survey.
  • Examples  
    <? POLL var=RANK1 AUTO=show >
    <? POLL var=RANK1 AUTO=show ID=5651.1265126  >                   
    
    <? POLL var=QUALIITY CNUMBER=3 CT=USER_CT DISP=RESP1 >  
    <? POLL var=U_JUDGE AUTO=ask target=vu1 h3="A Simple Poll" >You be the judge<? /POLL>
    
    <? POLL var=MEASURE1 ALLSTATS AUTO=show >
    <? POLL var=MEASURE1 MEDIAN=astat1 MAX=astat2 RESPONSES=astat3 >
    <? POLL var=MEASURE1 CHART=mychart chartspec=1,200,10,RED,CYAN,BLACK,GREY  >
    
    <? POLL var=MEASURE1 h3="Current results for $VARNAME=SenateRace " AUTO=update target=VIEWR >
    
    <? POLL var=RANK1 h3="Your ranking of this story: $VARNAME=$ABSTRACT " 
               AUTO=ask #onClick="window.alert('Results will be aggregated')" target=VIEWR >
    
    

    READFILE Read a file.
    READFILE is used to the contents of a file, on your server's hard drive. These contents can then be written to the output file, or saved to a user-defined variable for further processing. Syntax:
       <? READFILE varname >
    or...
       <? READFILE filename.ext >
    or...
       <? READFILE name=varname options >

    where
       varname is CMS dataseries variable, or a user-defined variable.
       filename is a relative, or fully qualified, filename

    READFILE complements the FILENAME option of the VAR CMS-element, which is used to read the contents of file or url type of CMS variables. The variables point to files (on your server's hard drive) that have been uploaded by clients; either from their own machines, or from a URL they specified.

    In contrast, READFILE can be used to read the contents of any file on your server's hard drive. Furthermore, the varname should be a string type of CMS variable.

    If no path information is specified (in varname or in filename.ext), filenames specified in READFILE are assumed to be relative to the FileDir specified for the CMS dataseries.

    The first format (<? READFILE varname > ) will look for the filename (with a name specified in varname) in the FileDir directory. If it is not there, an empty string is returned. If it is there, the contents of this file are written to the output file.

    The second format (<? READFILE filename.ext > ) will look for the filename with the name fileame.ext -- note that you must include a period!
    If no such file exists, an empty string is returned.
    If filename.ext contains no path information, look in the FileDir.

    The third format can be used to specify a different directory, and to save the contents to a variable (rather then immediately write the contents to the output file).

    The case-insensitive options are:

    name=vfame This is either the variable containing the name of the file to read; or the relative or fully qualified filename (to specify a filename, include a period in vfname)
    save=uvarname If specified, CMS will store the contents of the file to the uvarname user-defined variable. You can then use SHOW to write these contents to the output file; perhaps after first modifying them with SET.
    dir=dirname dirname will be used as the base-directory for the filename (specified in varname). That is, dirname will be used instead of the FileDir.
    NoDisplay=1 If NoDisplay=1 is used, then nothing will be written to the output file. Otherwise, the contents will be written to the output file.
    Notes 
    • varname can specify a fully qualified file; the dirname or the FileDir are only used with non-fully qualified filenames.
    • If dirname is a relative directory, it will be treated as a subdirectory of the FileDir. If you specify a filename, it must contain a period
    • If the file does not exists, an empty string is returned (no error message is generated).
    • If the uvarname user-defined variable exists, its value will be overwritten.
    Examples  <? READFILE resume >
    <? READFILE name=oldresume save=oldstuff dir=archive\old nodisplay=1 >

    REPEAT and /REPEAT Start and end a "repeat for all records" block
    Syntax:
       <? REPEAT option >
    (/REPEAT does not take any options).

    Where option is one of the following

    AGE=ddd Use records entered within the last ddd days (ddd can be fractional, so that AGE=0.5 means "last 12 hours")

    Example: <?Repeat age=7 >

    DATERANGE=d1-d2 Use records entered between date d1 and date d2
    Format of d1 and d2 is yyyymmdd:hr:min
    where hr:min are optional (leave them out to mean anytime within this date)

    Example: <?Repeat daterange=20030925:10:00-20030926:13:30 >

    ID = an_id Just process the record with an ID equal to "an_id".

    Reminder: CMS ids all have the form dddd.ffff; where dddd refers to the day, and ffff to the fraction of a day. Example: <?Repeat ID=5017.09565973>

    Special value:
    if you use ID=NONE, then the repeat loop will run once, with all CMS variables set to ' ' (including the ID).

    This is useful when you want to use IF and GOTO but do not want to access values for an particular record.

    Example: <?Repeat ID=NONE >

    RANGE=n1-n2 Use record numbers n1 to n2 (inclusive)

    Example: <?Repeat range=100-199 >

    • Note: REPEAT blocks can not be embedded (you can not put a REPEAT .. /REPEAT inside of a larger REPEAT .. /REPEAT).
    • Hint: instead of the AGE, RANGE, and DATERANGE options, it may be easier to use
         <? IF DateTime(..) .. ><? Iter > <? /IF >
      elements (within the REPEAT block).
    REM A comment that will NOT be included in the output file
    Example:
        <? REM This section displays personal information >

    If you want to include a HTML comment in the output file, you can use:
        <!-- My comment -->
    Or, for long comments that may include HTML elements (or CMS elements):
        <? !-- > My long comment <? -- >

    SERIES Info on this series
    Syntax:
        SERIES option
    where option can be one of:
    NAME data series name
    CREATION creation date
    MODIFIED last modified
    RECORDS current number of records
    DESC description
    VARS variables in this CMS dataseries
    SORTABLE "sortable" variables in this CMS dataseries

    Example: <? SERIES NAME>

    SET Set the value of a "user-defined variable"
    This is used for saving variables that will retain their value. That is, the value will be kept until changed (it will not change when a new record is processed).

    Syntax: one of the following ...:
       <? SET expression>
    where expression should have the form:

    1. userdef_varname = a_value
      a_value should not have any embedded spaces
    2. userdef_varname="a string"
      a_value should may have any embedded spaces
    3. userdef_varname=func(args)
      args should contain a list of arguments, one of which must be previously SET variable.
      func should be one of the var-functions.

    Examples: <? SET section="Introduction" >
    <? SET page=102 >
    <? Set Cnt1 >
    <? Set where1=pos('1',numbers) >
    <? Set midwords=subword(myreport2,20,10) >

    <? var name=report nodisplay=1 assign=tmp1> <? set tmp2=wordpos("Two",tmp1,,I)> Location of the word <tt>two</tt>: <? show tmp2>

     
    Notes:
    • SET only works with user-defined variables. To work with variables from a CMS dataseries, use the VAR element.
    • See the CALL keyword for details on how these user-defined variables can be used.
    • See the SHOW keyword for details on how to write SET values to the output file.
    • See the INC keyword for details on how to increment the value of a SET variable.
    • you can NOT set the following varnames: !ID, !SERIES, and the variables defined for the CMS dataseries
    • To assign the value of a CMS variable to a user-defined variable, see the ASSIGN option in the VAR element.
    • the default value is 0. It is used if you do not specify a value.
          Example: <? set myVar >
      (MYVAR will be assigned a value of 0).

    SORT Sort the records on one of the "sortable" variables. This can NOT be used in a REPEAT bloc
    SORT is typically used right before a <? REPEAT> (though it can be used anywhere before a <? REPEAT>).

    Syntax:
        SORT name=varname order=xx
    where:

    varname : one of the "sortable" variables in the CMS dataseries
    xx either A (ascending) or D (descending). Default is A.
    • You MUST specify a name=varname (order=xx is optional).
    • For all REPEAT blocks following a SORT, the records will be displayed in the order specified by the SORT element. To reset to the default sort order, use <? Sort name=!ID >
    • If you use SORT, you can not use the AGE and DATERANGE options of REPEAT.
      You can use the RANGE option, but the range will refer to the post-sorted positions. ID can be used as is.
    • You can only sort on variables that were defined as "sortable" when the CMS dataseries was created. Number-type variables will be sorted using numeric rules. String and select-list variables will be sorted using case insensitive string rules.
    • only string, numeric, and select-list variables can be "sortable".
    • you can define up to 5 "sortable" variables per dataseries.
    • only the first 50 (or less) characters will be used when sorting on a non-numeric variable.
    • you can also choose a SORT variable when you invoke the CMS "generate output files" option. However, <? SORT ..> overrides these "invocation" options.
    Examples:   
    <? Sort name=city order=A>
          <? REPEAT >
        Hello to <? var name=customer> from <? var name=city>
     <? /repeat>
    or, a little more fancy:
      <? Sort name=city order=A>
      <? REPEAT >
            <? if city ne >Customers from <? var city ><br> <? /if>
        Hello to <? var name=customer> <br>
     <? /repeat>
     <? Sort name=!ID >

    SHOW Write the value of "user-defined" variable to the output file
    Syntax:
        SHOW userdef_var
    or
        SHOW $System_variable

    User-defined variables are created (and modified) by the SET and INC keywords. They can also be set within CALLs (as stored in the INFO. stem).

    System variables are general information. The currently available system variables are:

    $TIME fmt: current time
    $DATE fmt: current date
    For both $TIME and $DATE, if fmt is left out, the N (normal) format is used. See the appendix for a list of supported formats.

    Examples:
      <?Set Fruit="grapes">
      <? Show fruit >
      <? Show !LOOP_S >
      <? Show $DATE >
      <? SHOW $TIME S >
    Notes:
    • to display values of CMS dataseries variables, including the !ID, use VAR.
    • You can use SHOW !ARG to display the "optional argument string" (that can be set by you each time you generate the output file).
    • Within a REPEAT block, SHOW can be used to display the !LOOP_S, !LOOP_E, !CURRENT, !NUMREC, !CURRENT, and !CURRENT_BLOCK special variables.

    SHRINK and /SHRINK Remove extraneous spaces, tabs, and line feeds between a SHRINK and a /SHRINK. Can only be used in a REPEAT block.
    Syntax:
    <? SHRINK >
       lines of code
       including CMS elements 
    <? /SHRINK >
    
    CMS will take all of the output, between a SHRINK and a /SHRINK, convert tabs and CRLFs to spaces, and then remove all extraneous spaces (multiple spaces will be converted to single spaces).

    This can be useful when you have a large block of CMS elements, such as a complicated set of CASE statements. CMS will output all the CRLFs, even though nothing on the lines containing the CRLFs (say, CASE statements that are not true) is used.

    You can use SHRINK ... /SHRINK to get rid of this (possibly annoying) extraneous white space.

    TEMPLATE Info on the template file
    Syntax:
        TEMPLATE option
    where option can be one of:
    NAME name of template file
    FULLNAME fully qualified name of template file
    DESC description
    Example: <? Template desc>

    TR, TH, and TD Typically used in a REPEAT block.
    TR -- a <TR ...> element (used in tables)
    TH -- a <TH ...> element (used in tables)
    TD -- a <TD ...> element (used in tables)
    Syntax:
        Tx options
    where Tx is one of TR,TH, or TD, and the options are either:
       ?COLORS=COLOR1,COLOR2,...

    You can specify up to 10 colors. each seperated by a comma.
    colorN should be a color code (6 hex digits, with FFFFFF being white).
    Rows of the table will alternate in color.
    For example, if you use <?TR COLORS=999999,AA0033>,
    then row1 will use color #999999,
    row2 will use color #aa0033,
    row3 will use color #999999 ,
    etc etc etc

    or..

       ?COLORS=$user_var

    user_var is one of your user-defined variables (say, as defined in by SET).
    For example...
       <? VAR name="Fave_Color" assign="ROWCLR">
       <?TR COLORS=$ROWCLR >
    ,
    would use as a row color the value stored in the FAVE_COLOR CMS-dataseries variable. This should be a valid colorname or # followed by a 6 digit hex code (note that the preceding # is not automatically added).

    Note: any options following a ?TR, ?TD, or ?TH (and before the terminating >) that does not begin with ? are included in all TR elements (or TD or TH elements).

    Thus,
        <? TR ?colors=AAAAAA,929192 align="left">
    means

  • a table, with one row (<TR ...> element) per record, will be created;
  • each row will contain a bgcolor="#rrggbb", with rrggbb alternating (between AAAAAA and 929192)
  • each row will contain an align="left"
  • VAR Extract value of a variable from CMS dataseries. Typically used in a REPEAT block
    Syntax:
       <? Var name=VARNAME opt1=optval .. >
    or
       <? Var filename=VARNAME opt1=optval .. >
    or
       <? Var filename_local=VARNAME opt1=optval .. >>

    where the following options can be used:

    NAME=varname Extract the value of the varname variable (from the CMS dataseries).
    Or, extract some meta-data about the record (see below).
    FILENAME=varname
    and
    FILENAME_LOCAL=varname
    If the type of the varname variable is uploaded file (or a uploaded web resource), then:
  • FILENAME will return the original name (without path info) of the uploaded file.
  • FILENAME_LOCAL will return the local filename (on the server's hard drive) that contains the contents of this upload
  • Thus, if varname is a uploaded file type.
    NAME=VARNAME
    returns the actual contents of the file (that was uploaded when the record was created).
    FILENAME=VARNAME returns the original filename (as submitted by the user), without path information.
    FILENAME_LOCAL=VARNAME returns the local filename (on the server's hard drive), without path information.
    However, if varname is not a uploaded file type
    NAME=VARNAME, FILENAME=VARNAME, and FILENAME_LOCAL=VARNAME return the same thing

    Notes:

    • you can NOT use NAME=VARNAME and either FILENAME_LOCAL=varname or FILENAME=varname in the same element.
    • You can also use READFILE to read the contents of a file.
    ASSIGN=user_defined_variable Assign the value of the variable, after any var-function modifications, to a user defined variable (just like a user defined variable created with the SET keyword).
    NODISPLAY=1 If NODISPLAY=1 is used, then nothing will be written to the output file. This is meant to be used with ASSIGN (so that you can assign a value, without writing anything).
    ID=record_id Extract the value of VARNAME from the record with an id of record_id.

    Note that CMS record_ids all have the format: dddd.tttttttt,
    (where dddd is a date, and tttttttt is a fraction of a day).


    Examples:
            <? VAR UserName >
            <? Var name=DOCUMENT_1   >
            <? Var filename=document_1 >
            <? Var name=subject_a assign=subject_ab >
            <? Var name=subword(subject_a,1,3) assign=subject_3words >
            <? var name=$Abstract id=5014.87653513 >  

    Notes

    • if you use <? VAR outside of a REPEAT block, you must specify a valid ID (otherwise, a <!-- error ... --> will be inserted into your output file).
    • You can use the following simplification:
         <? Var varname >
      instead of
         <? Var name=varname >
    • to display the records id, use <? VAR NAME=!ID >
    • to display the abstract (if it was enabled), use <? VAR $ABSTRACT>
    • to display values of user-defined variables (such as variables created by SET), use the SHOW element. You can also use SHOW to display the !CURRENT, !COUNT, and !COUNT_BLOCK counters.

    • To extract meta-data about the record, use a syntax of:
         Meta_data(option)

      The currently supported meta-data items are:

        TIME(tfmt)  -- time of record creation
        DATE(dfmt)  -- date of record creation
        STATUS(StatusVar[,dfmt,tfmt]) -- # of comments, last comment added time, modification time.
               StatusVar can be CMT_CNT, CMT_MOD, or MOD.
               Dfmt, and Tfmt (which are optional) are time and date display formats
               (see the appendix for a description of the time and date 
                display formats).
      Examples:
         <?Var time() > 
         <?VAR name=date(u) id=5012.89388889 >
         <?VAR status(CMT_CNT) >  <? VAR status(CMT_MOD,N,C) >

    • To extract substrings and other information, from the value of CMS variable, use a syntax of:
         AFunction(option1,option2,...)

      The currently supported var-functions are:

        (varname)             -- returns the value of varname. This is used in SET:
                                 i.e.; ?SET myvar_copy=(my_var)
        DATETIME(fmt,varname) -- day, year, or other format of the datetime value.
                                 Varname should be !ID, or one of the CMS datetime type of variables
                                 For the details, see the description  of DATETIME in the If-functions appendix.
        HTML_REMOVE(varname)  -- encode special HTML characters  (i.e.; < betcomes &lt)
        HTML_REMOVE(varname,DROP) -- remove HTML elements (stuff between < and >)
        HTML_MAKE(varname)    -- convert text into HTML friendly text. This entails
                                 adding <P> (to replace blank lines), adding
                                 <A href=".." > elements whenever a URL
                                 is detected (a word with more then one period), and
                                 adding &nbsp; characters when tabs (or leading spaces)
                                 are found.
        INC(varname)     -- increment a variable. If varname is not-numeric, return ''
                             Note: for more complicated math, you can use the
                             MATH CMS procedure.
        LENGTH(varname)  -- length (in characters) of varname
        LINES(varname)   -- # of lines in this varname (crlf delimited)
      
        POS(substring,varname,[iat],[i])  -- position of substring within varname. 
                                             Optional offset of iat (default of 1).
                                             If I specified, case insensitive search.
                                             If no match, returns 0.
      
        SUBSTR(varname,iat,ilen)  --  substring, starting at character #iat, with ilen characters,  
                                      extracted from  varname. 
        SUBWORD(varname,iat,ilen) -- substring, starting at word # iat, with ilen words,  
                                     extracted from  varname. Note that prior to extraction, all
                                     CRLFs and TABS are converted to spaces (so the returned result
                                     will NOT have CRLFs or TABS).
        SUBLINE(varname,iat,ilen) -- substring, starting at line # iat, with ilen lines.
                                     CRLFs and TABS are not removed!
      
        WORDS(varname)  -- length (in words) of varname (space, CRLF, and TAB are word delimiters)
      
        WORDPOS(aword,varname,[iat],[i])  -- word position of aword within varname. 
                                             Optional offset of iat words (default of 1).
                                             If I specified, case insensitive search.
                                             If no match, returns 0.
                                             Space, CRLF, and TAB are word delimiters.
      Notes:
      • these functions are identical to several of the If-functions
      • these functions can also be used by the SET element
      • Sorry, but substring must not contain spaces, commas, or = signs.
      • the filename= option is not supported for these functions (you can not apply these functions to the filename of a "FILE" type variable).
      Examples:
         <?Var length(report) > 
         <?Var wordpos("dog",pets,,I) > 

    IV. Appendices

    1. Meta-data functions

    1a. The DATE function

    DATE, when used with a VAR element, displays a record's entry date. The FMT specifies how the date will be displayed.

    Note that these formats are also used in <? SHOW $DATE fmt>.

    The FMTs basically follow the syntax of the REXX DATE function (with the addition of the 'WN', 'WB', 'WB2', 'Y', and 'J' options). Note: the default is N

    Option   Desc           Example
    ====     =====          =======
    B     basedate:         729627
    D     day (of year):    240
    E     European:         27/08/98
    J     basedate 1/1/80:  3160 
    L     local-version:    27 August 1998  (this may vary across nations)
    M     month:            August
    N     Normal:           27 Aug 1998     (this is the default)
    O     Ordered:          98/08/27
    S     Sorted:           19980827
    U     USA:              08/27/98
    W     Day of Week:      Saturday
    WN    Week number:      451             (week, since  Sunday, 1/6/90)
    WB    Week bounds:      23 Aug 1998 to 29 Aug 1998 (Sunday to Saturday of this day's week)
    WB2   Week bounds, US:  08/23/98-08/29/98          (Sunday to Saturday of this day's week)
    Y     Year              1998
    
    
    Examples:
       <? var date(B) >
       <? VAR DATE() >
       <? var date(WB2>
       <? Show date M> 

    1b. The TIME function

    TIME, when used with a VAR element, displays a record's entry date.

    The FMT specifies how the date will be displayed.
    Note that these formats are also used in <? SHOW $TIME fmt>.

    Basically, they follow the syntax of the REXX TIME function (with the addition of the 'F' option). Note: the default is N.

    Option   Desc       Example
    ====    =====       =======
    
    L     long        16:54:22.120000   
    H     hour        16
    M     minutes     1014          (54 + 60*16)
    S     second      60862         (22 + 60*(54+60*16) 
    N     normal      16:54:22      (the default)
    C     civil       4:54pm
    F     fraction    0.70442130    (*86400=seconds)
    
    Examples:
      <? Var time(c) >
      <? Show time  L>

    1c. The STATUS function

    STATUS, when used in a VAR element, extracts status information on the current record. Three status variables are currently supporte:

    1. CMT_CNT : The number of comments associated with this record
    2. CMT_MOD : Time the most recent comment was added
    3. MOD: Time the record was last modified.

    The DFMT and TFMT formats are used with CMT_MOD and MOD. They control how the date and time will be displayed (seperated by a space).
    DFMT and TFMT take the format codes listed above. The default is N (for both date and time).

    In addition, a "0" format is supported -- it means don't display" (either the date or the time).

    Examples:

      <? var status(cmt_cnt) >
      <? var status(MOD) >
      <? var status(CMT_MOD,D,S) >
      <? var status(MOD,N,0) >

    2. Description of the !SPECIAL information variables

    Several "information and status" variables can be used by IF (and other keywords). All of them start with !

    !SERIES : the name of this CMS dataseries
    !ARG    : the argument (entered by the client from the Generate output files form).

    and several that only are used inside of REPEAT blocks

    !ID      : the id of the current record
    
    !LOOP_S  : record number of first record examined (by default, 1)
    !LOOP_E  : record number of last record examined  
    !CURRENT : current record number (between LOOP_S and LOOP_E)
               Example: <? If !CURRENT eq !LOOP_E > This is the last record! </if>
    
    !DEFFILE: Name (no path) of the ".DEF" file used to define the current dataseries.
              This is useable by CALLable procedures.
    
    !NUMREC  : total number of records (often the same as LOOP_E)
    
    !FILE_VARS : list of CMS dataseries variables that are of FILE type.
    
    !COUNT  : number of records processed (including current record).
    
             If a DROP option is used with ITER or LEAVE, then the record is NOT considered
             to be processed. Otherwise, the record is considered to be processed, even if nothing 
             was actually written to the output file.          
    
             Example:
                    <!-- display only  females -->
                    <? REPEAT >
                       <? If SEX="MALE" >
                            <? Comment If here, MALE entry. So skip it >
                            <? ITER DROP >
                       <? /IF >
                       <? SHOW !COUNT >: Hello <? Var name >
                    <? /REPEAT>
    
                This will produce a consecutively numbered list of FEMALE records, with 
                interleaved MALE records ignored.
    
             Notes:
    
                * the count is maintained across the entire output file. That is, it
                  is not reset when a second, third, or later REPEAT block is processed.
                    
    
    !COUNT_BLOCK  This is the same as !COUNT, but only for records written within this
                  REPEAT block (it is reset to 0 for each REPEAT block).
    
    Example:
         <? repeat > 
         <? REM update or create comments, based on argument string > 
         <? if !arg="UPDATE"> 
             <? Comment ?output=f:\www\blogs\comments\T1$CMT_*.HTML
                  ?url=/blogs/comments/
                  ?quiet=1
                  ?mode=update   > 
         <? /if>
         <? if !arg="CREATE"> 
            <? Comment ?output=f:\www\blogs\comments\T1$CMT_*.HTML
                  ?url=/blogs/comments/
                  ?quiet=1
                  ?mode=create   > 
         <? /if> 
         <? /repeat >  

    Note that these special variables can also be used in CALLed procedures.


    3. If-functions

    These "if-functions" can only be used in the terms of IF statements. They extract summary information about the currently active CMS record.
    Examples
        <? If COUNT(10) ne >
    will be true when the !COUNT counter is 1, 11, 21, ...

       <? If DATETIME(W) ne >
    will be true when the entry-week of a record changes (compared to the previously processed record).

    :::: List of If-functions:

    COUNT(nth,[B]) -- the "nth" group of the !COUNT or !COUNT_BLOCK counters.
    
       nth is an integer number greater than 0.
       B is optional. If present, then work with the !COUNT_BLOCK counter.
       Otherwise, work with the !COUNT counter.
    
       The COUNT "meta-data" function will return what "group of n" the counter's value
       lies within.
    
       For example, 
            for the !COUNT value ..... COUNT(3) yields
                  1                         1
                  2                         1
                  3                         1
                  4                         2
                  5                         2
                  6                         2
                  7                         3
                 etc.
     
    DATETIME(opt)  -- information about the date and time of entry
    
      or
    DATETIME(opt,varname)  -- information about the varname variable (varname should
                              be a "datetime" type of CMS-variable)
      or
    DATETIME(opt,"")     -- information about the current date and time
    
      or
    DATETIME(opt,"date time")  -- information about the current "normal"
                                  date and time. 
                                  "Date time" format should either be:
                                      Normal; eg. "03 Jun 2004 16:31:03" 
                                   or
                                      CMS-datetime; eg. 5020.4389
    
      Opt can be:            (examples)
            N   = normal     (30 Sep 2003 10:32).  This is the default.
            N   = normal long (30 September 2003 10:32)
    
            Y   = year       (2003)
    
            MO  = month      (200309)
           MO_Y = month within year  (9)
           MO_80 = month since 1 Jan 1980 (285)
    
            W    = week       (717 -- week since Sunday, 5 jan 1980)
            W_Y  = week within year (39)
            W_80 = same as W   (717)
            W_IS = the date of the sunday of this week (28 Sep 2003)
                   
            D   = day        (20030930)
           D_Y  = day within year  (273)
           D_M  = day within month  (30)
           D_80 = day since 1 Jan 1980 (8672)
    
            H  =  hour       (20030930:10)
           H_D =  hour within day (10)
    
            MI =  minute     (20030930:0623)
           MI_D = minute within day (623)
           MI_H = minute within hour (32)
    
            S  =  second     (20030930:37388)
           S_D = second within day (37388)
           S_M = second within minute (32)
    
           CMS  = cms-format datestamp (5020.43890046)
    
       Notes:
          * in the H, M, and S outputs, the stuff after the ":" will be left-padded with 
            zeros if necessary.
          * if opt is not specified, N is used
          * use the *_80 functions if you want to compare (or do math) on
            dates
          * M, M_Y, and M_80 are synonymous with MO, MO_Y, and MO_80 (respectively)
          
    FILE_EXISTS(varname)
      
       If varname is of File type, check to see if a file was actually
       uploaded, and still exists.
       If so, return the fully qualified filename.
       If not, return a ""
    
       If varname is not of  File type, return a "".
    
       Thus, to check if there is a file available (say, for use in a 
       ?A URL_FILE=varname), use FILE_EXISTS in an ?IF, and check for ne "" .
    
    LENGTH(varname)
       The length, in bytes, of the varname.
       If varname is of File type, the length of the uploaded file
       (or downloaded URL).
    
    LINE(varname)
       The length, in lines, of the varname.
       If varname is of File type, the length of the uploaded file
       (or downloaded URL).
       Note that files are delimited by CRLF ('0d0a'x).
    
    
    POS(substring,varname,[istart],[I])
      Position of substring inside of a string. Similar to the REXX POS function.
     
         varname is a cms variable. It's value will be searched.
         substring can be within " " characters.
            Note: Sorry, but substring must NOT contain spaces, commas or, = signs.
    
         istart is optional -- if specified, start the search at the istart'th
         character (of varname's value).
         I is optional. If specified, case insensitive search.
         
         If no match occurs, a 0 is returned.
           
         Examples:
            if the PRODUCT variable has a value of "Summer squirt Gun"
         Then
             pos("squirt",product)  -- returns 8
             pos("quirt",product)   -- returns 9
             pos("SQUIRT",product)  -- returns 0
             pos("gun",product)     -- returns 0
             pos("gun",product,,I)  -- returns 15
             pos("s",product,3,I)   -- returns 8
      
    
    STATUS(opt[,dfmt,tfmt])
       STATUS, as with its use in a VAR element, extracts status information 
       on the current record.
    
       Three options are currently supported:
    
         i)  CMT_CNT : The number of comments associated with this record
        ii)  CMT_MOD : Time the most recent comment was added
        iii) MOD     : Time the record was last modified.
    
        Note that CMT_MOD and MOD both can take a "date format" and a "time format"
        (dfmt and tfmt respectively).
    
    SUBSTR(varname,[istart],[ilen])
      Extracts ilen characters from varname, starting at character istart. 
     
    
       Examples:                                  123456789a123456789a1
          if the  PRODUCT variable has a value of "ABC  = 5567  : candle"
       Then (without the "s).
         substr(product,1,3)  -- returns "ABC"
         substr(product,10)   -- returns "67  : candle"  
         substr(product,8,2)  -- returns "55"
    
    SUBWORD(varname,[istart],[ilen])
       Extracts ilen words from varname, starting at word istart. 
    
    • Before extraction, all CRLFs and TABs are converted to spaces (so that tabs and CRLFs become valid word delimiters). Hence, the returned result will NOT have CRLFs or TABs.
    • varname is a cms variable name. It's value is used as the string (from which a substring will be extracted).
    • istart is the starting position (first word is 1). The default value is 1.
    • ilen is the length of the substring. If not specified, all remaining words (after istart) will be extracted.
    • Similar to the REXX SUBWORD function.
    
    SUBLINE(varname,[istart],[ilen])
      Extracts ilen lines from varname, starting at line istart. 
    
    • The extracted string will have CRLFs and TABS.
    • varname is a cms variable name. It's value is used as the string (from which a substring will be extracted).
    • istart is the starting position (first word is 1). The default value is 1.
    • ilen is the length of the substring. If not specified, all remaining words (after istart) will be extracted.
    WORDPOS(subword,varname,[istart],[I]) Position of subword, inside a string containing multiple words. Similar to pos, except a "word" search is done. SImilar to the REXX WORDPOS function. See POS for the description of istart and I. Note: Sorry, but subword must NOT contain spaces, commas, or = signs. The word position (not character position) is returned. As with POS, 0 is returned if there is no word match. Examples if the PRODUCT variable has a value of "Summer squirt Gun squirt" Then pos("squirt",product) -- returns 2 pos("quirt",product) -- returns 0 pos("SQUIRT",product) -- returns 0 pos("SQUIRT",product,3,I) -- returns 4 pos("gun",product) -- returns 0 pos("gun",product,,I) -- returns 3 pos("s",product,,I) -- returns 0

    4. Controlling access to CMS dataseries

    When you define a CMS dataseries, you can specify a list of "owners". If you leave this empty, then anyone can access, modify, and otherwise work with this CMS dataseries (assuming that there are no SREhttp/2 access controls on the CMS addon).

    The OWNERS field is used to limit access to one, or several, users. To do this, enter a space delimited list of "usernames", where "usernames" are defined by the SREhttp/2 username/password/privilege utilties.

    Or, enter * to allow access to any client with a valid username for this site.

    If you define such a list, then before any CMS action is done to this dataseries (such as generating an output file), CMS will check that the client has a valid username (has been granted a username and password for this site).

    If this username does not exist, the user will be sent an authorization request. He can keep trying until he gets it right (in other words, there is only minimal security).

    In addition to the OWNERS list, CMS supports a OWNERS_COMMENT list. The OWNERS_COMMENT list works just like OWNERS, but is used only when comments are being added to a CMS record. The notion is that you may want control who can add and manipulate records in your database, but you will let anyone add comments to these records. Using OWNERS (say, with a list of usernames), and a less stringeng OWNERS_COMMENT (say, leave it blank or use *), you can do this.

    Technical notes:

    1. A 30 minute duration cookie is granted to the client after he enters a valid username (and password). This is specific to the CMS dataseries.
    2. You can also use SREhttp/2 client privileges to grant access to CMS dataseries. To do this, assign a client privileges of the form CMS:seriesname.
      This client privilege can either be assigned by username/password, or by using the INHOUSEIPS. facility of SREhttp/2.
      For example, to grant access to the EXAMPLE10 dataseries, specify a privilege of CMS:EXAMPLE10
    3. When defining a new dataseries, only users with either a SUPERUSER or a CMS_DEF privilege are granted access.

    5. Using the ARCHIVE element

    The ARCHIVE element makes it easy to create archive documents of the records in your dataseries. Typically, these documents will contain a subset of the records. For example, you can use ARCHIVE to create a seperate document for each month of entries (that is, all and only the entries from Dec 2003 will be in a unique document).

    ARCHIVE makes this easy -- just specify a general rule to use in determining how to create these subsets, and CMS will do the rest -- including creating a list of links to these documents!

    There are basically two kinds of archive documents:

    1. Subsets. These will contain several records that share a feature. Typically, this feature is a time of entry -- such as "all records entered in the month of August 2003". To specify subsets, <? ARCHIVE ...> must not be inside of a REPEAT block.
    2. Singletons. These will contain just one record. To specify singletons, use <? ARCHIVE ...> inside of a REPEAT block.
    The ARCHIVE element has the following syntax:
    For subset archives: <? Archive option=value option=value ..>
    For singleton archives: <? Archive option=value option=value ..> link-string <? /ARCHIVE>

    The options are:
          FILE = template_file  
          TYPE = nnn|HOUR|DAY|WEEK|WEEK2|MONTH|MONTH2|YEAR|SORT 
          LIST = ul|ol|table|ulA|olA|tableA
        OUTPUT = output_file_pattern
        UPDATE = 0|1|AUTO 
           URL = base_url
       MESSAGE = "a message" 
        #FIELD = "field contents"
    Note that FIELD in #FIELD can be any field name.

    Details on options.

    FILE=template_file
       The template_file should be a file containing CMS elements.
       It will be used to determine how to display the subset
       of records.
    
       Template_file, if not fully specified, is relative to the current
       template file. 
    
       Note that the template file can contain a SORT element --
       which will cause a sorting of the subset of records
       within a given archive document (say, a descending sort of the 
       records in a week).
    
    TYPE=one of the various types: nnn|HOUR|DAY|WEEK|WEEK2|MONTH|MONTH2|YEAR|SORT 
    
    
        TYPE is used to specify how to divide all the records in the dataseries
        into "subsets".
            == If you are creating a singleton (by specifying ARCHIVE
            == inside of a REPEAT block), TYPE is ignored.
    
    
       nnn, where nnn is a number > 0
            Create subsets, with each one containing nnn records.
            Before dividing into subsets, CMS will sort the records 
            in order of entry (by entry time).
            The first subset starts with the earliest entry. Thus,
            the last subset will frequently contain less than nnn records.
    
       hour
            Include records entered in the same hour (where hours change
            across days).  Note that this does NOT mean the creation of
            one document per hour (with lots of documents having no records).
    
       day and day2
            Include records entered in the same day
            day2 leads to a more compact list of entries then day.
    
       week  and week2
            Include records entered in the same week (Sunday to Saturday).
            week2 leads to a more compact list of entries then week.
    
       month and month2
            Include records entered in the same calendar month (Jan, Feb,...).
            month2 leads to a more compact list of entries then month.
    
       year
            Include records entered in the same calendar year (2003, 2004, ...).
    
       sort
            The SORT type means "by value of current sort variable"
            If no sort variable currently selected, use of SORT yields an error/
                 
            You can specify the SORT variable either when you invoke CMS,
            or by including a <? SORT ..> element before the <? ARCHIVE ..>
            element.  Note that a <? SORT element > overrides the SORT
            variable chosen at invocation.
    
    
      For all of the types, NO observations are de-selected (all records in the
      dataseries will be available in one, and only one, of the archive documents).
    
      Of course, if the template has additional logic in it (such as IF statements),
      it is possible that a record "available" to an archive document will 
      not be displayed.
    
    
    list 
       List specifies how to create the links to the archive files.
       UL and OL are HTML bulleted lists.
    
            == If you are creating a singleton (by specifying ARCHIVE
            == inside of a REPEAT block), LIST is ignored.
    
       TABLE is an HTML table
       ULA, OLA, and TABLEA are the same as above, except entries 
       are displayed in "ascending" order (the top most bullet or row
       will point to the archive document with the oldest records).
    
    
    OUTPUT
       Output is used to specify the names of files used for
       the several archive documents.
       The output_file_pattern must either:
         i) contain a * (the * will be replaced by a number). 
        ii) be $varname, where varname is an existing CMS dataseries, or user-defined
            variable. THIS CAN ONLY BE USED WITH SINGLETON ARCHIVES.
       iii) Not be specified.  
    
       If not specified, a suitable modification of the current
       output file will be used. If specified, and relative, a file
       relative to the default output directory will be created (or to the
       CMS\FILES directory, if no default output directory is defined for this
       dataseries).
    
       For example:
        if 
           * the output directory is F:\WWW\BLOG
           * you specify OUTPUT="*.SHT" 
        then
            F:\WWW\BLOG\_4Nov2003.SHT could be a name of a  "daily" archive file.
    
      Or, if there is NAME CMS variable with a value of Joe_Bloe
      
         <? call concat useme="f:\www\archives\" $+ name $+".SHT"  >
    
        <? archive file=single.tpl   url="/ARCHIVES/" output=$useme> <? var name><? /archive>
     
      then 
         F:\WWW\ARCHIVES\JOE_BLOE.SHT would be the name used for a "singleton"
         archive.
       
    
    UPDATE
    
        If UPDATE=AUTO, or if UPDATE is not specified, then UPDATE is set by whether
        the the client checked the
                Only update (the latest archives & possibly comments) 
        checkbox (when he generates the output file).
    
        Thus: 
            If UPDATE=1, then UPDATE=1
            If UPDATE=0, then UPDATE=0
            If UPDATE=AUTO or if UPDATE is not specified, then 
                    UPDATE=1 if the box is checked
                    otherwise UPDATE=0
           
        The effect of UPDATE depends on whether you are creating subsets or singletons.
    
        Subsets:
           If UPDATE=1, or if UPDATE is not specified, then update files
           that have changed, and update the most-recent archive (i.e.; the
           archive for this month).
    
             Note: the "most recent" archive will always be re-written, even
                   if nothing has changed.
    
           If UDPATE=0, then create all archives (if necessary, 
           overwriting any pre-existing files).
      
         Singletons:
    
            If UPDATE=1, or is not specified then only create singleton archives 
            if no singleton archive file exists for this record, or if the record 
            has changed since its singleton archive was created.
    
            If UPDATE=0, write singleton archive files for all records (overwriting
            pre-existing records if necessary).
    
    
    URL
        A "base_url" that will be used in the list of links to the archive documents.
        Each of the filenames (of the files created using the OUTPUT option) will be
        appended to this "base url". Obviously, the result (base_url + filename)
        should be a valid url to the document
    
        The base_url can either be a string (without quotes), or can be a variable name (either user defined or
        dataseries). To specify a variable name, use a $ before the base_url.
    
       Examples:
             url=/people/results
             url=$my_dir
     
        Thus, you should use a OUTPUT option that writes the archive documents 
        to a subdirectory that is web-accessible (using the base_url),
        or you should be sure not to forget to move them to this web-accessible  
        directory (after CMS finishes running).
    
    
    MESSAGE
        A text sentence that can be accessed (within the archive template file)
        by using <? SHOW !ARG > or <? SHOW !MESSAGE >
    
        Note: you can use  <? TEMPLATE DESC >, or <? SHOW !DESC > to display a short description of
              the "subset" of the recores. For example, "November 2003".
    
        Note: you can use r <? SHOW !ARCHIVE_TITLE > to both the "message" and the "description"
        For example, "The blog monthly archives: November 2003".
    
    
    #FIELD
    
      FIELD can be any field name. 
      After removing the leading # character, it will be included as is in the 
      <A ... > links created by ARCHIVE.  
       
       For example:      #Target="ae_window"       
       
       Note:
            In the LINK, COMMENT, and A elements, options that start with a ? are 
            processed by CMS, while all other options are used as is.
            In contrast, in ARCHIVE options that start with a # are used as is,
            while other options are either processed by CMS, or ignored. 
    
            And yes, the fact that ARCHIVE is different then these other elements 
            really can not be called a residue of  good design. 
            But at this point it's hard to rectify.              
    
    
    Example (subset):
      <? archive file=arc1.tpl type=DAY message="A daily archive" list=UL
         url="/BLOGS/"  output=f:\www\blogs\*.sht  update=1  #target="windowA" >
    Could yield the following list written to your output file:
      <UL>
        <li><a href="BLOGS/_4Nov2003.SHT" target="windowA"  > 4 Nov 2003</a>
        <li><a href="BLOGS/_6Nov2003.SHT" target="windowA"  > 6 Nov 2003</a>
      </ul>
    where each of these files (i.e.; _4Nov2003.SHT) will be in the F:\WWW\BLOGS directory.

    Hint:     If arc1.tpl (which will be in the same directory as the template file containing this <? ARCHIVE ...> element) contains:
       This is <? show !arg> [ <? template desc > ]
    then the archive documents will contain lines like...
       This is A daily archive [6 Nov 2003 ]
    (the 6 Nov 2003 will vary across the different documents).

    Example (singleton):
      <? archive file=arc1.tpl  message="A weekly archive" url="/BLOGS/RECS/" 
                 output=f:\www\blogs\recs\rec1$*.html  update=1 >Just this record<? /archive>
    This will yield a seperate file for EVERY record. If you have a lot or records, this might take a while to process. Note that by using update=1 (the default), CMS will not attempt to overwrite files that have been already created for this record -- which can save processing time.

    Note:    When creating singleton archives... you must follow the <? ARCHIVE ..> with a link string and a <? /ARCHIVE>
    (the link string is what the browser displays, and <? /ARCHIVE> is replaced by </A>).


    6. Using the COMMENT element

    The COMMENT element makes it easy to create and view "comment documents". Each comment document will contain the comments associated with a single record.

    COMMENT is similar to ARCHIVE -- you specify a general rule to use in determining how to create these comment documents, and CMS will do the rest -- including creating links to these documents!

    Note that as of this implementation, COMMENT can only be used inside of a REPEAT block.

    Syntax:
       <? COMMENT option=value option=value ..> link-string <? /COMMENT>

    The important options are:

          ?FILE=template_file
          ?OUTPUT=output_file_pattern
          ?URL=base_url
          ?MODE=UPDATE|CREATE|AUTO|SHOW|ADD
          ?RETAIN=varname
          ?RESPFILE=response_file_name
          ?QUIET=0|1  
    The link-string is any string -- it is what the browser will display. The <? /COMMENT > will be converted to a </A>. Note: if ?QUIET=1, then do NOT include the "link-string <? /COMMENT>"

    Other options, that do not start with a ?, can also be included -- these will be inserted verbatim into the <A..> elements inserted into the output file.

    OUTPUT, URL, and FILE are the same as in ARCHIVE

    1. OUTPUT should contain a *, and is used to specify what filenames to use.
    2. URL is a base URL, it is combined with the file names (without path information) to form links to the comment files.
    3. FILE specifies a template file used to create the comments-file (for a record).
    QUIET is used to suppress output -- if ?QUIET=1 is used, then your output file will not contain links.
    Hence, you should not follow
        <? COMMENT QUIET=1 ...>
    with
       link-string <? /COMMENT>

    RESPFILE is used to specify a file to use to create a response to the submission of a comment.
    • If RESPFILE is not specified, a generic response is returned.
    • The RESPFILE must be a file name relative to the CMS\LIB subdirectory, or to the file-directory of this CMS data series.
    • CMS will make a few subsitutitions into this RESPFILE.
    • For the details, see Add comment response section in the description of customizable forms.
    RETAIN is used to retain one of the variables (for this record), so that it may be used in the comment template file.
    The varname, in RETAIN=varname, must be one of the CMS variables defined for this dataseries.
    The value of this variable will be retained, so that the comment-template file can reference it.
    To do this, use (in the comment-template file):    <? SHOW $RETAIN >

    Notes:
  • You can only retain one variable.
  • Reminder: $ABSTRACT variables (assuming one was specified when the CMS dataseries was defined) can be displayed using ;<? VAR $ABSTRACT >
  • # of comments, last comment modification, and last record modification can be displayed with <? VAR STATUS(CMT_CNT) >, etc.
  • MODE takes the following values:
      UPDATE : update comment files. Thus, if a comment file (for this record) exists,
               and no new comments have been added (for this record) since this file was
               created, then do NOT (re)create the comment file (for this record).
    
                    Technical note: this works by comparing the file's datestamp with
                    the datestamps of the comments. If you modify the file (say, with
                    a text editor), the datestamp will be updated; which may inappropriately
                    indicate that the file does not need to be updated.  Thus,
                    if are likely to hand-edit comment-files, you probably should not use UPDATE.
                    
      CREATE:  always create a comment file, even if one currently exists.
      
        AUTO:  Use either UPDATE or CREATE, depending on whether the user checked the 
               Only update (the latest archives & possibly comments) checkbox.
                  If checked: UPDATE mode.
                  Otherwise: CREATE mode.
    
       NAME:   Return the name of the comment document, constructed using the file name
               and the URL. This will NOT create the comment file, it just returns the
               name that is used.
    
      SHOW:    Create a link to the comment file for the current record.
               Basically, SHOW uses NAME to create a link.
    
    
       ADD:    create a link to the "add comments" CMS input form. This lets you put
               a "would you like to add a comment" link in your output file.
    
               URL and OUTPUT are ignored.
               FILE can point to a "comments template file", and RESPFILE can point
               to a response file. Both of these are  located either in the LIB 
               subdirectory of the CMS directory, or in the FileDIR specifed for
               this series (a FileDIR version takes precedence). 
    
                   Interested in more details on working with CMS customizable forms?
                
    

    Notes:

    Examples:
      <? Repeat>
           Info on user:  <? var Username><br>
           Would you like to view the 
           <? Comment 
                  ?output=f:\www\blogs\comments\T1$CMT_*.HTML
                  ?url=/blogs/comments/
                  ?mode=show   > < ? var status(cmt_cnt) >  current comments <? /comment>
       <? /repeat> 
    In this example, note the use of the <? /COMMENT>
    1. the <? COMMENT ..> is replaced by a <A ...>. and
    2. the <? /COMMENT> is replaced by a </A>.

       <? repeat  
          <? REM update comments for this record, don't bother creating a link >
           <? Comment 
                  ?file=t1_cmt.tpl
                  ?output=f:\www\blogs\comments\T1$CMT_*.HTML
                  ?url=/blogs/comments/
                  ?quiet=1
                  ?mode=update   > 
        <? /repeat>
    In this example, since there will be no output, you should not follow the <? COMMENT ...> with a "link string" and a <? /COMMENT>.

    "Include" the comments in an archive file, (each archived record would be immediately followed by its comments)

    With these elements in the main template ..

      <? REM create weekly archive files (that will be subject to SSI's) >
      <? archive file=t10a.tpl 
               type=WEEK
               url=/blogs/
               output=f:\www\blogs\*.sht
               message="A sample " >
    
      <? REM create comment files for each record, but don't display any results >
      <? repeat> 
        <? comment  ?output=f:\www\blogs\comments\T1_CMT_*.INC
                    ?url=/blogs/comments/
                    ?FILE=t10c.tpl
                    ?mode=update
                    ?quiet=1 >
      <? /repeat>
    You can use this element in the t10a.tpl (archive) template ..
      <? Repeat>
         This record belongs to <? var name=lastname>
         <blockquote><? var name=short_story> </blockquote>
    
       <? REM Include the comment files for each record >
         <table border=1><tr><th>Comments</th>
             <tr><td><pre> <? !-- > #include virtual="<? comment
                     ?output=f:\www\blogs\comments\T1_CMT_*.INC
                     ?url=/blogs/comments/
                     ?mode=name >" <? -- > </pre> </td>
         </table>
       <? /repeat>
    Note that the output and url fields in the first and second COMMENT elements are exactly the same.
    Also note the use of the <? !-- > and <? -- > CMS elements -- this allows creation of Server Side Include elements (that SREhttp/2 will replace when one of these archive .SHT files are requested).

    Creating a form-to-submit-a-comment within a document.

    You can use the COMMENT1.CMS CMS procedure to start a FORM that will add a comment. After CALLing COMMENT1, you can put in as many HTML (and CMS) elements as you want.
    Be sure to end the form with SUBMIT and /FORM elements!

            <? CALL comment1 >
                    .... various INPUT, TEXTAREA, etc. elements referring to
                         comment variables defined for this dataseries ......
            <Input type="submit" value="submit">
            </form>
    This will display a form that, when submitted, will add a comment for this record.


    7. Example of the COMMENT element

    Let's summarize the basics of CMS comments: Some examples of COMMENT
    A useful
    trick:
    • In your main template file:
      1. Create singleton-archies (using <?ARCHIVE ... > elements, and
      2. Create comments using < ?COMMENT MODE=UPDATE ... > elements)
        Or, if you don't want to bother including a link to the comment-document (in the main output file), include a QUIET=1 option in this COMMENT CMS-element.
    • In the archive template file, create links to comments without regenerating the actual comment document. To do this, use < ?COMMENT MODE=SHOW ... > elements.
    • In this COMMENT element, be sure to use the same URL and OUTPUT fields that you use in the MODE=UPDATE element (that you include in the main template file).

    8. Creating blogs using predefined files

    To ease the creation of blogs, CMS comes with several pre-defined blog templates. These templates allow you to define your own blog -- you simply chose one of the pre-defined blog templates, specify the location of the files, and select the values of several identifying & descriptive variables. The blog will then be created & be ready for use!

    Creating your own, custom-designed, pre-defined blog template is fairly straightforward. These are specifying using xxx.DEF files. These .DEF files contain instructions on how to create the blog from a set of pre-defined template files, response files, and other such files. Of course, it is your responsibility to create these other pre-defined files.

    Both the .DEF file, and the other pre-defined files, must be stored in the LIB\PREDEF subdirectory of your CMS directory (say, in D:\SRE2003\SREHTTP2\ADDON\CMS\PREDEF.

    For details on how the specific of .DEF files, see BLOG1.DEF in this CMS\PREDEF directory.


    9. The CMS database files

    CMS uses SRE2003's built-in database engine (.SDS files). Each dataseries is contained in two of these .SDS files: one file contains the actual records, the other file contains comments pertaining to these records.

    The .SDS files are stored in the DATA subdirectory of the CMS directory. These are structured text files. They can be viewed with a text editor, but they should NOT be modified!

    In addition, CMS uses "index" files to store meta-data on the data series, such as names of variables and the location of the upload directory (to use for this data series). These index files, which are located in the INDEX subdirectory of the CMS directory, are simple text files.

    If you are careful and ambitious, you can modify these index files using a text editor.

    The following is a sample of an index file:

            ; CMS index file created 19:31:53 26 Oct 2003
            Series: t6
            File: F:\test\srehttp2\ADDON\CMS\DATA\t6
            CommentFile: F:\test\srehttp2\ADDON\CMS\DATA\t6_CMT
            Created: 19:31:53 26 Oct 2003
            Desc: Job applicants
            Owners:  me
            OwnersComment:
            VarNames: $STATUS $ABSTRACT NAME AGE EDUCATION SYNOPSIS RESUME REJECT RANK
            VarTypes:  N A 1 N S M F C P
            Pack: NAME     SYNOPSIS RESUME REJECT
            Specials: $ABSTRACT  $CMT_CNT AGE EDUCATION POLL
            Select: EDUCATION = education7;
            Poll: RANK = rank_choices ;
            FileDir: F:\test\srehttp2\ADDON\CMS\FILES
            UploadDir: F:\test\srehttp2\ADDON\CMS\UPLOADS
            Template: T6.OUT T6.TPL , THIS IS FOR T6 output file
            Template: Index.HTML I1.TPL , Use this for the main page
            Hint: Although the Abstract and Synopsis are similar,
    Hint: keep qualitative statements in the synopsis

    The file and upload directories

    The FileDir and UploadDir fields are used to define..
    1. FileDir: the default output directory. This is the root directory used by CMS to write files that it generates.
      It is also the default directory for template files.
      Thus: if you did not include path information when you specified your template (or output) files, CMS will use the FileDir.
    2. UploadDir: the default upload directory. This is the root directory used by CMS to store files that have been uploaded. Note that file upload typically occurs when a client adds a record that contains a File or URL type of CMS variable.
    You can change the FileDir and UploadDir be sure to use a valid directory! Also, be sure to move files in the prior FileDir (orUploadDir) directory to this newly specified directory.

    8. CMS subdirectories and files

    Typically, CMS is installed to a "CMS" subdirectory of the ADDON directory of your SREhttp/2 server. For example: F:\SRE2003\SREHTTP2\ADDON\CMS CMS also creates several subdirectories (under this CMS directory). These are:
    
        DATA:   the CMS dataseries files (.SDS files) are stored here
       INDEX:   the CMS "index" files (.IND files) are stored here
        LIB:    .OPT files (for Select List variables) are stored here.
                In addition, this is the default location for "CALLable" CMS procedures
       LIB\POL:  .POL files (poll-definitions) are stored here.
       UPLOADS:  The default location for uploaded files (or uploaded contents of URLS).
        FILES:   The default location for output files, archive files, and template files.
    
    Files in the LIB directory.
    The .OPT files are used with Select-List variables
     nations.opt            : List of nations
     months.opt             : 12 months of the year
     education7.opt         : Seven education levels (no HS to phd)
     states.opt             : List of 51 states (DC included)
     Income_levels.OPT      : Several income levels
     yes_no.OPT             : A YES / NO list
     sex.OPT                : A Male / Female list
    
    The .CMS files are "CALLable" CMS procedures
     example.cms          : Simple example of a CALLable CMS procedure
     comment1.cms         : Create a FORM to use to add comments to a record
     cms_cmt.htm          : An example of a "comment" template file (used with ?COMMENT ?MODE=ADD)
    
    Example files (in CMS directories):
    
       INDEX\DEFAULT_exampl_001.DEF  : the "definition" file for the EXAMPLE dataseries
       DATA\EXAMPLE.SDS  : the main database for the EXAMPLE dataseries
       DATA\EXAMPLE_CMT.SDS : the "comments" database for the EXAMPLE dataseries
       DATA\*.SDI    : index files for the above .SDS files
       FILES\*.TPL   : several template files used to generate files from the EXAMPLE dataseries
                       You can look at, and modify, these .TPL files with your favorite text editor
    

    9. CMS callable procedures

    CMS callable procedues are stored in the CMS\LIB directory, and should have a .CMS extension.
    Would you like to view the currently available CMS procedures.

    Would you like to read about the CALL CMS_element?

    CMS customizable forms are used to customize the pages shown to clients interested/allowed to enter new records and comments.
    Would you like to read more about customizable forms?


    10. SELECT and POLL CMS variables

    The SELECT, and especially the POLL, CMS variables are somewhat different then other CMS variables.
    SELECT
    SELECT variables are used to implement a selection list. Clients will be shown drop-down selection list, from which they can choose one choice.

    To implement these SELECT variables, a .OPT file must be specified. These .OPT files contain a list of the selections to be included in the drop-down list. The syntax of these files is fairly simple: Each selection list will variable typically contain a unique set of choices (for example, the nations of the world, or gender information)

    Example of an option file.
            ; DESC= income levels, roughly us quintiles
            ;Created 4 Oct 2003 08:50:33
    
            1 = < 10,000
            2 = 10,000-25,000
            3 = 25,000-50,000
            4 = 50,000-75,000
            5 = 75,000-125,000
            6 = >125,000
            $ = user entered value 
    which would create...

    Notes:
    • Lines beginning with semi-colons (;) are comments (they are ignored)
    • However, a comment line that starts with DESC= is special -- it is used by CMS to describe this .OPT file
    • Options lines have the format:
         internal_value = display_value
      The internal_value is the value retained in the CMS database, the display_value is what is displayed to the client (in the drop-down list).
    • You can list as many option as desired
    • The $ internal-value is special: if the client choose this option, a javascript popup will ask for a choice. The value entered by the client will be saved to the CMS dataseries. This allows you to easily provide a set of pre-coded suggestions, with a clean way for the client to enter their own other value
    • .OPT files are stored in the CMS\LIB sub-directory.

    POLL
    POLL variables are used to implement a poll.

    POLL variables are qualitiatively different from other CMS-database variables:

  • Other CMS-database variables are typically entered when a record is created. After entry, their value infrequently changes. Perhaps one might update the contents of record (say, add an latest news sentence to the bottom of a report), but that happens infrequently
  • POLL variables are designed to be dynamic -- they are designed to be modified numerous times. That is, they are designed to keep a running count of the number of times a choice has been made
  • In particular, each POLL variable contains an overall count (the number of times the poll has been answered), and a running count for each choice (the number of times each choice was taken). The sum of these choice-counts will add up to the overall count.

    To implement these POL variables, a .POL file must be specified. These .POL files contain a list of the choices to be chosen from, as well as instructions on how to construce the the questionaire (within which the choices are embedded).

    For example ...
  • The POLL keyword, and the
  • The CMS add-record option
  • use the information in a .POL file to construct a questionaire.
    Example of a poll file.
      ; this is an example of a poll definition file
      ; DESC = Vote on how interesting.
    
      ?: How would you rate this article?
    
      1: Uninteresting
      2: Mildly interesting
      3: Interesting
      4: Uninteresting
    
      Footer: <tt>(your answer is anonymous)</tt>
      Footer: <p><em>Thanks for your input</em>
    
      SOutput: SvyOut.1 
      SFormat: _ID : _POLL   _DATETIME REGION
    
      color: yellow 
    which would create...

     
    How would you rate this article?
    • Uninteresting
    • Mildly interesting
    • Interesting
    • Very interesting
    (your answer is anonymous)

    Thanks for your input


    Notes:
    • As with .OPT files, semi-colons signify comment lines; and comment lines that start with a DESC= are used by CMS for descriptive purposes.
    • ?: line(s) are used to form the question to be answered.
    • Lines that start with a number (followed by a colon) are the values. The numeric value is stored, while what follows the colon is displayed
    • Footer: and Header: lines are used to create footers (that are placed after and before the questionaire).
    • color: is used to specify a background color (for the box containing the questionaire). The value should be a browser recognized color code, or a #rrggbb color code.
    • You can use the POLL keyword to work with poll variables.
    • .POL files are stored in the CMS\LIB\POL sub-directory, and in the POLL subdirectory of the series-specific output directory (the FileDir).
    • To ease readability, you can have several ?:, Header:, and Footer: lines -- the contents of each of these lines will be concatenated (as shown, for Footer, in the above example).

    11. Using POLL to implement a survey

    The basic use of POLL variables is to store a running count of the number of responses given to each of several choices to a poll. A poll is specific to a single variable in a single record.
    In a sense, POLL allows a quick means of recording comments about an article (albeit in an aggregated format).

    To extend the capabilities of POLL, you can use several SURVEY options. Basically, these allow you to save the responses to the poll, along with a number of other varibles, to a specified survey-output file. As of this writing, CMS will not attempt to analyze this output file. However, you can structure the output file (which will be written as a simple text file) so it can be read by spreadsheet or statistical packages.

    The relevant options are SOutput and SFormat (specified in the poll-definition file), and Form (an option of <? POLL AUTO=ASK ... > CMS-elements).

    SOutput
    SOutput specifies an output file to contain the survey results.

    This file will always be written to the POLLS subdirectory of the series-specific output directory.

    If you do not specify SOutput, CMS will not attempt to save responses (where would it put them?).
    Note that all data for a single response is written to a single line of the SOutput file.
    Example:   SOutput: survey_voters.out

    SFormat
    SFormat specifies how to write results to the SOutput file.

    SFormat uses a very flexible format. Basically, you should specify a line that contains formatting elements (including spaces, commas, and notes) and variable names. CMS will replace these variable names with the response-specific values (corresponding to these variable names).

    Example:   SFormat: _ID _VAR _DATETIME : _POLL City VCITY Age VAGE

    FORM
    The FORM survey questionaire file option that is specified in <? POLL AUTO=ASK .. > CMS-elements.

    The variable names, whose values are to be written to SOutput, are specified in this survey questionaire file, using standard HTML-form elements.

    Example:   <? POLL auto=ASK form=svyform.htm var=election target=win1>Fill out a survey <? /poll>


    Assuming that you've specified these options, CMS uses the following logic:
    1. When a client clicks on a take a poll link (created by a <? POLL AUTO=ASK .. > CMS-element), CMS will check for a FORM option.
    2. If one is found, the file it specifies will be read and used to create a survey form
      Typically, this file will specify the poll question, along with a variety of other questions (such as age and income) for the client to fill out.
    3. After the client answers the questions and submits the form, CMS will usually save (in the CMS dataseries) the choice given to the poll (CMS will increment the appropriate counter of the appropriate POLL variable).
    4. CMS will then check the poll-definition file for a SOutput option.
    5. If there is no SOutput option, nothing else is done.
      Otherwise, CMS checks for an SFormat option
    6. If there is no SFormat option, nothing else is done.
      Otherwise, the SFormat is used to create a line containing the answers given in the survey form.
    7. This created line is then appended to the SOutput file.
    8. That's it.

    SFormat

    SFormat has a simple structure: for every variable specified in the FORM file, CMS will see if there is a match in the SFormat line. If there is, then the value (of the matching variable) will replace the variable name in SFormat.

    In addition to variables explicitily specified in the FORMsurvey questionaire file, several other variables will be looked for:

    Example:  Assume that...
    • The poll can take three values: 1,2, and 3
    • The FORM survey questionaire file specifies the following variables: VAGE and VINCOME.
    • The variable name is RANK, and the observation ID is 5125.315125
    • The SFormat line is:
      _ID  ~20; _VAR   _DATETIME:   _POLL   with age=VAGE and Income=VINCOME
    If...
    • at 2 April 2004 10:52:03 AM, a client chooses choice 1, and types in an age of 45 and income of 62
    Then ...
    • The following line will be appended to the SOutput file:
      5125.315125         RANK   10:52:03 2 April 2004:   1   with age=45 and Income=62
    Note that the descriptive stuff (such as the spaces, the :, and the age= are retained).

    The survey form file

    Basically, CMS will create an HTML page, and insert the file specified by FORM survey questionaire file into it.

    This survey questionaire file should contain descriptive text; and input, textarea, and other such elements supported by HTML forms. It should not contain the FORM, BODY, or HEAD HTML elements.

    There is one special element that CMS will check for:
      <!--_POLL-->
    You must use this exact syntax: capitalize _POLL, and have no spaces between both the -- and the _POLL
    This element will be replaced by the poll questionaire.

    Instead of <!--_POLL-->, you can specify your own custom-design form elements (such as a selection box) to ask the client to choose a poll choice. This custom-design must use _POLL as the NAME.

    Example:  
      <Select name="_POLL">
      <Option value="1">Dislike
      <Option value="10">Okay
      <Option value="50">Good
      <Option value="100">Great
      </Select"> 
    Note that the values specified in this custom design must match the stored values you specify in the poll-definition file (rather then the choice number).
    If you use a value that is not specified in the poll-definition file, CMS will return an error message!

    Notes


    Document updated 1 April 2004