HP3000-L Archives

October 2000, Week 4

HP3000-L@RAVEN.UTC.EDU

Options: Use Monospaced Font
Show Text Part by Default
Show All Mail Headers

Message: [<< First] [< Prev] [Next >] [Last >>]
Topic: [<< First] [< Prev] [Next >] [Last >>]
Author: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
Subject:
From:
Wirt Atmar <[log in to unmask]>
Reply To:
Date:
Sat, 28 Oct 2000 16:34:46 EDT
Content-Type:
text/plain
Parts/Attachments:
text/plain (771 lines)
Tom Jr. writes:

> Ric Merz wrote:
>  >
>  > Is this the same Basic/V that only allows 2 character data names (A1, A2,
>  > etc) and doesn't support the "packed numbers" data format?
>
>  It doesn't have a Long Integer either - just a Short Integer.

Almost all of the languages on the HP3000 support only a subset of the
datatypes that IMAGE uses. I spend my days looking at other peoples'
databases -- and I can tell virtually instantly what language the primary
application for the database was written in. COBOL-based databases are filled
with I, J, X, Z, and P dataitems, but no real numbers. In contrast, BASIC and
FORTRAN databases are populated generally onlywith I, X, and R fields.

Clearly, it would be better if all languages supported all datatypes, but
that's part and parcel of what the shared source program is all about. If you
now want an increased range of datatypes supported in BASIC, all you need do
is write the code and submit the modified source back to the "controlling
legal authority" [whoever that might be; I am actually a little unclear on
the details of the process :-)].

Nonetheless, BASIC's limitations shouldn't be taken as limitations. As long
as you have a CALL statement that allows you to call a
macroassembler/primitive programming language, you can do anything you need
to do. Traditionally, the macroassembler/primitive programming language has
been SPL on the HP3000.

Having BASIC on your resume is never going to do anyone any good, but if you
program from an engineering/business point of view, you're not as interested
in "geekiness" of the language that you're using. Rather, what you want to do
is lay down the most *behavior* you that you possibly can, in the shortest
period of time, and have it be as maintainable that you possibly can make it,
without requiring the employment of technical gurus. For those purposes,
BASIC is nearly the ideal upper level language.

I have for a very long time been enthusiastic about the notion of finite
state automata theory, for both the design of analog and digital hardware, as
well as software. Indeed, everything we've ever built here has been based
around the idea.

If you're familiar with the idea of Markov chains, then you are reasonably
familiar with the notions of finite state automata. The only difference is
that Markov chains are intrinsically an observational event; you have no idea
why the process changes state, all you do is simply measure and record the
probablity that it will change from its present state, and to which state it
will progress.

In FSA theory, the transition from state to state is most normally highly
deterministic, based on the presence of a signalling event. Virtually all
electronics instruments and real-time/event-driven programming practices
(such as HP's old RTE and Microsoft's VB) are built around the notion of FSA.
Further, I've always considered object-oriented programming practices to be a
subset of FSA.

However, after saying all of this, the idea is not complicated. An FSA
program exists in a hierarchy of layers, with the topmost being most normally
simply a "wait loop." Based on the input that the program receives in the
wait loop, the received command is directed to any one of a number of primary
behavior programs that sit just below the wait loop. These second-tier
primary behaviors can then call any number of highly modularized programs
that do one or a very few specific tasks, and no more. These task-specific
programs represent a third sublayer, with a fourth sublayer being the highly
optimized drivers and utilities.

While the upper two layers will represent about 95% of all of the code,
simply because they are the behavioral layers that create the program's
presentation to the world, the actual hard work of the program's processing
is done in the third- and fourth-level layers, and it's here that you spend
your time optimizing the code for maximal efficiency.

The upper layers tend to be supervisory -- and like any good supervisor, they
should do no real work themselves. Rather, they should simply walk around
with clipboard and pencil in hand and point out that this needs to be done,
and then that needs to be done, and in what order. The real work should be
done by the lower-level, highly optimized and efficient driver/utility drones.

This design architecture not only allows for very maintainable code that
tends to execute at very high speeds, it also allows for very high
plasticities (what biologists call "mosaic evolution"), such that major new
behaviors can be added (or dropped) without much affecting the whole of the
program -- while minimizing pleiotropies (interdependencies) in the code.

Bill Gates said a few years ago that he really loved Visual Basic, but that
it couldn't be used for the development of commercial products. I was
extremely disappointed to hear him say that, and a great portion of the
reason we put QCTerm together in VB was simply to demonstrate that Bill's
statement wasn't true. [However, when we first got QCTerm to begin to work,
it took something like 20 seconds to paint a screen -- and my heart sank. I
wasn't all that sure that we would ever get it to work fast enough. But now,
after a great deal of optimization and understanding of what was causing
those initital speed delays, QCTerm is faster than Reflection in every way
that we can measure].

