Super Models, Version 3.6i
(c) Copyright 1989-94, BoxSoft Development Inc.

Here's what you'll find in 3.6i:

1.   Numerous minor bug fixes.  There was nothing major wrong with 3.6h,
     which is the main reason that we've waited so long to release the new
     version.

2.   New documentation to describe the security and the field-level help. 
     You'll find this information later in this document.

3.   New virtual memory feature to reduce memory needs.  There were many
     places where the old model would use a memory table to store temporary
     record and memo values.  If your records and/or memos were large, this
     could have a large impact on your memory needs.

     The new virtual memory feature uses the SUPER.BIN LEM to swap these to
     a disk file.  Because it's C code, it's very fast, especially if you
     are using disk caching software.  The filename is $TM#####.TMP.  This
     file will be deleted by the system if you exit the program normally. 
     You may still want a batch file to clean up these and any other swap
     files that you may have.  Here's what we normally do:

          @echo off
          cls
          echo Loading ProgName...
          if exist $t*.tmp del $t*.tmp
          if exist lpm_swap.* del lpm_swap.*
          progname

     The virtual memory operations will attempt to reuse freed memory
     blocks.  This means that the swap should not grow very large.  It is
     also quicker to write to an existing file region than it is to extend
     the length of the file.  This makes swapping much faster.

     There are various functions and procedures added to the SUPER.BIN to
     support the virtual memory feature:

     OpenMem_(filename) - This procedure creates and opens the swap file. 
          The "filename" parameter is the name of the swap file.

     CloseMem_() - This procedure closes and deletes the swap file.

     AddMem_(variable) - This function stores the variable to the swap
          file.  The variable can be any record, group, string or memo
          structure.  It returns the "handle" as a LONG, which must be used
          for future operations related to that memory block.

     PutMem_(handle, variable) - This procedure updates the memory block in
          the swap file.  The "handle" is the value returned by AddMem_(). 
          The "variable" is the thing to be stored.  This will normally be
          the same object that was originally passed to AddMem_().

     GetMem_(handle, variable) - This procedure retrieves the memory block
          from the swap file.  The "handle" is the value returned by
          AddMem_().  The "variable" is the destination for the retrieved
          block.  This will normally be the same object that was originally
          passed to AddMem_().

     DelMem_(handle, variable) - This procedure performs two operations. 
          First it calls GetMem_(), which retrieves the memory block from
          the swap file into the variable.  Then it frees the block in the
          swap file for future use.  The "handle" is the value returned by
          AddMem_().  The "variable" is the destination for the retrieved
          block.

     CmpMem_(handle, variable) - This function compares the memory block in
          the swap file specified by the "handle" to the value of the
          passed "variable".  It returns zero if the values match, or a
          non-zero if they are different.

          This would normally be called at the end of the Form procedure. 
          At the start, the system will remember what the record looked
          like.  At the end, it says, "Here's what it looks like now.  Has
          it changed?".

---------------
System Security
---------------
A "how-to" section was added to the Super Template documentation, which has
significantly improved people's understanding of the Security features. 
Therefore, we've decided to copy it here, and modify it to fit the Super
Models.


Using Levels:  Step by Step
--------------------------- 
You should use levels if your security requirements are simple.  The users
access rights must be a simple hierarchy, with each access level being a
superset of the lower level.

1.   Choose the level numbers.  You may want to use 1-2-3, or 100-200-300. 
     You should not be attempting complex security installations using
     levels, so there will rarely be more than 3 or 4 different levels. 
     Remember, the lower level number indicates less access, while the
     higher level number indicates greater access.  Let's pretend that the
     company's hierarchy is clerk (10), administrator (20), manager (30),
     and president (40).

2.   Go to the SUPER\DOOREDIT directory and load DOOREDIT.APP.

3.   Generate, Compile and Translate DOOREDIT.EXE.  Copy this program into
     the SUPER directory.  Make sure that this directory is in your DOS
     PATH.

4.   Go back to the SUPER\USEREDIT directory.

5.   Edit DOOR.CPY.  Change the EQUATE value for eD_Security.  The system
     administrator must have the same level as the President, or must use
     the backdoor password to run UserEdit.

6.   Edit INIT1.CPY.  Set the sSecType variable to 'L'.

7.   Load USEREDIT.APP.  Now Generate, Compile and Translate USEREDIT.EXE.

8.   Copy USEREDIT.EXE into your application directory.  You will be
     distributing this program with your application so that the system
     administrator can update user access rights.

9.   Change to your application directory and run DoorEdit.  Create a door
     for each level.  You'll have to override the default or "eD_" for each
     of the levels, or you may choose to use that instead of "eL_".

          10   eL_Clerk       Clerk
          20   eL_Admin       Adminstrator
          30   eL_Manager     Manager
          40   eL_President   President

     Before you exit DoorEdit, execute the menu option to make DOOR.CPY. 
     It will save you the trouble of creating your equates manually. 
     You'll be able to reference these equates instead of specifying the
     numbers directly.

10.  Now load your APP.

