[comp.sys.handhelds] SWING for HP48

lennartb@lne.kth.se (Lennart Brjeson @ KTH, Stockholm) (03/12/91)

**HP48**

This is SWING for the HP48. SWING was named after an old PD utility for VMS.
SWING draws a tree representing your entire directory structure and lets
you walk around in it using the cursor key. SWING "precompiles" the tree so
it can be redrawn easily, this means that you must execute the SWSAVE routine
anytime you have created or deleted directories if the SWING tree is to be
correct. SWING is written in user RPL but I myself find the speed acceptable.
SWING must be installed as a library (or be placed in the HOME directory) in
order to work. Exit SWING by pressing ENTER, this will change your path to
the one indicated. RUBOUT (key 55) quits without changing the path.
SWING is assigned library 1644, BTW.

Library and source follows.

The library in ASC format:
--Cut here-----------------------------
%%HP: T(3)A(D)F(.);
"04B201171011357594E47402269702C456E6E61627472411C664100000000DC0
002A610E4A20EB00000000000000000064000E40006700000000000000000000
00000000000000000000000000000000005000404524C44430050357594E4740
005035757454452005074C424C44440060357535146554100E30006100093000
A500043000E4A20F50001600039100872004F20053300F46000770029800F690
0DF900B701098210A0310DD310C74103C41035510B75108C66000D9D20E16323
CE22491A14563284E204005051425976324BAC1AFE22D9D2084E204005051425
9C2A2387C147A2084E204005051425DCC02B213076BA1B21305BF2247A2047A2
084E204005051425B2130EFE02B21305DF2229E20C66500521A1779200000000
000000000000000000000000029E20C669003FBF1E0CF1A59C18DBF1EB3A13CE
22AFE22EB3A15BF228DBF15DF2293632B21308C66100D9D20E1632521A1041A1
29E20C66300E4A2051000000000000000000078BF12ABF129E20C66400E4A205
1000040000000000000029E20C66010DBBF1E4A2051000380000000000000029
E20C66010DBBF13F2A2387C14563284E2090357796E6764416471697632DCC02
EB3A193632B21308C66200D9D20E1632FD33284E2090357796E67644164716F1
732D9D208DBF129E20C6610029E20C66200B21305BF22D9D20B7FC18DBF1B213
05DF2293632B21308C66300D9D20E1632521A147A20041A1B213029E20C66700
DBBF1EB3A193632B2130000C66400D9D20E16321C432D6E2020D687D6E2020D6
97D6E201087D6E201097E1632B7FC18DBF1DBBF178BF19C2A2387C1B0BC13F2A
292CF18B9C1ED2A290DA1C58C1D6E201087D6E201097ED2A2387C1DBBF13F2A2
387C178BF13F2A26C7D129E20C668008B9C1D6E20109776BA1D6E2020D69729E
20C6601045632D6E2020D69797632DCC02D6E20108776BA1803A276BA145632D
6E20108797632DCC02D6E201087D6E2020D68729E20C6601045632D6E2020D68
797632DCC02DBBF1B7FC11C432D6E201037E16323CE22D6E201037AFE22D9D20
9C2A2D6E20103730132D6E2010375BCF1D6E2010375BCF1ED2A2387C1D6E2020
D687D6E2020D697D6E201087D6E20109729E20C66400D6E2020D69729E20C660
1045632D6E2020D69797632DCC02D6E2020D68729E20C6601045632D6E2020D6
8797632DCC02D6E2020D69745632D6E20109797632DCC0247A20B2130ED2A208
33247A20B21309C2A2D6E2010373013276BA1C4232B21305BF2247A20B21305D
F229C2A2387C176BA1EF532D6E2020D687D6E2020D697EF53293632B2130D9D2
0E163229E20C662002ABF1614E1634E1DCC02BB6919C2A290DA14B2A2DBBF1E9
7C1DBBF1BB6919C2A290DA14B2A2E97C1ED2A2387C147A2084E2010854B2A277
92000000000000000000000000000000000166E184E201095B213076BA145632
84E20400505142597632DCC02743A24A5A177920000000000000000000000000
000000000F2E129E20C6660093632B2130D9D20E1632A59C11C432D6E201037E
16323CE22D6E201037AFE22D9D209C2A2D6E20103730132D6E2010375BCF1D6E
2010375BCF1A72E1D6E2010375BCF12ABF1634E1E0CF1E0CF129E20C66800AE8
C192CF129E20C66D00D6E2010375BCF129E20C66600803A208332D6E2010379C
2A290DA1A9CF1803A2A9CF129E20C66C00B21305DF22D6E201037387C1EF5329
3632B2130D9D20E163278BF1EB3A1339201000000000000510FA1A11C432D6E2
01067E163247A20B21304B2A2D6E2010678B9C10A132D6E2010963CE22D6E201
096AFE22D9D20D6E201067D6E20109678BF1C58C129E20C6670076BA1B21305D
F22C42329C2A2387C176BA1EF532B51A193632B2130D9D20E16329C2A2DA5E17
8BF18B9C19C2A276BA1DBBF19C2A276BA1DBBF1614E147A20E4A205100010000
00000000000E4A20510001000000000000000B2130E0CF1AE8C193632B2130D9
D20E1632DBBF178BF19C2A29C2A2C58C1DBBF1ED2A292CF18B9C1C58C14B2A27
8BF11C432D6E201046D6E20200767D6E2020C613D6E2020C623D6E201027D6E2
01056E16323C032D6E201046D6E2020C613B7FC18DBF14BAC178BF11C432D6E2
01007D6E20200707E16323C0323CE22D6E2020C6238B9C1AFE22D9D20D6E2010
46D6E2010073F2A276BA16C7D1D6E2020C623D6E2020076729E20C6690045632
D6E2020076797632DCC023CE2278BF1F88E1AFE22D9D203FBF14B2A278BF1B21
305DF2245632D6E20105697632DCC0245632D6E20102797632DCC0245632D6E2
020C62397632DCC02B21305BF22D9D20634E1D6E201046D6E2010077C8D14563
2D6E2020C613976329C2A2E0CF1704D17C8D1E0CF1E0CF16C7D129E20C668005
99A1D6E2020076729E20C66A0045632D6E2020076797632DCC024B2A2F17A1D6
BB11C432D6E2010B6E1632D8732D9D20D6E2010B633920100000000000052016
7E1D6E2010B6339201000000000000530167E1908E18A732D9D20D6E2010B633
920100000000000003090DA1D13A250FA1803A2EEDA1D6E20100776BA19C2A29
0DA1D6E2010468B9C1D4EB19C2A276BA145632D6E2020070797632DCC02B2130
5DF22D6E2010B6339201000000000000430167E18A732D9D2047A20B21304563
2D6E2020C61397632DCC029C2A245632D6E20102797632DCC02B21305DF22D6E
2010B6339201000000000000630167E18A732D9D20D6E201046D6E2010073F2A
276BA16C7D19C2A278BF1C58C145632D6E2020C62397632DCC02B21305DF22D6
E2010B6339201000000000000150167E18A732D9D209C2A245632D6E20102797
632DCC029C2A245632D6E20105697632DCC02B21305DF22D6E2010B633920100
0000000000550167E18A732D9D209C2A245632D6E20105697632DCC02B21305D
F223392030000000000420103392099900000000005204C5A1B21305DF22EF53
2634E1D6E201046D6E2010079C2A276BA17C8D1E0CF1E0CF16C7D129E20C6680
0AE8C1D6E2020070745632D6E20100797632DCC02B21305DF22DE032D6E20102
7D6E201056908E19B632EF532DE032D6E201027D6E201056908E19B632D6E202
0C613D6E2020C62376BA1D6E201027D6E201056D6E20200767EF53293632B213
0D9D20E1632E89C11C432D6E20200787D6E20200797E1632E0CF13F2A2A9CF13
F2A2A9CF1AE8C18B9C1E0CF1E89C11C432D6E201077D6E201086D6E20207687D
6E20207697E163247A20EBBE1B2130D6E2020768745632D6E202007879763229
E20C66B0047A20EBBE1B2130D6E2020769745632D6E202007979763229E20C66
B0047A20D5CE1B2130D6E20207687D6E201077BB69176BA1803A276BA1339202
00000000000131090DA145632D6E202007879763229E20C66B0047A20D5CE1B2
130D6E20207697D6E201086BB69176BA133920100000000000046090DA145632
D6E202007979763229E20C66B00D6E20200787D6E20200797E97C178BF10F2E1
EF532EF53293632B2130D9D20E16321C432D6E2010E6D6E201067E16323CE22D
6E2010E6D6E201067EB3A1E0CF1EB3A1AFE22D9D20D6E2010E6D6E201067DCC0
2B21305DF22EF53293632B2130D9D20E16323CE2278BF1E89C18DBF1AFE22D9D
20779200000000000000039000000000000002076BA1DBBF178BF17792000000
00000000049000000000000002076BA1A13E1779200000000000000039000000
000000002076BA1893E1B21305BF223FBF15DF2293632B2130D9D20E16323CE2
278BF1E89C18DBF1AFE22D9D2077920000000000000002900000000000000207
6BA178BF1779200000000000000019000000000000000076BA1893E1B21305BF
228DBF15DF2293632B213047A2029E20C6600029E20C6650029E20C6610029E2
0C6620029E20C6630029E20C66400B213047A207792000000000000005690000
000000000139779200000000000000560000000000000023084E2010854B2A27
792000000000000000000000000000000000166E184E201095B2130D9D20E163
2BB691DBBF1BB69117CB1B969193632B2130D9D20E1632339203000000000044
6108441293632B2130EC755EA0"
--Cut here-----------------------------

