------------------------------------------------------------------------------
------------------------------------------------------------------------------
        NNNNNNNNNNNN        NNNNNNNNNNNN  NNNNNNN    NNNNNN NNNNNNN    NNNNNN
       NNNNNNNNNNNNNN    NNNNNNNNNNNNNN  NNNNNNNN   NNNNNN NNNNNNNN   NNNNNN
      NNNNNN    NNNNN  NNNNNNNNNN       NNNNNNNNN  NNNNNN NNNNNNNNN  NNNNNN
     NNNNNN    NNNNN NNNNNNNN          NNNNNNNNNN NNNNNN NNNNNNNNNN NNNNNN
    NNNNNNNNNNNN    NNNNNN            NNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNN
   NNNNNN   MNNNNN NNNNNNN           NNNNNN NNNNNNNNNN NNNNNN NNNNNNNNNN
  NNNNNN   MNNNNN  NNNNNNNN         NNNNNN   NNNNNNNN NNNNNN   NNNNNNNN
 NNNNNNNNNNNNNN     NNNNNNNNNNNNN  NNNNNN    NNNNNNN NNNNNN    NNNNNNN
NNNNNNNNNNNNN        NNNNNNNNNNN  NNNNNN     NNNNNN NNNNNN     NNNNNN
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Boston Computer News Network                                        July, 1994
A Service of the Boston Computer Society, USA                      Vol.3  No.7
Sponsored by the Xbase Language Group                          Clipper Version
------------------------------------------------------------------------------
 1. No Visual Objects in 1994.
    --------------------------------------------------------------------------
    ReplyTo:   Les Squires bcnn@world.std.com  [73020,3435]

    "Concerned that its CA-Visual Objects has only one chance to succeed,
    Computer Associates International Inc, delayed shipment of the Windows
    application development tool until the end of the year with the goal of
    ensuring a bug-free product. . . ", reported Scott Mace, Washington D.C.
    Bureau Chief of InfoWorld (July 4, 1994)

    The article goes on to quote Marc Sokol, Computer Associates' Director
    of Product Strategy, "We only have one shot. . .  If this product comes
    out with severe flaws, we're dead."

    CA has added more beta testers.


 2. New Breed of Developers Needed for UpScale Applications (July Meeting).
    --------------------------------------------------------------------------
    ReplyTo:   Les Squires bcnn@world.std.com  [73020,3435]
    ReplyTo:   Runjan Sinha, Strategic Network Designs Inc.
               60 Walnut Avenue, Clark NH 07006 USA, 908-396-0800
    Meeting:   July 19, 1994, 6:30 p.m.
    Subject:   Distributed Database Models
    Place:     Boston Computer Society, Waltham, MA USA 617-290-5700

    You're a developer.  You're looking for some new and exciting work.
    You run across the following list of available jobs:

    o  50 or more franchised restaurants need to collect and disseminate
       information (sales, inventory, menu, pricing, training manuals,
       payroll and reporting) to restaurant managers.

    o  Hotel chain needs registration, inventory and supply management,
       payroll, rates, management reporting.

    o  Retail stores (200 of them!) need inventory, receipts, pricing,
       training, payroll and reporting.

    o  100-5000 franchised repair shops (Midas, Quick Lube, Jiffy Lube,
       AAMCO, etc.) need sales, inventory, parts lookup and description
       manuals, pricing, warranty logs, etc.).

    o  Local gas company wants gas and electric meter reading.

    o  Car manufacturer needs contracts, standards, dealer development,
       news bulletins, inventory management, car locators, and parts
       processing.

    o  Loan company needs load application processing for credit union
       members with electronic funds disbursement.

    o  Cellular phone company needs registrations (including the giving out
       of numbers) in the field for 600 sales persons.

    o  Drug manufacturer and distributor (1000 sales reps covering 120,000
       doctors) needs to display new products (image and text), take
       orders, get updates on pricing and documents everyday, and provide
       EIS for management.

    o  Software manufacturer with 300 roaming sales persons needs email,
       contact management, order processing, demo updates, and pricing.

    So . . . , you're a CLIPPER developer.  How would you bid this class of
    work?  What tools would you use?  It's not DBF-time anymore!  Clipper
    87 programmers need not apply!  And, of course, it all has to be in
    Windows! <g>

    In the July Clipper meeting, we lay a framework for 'upsizing' the
    types of databases that we can get our Clipperheads around.  Multi-site
    distribution, central vs. remote sites, accidental disconnection
    recovery, data transmission across disparate devices (Mainframe, SQL
    Servers, Networked Servers), system disaster recovery, transaction
    tracking and rollback, and use of networks (Public dial, X.25, Switched
    56, ISDN, Cellular, VSAT, etc.). It sounds like a good three-hour
    meeting! <G>  And Runjan Sinha of Strategic Network Designs Inc. is
    just the person to lay that framework.


 3. UDF@Showcase.  SOURCE\SAMPLES\*.PRG:  Why Re-invent the Wheel?
    --------------------------------------------------------------------------
    ReplyTo:  Roy Corneloues <100016.63@CompuServe.COM>
              Managing Director, xWare Solutions Limited

    After reading the June BCNN, I found contributions replicating code
    which can already be found in the Clipper 5.x box.  How many devlopers
    have actually looked at the source in the SAMPLE directory?  Or, even
    know that a SAMPLES.LIB actually exists?

    Scott Barnes contribution FixedPop() is simply a mild imitation of the
    function LISTASARRAY() which converts a string to array elements based
    on a supplied delimiter.

    His example then becomes:

    PROCEDURE Main
       LOCAL aTokens
       LOCAL cString := "This is a Test"

       aTokens := LISTASARRAY(cString)     //-Default delimiter is <space>
       AEVAL(aTokens, {|token| QOUT(token)}

       //-or

       AEVAL(LISTASARRAY(cString), {|token| QOUT(token)}
       RETURN

    Richard Grosser supplied a pseudo-stack system.  Again there is already
    a stack system supplied in SOURCE\SAMPLE\STACK.PRG.

    His example then becomes:

    PROCEDURE Main
      LOCAL aStack := StackNew()

      StackPush(aStack, SAVESCREEN(0, 0, MAXROW(), MAXCOL())
      StackPush(aStack, SETCURSOR(SC_NONE))
      StackPush(aStack, SETCOLOR(COLORS_EDIT))

      ... code

      SETCOLOR(StackPop(aStack))
      SETCURSOR(StackPop(aStack))
      RESTSCREEN(0, 0, MAXROW(), MAXCOL(), StackPop(aStack))

    SAMPLES also includes a dictionary, scroll bar, file manager,
    percentage gauge, time and time functions, plus many others.

    Make sure you check out the CA-Clipper Sample Reference Norton Guide
    for all the information, and remember you don't need to compile any of
    them, just specify SAMPLES.LIB on your link line or in your link file.

    Editor's Note.  Reference Clipper will be running a full article on the
    SAMPLES library in an upcoming issue.  Sorry, Savannah beat me to it!
    Let her know what you think at <71024,3374>! <bg>


 4. What's New at Technicon:  ZAC Catalog Of VO Only Tools.
    --------------------------------------------------------------------------
    ReplyTo:  Leonard A. Dozois <76340.1123@compuserve.com>
              Zachary Software, Inc., 106 Access Road, Norwood, MA 02062
              800-V-OBJECTS USA/Canada
              617-551-0860 outside USA/Canada
              Fax 617-551-0857
              CompuServe and INTERNET requests will be honored as well.

    Zachary Software Inc., publishers of Zachary - The Software Machine and
    the ZAC Catalog Of Clipper Only Tools will introduce its new Visual
    Objects Tools Catalog at TechniCon.  The catalog promises to offer
    great deals on VO training, books, videos and brand new VO Tools.  They
    are also rumored to be planning an exclusive VO Mystery Bundle that
    will pair up Visual Objects with a tool that is so critical to the
    migration from Clipper to VO that you won't want to be without it.  If
    you're already receiving their Clipper catalog then you'll get the VO
    Edition automatically.  Otherwise call one of the above numbers.


 5. UDF@Showcase.  DIRCHECK() Part I.
    --------------------------------------------------------------------------
    ReplyTo:  Stuart Gordon <100101.1160@CompuServe.COM>

    I enjoy reading through the UDF Showcase contributions - it is very
    interesting to see how others tackle their day to day work.  Parallel
    evolution seems to be an everyday event!  However, sometimes knowledge
    from other areas of computing life effect the way we solve problems -
    in the BCNN June 1994 DirCheck() from Karlheinz Walder we see a totally
    Clipper approach, whereas by a combination of using the DOS NUL with
    Clipper this can be reduced to a single line function...

    FUNCTION DirCheck(cDirName) ; RETURN FILE("\"+cDirName+"\NUL")

    For example, to check for a specific directory:

    FILE("C:\WINDOWS\SYSTEM\NUL")


 6. UDF@Showcase.  DIRCHECK() Part II.
    --------------------------------------------------------------------------
    ReplyTo:  Douglas Schwarz <70474.2520@compuserve.com>

    Karlheinz Walder's DirCheck() function (BCNN, June 1994) works only if
    the directory being checked for is a subdirectory of the current
    directory.  The version below works for ANY drive or directory.

    I also take advantage of the fact that DIRECTORY("*.*","D") will pick
    up the "." and ".." entries in the file table as directories.
    Therefore, even if the target directory is empty, it will return
    information on two "files."  Only if the directory does not exist will
    the function return an empty array.

    *-----------------------
    FUNCTION ISDIR(cDirName)
    *-----------------------  Does directory CDIRNAME exist?
    //-cDirName may include a drive designation and subdirectories.
    //-Code below eliminates case errors, and attaches a trailing "\"
    //-to the directory name if necessary.

    local lBack := .F., aDir

    cDirName = upper(cDirName)
    if substr(cDirName,len(cDirName),1) # "\"
       cDirName += "\"
    endif

    //-Now directory() of cDirName.  If ANY info returned, cDirName exists.
    aDir := directory(cDirName + "*.*", "D")
    if len(aDir) > 0
       lBack = .t.
    endif
    return (lBack)


 7. UDF@Showcase:  FSEARCH():  FAST Low Level File Searches of DBFs.
    --------------------------------------------------------------------------
    ReplyTo: John E. Graceland [72410,350]

    FSearch()  FAST low level file search of .DBF in current workarea.
    Syntax:    FSearch( <ExpC>, <ExpL1>, <ExpL2> ) -> RECNO()
    Arguments: <ExpC>  Search string
               <@ExpN> Starting position of search, 0 = from top of file
               <ExpL> Logical that determines if search case sensitive.
    Returns:   RECNO() on match, 0 on NO match.
    Descrip:   Fsearch() is a LOW Level file function that searches the
               .dbf in the current work area for any string.
               Kill search with K_ESC.
    Example:   USE Cus SHARED
               cSearch4  := "Micro"
               nStartAt  := 0
               lCaseSen  := (.F.)
               lContinue := (.T.)
               WHILE lContinue
                 dbGoTo(  Fsearch( cSearch4, @nStartAt, lCaseSen ) )
                 IF !EOF()
                    //-display data or do something
                    lContinue := ALERT("Search for Next?",;
                                        {"Ok","Cancel"})==1
                   ELSE
                    lContinue := (.F.)
                    Alert("End of Search!")
                   END
                END


    #include "inkey.ch"

    *---------------------------------------------------
    FUNCTION FSearch( cSearchStr, nStartAt, lIsCaseSen )
    *---------------------------------------------------
    LOCAL;
      cDbfFile   := ALIAS()+".DBF",;
      nBytesRead := 20000,;
      cBuffer    := SPACE(20000),;
      nFoundAt   := 0,;
      lFound     := (.F.),;
      nOffSet    := 0,;
      nRecNo     := 0

    nHandle := FOPEN( cDbfFile, 66)  //-open .dbf for SHARED use.
    FSEEK( nHandle, nStartAt, 0 )    //-Move to the starting point.

    //-Read 20,000 bytes per FREAD(), increase this number to cut down
    //-number of iterations - Kill with K_ESC
    WHILE nBytesRead == 20000 .AND. !lFound .AND. nHandle > -1 .AND.;
          INKEY()!=K_ESC
          nOffSet    := FSEEK(nHandle,0,1)
          nBytesRead := FREAD(nHandle,@cBuffer,20000)
          nFoundAt   := AT( IIF(!lisCaseSen,ALLTRIM(UPPER(cSearchStr)),;
                        ALLTRIM(cSearchstr)),;
                        IIF(!lisCaseSen,UPPER(cBuffer),;
                        cBuffer))
          lFound     := nFoundAt != 0
    END

    IF lFound
       nStartAt := nOffset + nFoundAt
       //-convert offset to .dbf Record number.
       nRecNo := ( nStartAt - HEADER() ) / RECSIZE()
       nRecNo := IF( MOD((nStartAt - HEADER()),;
                     RECSIZE()) !=             ;
                     0,INT(nRecNo)+1,nRecno)
       nRecno := IF(nRecNo==0,1,nRecNo)
    END

    nStartAt := IF( !lFound, 0, nStartAt )  //-Reset static if last search.
    FCLOSE( nHandle)                        //-Close DBF.
    RETURN ( nRecNo )


 8. UDF@Showcase.  Testing Critical Fields for Presence of Data.
    --------------------------------------------------------------------------
    ReplyTo: D. Buckman <70412.3222@CompuServe.COM>

    Here is one of the first and most used functions I have written.
    Granted is could be improved upon but it works and is generic for most
    of my applications.  I still remember the old DBase III days of 5 page
    validations PRGs plus the FMT:  what a mess to maintain.  With this
    routine you only need to code the GET's with VALID clauses.  Everything
    is in one place.

    Note.  This routine is an example of your tax dollars at work.  Written
    for US Army Corps Of Engineers way back when...  Since US tax dollars
    paid for it you may use it--JUST DON'T TRY TO SELL IT AS YOURS.

    * Program..: NOTVALID.PRG
    * Author...: D. BUCKMAN
    * Date.....: 09/02/92         Version 1.01
    * Notice...: Copyright (c) 1992,
    * Compiler.: CLIPPER, VERSION 5.01a
    * Libraries: CLIPPER, EXTEND
    * Notes....: Updated to CLIPPER 5.2c

    Function to test get field validations.  After READ has been executed
    but not CLEARed, use a READ SAVE command to accomplish this.  After
    this 'NOT_VALID' function call issue a CLEAR GETS to keep everything in
    order.

    USAGE:      IF  NOT_VALID(;
                    <expN1>, [<expO>, <expA>], <expL>, <expN2>, <expN3>)

    WHERE:  <expN1>- numeric variable, PASSED BY REFERENCE, to hold
                     numeric position within <expA> of the
                     getobject:postBlock which does not pass validation,
                     if <expA> is an object <expN1> will be 1 if
                     validation fails.  If all getobject:postBlocks are
                     True <expN1> will be zero.

            <expO> - Get Object to be tested.  If fails <expN1> will
                     be 1 else <expN1> will be 0.

            <expA> - Array of get objects to be validated, will use
                     visible 'GetList' array if <expA> if not an
                     object or array. If 'GetList' is NIL or not
                     visible <expA> will be set to an array of 0
                     length, {}.

            <expL> - logical .T. if to data to be displayed on screen for
                     error or valid condition, error is flashing valid in
                     standard unselected color, for data with VALID
                     clauses

            <expN2>- numeric value of first element in <expA> to start
                     with, default is 1.

            <expN3>- numeric value of last element in <expA> to stop with,
                     default is LEN( <expA> ).

    RETURNS:    .F. if all fields are valid  <expN1> # 0
                .T. if any field is invalid  <expN1> = 0 (Default)

    NOTE:  Two values will be passed to each validation clause.  The first
           will be the current Get object being evaluated followed by the
           current value of the get variable name.

                       EVAL( oGet:postBlock, oGet, xData )

    Sample Code Segment

    //- DISP_ERMSG() displays error messages to your customers.

    #include "INKEY.ch"

    LOCAL GetList   := {}         //-keep it local to allow nesting.
    LOCAL nGetField := 1

    cSrcTbl = SPACE( 254 )
    cMrgTbl = SPACE( 254 )
    cOtTbl  = SPACE( 254 )

    SET FUNCTION 10 TO CHR( K_CTRL_W )   //-My default F10 key setup

    @ MAXROW() -1, 10 SAY " Press 'F10' To Accept File Names. " ;
                      COLOR At_Msg_Col

    @ 10,10 SAY ' Enter Source Host Table File:'        ;
            GET  cSRCTbl PICTURE '@!S20'                ;
            VALID  {|oGet| FILE( LTRIM( TRIM( oGet:VarGet()))) .OR.;
                    DISP_ERMSG( ' You Must Enter A Valid '+ ;
                    'File Name. ',, oGet:Focus() )}

    @ 12,10 SAY ' Enter Merge Host Table File :'        ;
            GET   cMrgTbl PICTURE '@!S20'               ;
            VALID {|oGet| FILE( LTRIM( TRIM( oGet:VarGet() ))) } ;
            WHEN  {|oGet| !EMPTY( cSRCTbl ) }

        @ 14,10 SAY     ' Enter Output Host Table File:' ;
                GET     cOtTbl                           ;
                PICTURE '@!S20'                          ;
                VALID   {|oGet| EMPTY( oGet:VarGet() )}

        nGetField = 1        //-We usually start at first get field.
        DO WHILE  .T.        //-Don't exit loop until passes VALIDATION.
            SETCURSOR( 1 )   //-Turn Cursor ON.
            ReadModal( GetList, nGetField )
            SETCURSOR( 0 )   //-Turn Cursor OFF.
            nGetField  =  0
            IF  LASTKEY() # K_ESC .AND.                 ;
                NOT_VALID( @nGetField, GetList, .T. )
                //--- Screen of GETs did not validate
                //-tell everyone in the office
                TONE(300,1)
                TONE(499,3)
                TONE(700,3)
            ELSE
                //--- Screen of GETs validated ok so
                //-Press On With Pride....
                CLEAR GETS      //-This is required to reset GetSystem
                EXIT
            ENDIF
        ENDDO

        //-Update database and get next input. . .
        //-and so on and so on and so on  . . .

    End of Sample

    *------------------------------------------------------------------
    FUNCTION NOT_VALID( nFieldPos, aGetList, lDispData, nStart, nStop )
    *------------------------------------------------------------------
    MEMVAR  GetList
    LOCAL I, oGet
    LOCAL cGetColor, cDftColors, xData

    IF  VALTYPE( aGetList ) # 'A'
        IF  VALTYPE( aGetList ) == 'O'
            aGetList = { aGetList }
        ELSEIF  VALTYPE( aGetList ) # 'A'  .AND.  TYPE( 'GetList' ) == 'A'
            aGetList = GetList
        ELSE
            aGetList = {}
        ENDIF
    ENDIF

    nFieldPos = 0    //-Return bad field position (passed by reference )
    lDispData = IIF( VALTYPE( lDispData ) == 'L', lDispData, .T. )
    nStart    = IIF( VALTYPE( nStart ) # 'N', 1, nStart )
    nStop     = IIF( VALTYPE( nStop  ) # 'N', LEN( aGetList ), nStop  )

    cDftColors = SUBSTR( SETCOLOR(), AT(',', SETCOLOR() ) +1)
    cDftColors = SUBSTR( cDftColors, 1, AT(',', cDftColors ) -1) + ;
                 SUBSTR( cDftColors, RAT(',', cDftColors ) )

    FOR  I = nStart  TO  LEN( aGetList )
         oGet = aGetList[ I ]
         //-Test WHEN block if there is one
         IF IIF( ( oGet:preBlock <> NIL ),                   ;
                   Eval( oGet:preBlock, oGet ), .T.);  .AND. ;
                       ( oGet:postBlock <> NIL )

            //-Must be code block validation clause and valid WHEN block.
            IF  EVAL( oGet:PostBlock, oGet )
                //--- data was correct so make sure it is displayed
                //-correctly on the next pass.
                oGet:ColorSpec := STRTRAN( oGet:ColorSpec, '*', '')
            ELSE
                //--- data was not correct so make sure it is flashing
                //-the next time it is displayed with a GET/READ
                cGetColor = '*' + IIF( EMPTY( oGet:ColorSpec ), ;
                                       cDftColors, oGet:ColorSpec )
                oGet:colorSpec := cGetColor
                //-Do not update nFieldPos after first error field.
                nFieldPos = IIF( nFieldPos = 0, I, nFieldPos )
            ENDIF
            IF lDispData
               oGet:Display()
            ENDIF
        ENDIF
    NEXT
    RETURN( nFieldPos # 0 )  //--EOF NotValid


 9. UDF@Showcase.  ParseFilter()
    --------------------------------------------------------------------------
    ReplyTo: Jonathan Danylko <73361.2222@CompuServe.COM>
             Aspect Software, 1804 Treetop Drive, Erie, PA  16509

    *-------------------
    FUNCTION ParseFilter
    *------------------- Given a filter, parse elements into an array.
    * Parameters       : Character Filter
    * Returns	       : Array of the parsed filter
    * Note	       : If cCondition is empty, dbFilter() is used.

    LOCAL nAndAt
    LOCAL nOrAt
    LOCAL aConds := {}

    DEFAULT cCondition TO dbFilter()

    WHILE !EMPTY( ALLTRIM(cCondition) )
           nAndAt := AT(".AND.", cCondition )
           nOrAt  := AT(".OR.", cCondition )
           IF EMPTY(nAndAt) .AND. EMPTY(nOrAt)
              aAdd( aConds, ALLTRIM(cCondition) )
              cCondition := ""
              ELSEIF !EMPTY(nAndAt) .AND. EMPTY(nOrAt)
                     aAdd( aConds, ALLTRIM(SUBSTR(cCondition,1,nAndAt+5)))
                     cCondition := ALLTRIM(SUBSTR(cCondition,nAndAt+5))
              ELSEIF EMPTY(nAndAt) .AND. !EMPTY(nOrAt)
                     aAdd( aConds, ALLTRIM(SUBSTR(cCondition,1,nOrAt+4)))
                     cCondition := ALLTRIM(SUBSTR(cCondition,nOrAt+4))
              ELSEIF ( nAndAt < nOrAt)
                     aAdd( aConds, ALLTRIM(SUBSTR(cCondition,1,nAndAt+5)))
                     cCondition := ALLTRIM(SUBSTR(cCondition,nAndAt+5))
              ELSEIF ( nAndAt > nOrAt)
                     aAdd( aConds, ALLTRIM(SUBSTR(cCondition,1,nOrAt+4)))
                     cCondition := ALLTRIM(SUBSTR(cCondition,nOrAt+4))
              ENDIF
         ENDDO
    RETURN aConds


10. UDF@Showcase.   Imports Data from Mainframes.
    --------------------------------------------------------------------------
    ReplyTo:  Robert S. Torello   71610.3556@CompuServe.COM

    I don't always have control of the format of the downloads from the
    mainframe and occasionally get signed numerics with the high order bit
    set for +/-.   CtoNum() lets ME control the incoming data rather than
    waiting for mainframe programmers to change/fix download routines.

    *---------------------------
    FUNCTION CtoNum (cNum, nDec)
    *---------------------------
    * Purpose:  Convert Numerics stored as character string with highbit s
    * Input:    Character
    *           Number of decimals
    * Output:   Numeric.
    * Warning:  Decimal is implied.
    * Used for converting numbers stored as Character String numerics.
    * Handles converted mainframe fields of form 'S9'.
    * Syntax: CtoNum ( <cNum>, [<nDec>] ) -> nNum
    * Arguments
    *   <cNum> Character string number may have sign bit embedded as a h
    *   <nDec> Optional number of decimals, note decimal is implied
    * Returns: Value of stored number

    STATIC aSignChars := { {'{','A','B','C','D','E','F','G','H','I', '}',
                          {'0','1','2','3','4','5','6','7','8','9', '0',
    LOCAL nN, ;
          nNum

    IF ( nN := ASCAN( aSignChars[1], RIGHT(cNum,1) ) ) == 0
         nNum := VAL(cNum) / IIF(nDec==NIL, 1, nDec)
    ELSE
      IF nDec == NIL
         nNum := VAL( STUFF( cNum, LEN(cNum), 1, aSignChars[2,nN] )) * I
      ELSE
         nNum := VAL( STUFF( cNum, LEN(cNum), 1, aSignChars[2,nN] )) / n
      ENDIF
   ENDIF
   RETURN nNum


11. UDF@Showcase.  Saving Screen Coordinates with Save Screen.
    --------------------------------------------------------------------------
    ReplyTo:  Neil Price  <100075,430>

    The idea behind this pair of pseudo-functions is avoide bother of
    remembering screen co-ordinates of the screen area you just saved with
    savescreen().  Assigning the result of ScreenSave() to a variable
    assigns a five element array containing the four screen co-ordinates
    and the screen area itself.  ScreenRest() knows exactly what to do with
    these five elements.

    #translate ScreenSave( <tRow>, <tCol>, <bRow>, <bCol> );
            => { <tRow>, <tCol>, <bRow>, <bCol>, ;
               SAVESCREEN( <tRow>, <tCol>, <bRow>, <bCol> ) }

    #translate ScreenRest( <aScrn> );
            => RESTSCREEN( <aScrn>\[1], <aScrn>\[2] , <aScrn>\[3],
               <aScrn>\[<aScrn>\[5] )

    Put the following into a file "savescr.ch" and use as follows:

    #include "savescr.ch"
    local screen
    screen:=ScreenSave(10,10,15,70)
    dosomestuff()
    ScreenRest(screen)


12. UDF@Showcase.  VDATE() Adds Current Year to Date Input on READs
    --------------------------------------------------------------------------
    ReplyTo:  Andre Roy <ANDRE@EINSTEIN.UNIPISSING.CA> Programmer/Analyst
              Nipissing University, North Bay Ontario, Canada                                                                  |

    Users only have to type '01/27' with vDate(), assuming that the Date
    format is set to mm/dd/yy, and that the default year is set to the
    current year.  For example:

      dDate := ctod( "" )
      @10,10 get dDate valid { | oGet | vDate( oGet ) }
      read

    You do have to call it as a code block.  It only works if the date
    format is one in which the year is the last field, so it's not to good
    for ANSI style dates.

    #translate sz( <n>, <p> ) =>  padl( ltrim( str( <n> )), <p>, "0" )

    *---------------------
    function vDate( oGet )
    *---------------------
    local dd := oGet:varGet()
    local rr := ""
    local sCent, sDate, m, d, y

    if oGet:changed                       //-Never mind if no change.
       sCent := __SetCentury( .t. )       //-!!  INTERNAL  !!
       sDate := set( _SET_DATEFORMAT, "DD.MM.YYYY" )
       if year( dd ) % 100 == 0           //-No year on even century.
          d := day( dd )
          m := month( dd )
          if d == 0 .and. m == 0           //-Nothing entered.
            rr := ""
          else
            rr := sz( d, 2 ) + "." + sz( m, 2 ) + "."
            if sCent
              rr += sz( year( date()), 4 )
            else
              rr += sz( int( year( date()) % 100 ), 2 )
            endif
          endif
          oGet:varPut( ctod( rr ))       //-Put the new value into GET.
        endif
        set( _SET_DATEFORMAT, sDate )      //-restore this stuff
        __SetCentury( sCent )              //-!!  INTERNAL  !!
      endif                                //-oGet:changed
    return .t.                             //-Always


13. New Third Party Product:  MrDebug for CA-Clipper.
    --------------------------------------------------------------------------
    ReplyTo:   Roy Corneloues <100016.63@compuserve.com>
    Available: UK: SDC, tel: +44 (0) 452 812 733
               Germany: SOFTSOL: +49 (40) 766 12 90
               US, Building Blocks Publishing: 201 301 0822

    MrDebug, the premiere debugger for CA-Clipper 5.2d, has been designed
    by programmers, for programmers to reduce the amount of time spent
    debugging programs. As a beta tester, I can say its a really cool
    product, and the price (L99.00/$149.00) + TAX, makes it irresistible
    too.

    o Color Syntax Highlighting of Source Code makes it easy to tell the
      difference between keywords, operators, strings, numerics,
      # directives and comments.

    o Protected Mode Compatibility means there should be no problems with
      Blinker, Exospace, or Causeway.  No matter how big applications get,
      MrDebug will work.

    o Real Mode Support.  Over 90% of MrDebug can be overlaid with Blinker.
      For .RTLink users we have an entertaining link script.

    o Timing Runs.  Each run or step of code can be timed to provide
      accurate reflections of how long code will take to execute.

    o Pass Points let you mark a line of source code and have a counter
      incremented each time that the marked line of code is executed.

    o Enhanced Break/Trace/Watch Points.  Select and mark source code as a
      Trace or Watch point, including mark expressions as a trace or watch
      point.

    o Mouse support makes it easy to re-size and move windows, but you can
      also mark expressions for use as trace points or watch points.

    o Short-Cut Keys for most frequently used operations.

    o ALTD() function enhancements (can be disabled within source code):

      ALTD(0) - disables an <ALT D> keystroke
      ALTD(1) - enables  an <ALT D> keystroke
      ALTD(2) - Animate the program
      ALTD(3) - halt animation and run the program
      ALTD(4) - start speed mode
      ALTD(5) - halt speed mode
      ALTD(6) - bring up the workarea screen
      ALTD(7) - start profiling
      ALTD(8) - stop profiling

    o Enhanced Object Browser views CA-Clipper or Class(y) objects,
      including a class hierarchy structure for viewing class inheritance.

    o Real Screen Usage takes advantage of the text mode your video card
      supports.  Use 132 columns by 60 rows, for example, and you can end
      screen swap and constant flicking between the debugger and the
      application windows.

    o Enhanced Database Browser is more like DBU than CLD, and includes
      support for the SIX drivers and Comix.

    o Program Dump File can automatically create detailed information about
      status of programs as crashes occur, including variables, system
      error, workareas, screen shot and call stack.

    o Symbol Table Lists.  View and search through the symbol list(s) to
      work out just what exactly has been linked in and what hasn't.


    And the description of functionality goes on to include function list
    browsers, tracked variables, system error window, more run modes,
    workarea status windows, expression evaluator, profiling, etc.  Contact
    Roy!


14. Book on Clipper and Windows.
    --------------------------------------------------------------------------
    ReplyTo:  Craig Yellick <76247.541@compuserve.com>
              CIS:76247,541, INTERNET:76247.541@compuserve.com

    Got the VO fever?  Get a jump-start with 'La Strada del La Dolce Vita',
    subtitled, 'The Guide to Windows for Clipper Programmers'.  La Strada
    contains everything you need to protect your existing investment in
    Clipper while moving forward into Windows. Comes complete with an
    Educational Edition of Dolce Vita, no additional purchase necessary.


15. MIS Investment in Client/Server.
    --------------------------------------------------------------------------
    Reply To:  Franz-H. Mannsberger CIS: 100012,3304
               Vienna / Austria     I-Net: fmannsb@mannsberger.co.at
    Source:    "Computerwelt" Austria - (a IDG Communictions Company)

    The "Computerwelt" has asked several Manager in mid-europe, in what
    technology they will invest within the next 24 month.

    Interesting is that nearly the half said, they plan to invest in client
    server technology.  What does this mean to an independent software
    developer?  Suddenly C/S will be important within next decade.  But we
    already see some companies in the US and elsewhere, canceling their C/S
    projects, or at least think about them twice.

    While C/S looks very cost effective in the first run, a lot of people
    "forget" to mention the costs in the long run.  More training for
    administration, the costs for downsizing, the change of a already
    established infrastructure, to name only a few.

    Microsoft ACCESS is not bad as a front end to several SQL databases.
    It is suddenly not a fault to design an application with a later change
    to one of the several SQL RDBMS in mind.  Use what is useful from the
    C/S technology, wherever possible. However, with experience (in
    handling and design), some fine tuning and the right HW, ACCESS is able
    to compete with some of the "bigger" DBMS.

    "Computerwelt" - Investment Study.
    ---------------------------------------------------------------------
    Client/Server     ################################################ (48%)
    Open System       #################### (20%)
    EDS               ################# (17%)
    Object Oriented   ############# (13%)
    Wireless          ######## (8%)
    DBMS              ######## (8%)
    LAN               ###### (6%)
    MIS-/EIS-Systems  ##### (5%)


16. Editorial Positions for Advisor Publications.
    --------------------------------------------------------------------------
    ReplyTo:  John L. Hawkins [Advisor Pubs] <75300.575@CompuServe.COM>
              Editor-in-Chief, Advisor Publications Group
              4010 Morena Blvd #200, San Diego, CA 92117 USA
    Via:      Due to heavy travel, e-mail is the best way to reach John.
    Note;     Please, editorial candidates only.  No junk e-mail!

    I've been posting the following notice here and there, hoping to
    uncover some talented people who want to get involved with our
    magazines.  We are growing very rapidly, adding more titles this fall
    and more again next year.  If you know of anyone who's interested and
    qualified, please let me know. Feel free to post this in your
    newsletters.

    The publisher of several technical computer magazines is growing
    rapidly and needs top notch editorial people for present and future
    magazines.  Desirable background includes application development
    experience, database & client/server knowledge, technical orientation,
    and writing/editing experience. Here are some of the present needs:

     Managing Editor
     Technical Editor
     Technical Writer
     Copy Editor

    Living in sunny San Diego is the preferred arrangement, though free-
    lance e- mail collaboration is worth discussing for some positions.

    Help us turn complex technical information into superb magazine
    articles, and grow in an innovative editorial environment, as we
    produce the leading and fastest-growing group of developer-oriented
    magazines: DATA BASED ADVISOR, CLIENT/SERVER ADVISOR, ACCESS ADVISOR,
    CLIPPER ADVISOR, dBASE ADVISOR, FOXPRO ADVISOR, and more to come very
    soon.



17. ReCycling of Used Software.
    --------------------------------------------------------------------------
    ReplyTo:  Steve Graham <100033.1210@CompuServe.COM>

    If you're like me you've probably got several libraries and software
    that you used to use and it's now sitting in a corner someplace unused
    but you don't get rid of them because you paid good money for it and it
    was lead edge when you bought it?

    Editor's Note. Contact Steve if you have software that you would like
    to recycle.  If a sufficient number of people are interested, then
    let's consider organizing something official.


18. Resources for C++ Programmers.
    --------------------------------------------------------------------------
    ReplyTo:  Robin Rowe of Redmond, WA USA  <rrowe@halcyon.com>
    Note:     Ask to be put on the C++ Email Mailing List.

    Robin spoke on "Software Engineering in C++" at Object Expo in New York
    City on June 9th.  The text published in the conference proceedings
    (available from SIGS Conferences, Inc., 212-274-0646.  ISBN 1-884842-
    02-X).  Robin concentrated on code examples, mainly templates,
    demonstrating techniques to handle runtime errors.  Robin's
    presentation was one of the most code intensive at the conference, and
    participant response was positive.

    Robin will be presenting a similar talk, "C++ Engineering," at the
    Symantec Professional Developers Conference in Monterey in September.
    He will be presenting two topics there, the other is "C++ Testing."


19. FootNote on Internet/CompuServe.
    --------------------------------------------------------------------------
    ReplyTo:  Gagarin Sepulveda of Chile   taylor@cecux1.cec.uchile.cl

    Thanks for your advice concerning the Compuserve connection through
    Internet, which means saving a lot of money in monthly communications
    from Chile to USA.


20. BCNN Statement of Ownership, Copyright, and Responsibility.
    --------------------------------------------------------------------------
    The BCNN Newsletter is sponsored by the Xbase User Group of the Boston
    Computer Society.  BCNN is dedicated to keeping professional database
    developers (both consultants and corporate employees) informed about
    educational events, meetings, job openings, world events, notable
    articles, technical tips, new and 'must have' products, etc.

    As an electronic network, organized by interest rather than geography,
    BCNN is also a hub where developers can address world class issues to
    fellow developers around the world.  Recipients agree to respond via
    Email to periodic polls of their directions, opinions, and needs. For
    those who do not have User Groups in their areas, BCNN is a vehicle
    where individuals can volunteer and contribute to something larger than
    themselves.  Over 10,200 persons world-wide participate in discussions
    on CA-Clipper, Microsoft Access, FoxPro, and Suiteware.

    The newsletter is distributed monthly by electronic mail via CompuServe,
    Internet, FidoNet, and other electronic gateways.  It is free of charge
    to individual developers.  Modest fees are charged to corporations for
    job placement and third-party announcements.  Opinions expressed are
    solely expressed by the authors or by the Xbase Language Group of the
    Boston Computer Society, even in cases where 'Xbase Language Group'
    is abbreviated to 'BCS'.  All materials are copyrighted by the BCS,
    unless otherwise indicated, and free for any user group to
    redistribute on their own BBS on the condition that a by-line
    referencing the BCNN and the individual author are included.

    Les Squires, Director
    Xbase User Group
    c/o Word Jenny, Incorporated
    P. O. Box 126
    29 Brick Kiln Road, Kilnwood
    Center Harbor, New Hampshire 03226-0126 USA
    603-253-6109                  //-Primary Phone & Messages 24 hours
    603-253-7214                  //-Messages Only 24 hours
    603-253-9864                  //-Fax 24 hours a day
    INTERNET:bcnn@World.Std.Com   //-First choice for Email.
    CIS:73020,3435                //-Second choice for Email.

    Boston Computer Society, Inc.
    101 First Avenue, Suite 2
    Waltham, MA 02154
    617-290-5700  General Number
    617-290-5700  Ext. 432 for up-to-date meeting information.

    Add Subscribers:        @BCNN@ClipperYes to bcnn@World.Std.Com.
    Delete Subscribers:     @BCNN@ClipperNo  to bcnn@World.Std.Com.
    Address Change:         Email using OLD Address. Indicate New Address.
    Back Issues:            CompuServe CLIPPER Forum, LIBS 17.
                            FTP samba.iss.uw.edu.pl (CD pub/clipper/bcnn)

    BCNN Email Services donated by Word Jenny, Inc. LSquires@World.Std.Com

    (c) 1994 Boston Computer Society, Inc.