11.  Turn on security in your application.  This involves editing (or
     creating) INIT1.CPY, and setting sSecurity=True, and sSecType='L'.

12.  Decide which procedures to protect.  Remember that the user will logon
     when they start the application.  Therefore, you have already
     prevented any completely unauthorized access.  The only things you
     should start protecting now are procedures which not all authorized
     users are allowed to access.  This means that you probably don't need
     to assign eL_Clerk to any procedures.

     The only exception would be if you were planning on adding a lower
     level in the future (ie:  eL_Temp=5).  In that case you should
     probably be adding that level up front.

13.  Let's say that you want to restrict access to a revenue report so that
     it can only be run by the manager.  Go into the report, press Ctrl_O
     then place the following code into the "Setup Procedure":

          S:RunDoor = eL_Manager

14.  If you wanted to prevent the clerk from adding customers, you would
     put the following code into the "Setup Procedure" of the customer
     table:

          S:AddDoor = eL_Admin

     If only managers were allowed to delete customers, you would add
     another line at the same point:

          S:DelDoor = eL_Manager

15.  Make your application EXE file.

16.  Before running your application, run UserEdit to add some test users. 
     Create one for each level.

17.  Test your application to make sure that the security works as desired.

18.  When you distribute your application, you will need to send along
     USEREDIT.EXE and DOOR_.*.  You may want to send a default version of
     USER_.* as well.


Using Doors:  Step by Step
--------------------------
Doors are used when your security system requires more flexibility.  Doors
are assigned to procedures according to functionality, and users may be
granted or denied access to any combination of doors.

1.   You must decide how flexible to make your security.  Take a look at
     your application and decide what types of things need to be protected. 
     You'll probably start to realize that they fall into groups of
     functionality.  Various procedures may be used for updating customers. 
     Other areas are for running day-to-day reports, while other reports
     are history reports for management decisions.

     After getting a feel for the security needs, jot down the doors that
     you think you'll need.  Everyone will approach this differently, and
     there are no right or wrong ways to do it.  The only important measure
     of your success is whether the system administrator can control access
     rights to his satisfaction.

     For the purpose of our example, let's pretend that there are four
     doors:  eD_Cash, eD_Admin, eD_Report, and eD_Security.  They will have
     values of 100, 200, 300 and 1000, respectively.  The actual numbers
     are not important when using doors.  Each door is considered distinct
     and unrelated to other doors.  We will create these doors with
     DoorEdit.

     If possible, it is best to group the doors numbers by common
     functionality.  This is because they will be listed by door number in
     UserEdit.  It's easier to update access rights if similar doors are
     grouped together rather than randomly scattered throughout the scale. 
     You may want to leave some space between the various door numbers for
     future expansion.

2.   Go to the SUPER\DOOREDIT directory and load DOOREDIT.APP.

3.   Generate, Compile and Translate DOOREDIT.EXE.  Copy this program into
     the SUPER directory.  Make sure that this directory is in your DOS
     PATH.

4.   Go back to the SUPER\USEREDIT directory.

5.   Edit DOOR.CPY.  Change the EQUATE value for eD_Security.  The system
     administrator must have the same level as the President, or must use
     the backdoor password to run UserEdit.

6.   Edit INIT1.CPY.  Set the sSecType variable to 'D'.

7.   Load USEREDIT.APP.  Now Generate, Compile and Translate USEREDIT.EXE.

8.   Copy USEREDIT.EXE into your application directory.  You will be
     distributing this program with your application so that the system
     administrator can update user access rights.

9.   Change to your application directory and run DoorEdit.  Create a door
     for each level.

          10   eD_Clerk       Clerk
          20   eD_Admin       Adminstrator
          30   eD_Manager     Manager
          40   eD_President   President

     Before you exit DoorEdit, execute the menu option to make DOOR.CPY. 
     It will save you the trouble of creating your equates manually. 
     You'll be able to reference these equates instead of specifying the
     numbers directly.

10.  Now load your APP.

11.  Turn on security in your application.  This involves editing (or
     creating) INIT1.CPY, and setting sSecurity=True, and sSecType='D'.

12.  Let's say that you want to restrict access to a revenue report so that
     it can only by run users who have access to the eD_Report door.  Go
     into the report and press Ctrl_O to access the Options screen.  Then
     place the following code into the "Setup Procedure":

          S:RunDoor = eD_Report

13.  If you wanted to prevent users from adding customers unless they had
     access to the eD_Cash door, you would put the following code into the
     "Setup Procedure" of the customer table:

          S:AddDoor = eD_Cash

     You could restrict the deletion of customer to users with access to
     the eD_Admin door by adding another line to the same source point:

          S:DelDoor = eD_Admin

14.  Make your application EXE file.

15.  Before running your application, run UserEdit to add some test users. 
     Assign a variety of access rights to the users.

16.  Test your application to make sure that the security works as desired.

17.  When you distribute your application, you will need to send along
     USEREDIT.EXE and DOOR_.*.  You may want to send a default version of
     USER_.* and ACCESS_.* as well.