QCTerm is programmed as a finite-state automaton. VB is the upper-level
supervisory code which calls a great number of APIs (intrinsics in HP3000
parlance).

QueryCalc, our primary product, is programmed in exactly the same way, being
composed of about 200 BASIC programs and 200 small, highly task-specific SPL
routines. Fifteen years ago, when we first began QueryCalc's design, we
looked at every language then available on the HP3000. BASIC easily won out
because it was not only the fastest high-level language availabe at the time,
it also has excellent string handling characteristics (which is an absolutely
necessary attribute for good user interface design) and a truly nice
BASIC-IMAGE interface.

But BASIC, as has been pointed out, also has some obvious deficiencies, so
almost immediately we wrote callable SPL subroutines to handle integers of
any reasonable length (I1, I2, I3, I4, etc.), as well as packed and zoned
numbers. Further, we found in our investigations that BASIC, in distinct
contrast to C, protects us too much, and thus file I/O is a little slow in
BASIC, and thus a good portion of the 200 SPL routines we wrote were for the
purposes of doing high-speed file transfers.

As long as I'm making this posting long, I've included below one module of
QueryCalc code -- now long obsolete -- that built color bitmaps inside the
HP3000 specifically for the then-popular HP PaintJet printers. We used to
have dozens of these routines for different printers before we adopted
PostScript as our primary printing language. This code is third-layer code
(in that it does some real work, but it is also supervisory in that it calls
the very low-level specific SPL routines that were written for this task; you
can see these routines peppered throughout the code)

This code is not only a good example of the mosaic evolutionary nature of the
design (major behaviors can be dropped in and out without affecting the
whole), it also exhibits two very important ideas in BASIC: code segmentation
and a COMMON area. The COMMON area is uniformly the same in all 200 QueryCalc
BASIC programs -- and represents both an easy data transfer mechanism between
programs (which might be called "pipes", and are the strings I$, I1$, I2$)
but it is also the finite state table(s) necessary to
FSA/real-time/event-driven programming. There is one table on page 3-6 in the
BASIC compiler manual that is so important to this idea that it should be
memorized. As you'll see on the chart, the COMMON area is static; the
segmented program local variables move up and down on the stack as necessary.

Nonetheless, after saying all of this, you don't need to worry about any of
this when you first start writing IMAGE-interactive programs in BASIC. Nor do
you need to curse the deficiencies of BASIC; given a proper architectural
design, you can do anything you wish.

Wirt Atmar

========================================

