         AVALON - THE REVOLUTIONARY FOXPRO LIBRARY!
         ------------------------------------------


         Version 0.89

         By Roland Kappeler, Q-Line Software AG


         Copyright (C) 1992 Q-Line AG
         All rights reserved.





         REGISTRATION
         ------------

         AVALON is not only a fictionary island in the fog. It is also a
         Foxpro library, and it is not free. You must register after a
         30 day evaluation period.

         AVALON is a Shareware Product. It is distributed through public
         access channels so that perspective buyers can evaluate the
         product before making a decision to buy. If you decide to use
         this software, then you are under both legal and moral
         obligation to register it with the author. But if you decide
         not to use it after evaluating the software, you are under no
         obligation.

         If you continue to use AVALON after 30 days, or if you decide
         to use the library code in any of your own programs, you must
         register ist.


         Registration fee:      $ 49.00 US


         To register your copy of AVALON, fill in the registration form
         at the end of this file and mail it along with a check that can
         be cashed at any US bank, or with an international money order,
         (US money orders are NOT accepted!) to the address indicated in
         the form.


         SERVICES FOR REGISTERED USERS
         -----------------------------

         When you register, you are granted the unlimited right to
         distribute AVALON.PLB along with your own Foxpro applications.
         Also you are entitled to receive at least one upgrade version
         of AVALON.PLB, containing a complete, sophisticated printer
         spooler that simultaneously distributes multiple files to
         different printer ports, all in the background. Additionally,
         you will receive a modified GENSCRN.PRG that automatically
         creates scrollable masks of any size.

         As a registered user, you can also write or fax to us, if you
         have questions or problems. Additionally you are entitled to
         get any bugs fixed within a reasonable time for a period of six
         months after registration.

         AVALON, including its demonstration files and documentation,
         may be distributed by Shareware Distributors for a fee under
         US $8.00, which is to cover copying and other administrative
         costs.



         WHAT IS SO REVOLUTIONARY ABOUT AVALON?
         --------------------------------------

         First of all, AVALON also contains all those little utilities
         that are often useful, but not really exciting. Only the one
         thing is going to shake up the Foxpro world:

                   -------------------------------------
                   | SIZEABLE MULTI PAGE READ WINDOWS! |
                   -------------------------------------

         In Foxpro, a READ window cannot be sized or scrolled by the
         user. AVALON provides you with an extremely easy to use
         function that allows you to create sizeable READ windows
         including scroll bars. Like in a memo window, the content of
         the mask can be almost as many screen pages as you like!

         Use AVALON to create multi page masks with one single READ.
         Solve the problem of different screen sizes: with AVALON you
         can fully automatize the management of different resolution
         modes - without adding any code! And think of the advantage to
         sizeable windows in an event-oriented environment - it's a
         MUST!

         In multi-page windows, AVALON controls the window size, the
         position and movement of the scroll bars, and the proper
         display of the active entry object. Whenever the cursor moves
         outside the visible window area, the window content is
         automatically redisplayed. You really don't have to care about
         anything! But you still have access to all Foxpro window
         functions - the sizeable READ windows are nothing but regular
         Foxpro windows. Nothing stops you from programming your
         applications exactly as you did without AVALON - only much
         easier!

         All window elements can be operated with the mouse or with the
         keyboard, just as everybody is used to from the original
         environment. Additionally, the window content can be scrolled
         with the Cursor-Keys and with PgUp/PgDn.


         AVALON DEMO PROGRAM
         -------------------

         Try the demo program included: DO DEMO.PRG. This simple
         demonstration mask covers about two 25 line pages. It
         automatically opens in full size when running in 50 lines mode.
         Resize the window, and test the cursor movement when entering
         data. And - look at the source code: it's so damned easy - it's
         going to take you a while to believe it!

         THE AVALON LIBRARY FUNCTIONS
         ----------------------------

         First, you must SET LIBRARY TO AVALON in order to use any of
         AVALON's procedures. All AVALON procedures are used like
         FUNCTIONS, even if all do not return a value.

         The following is a description of all procedures currently
         available in AVALON. There are some more definitions already
         prepared for the printer spooler, but these functions are not
         implemented in this version.

         The following two names are reserved, these functions are NOT
         to be called:

         FUNCTION INITAVAL
         FUNCTION EXITAVAL

         -----------------------------------------------------------

         FUNCTION BEEP
         -------------

         Parameters:       >I   Optional: Duration in 1/10 Secs.
                           >I   Optional: Frequency in Hz.

         Function Result  <L   always .T.

         This replaces the ? CHR(7) for warning sounds. The default
         values are 4 for the duration, 400 Hz for the frequency.

         -----------------------------------------------------------

         FUNCTION DRIVEOK
         ----------------

         Parameters:       >C   Drive letter (string can be of any
                                length, only the first character is
                                used. Character case is ignored.

         Function Result:  <L   Delivers .T. if the drive is ok.

         Loading AVALON prevents your programs from any DOS Ignore/
         Abort/Retry messages. Call this procedure to check if a drive
         is ready to use.

         ----------------------------------------------------------

         FUNCTION MAKEDIR
         ----------------

         Parameters:       >C   Path to new directory

         Function Result:  <L   .T.  New directory was created.
                                .F.  Error, not done

         Use this function to create a new DOS directory.

         ----------------------------------------------------------

         FUNCTION WHATKEY
         ----------------

         Parameters:            none

         Function Result:  <I   Last key pressed.

         This returns a unique number for every available key and key
         combination. The value returned here is correct after every
         Foxpro input function. A complete list of WHATKEY values you
         find below.

         You cannot use WHATKEY() values for Foxpro commands like ON KEY
         etc.! But unlike READKEY() or LASTKEY() this function allows
         you to distinguish all keys, especially where the Foxpro
         commands return equal values for different key combinations.

         ----------------------------------------------------------

         FUNCTION SAYHEAD
         ----------------

         Parameters        >C   New title for the active window

         Function result:  <C   Empty string

         With this you can replace the title of the active window.
         The return value of an empty string makes it possible to use
         the function directly in a GET MESSAGE command.

         Remark: on sizeable masks as described below it does not matter
         whether the outer or the inner window is active, the title
         always replaces the one on the outer window.

         ----------------------------------------------------------

         FUNCTION SAYFOOT
         ----------------

         Parameters        >C   New footer for the active window

         Function result:  <C   Empty string

         This is the same as SAYHEAD, but for the window footer. Use
         this command as a GET MESSAGE clause to provide a brief
         explanation of the current get object. AVALON handles the
         correct refresh of the footer together with the horizontal
         scroll bar.

         ----------------------------------------------------------
         |                 SIZEABLE MASK WINDOWS                  |
         ----------------------------------------------------------

         Probably the most amazing feature of AVALON are its sizeable
         windows holding READs. As far as we know, this is not available
         in any other tool for Foxpro. Masks of up to 120 rows by 120
         columns can be created without any special effort. The windows
         behave just like memo windows: they carry scroll bars for both
         directions, and they can be resized and moved with the keyboard
         or with the mouse. The almost fully automatic cursor
         positioning centers the current READ object within the visible
         area, so that the program normally does not have to care in any
         way about the window size and position.

         ----------------------------------------------------------

         FUNCTION INITGROW
         -----------------

         Parameters:       >C   String holding the complete DEFINE
                                command for a sizeable window.

                           >C   String holding
                                   "MAX <height>, <width>"
                                Limits the size of the above window when
                                zoomed or resized.

                           >C   Optional: String holding
                                   "MIN <height>, <width>"
                                Sets a minimum size for the window
                                defined in the first parameter.

                           >C   String holding a complete DEFINE command
                                for a window IN the above window.

         Function result:  <L   always .T.


         This is used to create sizeable windows, especially for READ
         masks. The basic idea is that you actually have two windows:
         a large one that holds the GETs, and one that "overlays" the
         background and only lets you see a small rectangle of the whole
         picture at a time. Therefore, this "outer" window (or "top"
         window, but this describes only the optical arrangement) limits
         the visible area. The "outer" window is usually defined as a
         SYSTEM window. Its frames are equipped with all the gadgets
         like Closer, Zoomer, and Grower. AVALON adds scroll bars to it,
         if the GROW statement is in the definition.

         The "inner" window holds the GET objects. Therefore, normally
         the inner window is the active one when filling in its fields.
         Normally you will only activate the inner window after the
         outer window was once displayed.

         The inner window can be of almost any size; Foxpro allows up to
         120 rows by 120 columns, which gives you almost six pages on a
         regular 25 row screen.

         The definition of the inner window IN outer makes the word make
         sense: like through a window frame you are looking at one
         section of the picture "behind".

         The Foxpro command MOVE WINDOW would allow you to change the
         view on the inner window. But, since AVALON handles all this
         automatically, you should normally not use this command in your
         code. Instead, you should call the AVALON function CENTERPOS,
         if you want to change the view "manually".

         The following is a more detailed description of the INITGROW
         parameters:


         Parameter 1:  String holding the complete (executable) DEFINE
                       statement for the "outer" window.

                       You should always define this window with a frame
                       (preferrably SYSTEM). Add the gadgets you like:
                       GROW, ZOOM, MINIMIZE, CLOSE and so forth. As
                       usual you can also define a title and a footer
                       here.

                       Test the statement before you pass it in a string
                       to INITGROW. The proper behaviour of the library
                       is not guaranteed if Foxpro cannot execute the
                       definition line.

                       After testing, simply set the whole statement in
                       quotes (for multiple line statements you must
                       assemble the string with + signs).

         Parameter 2:  This string is to limit the maximum size of the
                       outer window when zoomed or resized. If your
                       "inner" window ist smaller than a 50 lines
                       screen, you will probably set the maximum size on
                       the same as the size of the inner window.
                       The maximum values that make sense here are 49 by
                       80 (AVALON limits the window size to the current
                       screen size).

                       Please note the format of the command String:

                          "MAX <height>, <width>"

                       The MAX statement can be omitted, it is intended
                       to increase the readability of the code.

         Parameter 3:  This optional parameter limits the minimum size
                       of the "outer" window. AVALON limits the size to
                       5, 5, smaller values are ignored. The minimum
                       size must not be greater than the maximum.

                       If you want to use the default limit, you can
                       omit this parameter (if there is no inner
                       window), or pass an empty string.

                       Again, for better readability you can add the MIN
                       statement.

         Parameter 4:  Here you define the "inner" window, the "big
                       picture" of your multi-page mask. You should
                       always define this window starting FROM 0, 0.
                       Additionally you should always add the NONE frame
                       command. Here you don't add any window gadgets,
                       and also no title or footer. Of course, you can
                       define COLORs as usual.

                       Never forget the IN WINDOW <outerName> command,
                       otherwise you will get anything but a sizeable
                       mask!

                       Usually the inner window will be at least the MAX
                       size of the outer (remember that row 0 is also a
                       row, so you have to add one for it when computing
                       the size).

                       Technically, you don't *have* to define an inner
                       window; this parameter is optional. But this is
                       only if you don't want to use READ in the outer
                       window, and if you really plan to compute all the
                       scroll bar movements and the screen offsets
                       yourself. A number of procedures below support
                       this attempt - but there is rarely any reason
                       for this approach.

         INITGROW internally executes the DEFINE WINDOW Statements.
         Therefore, after calling INITGROW, you can ACTIVATE the two
         windows at any time. Normally, you should ACTIVATE the outer
         window first, then the inner window. To the inner window
         you issue all your SAY's and GET's, no matter if they are
         currently visible or not.

         SPECIAL CONSIDERATIONS ON SELECTION LISTS

         If you have selection lists in your mask, they are not centered
         automatically. Foxpro does not set the cursor position on
         lists, instead it writes directly to the screen when
         activating them. So AVALON cannot figure out where the current
         object is.

         Add a WHEN clause to any of your lists. There you call
         CENTERPOS with the the vertical position of the list cursor and
         the position of the lateral center of the list (relative to the
         *inner* window). The example in DEMO.PRG shows you how it is
         done.

         If you ever run into a centering problem with an object,
         calling CENTERPOS in the WHEN clause solves it. Instead of the
         WHEN clause you can also use the MESSAGE clause.


         Keys trapped by the multi-page mask handling:

         - Shift+Ctrl+LtArr      Scroll content to the right
         - Shift+Ctrl+RtArr      Scroll content to the left
         - Shift+Ctrl+UpArr      Scroll content down
         - Shift+Ctrl+DnArr      Scroll content up
         - PgUp (or Ctrl+PgUp)   Content page up
         - PgDn (or Ctrl+PgDn)   Content page down
         - Home                  Center cursor position, cursor on

         - Ctrl+F7               Move window
         - Ctrl+F8               Size window
         - Ctrl+F9               Minimize window
         - Ctrl+F10              Zoom window

         The Ctrl+PgUp/Dn functions are used instead of PgUp/Dn if
         TRAPPAGE is .F. (see function TRAPPAGE).


         IMPORTANT:
         ----------

         After a call to INITGROW you must call ENDGROW (see below)
         before RELEASE WINDOW. Otherwise you might get trapped in the
         _FIREWORKS_DISPLAY_MODE (not everytime, though, this is a
         matter of unpredictable timing hazards! So, never forget!).

         ----------------------------------------------------------

         FUNCTION ENDGROW
         ----------------

         Parameter         >C   Window name of "outer" window

         Function result   <L   always .T.


         This function MUST be called with the name of any outer window
         that is defined by INITGROW. Call ENDGROW before you RELEASE
         the two mask windows. Better call it one too many than not
         (i.e. AVALON does not know when you RELEASE WINDOWS ALL, so you
         must call this procedure anyway!).

         ---------------------------------------------------------

         FUNCTION CENTERPOS
         ------------------

         Parameter         >I   Vertical position in inner window
                           >I   Lateral position
                           >C   Optional: Window name

         Function result   <L   always .T.

         To adjust the view on the inner window, you can force AVALON to
         try to center a position within the visible area. The function
         does not execute if the passed position is visible.

         The result is always .T., so yo can use this function directly
         as a WHEN clause (i.e. for selection lists and popups).

         ---------------------------------------------------------

         FUNCTION TRAPPAGE
         -----------------

         Parameter         >L   .T. : use PgUp/PgDn for mask scroll
                                .F. : Don't trap PgUp/PgDn

                           >C   Optional: outer window name (or active)

         If .T. (default), AVALON traps the PgUp/Dn keys to scroll
         the mask. If .F., the library uses Ctrl+PgUp/Dn instead. The
         trap is set individually for each mask.

         ---------------------------------------------------------

         FUNCTION HSLIDER
         ----------------

         Parameter         >C   Outer window name
                           >I   Optional: new horizontal slider position

         Function result:  <I   (previous) horizontal slider position

         This and the following three functions are only for use with a
         grow window that has no "inner" window.

         The optional second parameter allows to set a new slider
         position within the possible range. The function returns the
         previous slider position.

         HSLIDER returns the current slider position in the range from
         0 through WCOLS("outer") - 5.

         --------------------------------------------------------

         FUNCTION VSLIDER
         ----------------

         Parameter         >C   Outer window name
                           >I   Optional: new vertical slider position

         Function result:  <I   (previous) vertical slider position

         All is the same as for HSLIDER, except this is for the vertical
         scroll bar. The values range from 0 through WROWS("outer") - 5.

         --------------------------------------------------------

         FUNCTION HOFFSET
         ----------------

         Parameter         >C   Outer window name
                           >I   Optional: new column offset

         Function result:  <I   (previous) column offset

         When a slider is moved, an offset is calculated from the MAX
         values and the visible window size. This function returns the
         current offset from left (i.e. the leftmost column visible).

         As above, with the optional Set parameter you can change the
         value, and the function returns the previous state. Changing a
         value here automatically adjusts the slider position.

         The return values range from
            0 through MAX<width>-WCOLS("outer")

         --------------------------------------------------------

         FUNCTION VOFFSET
         ----------------

         Parameter         >C   Outer window name
                           >I   Optional: new row offset

         Function result:  <I   (previous) row offset

         This is the same as HOFFSET, but for the vertical position
         (i.e. the top row visible). Values range from
            0 through MAX<Height>-WROWS("outer")

         --------------------------------------------------------
         |                   THE PRINTER SPOOLER                |
         --------------------------------------------------------

         The AVALON printer spooler prints any number of files directly
         from the disk. This is done during the idle periods, when the
         program waits for keyboard input. The spooler uses so little
         processing time that you will never realize that the machine is
         doing something else besides handling your keystrokes.

         The AVALON spooler can address all three LPT ports simul-
         taneously. Therefore, you can print some files on one, and
         other files on another printer, all at the same time. The
         number of files that can be held in the spooler list is only
         limited by the available memory. The spooler cannot print the
         *same* file simultaneously to two different printers.

         The spooler sends files byte by byte directly to the printer.
         No conversions or any other data modifications are performed.
         So, if you first "print" your data to a file, and then submit
         the file's name to the spooler, it will print exactly what
         otherwise would have gone directly to the printer. This
         includes any escape sequences and other special characters as
         generated by some special printer drivers.

         Don't forget that your file should also contain the necessary
         page feeds. Depending on the method used to "print to file" you
         cannot always use EJECT. Simply "print" a CHR (12) to the file
         at the appropriate positions.

         In Foxpro, there are several methods to "print to file".
         Probably the most common is to SET PRINTER TO <File>. If you
         are using the User Dialog program coming with AVALON
         (AVASPOOL.SPR), you should create files with names that the
         user understands, since he will see those names when opening
         the dialog screen. Often it is a good idea to use a known
         filename (i.e. the name of a database) together with a
         different extension.

         The "print to file" process must be completed *before* the
         filename is submitted to the spooler. The spooler cannot open a
         file that is still in use.


         The Screen Program AVASPOOL.SPR

         AVALON comes with a complete User Dialog Program AVASPOOL.SPR
         including its sources. This program not only handles errors
         that may occur, like Paper out, Disk not ready, and so forth.
         Additionally, the user can add or remove files manually from
         the spooler list.

         AVASPOOL.SPR is invoked by an ON KEY LABEL routine that your
         program must set. Although you can replace AVASPOOL.SPR by any
         other spooler handler, you MUST provide this ON KEY LABEL
         routine. Actually, instead of issueing the ON KEY LABEL
         command, you call the AVALON function SPOOLKEY() to set the
         trap. If you omit to set this trap, the spooler is unable to
         inform your program or the user when an error occured. As long
         as an error condition is not resolved, the spooler cannot print
         at all.

         AVASPOOL.SPR displays the current error state for each port. If
         there is a file error, the user should <remove> the top file
         from the list (the top file shown is always the one currently
         printing). Or, he can clear the entire list by selecting "Clear
         all". If there is a printer error, he should check if the
         printer is on and connected to the right port - you know the
         procedure.

         The user can also add files to the printing list. Normally, he
         will probably use this possibility to print Ascii files in the
         background.

         You are free to change or enhance AVASPOOL.SPR according to
         your own needs and ideas. But if you intend to write your own
         Spooler Handler, please consider the following:

         You MUST call RUNSPOOL (.F.) at the beginning of your spooler
         handler, if there is any keyboard input. Otherwise you could
         run into a recursion that would certainly crash the machine. At
         the handler exit you call RUNSPOOL (.T.) to reinvoke the
         spooler.

         How to obtain the necessary information from the spooler can be
         seen in the source of AVASPOOL.SPR. Mainly the subroutine
         FillVars (located in the CleanUp section of the screen program)
         shows how information can be fetched from the spooler.

         Two things *must* be done by the spooler handler: if there is a
         file error (Error codes 1 or 2, see function SPOOLSTAT), the
         file should be removed from the spooler list. If there is a
         printer error (codes 3 and 4), the user should be asked to
         solve the problem.

         --------------------------------------------------------
         |                 SPOOLER FUNCTIONS                    |
         --------------------------------------------------------

         FUNCTION SPOOLKEY

         Parameter         >C   Key label (as for ON KEY LABEL)
                           >C   Spooler Handler Procedure

         Function result:  <L   always .T.

         Use this function to set a key trap for the spooler handler.

         Important: this procedure MUST be set at *all* times (call
         SPOOLKEY again after PUSH KEY CLEAR and so forth!). Otherwise
         your program (and the user) will not know when something's
         wrong with the printer - an error message is only sent once by
         the spooler.

         It does not matter which key you use - it only has to be a
         valid ON KEY LABEL identifier. The sample program SPOOLDEM.PRG
         shows how it can be done with the <F2> label. This way, the
         Spooler Handler can also be invoked manually by pressing this
         key.

         As mentioned above, you don't have to use AVASPOOL.PRG (it is
         free anyway). You could also write an error handler that simply
         returns without any action, as long as all ports are ok
         (SPOOLSTAT (x) <= 0). But you should provide a mechanism that
         can resolve the possible error conditions.

         -------------------------------------------------------

         FUNCTION ADDSPOOL

         Parameter         >C   FULLPATH (FileName)
                           >I   Printer port number (1..3)
                           >C   End character ( "" or CHR(12) )
                           >L   Optional: if .T., the source file
                                          is deleted when done
                                          Default is .F.
                           >C   Optional: a message string that is
                                          displayed when the file is
                                          printed.

         Function result:  <L   always .T.


         This adds a filename to the spooler list. You should always
         pass a full path, since the current DOS directory may change
         during the program run. If no file is currently printing, the
         spooler immediately starts printing this file. Otherwise, the
         file is appended to the end of the file list for this port.

         The third parameter is a character to be printed after the very
         end of the file. Usually you will pass a CHR (12) here, a page
         feed. This page feed is automatically skipped if one was at the
         end of the file.

         If the optional fourth parameter is .T., the source file is
         deleted from the disk when printed.

         The last parameter can be a string holding a short message like
         "<Filename> ist printed.". This string is displayed by the
         spooler in a WAIT <String> IN WINDOW NOWAIT command at the end
         of the file.

         -------------------------------------------------------

         FUNCTION REMSPOOL

         Parameter         >C   FULLPATH (FileName)
                           >I   Port number (1..3)

         Function result:  <L   .T.: Filename removed
                                .F.: no such file in the list


         With this your program can remove a filename from the spooler
         list. Use SPOOLARR() to get the names currently stored.

         -------------------------------------------------------

         FUNCTION RUNSPOOL

         Parameter         >L   .T.  Spooler on
                                .F.  Spooler off

         Function result   <L   The previous state

         This turns the spooler on and off. Please note that this is the
         only function that can turn the spooler back on when it is off
         (except SET LIBRARY TO, but this also clears everything else).
         In case of an error, the spooler is turned off automatically,
         and the key that was submitted by SPOOLKEY is placed in the
         keyboard buffer, which invokes the error handler.

         -------------------------------------------------------

         FUNCTION SPOOLARR

         Parameter:        >C   Array name
                           >I   Port number (1..3)

                           <I   Number of elements in array


         This function is similar to ADIR: it fills an array with the
         data of the current spooler list for one port. The array is
         one-dimensional, and it holds the filenames as submitted by
         ADDSPOOL. The first element is the file that is currently
         printing.

         The array name is passed to the function in quotes. Like in
         ADIR, the array is created if it does not exist. If you use the
         same array more than once for this function, you should first
         clear it (Array = "").

         If the array data are to be edited, you must stop the spooler
         by calling RUNSPOOL (.F.), because otherwise the list will
         probably not be accurate for long (printed files are removed
         from the spooler list).

         Note: changes in the array do *not* change the spooler list.
         You must use REMSPOOL and ADDSPOOL to change the actual spooler
         list.

         -------------------------------------------------------

         FUNCTION CLRSPOOL

         Parameter         none

         Function Result:  always .T.


         This clears the entire spooler list (all ports). The current
         output (if any) is aborted. No files are deleted, even if it
         was demanded by the ADDSPOOL parameter.

         -------------------------------------------------------

         FUNCTION SPOOLSTAT

         Parameter         >I   Port number (1..3)

         Function result   <I   Error code


         With this you get information about the state of one port. The
         following codes are returned:

         -1    Port idle (or unused)
          0    Currently printing
          1    Top file in the list could not be opened
          2    Read error in current file
          3    Printer port error (off line, printer off, etc.)
          4    Paper out message received
          5    Internal error (should never occur)

         If you get an error number > 0 here, the spooler is off. Your
         program must take the appropriate action to solve the problem
         before restarting the spooler.

         Normally, on errors 1 and 2 you will remove the first entry
         from the file list with REMSPOOL. On errors 3 and 4 you should
         ask the user to solve the problem, or to clear the list.

         --------------------------------------------------------

         KEY CODE TABLE for WHATKEY()
         ----------------------------

         All character keys (including Alt/Decimalpad combinations) from
         CHR (1) through CHR (255) are returned as their original value.

         Not all defined keys are necessarily available on every
         system, and some are never returned because they are trapped
         by Foxpro. But whenever you get a chance to call WHATKEY you
         will get a correct identification of the last pressed key,
         including the left mouse button. The right button and the
         modified left button values are only returned if they are
         pressed during the WHATKEY call.


         F1  = 1017;  CF1  = 1617; SF1  = 1317;  AF1 = 1917;
         F2  = 1018;  CF2  = 1618; SF2  = 1318;  AF2 = 1918;
         F3  = 1019;  CF3  = 1619; SF3  = 1319;  AF3 = 1919;
         F4  = 1020;  CF4  = 1620; SF4  = 1320;  AF4 = 1920;
         F5  = 1021;  CF5  = 1621; SF5  = 1321;  AF5 = 1921;
         F6  = 1022;  CF6  = 1622; SF6  = 1322;  AF6 = 1922;
         F7  = 1023;  CF7  = 1623; SF7  = 1323;  AF7 = 1923;
         F8  = 1024;  CF8  = 1624; SF8  = 1324;  AF8 = 1924;
         F9  = 1025;  CF9  = 1625; SF9  = 1325;  AF9 = 1925;
         F10 = 1026;  CF10 = 1626; SF10 = 1326; AF10 = 1926;
         F11 = 1027;  CF11 = 1627; SF11 = 1327; AF11 = 1927;
         F12 = 1028;  CF12 = 1628; SF12 = 1328; AF12 = 1928;

         Alt1 = 1949;  Alt6 = 1954; CA1 = 2249;  CA6 = 2254;
         Alt2 = 1950;  Alt7 = 1955; CA2 = 2250;  CA7 = 2255;
         Alt3 = 1951;  Alt8 = 1956; CA3 = 2251;  CA8 = 2256;
         Alt4 = 1952;  Alt9 = 1957; CA4 = 2252;  CA9 = 2257;
         Alt5 = 1953;  Alt0 = 1948; CA5 = 2253;  CA0 = 2248;

         AltA = 1965;  AltH = 1972; AltO = 1979; AltU = 1985;
         AltB = 1966;  AltI = 1973; AltP = 1980; AltV = 1986;
         AltC = 1967;  AltJ = 1974; AltQ = 1981; AltW = 1987;
         AltD = 1968;  AltK = 1975; AltR = 1982; AltX = 1988;
         AltE = 1969;  AltL = 1976; AltS = 1983; AltY = 1989;
         AltF = 1970;  AltM = 1977; AltT = 1984; AltZ = 1990;
         AltG = 1971;  AltN = 1978;

         CtlA = 1665;  CtlH = 1672; CtlO = 1679; CtlV = 1686;
         CtlB = 1666;  CtlI = 1673; CtlP = 1680; CtlW = 1687;
         CtlC = 1667;  CtlJ = 1674; CtlQ = 1681; CtlX = 1688;
         CtlD = 1668;  CtlK = 1675; CtlR = 1682; CtlY = 1689;
         CtlE = 1669;  CtlL = 1676; CtlS = 1683; CtlZ = 1690;
         CtlF = 1670;  CtlM = 1677; CtlT = 1684;
         CtlG = 1671;  CtlN = 1678; CtlU = 1685;

         CAA  = 2265;  CAH  = 2272; CAO  = 2279; CAV  = 2286;
         CAB  = 2266;  CAI  = 2273; CAP  = 2280; CAW  = 2287;
         CAC  = 2267;  CAJ  = 2274; CAQ  = 2281; CAX  = 2288;
         CAD  = 2268;  CAK  = 2275; CAR  = 2282; CAY  = 2289;
         CAE  = 2269;  CAL  = 2276; CAS  = 2283; CAZ  = 2290;
         CAF  = 2270;  CAM  = 2277; CAT  = 2284;
         CAG  = 2271;  CAN  = 2278; CAU  = 2285;

         KEYCODES for WHATKEY(), continued


         Tab   = 1009; STab   = 1309;
         Home  = 1055;                CHome  = 1655;
         End   = 1049;                CEnd   = 1649;
         PgUp  = 1057;                CPgUp  = 1657; APgUp   = 1957;
         PgDn  = 1051;                CPgDn  = 1651; APgDn   = 1951;
         UpArr = 1056; SUpArr = 1356; CUpArr = 1656; SCUpArr = 2556;
         DnArr = 1050; SDnArr = 1350; CDnArr = 1650; SCDnArr = 2550;
         LtArr = 1052; SLtArr = 1352; CLtArr = 1652; SCLtArr = 2552;
         RtArr = 1054; SRtArr = 1354; CRtArr = 1654; SCRtArr = 2554;
         ESC   = 1027; SESC   = 1327;
         BS    = 1008;                CBS    = 1608;
         Enter = 1013; SEnter = 1313; CEnter = 1613;
         Ins   = 1048;
         Del   = 1046;
                       SSpace = 1332; CSpace = 1632;
                                      CMinus = 1645;

         LeftMouse      = 2999;
         RightMouse     = 2998;
         ShiftLeftMouse = 2997;
         CtrlLeftMouse  = 2996;

         Some more keycodes are generated by WHATKEY (you will easily
         recognize the pattern), but only the codes listed here are
         unique on all keyboards.

         --------------------------------------------------------

         REGISTRATION FORM for AVALON.PLB


         First/Name _____________________________________________

         Company    _____________________________________________

         Address    _____________________________________________

         City, St/Z ______________________________ ___ __________

         Phone/Fax  _____________________________________________

         Position   _____________________________________________

         Prod.Sect. _____________________________________________

         Comments/  _____________________________________________
         Suggestions
                    _____________________________________________

                    _____________________________________________

         In return for this registration I will receive at least one
         upgrade to AVALON, including the printer spooler, and a
         modified GENSCRN.PRG as described in the documentation.

         A [ ] US check or [ ] International Money Order for the
         registration fee of US $49.00 is included. Please make checks
         out to Roland Kappeler. Thank you.



         Mail to:

         Roland Kappeler
         Q-Line AG
         Aarbergergasse 52
         CH-3011 Bern
         Switzerland

         Fax: x41-31-22-26-11
         CIS: 100022,1370