--------------------
Field-Sensitive Help
--------------------
This is a feature that was added in 3.6g.  It was described briefly in the
reference section of the manual, but a number of users requested that a
"how-to" section be added.

Field-Sensitive Help allows you to attach a description to each field in
your system.  This help text will automatically be displayed as you move
from field to field.  The help entry may be edited at any time by pressing
the sHelpEditKey.  The default for this is Alt_F1.

The system has been configured in such a way that you don't actually need
to create help text for every field on every screen of your entire
application.  Here what the system looks for:

1.   Is there help text for the current field on the current screen?
2.   If not, is there help text for the current field not assigned to a
     specific screen?
3.   If not, is there help text for the current screen?
4.   If not, blank the help area.

This means that you can add generic field messages for your desired fields
and have the help text appear on all screens.  As necessary, you can
override this text for specific screens.  Because this is always done at
run-time, it is a very natural, interactive process.

The "help area" is an area of your screen that will be used to display
field messages.  This can any area on the screen, although there are a
number of logical places to put it:

1.   You may want to use the bottom row(s) (1-3) of the bottom of the
     physical screen.  You will use this for the entire application.

     a)   Make sure that none of your screens will overlap this area.  This
          can be done by making all of your screens "Fixed".

          If you need a particular screen to float, then extend the bottom
          of the screen by one row, move the border back to the original
          location, then paint this bottom row "transparent".

          If you do this, you will not want to use the automatic shadows on
          this screen.  Place the following code into that procedure's
          Setup Procedure

               sShadow=1; Source_(Init,sShadow=0)

     b)   In INIT1.CPY, place the following code:

               sHelpRow  = 25      !25=1 row, 24=2 rows, 23=3 rows
               sHelpCol  = 1       !Left column
               sHelpRows = 1       !1/2/3
               sHelpCols = 80      !Full line

     c)   The help system uses the SHOW command to display the help text. 
          Rather than forcing you to set the display colors in variables,
          it simply uses the existing screen colors.

          On your main menu, paint this region the desired color for the
          help text.  You may want something like LightGray on Black, or
          Blank on Green.  It should be something to set it off from the
          rest of the screen.

     d)   Run your application.  At each field where you want help, press
          Alt_F1 to call the Help Update Form.  The "Scope" relates back to
          the how specific this help message will be.  You can enter up to
          240 characters of text.  Remember that only as much text will be
          displayed as can fit into your defined help area (see 'b' above). 
          The text you enter will be word-wrapped to fit in the specified
          area.

          If you've got similar help in other locations, you can use
          "Lookup" to copy it into this screen.

          After you save the text, it will not be displayed until you come
          down the screen again.

2.   You may want to use a region of the current screen.  If so, you will
     specify this for each procedure, and there probably will not be any
     global settings.  (You could still use the global settings for most of
     the application, then override them on the desired screens.)

     a)   If your procedure is a floating screen, use the following code in
          the Setup Procedure:

               HelpRow_=ROW(Screen)+10; HelpCol_=COL(Screen)+1;
                    HelpRows_=2; HelpCols_=30

          This will create a 2 row, 30 column help area, starting on the
          11th (ROW(Screen)+10) row and 2nd column (COL(Screen)+1).  If
          your screen is Fixed rather that Floating, you could hard code
          the HelpRow_ and HelpCol_ settings.  You could still use the
          ROW() and COL() functions if you wanted to, just in case you ever
          moved the screen.

          If you wanted to display the help text in the first line of the
          screen, you would use the following settings:

               HelpRow_=ROW(Screen); HelpCol_=COL(Screen); HelpRows_=1;
                    HelpCols_=COLS(Screen)

     b)   The help system uses the SHOW command to display the help text. 
          Rather than forcing you to set the display colors in variables,
          it simply uses the existing screen colors.

          Paint this region the desired color for the help text.  You may
          want something like LightGray on Black, or Blank on Green.  It
          should be something to set it off from the rest of the screen,
          although this is not absolutely necessary.

     c)   Run your application.  At each field where you want help, press
          Alt_F1 to call the Help Update Form.  The "Scope" relates back to
          the how specific this help message will be.  You can enter up to
          240 characters of text.  Remember that only as much text will be
          displayed as can fit into your defined help area (see 'b' above). 
          The text you enter will be word-wrapped to fit in the specified
          area.

          If you've got similar help in other locations, you can use
          "Lookup" to copy it into this screen.

          After you save the text, it will not be displayed until you come
          down the screen again.

The help messages will be stored in a Clarion data file called HELP_.DAT
(with associated key files).  If you want to change it to something else,
place the following line into INIT1.CPY:

     sHelpFilenam = 'HELPNAME.DAT'

If you want to change the help edit key to something else, place the
following line into your INIT1.CPY file:

     sHelpEditKey = <keycode>

for example:

     sHelpEditKey = F3_Key         !Change Help Edit Key to F3
     sHelpEditKey = 9000           !Make the Help Edit Key unaccessible

The last option above could be used once you've created all of your field
help messages, and you want to prevent the user from changing them.  Since
9000 cannot be created by any key on the keyboard, this option will not be
available.