QCPJPIE
 1000 REM **************************************************************
 1010 REM
 1020 REM   QueryCalc Graphic routines
 1030 REM
 1040 REM       Types: PaintJet Graphs
 1050 REM
 1060 REM            100%/Pie Chart
 1070 REM
 1080 REM **************************************************************
 1090 COM I$[255],I1$[255],I2$[255],Q$[25,255],B$[30],F9$[2],N9$[30]
 1100 COM P$[10,60],L9$[255],L8$[255],D$[10,60],B1$[30],P7$[10]
 1110 COM INTEGER W[26,26],A[26],K0[26],J0[26],P7[26]
 1120 COM R,C,X,Y,P,C1,E,M,W1
 1130 COM LONG R0[6]
 1140 COM C[20],F3$[6],F4$[6]
 1150 COM R5[2340]
 1160 COM INTEGER R6[26],K[3],P[8],M5,V5,U5,M0[5],F[40],G[26,3]
 1170 REM **************************************************************
 1180 DIM I3$[255],I4$[255],I5$[8,100],I6$[255],H$[100],L5$[10,50]
 1190 DIM I9$[3,255],A$[255]
 1200 DIM G1$[60],G2$[60],G3$[20]
 1210 INTEGER X[4],X0,X1,Y1,Y4,Y9,C0[10],C1[10],F9,B9,T9[2700],B0,B1
 1220 INTEGER G0,G5
 1230 DIM X0[10],Y0[10],X1[10],Y1[10],X2[10],Y2[10]
 1240 DIM D1[10],M1[10],M2[10],F1[10],F2[10],L0[10],L1[10]
 1250 DIM X4[10],Y4[10],D4[10]
 1260 MAT X=ZER
 1270 DEF INTEGER FNM(X)=X
 1280 REM **************************************************************
 1290 REM   Variables:
 1300 REM
 1310 REM      R1 - Graph minimum
 1320 REM      R2 - Graph maximum
 1330 REM      W8 - Bar width
 1340 REM      W9 - Graph width
 1350 REM      D8 - No. of Data Points
 1360 REM      S8 - Graph Delta (Scale)
 1370 REM      S9 - Graph Spacing
 1380 REM      T9 - Type of Graph Spacing (0-Spaces at Top & Bottom)
 1390 REM                                 (1-No Spaces at T & B)
 1400 REM   D1[*] - Data
 1410 REM   D2[*] - Bar widths for X# of Data Points
 1420 REM   D4[*] - Direction for labels (0-leftwards, 1-rightwards)
 1430 REM   F1[*] - angle in radians of lesser pie border
 1440 REM   F2[*] - angle in radians of greater pie border
 1450 REM   Y0[*] - value of Y-offset to move pie segment outwards
 1460 REM   X0[*] - value of X-offset to move pie segment outwards
 1470 REM   Y1[*] - value of outer limits of lesser pie line (y)
 1480 REM   Y2[*] - value of outer limits of greater pie line (y)
 1490 REM   X1[*] - value of outer limits of lesser pie line (x)
 1500 REM   X2[*] - value of outer limits of greater pie line (x)
 1510 REM   X4[*] - location where label is to be written
 1520 REM   Y4[*] - location where label is to be written
 1530 REM   M1[*] - slope of lesser pie line
 1540 REM   M2[*] - slope of greter pie line
 1550 REM  L5$[*] - Data Point Labels (8 chars)
 1560 REM     G1$ - Graph Title
 1570 REM      T5 - Transparency flag (0 = normal, 1 = trancparency)
 1580 REM      G5 - First segment flag (0 = normal, 1 = >75%)
 1590 REM
 1600 REM **************************************************************
 1610 CALL SHRINKSTACK(FNM(0))
 1620 G1$=G2$=G3$=""
 1630 MAT L5$=NUL$
 1640 H$[1,100]=" "
 1650 R1=R2=W8=W9=D8=S9=E9=E=T5=0
 1660 MAT D1=ZER
 1670 E=0
 1680 REM *********************
 1690 REM   Read the Graph
 1700 REM   Information
 1710 REM *********************
 1720 CALL READPAGE(F[2],R5[*],NUM(I$)-64,E1)
 1730 IF E1<>0 THEN DO
 1740   E=142
 1750   END
 1760 DOEND
 1770 G1$=FNV$(ABS(R5[55]))
 1780 G2$=UPS$(FNV$(ABS(R5[368])))
 1790 I3$=UPS$(DEB$(FNV$(ABS(R5[394]))))
 1800 IF I3$[1;1]="Y" THEN T5=1
 1810 S8=0
 1820 Z9=184
 1830 IF R5[Z9]=0 THEN 1930
 1840 S8=S8+1
 1850 D1[S8]=FNV(ABS(R5[Z9]))
 1860 IF D1[S8]<0 THEN DO
 1870   E=166
 1880   END
 1890 DOEND
 1900 IF S8=7 THEN 1930
 1910 Z9=Z9+26
 1920 GOTO 1830
 1930 IF S8=0 THEN DO
 1940   E=136
 1950   END
 1960 DOEND
 1970 FOR Z9=1 TO S8
 1980   IF R5[185+(Z9-1)*26]=0 THEN 2000
 1990   L5$[Z9]=FNV$(ABS(R5[185+(Z9-1)*26]))
 2000 NEXT Z9
 2010 REM **************************************************************
 2020 REM   Draw the Graph
 2030 REM **************************************************************
 2040 RESTORE 2450
 2050 G0=7
 2060 B0=0
 2070 B1=0
 2080 IF G2$[1,2]="BL" THEN DO
 2090   RESTORE 2530
 2100   G0=7
 2110   B0=6
 2120   B1=0
 2130 DOEND
 2140 IF G2$[1,2]="YE" THEN DO
 2150   RESTORE 2450
 2160   G0=7
 2170   B0=0
 2180   B1=3
 2190 DOEND
 2200 IF G2$[1,2]="TU" THEN DO
 2210   RESTORE 2610
 2220   G0=7
 2230   B0=2
 2240   B1=6
 2250 DOEND
 2260 IF G2$[1,2]="OR" THEN DO
 2270   RESTORE 2610
 2280   G0=7
 2290   B0=1
 2300   B1=3
 2310 DOEND
 2320 IF G2$[1,2]="GR" THEN DO
 2330   RESTORE 2610
 2340   G0=7
 2350   B0=3
 2360   B1=2
 2370 DOEND
 2380 IF G2$[1,2]="RE" THEN DO
 2390   RESTORE 2450
 2400   G0=7
 2410   B0=1
 2420   B1=1
 2430 DOEND
 2440 REM yellow/blue/gray/org/grn/coral/pink
 2450 DATA 6,0
 2460 DATA 3,0
 2470 DATA 5,0
 2480 DATA 1,0
 2490 DATA 4,3
 2500 DATA 2,0
 2510 DATA 1,3
 2520 REM yellow/pink/gray/org/grn/coral/lt.grn
 2530 DATA 3,3
 2540 DATA 5,0
 2550 DATA 4,3
 2560 DATA 1,3
 2570 DATA 2,3
 2580 DATA 5,3
 2590 DATA 6,3
 2600 REM yellow/blue/gray/pink/lt.yel/coral/lt.grn
 2610 DATA 3,3
 2620 DATA 6,0
 2630 DATA 7,0
 2640 DATA 5,0
 2650 DATA 5,7
 2660 DATA 5,3
 2670 DATA 6,3
 2680 FOR Z=1 TO 7
 2690   READ C0[Z],C1[Z]
 2700 NEXT Z
 2710 FOR V=1 TO S8
 2720   T0=0
 2730   FOR Z=V TO S8
 2740     IF D1[Z]>T0 THEN DO
 2750       T0=D1[Z]
 2760       Z9=Z
 2770     DOEND
 2780   NEXT Z
 2790   T2=D1[V]
 2800   D1[V]=D1[Z9]
 2810   D1[Z9]=T2
 2820   T2=C0[V]
 2830   C0[V]=C0[Z9]
 2840   C0[Z9]=T2
 2850   T2=C1[V]
 2860   C1[V]=C1[Z9]
 2870   C1[Z9]=T2
 2880   I3$=L5$[V]
 2890   L5$[V]=L5$[Z9]
 2900   L5$[Z9]=I3$
 2910 NEXT V
 2920 V=S8
 2930 IF D1[V]=0 THEN DO
 2940   S8=S8-1
 2950   IF S8>0 THEN 2920
 2960 DOEND
 2970 IF S8=0 THEN DO
 2980   E=136
 2990   END
 3000 DOEND
 3010 GOTO 3530
 3020 REM*************************************
 3030 REM  By skipping over the next section of
 3040 REM  code, the graph will not be inter-
 3050 REM  leaved in its sort (big,small,big...)
 3060 REM*************************************
 3070 FOR V=1 TO S8 STEP 2
 3080   T0=0
 3090   T1=1L77
 3100   Z9=V
 3110   FOR Z=V TO S8
 3120     IF D1[Z]>T0 THEN DO
 3130       T0=D1[Z]
 3140       Z9=Z
 3150     DOEND
 3160   NEXT Z
 3170   IF T0>0 THEN DO
 3180     T2=D1[V]
 3190     D1[V]=D1[Z9]
 3200     D1[Z9]=T2
 3210     T2=C0[V]
 3220     C0[V]=C0[Z9]
 3230     C0[Z9]=T2
 3240     T2=C1[V]
 3250     C1[V]=C1[Z9]
 3260     C1[Z9]=T2
 3270     I3$=L5$[V]
 3280     L5$[V]=L5$[Z9]
 3290     L5$[Z9]=I3$
 3300   DOEND
 3310   Z8=V+1
 3320   FOR Z=V+1 TO S8
 3330     IF D1[Z]<T1 THEN DO
 3340       T1=D1[Z]
 3350       Z8=Z
 3360     DOEND
 3370   NEXT Z
 3380   IF T1<1L77 THEN DO
 3390     T2=D1[V+1]
 3400     D1[V+1]=D1[Z8]
 3410     D1[Z8]=T2
 3420     T2=C0[V+1]
 3430     C0[V+1]=C0[Z8]
 3440     C0[Z8]=T2
 3450     T2=C1[V+1]
 3460     C1[V+1]=C1[Z8]
 3470     C1[Z8]=T2
 3480     I3$=L5$[V+1]
 3490     L5$[V+1]=L5$[Z8]
 3500     L5$[Z8]=I3$
 3510   DOEND
 3520 NEXT V
 3530 T0=0
 3540 FOR Z=1 TO S8
 3550   T0=T0+D1[Z]
 3560 NEXT Z
 3570 IF T0=0 THEN DO
 3580   E=185
 3590   END
 3600 DOEND
 3610 FOR Z=1 TO S8
 3620   D1[Z]=D1[Z]/T0
 3630 NEXT Z
 3640 G5=0
 3650 IF D1[1]>.75 THEN DO
 3660   G5=1
 3670   FOR Z=S8 TO 2 STEP -1
 3680     D1[Z+1]=D1[Z]
 3690     C0[Z+1]=C0[Z]
 3700     C1[Z+1]=C1[Z]
 3710     L5$[Z+1]=L5$[Z]
 3720   NEXT Z
 3730   C0[2]=C0[1]
 3740   C1[2]=C1[1]
 3750   D1[2]=D1[1]-.75
 3760   D1[1]=.75
 3770   L5$[2]=""
 3780   S8=S8+1
 3790 DOEND
 3800 SYSTEM E9,"PURGE QCBITMAP,TEMP"
 3810 SYSTEM E9,"BUILD QCBITMAP;REC=2700,5,F,BINARY;DISC=80;TEMP"
 3820 I3$[1,28]="QCBITMAP"
 3830 CALL OPENFILE(I3$,F9,E9)
 3840 IF E9<>0 THEN DO
 3850   E=101
 3860   END
 3870 DOEND
 3880 P2=6.28319
 3890 A=.8
 3900 R0=250
 3910 R1=A*250
 3920 S7=0
 3930 CALL BACKGROUND(F9,B9,T9[*],G0,B0,B1,E9)
 3940 FOR Z=1 TO S8
 3950   F1[Z]=S7
 3960   F2[Z]=D1[Z]*P2+S7
 3970   S7=F2[Z]
 3980 NEXT Z
 3990 FOR Z=1 TO S8
 4000   IF G5=1 AND Z<3 THEN DO
 4010     IF Z=1 THEN DO
 4020       X0[1]=INT(20*SIN((F1[1]+F2[2])/2))+720
 4030       Y0[1]=INT(20*A*COS((F1[1]+F2[2])/2))+336
 4040     DOEND
 4050     ELSE DO
 4060       Y0[2]=Y0[1]
 4070       X0[2]=X0[1]
 4080     DOEND
 4090   DOEND
 4100   ELSE DO
 4110     X0[Z]=INT(20*SIN((F1[Z]+F2[Z])/2))+720
 4120     Y0[Z]=INT(20*A*COS((F1[Z]+F2[Z])/2))+336
 4130   DOEND
 4140   X1[Z]=INT(R0*SIN(F1[Z]))+X0[Z]
 4150   Y1[Z]=INT(R1*COS(F1[Z]))+Y0[Z]
 4160   X2[Z]=INT(R0*SIN(F2[Z]))+X0[Z]
 4170   Y2[Z]=INT(R1*COS(F2[Z]))+Y0[Z]
 4180   IF F2[Z]=P2 THEN X2[Z]=X2[Z]-1
 4190   M1[Z]=(X1[Z]-X0[Z])/(Y1[Z]-Y0[Z])
 4200   M2[Z]=(X2[Z]-X0[Z])/(Y2[Z]-Y0[Z])
 4210   X5=X1[Z]
 4220   Y9=Y1[Z]
 4230   GOSUB 5610
 4240   F1[Z]=F5
 4250   X5=X2[Z]
 4260   Y9=Y2[Z]
 4270   GOSUB 5610
 4280   F2[Z]=F5
 4290   IF F2[Z]<F1[Z] THEN F2[Z]=P2
 4300   X[1]=Y0[Z]
 4310   IF 0>=F1[Z] AND 0<=F2[Z] THEN X[1]=Y0[Z]+A*R0
 4320   IF P2/2>=F1[Z] AND P2/2<=F2[Z] THEN X[1]=Y0[Z]-A*R0
 4330   X[2]=Y0[Z]
 4340   X[3]=Y1[Z]
 4350   X[4]=Y2[Z]
 4360   GOSUB 5500
 4370   L0[Z]=X[1]
 4380   L1[Z]=X[4]
 4390 NEXT Z
 4400 MAT D4=ZER
 4410 Y5=670
 4420 FOR Z=S8 TO 1 STEP -1
 4430   IF (F1[Z]+F2[Z])/2>P2/2 THEN DO
 4440     IF Z=S8 AND D1[Z]<.07 THEN DO
 4450       D4[Z]=1
 4460     DOEND
 4470   DOEND
 4480   ELSE DO
 4490     D4[Z]=1
 4500   DOEND
 4510   Y4[Z]=INT(R1*1.2*COS((F1[Z]+F2[Z])/2))+Y0[Z]+10
 4520   IF D4[Z]=0 THEN X4[Z]=INT(R0*1.2*SIN((F1[Z]+F2[Z])/2))+X0[Z]
 4530   IF D4[Z]=1 THEN X4[Z]=INT(R0*1.2*SIN((F1[Z]+F2[Z])/2))+X0[Z]
 4540   IF D4[Z]=0 THEN DO
 4550     IF Y4[Z]<Y5-30 THEN Y5=Y4[Z]
 4560     ELSE Y5=Y4[Z]=Y5-30
 4570   DOEND
 4580 NEXT Z
 4590 FOR Y9=1 TO 672
 4600   FOR Z=1 TO S8
 4610     IF Y9>=L0[Z] AND Y9<=L1[Z] THEN DO
 4620       MAT X=ZER
 4630       X5=INT(M1[Z]*(Y9-Y0[Z]))+X0[Z]
 4640       IF X1[Z]<=X0[Z] AND X5>=X1[Z] AND X5<=X0[Z] THEN DO
 4650         IF Y1[Z]<=Y0[Z] THEN DO
 4660           IF Y9<=Y0[Z] AND Y9>=Y1[Z] THEN GOSUB 5700
 4670         DOEND
 4680         IF Y0[Z]<Y1[Z] THEN DO
 4690           IF Y9<=Y1[Z] AND Y9>=Y0[Z] THEN GOSUB 5700
 4700         DOEND
 4710       DOEND
 4720       IF X0[Z]<X1[Z] AND X5>=X0[Z] AND X5<=X1[Z] THEN DO
 4730         IF Y1[Z]<=Y0[Z] THEN DO
 4740           IF Y9<=Y0[Z] AND Y9>=Y1[Z] THEN GOSUB 5700
 4750         DOEND
 4760         IF Y0[Z]<Y1[Z] THEN DO
 4770           IF Y9<=Y1[Z] AND Y9>=Y0[Z] THEN GOSUB 5700
 4780         DOEND
 4790       DOEND
 4800       X5=INT(M2[Z]*(Y9-Y0[Z]))+X0[Z]
 4810       IF X2[Z]<=X0[Z] AND X5>=X2[Z] AND X5<=X0[Z] THEN DO
 4820         IF Y2[Z]<=Y0[Z] THEN DO
 4830           IF Y9<=Y0[Z] AND Y9>=Y2[Z] THEN GOSUB 5700
 4840         DOEND
 4850         IF Y0[Z]<Y2[Z] THEN DO
 4860           IF Y9<=Y2[Z] AND Y9>=Y0[Z] THEN GOSUB 5700
 4870         DOEND
 4880       DOEND
 4890       IF X0[Z]<X2[Z] AND X5>=X0[Z] AND X5<=X2[Z] THEN DO
 4900         IF Y2[Z]<=Y0[Z] THEN DO
 4910           IF Y9<=Y0[Z] AND Y9>=Y2[Z] THEN GOSUB 5700
 4920         DOEND
 4930         IF Y0[Z]<Y2[Z] THEN DO
 4940           IF Y9<=Y2[Z] AND Y9>=Y0[Z] THEN GOSUB 5700
 4950         DOEND
 4960       DOEND
 4970       X5=INT(SQR((A*R0)**2-(Y9-Y0[Z])**2)/A)+X0[Z]
 4980       GOSUB 5610
 4990       X5=2*X0[Z]-X5
 5000       GOSUB 5610
 5010       CALL LINECOLOR(F9,B9,T9[*],Y9,X[1],X[2],C0[Z],C1[Z],E9)
 5020     DOEND
 5030   NEXT Z
 5040 NEXT Y9
 5050 FOR Z=1 TO S8
 5060   X0=INT(R0*SIN(F1[Z]))+X0[Z]-1
 5070   FOR T0=F1[Z] TO F2[Z] STEP .008
 5080     X1=INT(R0*SIN(T0))+X0[Z]
 5090     Y1=INT(R1*COS(T0))+Y0[Z]
 5100     CALL BUILDGRAPH(F9,B9,T9[*],X1,Y1,E9)
 5110     IF X1<>X0 THEN DO
 5120       IF T0<P2/4 OR T0>3*P2/4 THEN DO
 5130         FOR Y4=1 TO 10 STEP 2
 5140           CALL BUILDGRAPH(F9,B9,T9[*],X1,Y1+Y4,E9)
 5150         NEXT Y4
 5160       DOEND
 5170       X0=X1
 5180     DOEND
 5190   NEXT T0
 5200   FOR T0=F1[Z] TO F2[Z]*1.0001 STEP F2[Z]-F1[Z]
 5210     IF G5=1 AND (Z=2 AND T0=F1[Z] OR Z=1 AND T0>F1[Z]) THEN 5380
 5220     A1=SIN(T0)
 5230     A2=A*COS(T0)
 5240     X0=X0[Z]-1
 5250     FOR R5=0 TO 250 STEP 2
 5260       X1=INT(R5*A1)+X0[Z]
 5270       Y1=INT(R5*A2)+Y0[Z]
 5280       CALL BUILDGRAPH(F9,B9,T9[*],X1,Y1,E9)
 5290       IF X1<>X0 THEN DO
 5300         IF F1[Z]<P2/2 AND T0=F1[Z] AND T0>0 OR F2[Z]>P2/2 AND T0=&
     F2[Z] AND T0<P2 THEN DO
 5310           FOR Y4=1 TO 10 STEP 2
 5320             CALL BUILDGRAPH(F9,B9,T9[*],X1,Y1+Y4,E9)
 5330           NEXT Y4
 5340         DOEND
 5350         X0=X1
 5360       DOEND
 5370     NEXT R5
 5380   NEXT T0
 5390   IF G5=1 AND Z=2 THEN 5470
 5400   A1=SIN((F1[Z]+F2[Z])/2)
 5410   A2=A*COS((F1[Z]+F2[Z])/2)
 5420   FOR R5=220 TO 280 STEP 2
 5430     X1=INT(R5*A1)+X0[Z]
 5440     Y1=INT(R5*A2)+Y0[Z]
 5450     CALL BUILDGRAPH(F9,B9,T9[*],X1,Y1,E9)
 5460   NEXT R5
 5470 NEXT Z
 5480 GOTO 5810
 5490 REM***************************************************************
 5500 FOR I5=1 TO 4
 5510   FOR I6=I5+1 TO 4
 5520     IF X[I6]<X[I5] THEN DO
 5530       T=X[I5]
 5540       X[I5]=X[I6]
 5550       X[I6]=T
 5560     DOEND
 5570   NEXT I6
 5580 NEXT I5
 5590 RETURN
 5600 REM***************************************************************
 5610 A5=(X5-X0[Z])
 5620 B5=(Y9-Y0[Z])/A
 5630 F5=ATN(ABS(A5/B5))
 5640 IF A5>=0 AND B5<0 THEN F5=P2/2-F5
 5650 IF A5<=0 AND B5<=0 THEN F5=F5+P2/2
 5660 IF A5<0 AND B5>0 THEN F5=P2-F5
 5670 IF F5<=F2[Z]*1.001 AND F5>=F1[Z]/1.001 THEN GOSUB 5700
 5680 RETURN
 5690 REM***************************************************************
 5700 IF ABS(X5-X[2])<2 THEN 5780
 5710 IF X5>X[2] THEN DO
 5720   X[1]=X[2]
 5730   X[2]=X5
 5740 DOEND
 5750 ELSE DO
 5760   IF X5>X[1] THEN X[1]=X5
 5770 DOEND
 5780 RETURN
 5790 REM***************************************************************
 5800 REM  Routine to play out the graph to PaintJet
 5810 REM***************************************************************
 5820 I6$='27"&k0S"'27"&l6D"'27"(s0B"'27"*t180R"'27"*r3U"'27"*b1M"'27&
     "*r0A"'27"&a+276V"
 5830 CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 5840 I5$[1]='27"*v90A"'27"*v88B"'27"*v85C"
 5850 I5$[2]='27"*v53A"'27"*v8B"'27"*v14C"
 5860 I5$[3]='27"*v3A"'27"*v26B"'27"*v22C"
 5870 I5$[4]='27"*v89A"'27"*v83B"'27"*v13C"
 5880 I5$[5]='27"*v4A"'27"*v4B"'27"*v29C"
 5890 I5$[6]='27"*v53A"'27"*v5B"'27"*v25C"
 5900 I5$[7]='27"*v2A"'27"*v22B"'27"*v64C"
 5910 I5$[8]='27"*v4A"'27"*v4B"'27"*v6C"
 5920 FOR Z=1 TO 8
 5930   CONVERT Z-1 TO A$
 5940   I6$=I5$[Z]+'27"*v"+A$+"I"
 5950   CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 5960 NEXT Z
 5970 I6$=H$[1,(80-LEN(G1$))/2]+G1$+'27"&a+100V"
 5980 CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 5990 FOR Y9=1 TO 676
 6000   CALL BREAKLINE(F9,B9,T9[*],Y9,I9$[1],I9$[2],I9$[3],E9)
 6010   FOR Z=1 TO 3
 6020     CALL RUNTIME(I9$[Z],R0)
 6030     CONVERT R0 TO A$
 6040     IF Z<3 THEN I6$='27"*b"+A$+"V"+I9$[Z]
 6050     IF Z=3 THEN I6$='27"*b"+A$+"W"+I9$[Z]
 6060     CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 6070   NEXT Z
 6080   IF T5=1 THEN DO
 6090     FOR Z=1 TO S8
 6100       IF Y9=Y4[Z] THEN DO
 6110         IF G5=1 AND Z<3 THEN DO
 6120           IF Z=1 THEN DO
 6130             CONVERT INT((D1[1]+D1[2])*1000)/10 TO A$
 6140             L5$[1]=DEB$(L5$[1])+" ("+A$+"%)"
 6150           DOEND
 6160           ELSE DO
 6170             L5$[Z]=""
 6180           DOEND
 6190         DOEND
 6200         ELSE DO
 6210           CONVERT INT(D1[Z]*1000)/10 TO A$
 6220           L5$[Z]=DEB$(L5$[Z])+" ("+A$+"%)"
 6230         DOEND
 6240         IF D4[Z]=0 THEN CONVERT X4[Z]*4-LEN(L5$[Z])*60 TO A$
 6250         IF D4[Z]=1 THEN CONVERT X4[Z]*4 TO A$
 6260         I6$='27"&k4S"'27"&a"+A$+"H"+L5$[Z]
 6270         CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 6280       DOEND
 6290     NEXT Z
 6300   DOEND
 6310 NEXT Y9
 6320 IF T5=0 THEN DO
 6330   I6$='27"&a-2704V"
 6340   CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 6350   T0=1
 6360   FOR Y9=1 TO 676
 6370     FOR Z=1 TO S8
 6380       IF Y9=Y4[Z] THEN DO
 6390         IF G5=1 AND Z<3 THEN DO
 6400           IF Z=1 THEN DO
 6410             CONVERT INT((D1[1]+D1[2])*1000)/10 TO A$
 6420             L5$[1]=DEB$(L5$[1])+" ("+A$+"%)"
 6430           DOEND
 6440           ELSE DO
 6450             L5$[Z]=""
 6460           DOEND
 6470         DOEND
 6480         ELSE DO
 6490           CONVERT INT(D1[Z]*1000)/10 TO A$
 6500           L5$[Z]=DEB$(L5$[Z])+" ("+A$+"%)"
 6510         DOEND
 6520         IF D4[Z]=0 THEN CONVERT X4[Z]*4-LEN(L5$[Z])*60 TO A$
 6530         IF D4[Z]=1 THEN CONVERT X4[Z]*4 TO A$
 6540         I6$='27"&k4S"'27"&a"+A$+"H"+L5$[Z]
 6550         CONVERT (Y9-T0)*4 TO A$
 6560         I6$='27"&a+"+A$+"V"+I6$
 6570         CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 6580         T0=Y9
 6590       DOEND
 6600     NEXT Z
 6610   NEXT Y9
 6620   CONVERT (676-T0)*4 TO A$
 6630   I6$='27"&a+"+A$+"V"
 6640   CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 6650 DOEND
 6660 I6$='27"*rB"'27"&k0S"'27"&a+280V"'27"&a0H"
 6670 CALL GRAPHWRITE(F[3],I6$,FNM(LEN(I6$)),E9)
 6680 CALL CLOSEFILE(F9,E9)
 6690 END
 6700 REM **************************************************************
 6710 REM
 6720 REM   Function to return the numeric value of a cell.
 6730 REM
 6740 REM     Parameters:  R0 - record number of the cell
 6750 REM         Return:  Long number value of the cell
 6760 REM
 6770 REM **************************************************************
 6780 DEF LONG FNV(REAL R0)
 6790   DIM C$[255]
 6800   LONG V
 6810   V=0L0
 6820   CALL GETACELL(F[1],C$,R0,K8)
 6830   CALL STRINGTOLONG(C$[4;8],V)
 6840   RETURN V
 6850 FNEND
 6860 REM **************************************************************
 6870 REM
 6880 REM   Function to return the text value of a cell.
 6890 REM
 6900 REM     Parameters:  R0 - record number of the cell
 6910 REM         Return:  Text value returned
 6920 REM
 6930 REM **************************************************************
 6940 DEF FNV$(REAL R0)
 6950   DIM C$[255],V$[255]
 6960   REAL T
 6970   V$=""
 6980   CALL GETACELL(F[1],C$,R0,K8)
 6990   IF C$[1;1]="N" OR C$[1;1]="R" THEN DO
 7000     IF C$[63;1]=" " THEN DO
 7010       I$=C$[25;2]+C$[4;8]
 7020       INVOKE "QCFORMAT"
 7030       C$[27;36]=I$
 7040       C$[63;1]="*"
 7050       CALL PUTACELL(F[1],C$,R0,K8)
 7060     DOEND
 7070     V$=DEB$(C$[27;36])
 7080   DOEND
 7090   IF C$[1;1]="$" OR C$[1;1]="Q" THEN DO
 7100     CALL STRINGTODBLE(C$[12;4],T)
 7110     CALL READTEXT(V$,T,F[*],K8)
 7120   DOEND
 7130   IF C$[1;1]="T" THEN DO
 7140     V$=DEB$(C$[64;186])
 7150   DOEND
 7160   RETURN DEB$(V$)
 7170 FNEND
 7180 REM **************************************************************

========================================

ATOM RSS1 RSS2