The source directory:
--Cut here-----------------------------
%%HP: T(3)A(D)F(.);
DIR
  SWING @ Main routine. No arguments.
    \<<
      IF VARS 'PPAR' POS        @ Check for existence of PPAR
      THEN                      @ PPAR exits, save it in post-swing procedure
        PPAR 1 \->LIST { PPAR STO } +
      ELSE                      @ doesn't exist, purge it in post-swing proc.
        { { PPAR } PURGE }
      END
      SHOWDIR                   @ Draw tree
      PATH (0,0) SWSUB          @ Start interaction at current path
      DROP2 ROT LIST\-> DROP EVAL @ Drop position, execute post-swing procedure
      IF                        @ If normal exit, change path, else drop it
      THEN EVAL
      ELSE DROP
      END
    \>>
  SWSAVE @ Pre-compile tree. No arguments.
    \<< 
      PATH HOME                 @ Save current path, goto HOME
      TBLD                      @ Build list of directories
      # 0h DUP DUP2 GLBLD       @ Convert list to graphic list
      # 40h MAXB SWAP           @ PICT must be at least 131x64
      # 83h MAXB SWAP
      3 \->LIST 'SwingData' STO @ Save in SwingData
      EVAL                      @ Return to old path
    \>>
  SWGET @ Get SwingData. No arguments.
    \<<
      IFERR SwingData           @ Check existence of SwingData
      THEN DROP SWSAVE SWGET    @ If not, create
      ELSE OBJ\-> DROP          @ Exists, extract graphic list and PICT size
      END
    \>>
  TBLD @ Build directory table (list). No arguments.
    \<<
      PATH                      @ Save current path
      { HOME } RBLD             @ Start at HOME, call recursive builder
      SWAP EVAL                 @ Restore path
    \>>
  GLBLD @ Graphic list builder. 
        @ Directory list = {[Dirname Directory_list_of_subdirs]...}
        @ Inputs: 5: Directory table from TBLD
        @         4: Max x, so far (binary)
        @         3: Max y, so far (binary)
        @         2: x position (binary)
        @         1: y position (binary)
        @ Outputs:3: Graphic list
        @         2: Max x
        @         1: Max y
        @ Graphic list = {[Dirname Dirpos Dirstr graphiclist_of_subdirs]...}
    \<< \-> mx my x y
      \<< OBJ\-> DROP           @ The HOME directory table has only one entry,
                                @ GLBLD will call itself with one-entry-lists
                                @ only, so we can drop the size.

                                @ To convert Dirname to a GROB, we can't just
                                @ do \->GROB, since HOME \->STR will result
                                @ in "HOME", but FOOBAR \->STR will result in
                                @ "'FOOBAR'". The current workaround is to
                                @ put the name in a list, convert the list to
                                @ a string and to extract the relevant part.
         SWAP DUP 1 \->LIST     @ Put Dirname into a list
         \->STR                 @ Convert to string
         3 OVER SIZE 2 - SUB    @ Extract "Dirname", i.e. Dirstr
         x y 2 \->LIST          @ Make the coord {x y}, i.e. Dirpos
         SWAP 3 \->LIST         @ Make {Dirname Dirpos Dirstr}
         DUP 3 GET EGROB SIZE   @ Get size of the GROB of Dirstr
         y + my MAXB 'my' STO   @ Update maximum y
         x + 4 + 'x' STO        @ Update x
         x mx MAXB 'mx' STO     @ Update maximum x
         SWAP OBJ\-> \-> s      @ Explode directory_list_of_subdirs
        \<<
          IF s                  @ If any subdirs at all...
          THEN 1 s              @ ...loop over all subdirs
            START s ROLL s ROLL @ Get next subdir 
            2 \->LIST           @ Make it a one-entry subdir_list
            mx my x y GLBLD     @ Call GLBLD recursively
            my MAXB 'my' STO    @ Update maximum y
            mx MAXB 'mx' STO    @ Update maximum x
            my 'y' STO          @ Update y
            { } 2               @ Dummy list to keep stack depth, loop step
            STEP { } 1 s        @ Concatenate the s graphic_subdir_lists
            START +             @ on the stack
            NEXT
          ELSE { }              @ No subdirs, return empty list
          END 1 \->LIST +       @ Make {Dirname Dirpos Dirstr subdir_list}
        \>> mx my               @ Return cuurent maximum x and y
      \>>
    \>>
  SHOWDIR @ Draws the tree. No arguments.
    \<<
      SWGET                             @ Get SwingData
      DUP2 BLANK PICT STO               @ Set size of PICT
      B\->R 1 - 0 SWAP R\->C            @ Lower left corner in user coords
      SWAP B\->R 1 - 0 R\->C            @ Upper right in user coords
      2 \->LIST { X 0 (0,0)             @ Make new PPAR
      FUNCTION Y } + 'PPAR' STO
      7 FREEZE                          @ Freeze display so we don't get clock!
      (0,0) PVIEW SHWSUB                @ Show PICT and call SHWSUB
    \>>
  SHWSUB @ Recursive tree drawer.
         @ Input: 1: Graphic list.
         @ Graphic list = {[Dirname Dirpos Dirstr graphiclist_of_subdirs]...}
         @ Output:1: Graphic list. (Pos changed to user coords.)
    \<<
      LIST\-> \-> s                     @ Explode list
      \<<
        IF s                            @ If non-empty list...
        THEN 1 s                        @ ...walk through all elements
          START s ROLL s ROLL           @ Get Dirname and Dirpos
            PX\->C                      @ Convert Dirpos to user coord
            s ROLL DUP2                 @ Get Dirstr, save Dirpos_u and Dirstr
            PICT ROT ROT EGROB          @ Make PICT Dirpos_u DirGROB
            REPL                        @ Put GROB in PICT
            OVER DRAWTAG                @ Draw a small horizontal tag at Dirpos
            s ROLL SHWSUB               @ Get subdir_list and draw it recurs.
            4                           @ Loop step
          STEP
          s 1 - PICK                    @ Get pos of first subdir
          4 PICK                        @ Get pos of last subdir
          DRAWBAR                       @ Draw vertical bar from 1:st to last
        END s \->LIST                   @ Rebuild Graphic list
      \>>
    \>>
  RBLD @ Recursive builder.
       @ Input: 1: Single directory name.
       @ Output: 1: Directory list.
       @ Directory list = {[Dirname Directory_list_of_subdirs]...}
    \<< DUP                             @ Save directory name
      EVAL                              @ Enter directory
      15 TVARS \-> v                    @ Get list of subdirs
      \<< { } 0 v SIZE                  @ Loop over all subdirs
        FOR i
          IF i                          @ If any subdir
          THEN v i DUP SUB              @ Get subdir # i
            RBLD                        @ Call builder recursively
            +                           @ Concatenate list
          END
        NEXT 1 \->LIST                  @ Make subdir_list
        +                               @ Make {Dirname subdir_list}
      \>> UPDIR                         @ Return to directory above
    \>>
  EGROB @ Extended GROB. Same as 1 \->GROB, only the grob is extended
        @ one row above and one column on the right.
        @ Input: 1: Any.
        @ Output: 1: Grob.
    \<<
      1 \->GROB                         @ Make original grob
      DUP SIZE 1 + SWAP 1 + SWAP        @ Get size + 1
      BLANK { # 1h # 1h } ROT REPL      @ Extend grob
    \>>
  SWSUB @ The interactive swing subroutine which traverses the tree.
        @ One complicating fact is that we may have to 'pan' the PICT around
        @ if it is bigger than the screen. The first-level argument keeps track
        @ of the current point to PVIEW.
        @ Inputs: 3: Graphic list
        @         2: Path of directory to traverse to
        @         1: PVIEW point
        @ Outputs:4: Updated path
        @         3: return-flag
        @         2: exit-flag
        @         1: Updated PVIEW point
    \<< SWAP                            @ Get path
      DUP 1 1 SUB                       @ Get {1:st-dir-in-path}
      SWAP 2 OVER SIZE SUB              @ Get {rest-of-path}
      0 DUP \-> d pv l1 l2 r e          @ Save gr_list, pview_point,
                                        @  sublist1, sublist2, 
                                        @  and init return-flag and exit-flag
                                        @ sublist1 is always 1 element long
                                        @ sublist2 is the subpath that remains
                                        @  to be traversed
                                        @ return-flag and exit-flag are used
                                        @  as follows:
                                        @ r | e | meaning
                                        @ ---------------
                                        @ 0 | 0 | Continue on current level
                                        @ 0 | 1 | Exit all, don't set path
                                        @ 1 | 0 | Exit current level only
                                        @ 1 | 1 | Exit all, set path
                                        
      \<<
        DO d                            @ graphic list
          l1 OBJ\-> DROP                @ get 1:st dir in path
          POS                           @ find position in graphic list
          DUP \-> p pp                  @ save in p and pp
          \<<
            DO                          @ Do while not (exit or return)
              IF l2 SIZE                @ Are there dirs left in path?
              THEN                      @ Yes, traverse down in tree
                d p 3 + GET             @ Get graphic list of subdir
                l2 pv                   @ Get subpath and pview point
                SWSUB                   @ Call SWSUB recursively
                'pv' STO                @ Update pview point
                IF DUP NOT              @ If not exit-flag...
                THEN DROP2 0 DUP        @ ...then don't exit further
                END 'e' STO             @ Update exit-flag
                'r' STO                 @ Update return-flag
                'l2' STO                @ Update subpath
              ELSE                      @ No, reverse (black) cur. dir in tree
                PICT                    @ PICT on stack
                d p GETI                @ Put current Dirname...
                'l1' 1 ROT PUT          @ ... in sublist1
                GETI                    @ Get current Dirpos...
                ROT ROT GET             @ ... and current Dirstr
                EGROB NEG               @ Make a reversed GROB of the Dirstr
                pv SWREPL               @ SWREPL is like REPL, but it also
                                        @  pans PICT if any part the current
                                        @  dir is invisible
                'pv' STO                @ Update PVIEW point
                0 WAIT                  @ Wait for keypress
                IP \-> k                @ Save key code in k
                \<<
                  CASE
                    k 25 SAME           @ If 'Up'- or...
                    k 35 SAME OR        @ 'Down'-key 
                    THEN k 30 - 5 / 4 * @ -4 if 'Up', +4 if 'Down'
                      p +               @ New p
                      1 - d SIZE MOD 1 +@ Wrap around
                      'pp' STO          @ Save new p in pp
                    END
                    k 34 SAME           @ If 'Left'-key
                    THEN { } 'l1' STO   @ Blank out sublist1
                                        @  (Sublist2 is already empty,
                                        @  so this will make the current
                                        @  subpath empty - which will make
                                        @  SWSUB remain at the level above
                                        @  the current.)
                      1 'r' STO         @ Set return-flag
                    END
                    k 36 SAME           @ If 'Right'-key
                    THEN d p 3 + GET    @ Get graphic list of subdirs
                      1 DUP SUB         @ Get 1:st subdir
                      'l2' STO          @ Save in sublist2 (Which will make
                                        @  SWSUB to traverse down one level
                                        @  in the next loop)
                    END
                    k 51 SAME           @ If 'Enter'-key
                    THEN 1 'r' STO      @ Set return-flag and...
                      1 'e' STO         @ ...and exit-flag
                    END
                    k 55 SAME           @ If 'RubOut'-key
                    THEN 1 'e' STO      @ Set exit-flag
                    END
                    1024 .25 BEEP       @ Beep on all other keys
                  END                   @ End of CASE
                \>>                     @ Exit, key dispatch, render dir normal
                PICT                    @ Save PICT on stack
                d p 1 + GETI            @ Get current Dirpos...
                ROT ROT GET             @ ...and Dirstr
                EGROB REPL              @ Make a GROB and put it in PICT
                pp 'p' STO              @ Update new p
              END                       @ END of IF any subdirs
            UNTIL r e OR                @ Exit if return or exit
            END
          \>>
        UNTIL r e OR                    @ Exit if return or exit
        END l1 l2 + r e pv              @ Exit SWSUB, return path,
                                        @  return-flag, exit-flag and
                                        @  current PVIEW point
      \>>
    \>>
  SWREPL @ SWREPL is like REPL, but it will also pan PICT if any part of
         @ the current dir is invisible.
         @ Inputs: 4: PICT
         @         3: coord
         @         2: GROB
         @         1: PVIEW point
         @ Output: 1: New PVIEW point
    \<< C\->R \-> px py                 @ Explode PVIEW point
      \<< ROT 3 PICK 3 PICK REPL        @ Save coor and GROB, do REPL
        SIZE                            @ Get size of GROB
        ROT C\->R                       @ Explode coord
        \-> w h gx gy                   @ Save width and height and coords
        \<< { < } gx 'px' SWCLIP        @ Clip on left edge of screen
          { < } gy 'py' SWCLIP          @ Clip on top edge of screen
          { > }
          gx w B\->R + 4 + 131 -        @ Right limit of GROB
          'px' SWCLIP                   @ Clip on right edge of edge
          { > }
          gy h B\->R + 64 -             @ Bottom limit of GROB
          'py' SWCLIP                   @ Clip on bottom edge of screen
          px py R\->C                   @ New PVIEW point
          DUP PVIEW                     @ Save it on stack, do PVIEW
        \>>
      \>>
    \>>
  SWCLIP @ Clips a variable to a value
         @ Inputs: 3: Condition operator
         @         2: Value number
         @         1: Variable name
         @ No output.
    \<< \-> n v                         @ Save number and variable
      \<<
        IF
          n                             @ Get number
          v EVAL                        @ Get value in variable
          ROT EVAL                      @ Evaluate condition
        THEN n v STO                    @ If true, store new value
        END
      \>>
    \>>
  DRAWBAR @ Draws a line between two directory positions
          @ (The bar is always vertical, from the first to the last
          @  subdirectory)
          @ Inputs: 2: Coord of first subdir
          @         1: Coord of last subdir
          @ No output.
    \<<
      IF DUP C\->R DROP                 @ If x coord nonzero then...
      THEN (-3,2) +                     @ Offset last pos
        SWAP DUP                        @ Get and save first pos
        (-4,2) + PIXON                  @ Extend the tag at 1:st dir
        (-3,2) +                        @ Offset last pos
        LINE                            @ Draw the bar
      ELSE DROP2                        @ ...else do nothing
      END
    \>>
  DRAWTAG @ Draws a short tag at the left of a directory
          @ Input: 1: Coord of dir
          @ No output.
    \<<
      IF DUP C\->R DROP                 @ If x coord nonzero then...
      THEN (-2,2) +                     @ Offset start position
        DUP (-1,0) +                    @ Offset stop position
        LINE                            @ Draw the tag
      ELSE DROP                         @ ...else do nothing
      END
    \>>
  CST @ Custom menu. Not included in library.
    { SWING SHOWDIR SWSAVE SWGET TBLD GLBLD }
  PPAR @ Default PPAR. Not included in library.
    { (-6.5,-3.1) (6.5,3.2) X 0 (0,0) FUNCTION Y }
  MAXB @ Maximum of binaries.
       @ Inputs: 2: Binary
       @         1: Binary
       @ Output: 1: Max binary.
    \<< B\->R SWAP B\->R MAX R\->B
    \>>
  $TITLE "SWING by LennartB"
  $VISIBLE { SWING SWSAVE SWGET TBLD GLBLD }
  $CONFIG
    \<< 1644 ATTACH
    \>>
  $ROMID 1644
  $VARS { CST PPAR SwingData }
END
--Cut here-----------------------------

!++
! Lennart Boerjeson, System Manager
! School of Electrical Engineering
! Royal Institute of Technology
! S-100 44 Stockholm, Sweden
! tel: int+46-8-7907814
! Internet: lennartb@lne.kth.se
!--
!++
! Lennart Boerjeson, System Manager
! School of Electrical Engineering
! Royal Institute of Technology
! S-100 44 Stockholm, Sweden
! tel: int+46-8-7907814
! Internet: lennartb@lne.kth.se
!--