c
c     ANZ - Analysis Software for Human Locomotion and more
c     Version 1.1 First PC based release
c
c     Copyright by Dwight Meglan 1990,1993
c
c     This program is copyrighted but may be freely distributed and various
c     sections used and/or modified by others under the following restrictions
c
c     1) When this code or some part is used proper attribution to the 
c        developers of this code- Dwight Meglan and the Gait Analysis Lab
c        of The Ohio State University- must be given.
c
c     2) If you make changes to the code and redistribute it subsequently,
c        these changes must be clearly described and marked.
c
c     3) This code must be provided free of charge if it is redistrbuted,
c        except for recovery of the cost of distribution.
c
c     4) NO part of this code may be included in any commercial software.
c        It may NOT be provided as an addon to a commercial product by the
c        manufacturer or distributor, even if no charge is made for it.
c
c     5) No profit should be derived from the use of this code. If it is used
c        in a clinical context, then cost recovery fees may be charged by the
c        user(s).
c
c     WARRANTY - THERE IS NONE !!
c
c     I, the Ohio State University, and Mayo Clinic take NO responsiblity for 
c     the accuracy of the numerical calculations in this code. I accept NO 
c     liability for any difficulties resulting from the use of the results of 
c     this code.
c
c     SORRY for the heavy handed language but in this crazy world of finger
c     pointing lawsuits, you just never know what will happen...
c
c
c     This code is UNSUPPORTED. It has been used extensively in both clinical
c     and research contexts and I have tried to find all the bugs, but with 
c     something the large there are bound to be some latent problems.
c     I am interested in hearing about uses of the code by others, improvements,
c     or problems indentified. I cannot help with debugging or teaching others
c     about what is in here. This is intended to be used as a teaching tool
c     for engineers primarily, not as a finished clinical product. In reality
c     it is being used as such and I am confident that it carries out this
c     role well, but I do not have the time or desire to support this as a
c     clinical product would require.
c
c     Comments can be sent to: Dwight Meglan, dmeglan@merle.acns.nwu.edu
c     Address should be valid until at least August 1994. I would prefer
c     email contact because of the potential for people calling me inspite
c     of all the disclaimers above.
c
c
c     ANZ
c
c     Copyright by Dwight Meglan 1993
c
c     Purpose: Main routine to access all the capabilities of ANZ. Commands
c              are typed in, parsed, and the appropriate subroutine called.
c
c
c	Routines called:
c     DisplayStatus
c     do_AVG_calc
c     do_CYC_calc
c     do_EMG_calc
c     do_FRC_calc
c     do_JNT_calc
c     do_MRK_calc
c     do_SEG_calc
c     ExportData
c     GetPatientInfo
c     InitFullBodyAnalysis
c     ParseLine
c     read_file
c     save_file
c     SetOptions
c     TypeHistory
c     zero_motion_flags
c     zero_force_flags
c     
c
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c
c   Force_Plate     FRC_COND...
c	Param			GP...
c     
      program ANZ
      implicit none
      include 'a_const.inc'
c
c     Include the definitions of the structures used.
c                                    
      include 'a_struct.inc'
      include 'a_prm.inc'
      include 'a_names.inc' 

      record /CmndLine/       CMND
      record /marker_flag/    MF
      record /segment_flag/   SF
      record /force_flag/     FF      
      record /joint_flag/     JF
      record /avg_pos_flag/   AF                                   
      record /cycle_flag/     CF
      record /emg_flag/       EF
      record /option_flag/    OF       
c
c     Define variables in the main program
c                                     
      integer*4 nhis,errnum,i,j,k
      character line*80,answer*1
      logical*4 data_read,data_saved,done
c
c     Initialize variables, flags and structures
c
      call zero_all_motion_params(.true.)
      call zero_all_force_params
      call InitAll( MF,SF,FF,JF,AF,CF,EF )

      do i= 1, MAX_NUM_HISTORY
         History(i).NumLine= 0
         History(i).NumHistory= 0
         do j= 1, 25
	    do k= 1, 20
               History(i).Line(j)(k:k)= ' '
	    end do
         end do
      end do

c                         
c     Begin main command interpretation loop
c
      data_read=  .false.    
      data_saved= .false.
      OF.UpDate= .true.
      done= .false.
      write(6,50)
50    format(//31x,'Welcome to Analyze'/
     &         17x,'An industrial strength gait analysis package'//
     &         22x,'Copyright (c) by Dwight Meglan 1993'/
     &         20x,'For Academic and Noncommercial use only'//)
      History(1).NumHistory=1
      History(1).NumLine= 0
1     do while ( .not. done )
        write(6,100)                        
100     format(' anz> ',$)
        read(5,110,end=102,err=102,iostat=errnum) line     
110     format(a80)
        if ( OF.ToLog ) write(3,101) line
101     format(' anz> ',a80)
102     call ParseLine( line,CMND )
	nhis= History(1).NumHistory
	if ( (History(nhis).NumLine .eq. 25) .and.
     &	     (History(1).NumHistory .lt. MAX_NUM_HISTORY) ) then
	  History(1).NumHistory= History(1).NumHistory + 1
	  nhis= nhis + 1
	  History(nhis).NumLine= 0
	else if ( (History(nhis).NumLine .ge. 25) .and.
     &		  (History(1).NumHistory .ge. MAX_NUM_HISTORY) ) then
	  History(nhis).NumLine= 24
        end if
        if ( CMND.CmndText(1) .ne. 'HIS' ) then
	  History(nhis).NumLine= History(nhis).NumLine + 1
	  History(nhis).Line(History(nhis).NumLine)= line(1:20)
        end if
        if ( CMND.CmndText(1) .eq. 'REA' ) then     
          call read_file( CMND,MF,SF,FF,JF,AF,CF,EF,OF,data_read )
          if ( data_read ) data_saved= .false.
                                 
        else if ( CMND.CmndText(1) .eq. 'SAV' ) then
          call save_file( CMND,MF,SF,FF,JF,AF,CF,EF,OF,data_saved )
                                           
        else if ( CMND.CmndText(1) .eq. 'STA' ) then
          call DisplayStatus( CMND,MF,SF,FF,JF,AF,CF,EF,OF )
                   
        else if ( CMND.CmndText(1) .eq. 'PAT' .or.
     &            CMND.CmndText(1) .eq. 'SUB'      ) then
          call GetPatientInfo( CMND,OF )   
          data_saved= .false.
                                         
        else if ( CMND.CmndText(1) .eq. 'MRK' ) then
          call do_MRK_calc( CMND,MF,SF,JF,CF,OF )
          data_saved= .false.

        else if ( CMND.CmndText(1) .eq. 'SEG' ) then
          call do_SEG_calc( CMND,MF,SF,JF,AF,OF )
          data_saved= .false.
                                  
        else if ( CMND.CmndText(1) .eq. 'FRC' ) then 
          call do_FRC_calc( CMND,FF,SF,JF,CF,OF )
          data_saved= .false.

        else if ( CMND.CmndText(1) .eq. 'JNT' ) then
          call do_JNT_calc( CMND,SF,FF,JF,OF )
           data_saved= .false.
                                            
        else if ( CMND.CmndText(1) .eq. 'AVG' ) then
          call do_AVG_calc( CMND,SF,JF,AF,OF )
          data_saved= .false.

        else if ( CMND.CmndText(1) .eq. 'CYC' ) then  
          call do_CYC_calc( CMND,MF,SF,CF,OF )
          data_saved= .false.
                       
        else if ( CMND.CmndText(1) .eq. 'EMG' ) then  
          call do_EMG_calc( CMND,EF,OF )
          data_saved= .false.
                       
        else if ( CMND.CmndText(1) .eq. 'OPT' ) then     
          call SetOptions( CMND,OF )

        else if ( CMND.CmndText(1) .eq. 'HEL' ) then
          ! call display_help( CMND,OF ) 
          write(6,150)
          if ( OF.ToLog ) write(3,150)
150       format(/' Sorry- Help was not implemented '//
     &           ' Please note that this program is UNSUPPORTED '//)

        else if ( CMND.CmndText(1) .eq. 'EXP' ) then
          call ExportData( CMND,MF,SF,JF,FF,AF,CF,EF,OF )

        else if ( CMND.CmndText(1) .eq. 'RES' ) then
	  call zero_all_motion_params(.true.)
          call zero_all_force_params
          call InitFullBodyAnalysis( .true.,.true. )
	  History(1).NumHistory= 0
	  nhis= 0

        else if ( CMND.CmndText(1) .eq. 'HIS' ) then
	  call TypeHistory( OF )

        else if ( (CMND.CmndText(1) .ne. 'END') .and. 
     &            (CMND.CmndText(1) .ne. 'BYE') .and.
     &            (CMND.CmndText(1) .ne. 'QUI') .and. 
     &            (CMND.CmndText(1) .ne. 'DON') .and.
     &            (CMND.CmndText(1) .ne. 'EXI')       ) then
          write(6,120)                     
          if ( OF.ToLog ) write(3,120)                
120       format(' Invalid command.'/
     &		 ' Valid commands are: ',
     &		 'REAd SAVe STAtus SUBject MRKer  SEGment'/
     &		 22x,'FRCe JNT   AVG     CYCle   OPTion EXPort'/
     &		 22x,'EMG  RESet HIStory STAtus  LIMits END')
          if ( errnum .ne. 0 ) then
            write(6,122) errnum
            if ( OF.ToLog ) write(3,122) errnum
122	    format(/' NOTE- Error number ',i4,
     &		    ' occurred during reading command')
          end if
        else if ( (CMND.CmndText(1) .eq. 'END') .or.
     &            (CMND.CmndText(1) .eq. 'BYE') .or.
     &            (CMND.CmndText(1) .eq. 'QUI') .or.
     &            (CMND.CmndText(1) .eq. 'DON') .or.
     &            (CMND.CmndText(1) .eq. 'EXI')      ) then
          done= .true.         
        end if
      end do ! while not quitting
c      if ( data_read .and. (.not. data_saved) ) then
        done= .false.
        write(6,130)                                          
        if ( OF.ToLog ) write(3,130)
130     format(/' Are you sure you want to quit (y/[n]) ? : ',$ )
        read(5,140,err=145,end=145,iostat=errnum) answer
140     format(a1)
145     if ( (answer .ne. 'y') .and. (answer .ne. 'Y') ) goto 1
c      end if
      if ( OF.UpDate ) write(6,160)
160   format(12(/),23x,'Exiting Analyze.  Have a good one...',11(/))
      stop ' '
      end             
c
c     Copyright by Dwight Meglan 1990
c
c     Purpose: Print out the history of the commands that have been executed to
c              produce the current state of the analysis. These commands are stored
c              in the data file so that one can always look at how a file has been
c              produced.
c
c     Routines called:
c       None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c       Param       History...
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c       None
c
      Subroutine TypeHistory( OF )
      implicit none  

      include 'a_const.inc'
      include 'a_struct.inc'                     
      include 'a_prm.inc'
                
      record /option_flag/ OF            
         
      integer*4 i,j,k
      character ans*1
                  
      k= 0
      do i= 1, History(1).NumHistory
        do j= 1, History(i).NumLine
          k= k + 1
          write(6,100) History(i).Line(j)     
          if ( OF.ToLog ) write(3,100) History(i).Line(j)
100       format(1x,a20)
          if ( k .gt. 21 ) then 
            write(6,120)
120         format(/' Press Return to continue...')
            read(5,130,err=135,end=135) ans
130         format(a1)
135         write(6,140)
140         format(/)
            k= 0
          end if       
        end do      
      end do
      return
      end
c                   
c     Copyright by Dwight Meglan 1990
c                    
c     Purpose: Set some options applying to general operation of the program as 
c              well as some specifics in the ForceAlign and Marker sections.
c
c     Routines called:
c       FlipLogical
c       GetFileName
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c       None
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c       Param       GP.int_poly_order
c       Param       FP.num_idle_frm
c       Param       FP.idle_percent
c       Param       FRC_COND.trig_percent
c       Param       FRC_COND.HS_tol_percent
c
      Subroutine SetOptions( CMND,OF )
      implicit none
      include 'a_const.inc'

      include 'a_struct.inc'                     
      include 'a_prm.inc'
      include 'a_gls2.inc'
      include 'a_frc.inc'

      record /CmndLine/    CMND
      record /option_flag/ OF

      integer*4 error,name_length
      logical*4 nameOK,GetFileName
      character filename*40,extension*3

      if ( CMND.NumCmnd .lt. 2 ) goto 1000 ! error
      if ( CMND.CmndText(2) .eq. 'GEN' ) then
        if ( CMND.CmndText(3) .eq. 'NUP' ) then
          OF.UpDate= .false.
        else if ( CMND.CmndText(3) .eq. 'UPD' ) then
          OF.UpDate= .true.
        else if ( CMND.CmndText(3) .eq. 'LOG' ) then
	  if ( .not. OF.log_file_created ) then
            nameOK= GetFileName( CMND.text(1),CMND.CmndStart(4),
     &                           filename,extension,name_length  )
            if ( (.not. nameOK) .or. (filename(1:1) .eq. ' ') ) 
     &         filename= 'anz.log'
	    open( unit=3,file=filename,status='unknown',
     &		  iostat=error,err=1010 )
            OF.ToLog= .true.
	    OF.log_file_created= .true.
          else   
            call FlipLogical( OF.ToLog )
          end if
        else if ( CMND.CmndText(3) .eq. 'INT' ) then
          if ( .not. CMND.CmndNumOK(4) ) then
            write(6,130) CMND.CmndText(4)
            if ( OF.ToLog ) write(3,130) CMND.CmndText(4)
          else if ( (CMND.CmndIntVal(4) .lt. 1) .and. 
     &       (CMND.CmndIntVal(4) .gt.  6) ) then
            write(6,180) CMND.CmndIntVal(4)
            if ( OF.ToLog ) write(3,180) CMND.CmndIntVal(4)
180	    format(' Error-',i3,
     &		   ' is not a valid interpolating polynomial order'/
     &             '        It must be between 1 and 6.')
          else                                
            GP.int_poly_order= CMND.CmndIntVal(4)
          end if ! interpret order of interpolating polynomial
        else
          write(6,125) CMND.CmndText(3)
125       format(' Error- ',a3,' is an invalid OPT GEN command.'/
     &           '        Valid commands are: LOG NUP UPD INT')
        end if ! which general option type
        
      else if ( CMND.CmndText(2) .eq. 'FRC' ) then         
        if ( CMND.CmndText(3) .eq. 'FRM' ) then
          if ( .not. CMND.CmndNumOK(4) ) then
            write(6,130) CMND.CmndText(4)
            if ( OF.ToLog ) write(3,130) CMND.CmndText(4)
130         format(' Error- ',a3,' is not a valid integer.')
          else if ( (CMND.CmndIntVal(4) .lt. 1) .and.    
     &              (CMND.CmndIntVal(4) .gt. FP.nfrm) ) then
            write(6,140) CMND.CmndIntVal(4),FP.nfrm
            if ( OF.ToLog ) write(3,140) CMND.CmndIntVal(4),
     &                                           FP.nfrm
140         format(' Error- ',i4,' is not a valid integer.'/
     &             '        It must be between 0 and ',i4,'.')
          else
            FRC_COND.num_idle_frm= CMND.CmndIntVal(4)
          end if ! interpret number of idle frames
                                       
        else if ( CMND.CmndText(3) .eq. 'IDL' ) then
          if ( .not. CMND.CmndNumOK(4) ) then
            write(6,150) CMND.CmndText(4)
            if ( OF.ToLog ) write(3,150) CMND.CmndText(4)
150         format(' Error- ',a3,' is not a valid real number.')
          else if ( (CMND.CmndRealVal(4) .lt. 0.) .and. 
     &              (CMND.CmndRealVal(4) .gt. 100.) ) then
            write(6,160) CMND.CmndRealVal(4)
            if ( OF.ToLog ) write(3,160) CMND.CmndRealVal(4)
160         format(' Error- ',f5.2,' is not a valid real number.'/
     &             '        It must be between 0 and 100 %.')
          else
            FRC_COND.idle_percent= CMND.CmndRealVal(4)
          end if ! interpret idle percentage
          
        else if ( CMND.CmndText(3) .eq. 'TRI' ) then
          if ( .not. CMND.CmndNumOK(4) ) then
            write(6,150) CMND.CmndText(4)
            if ( OF.ToLog ) write(3,150) CMND.CmndText(4)
          else if ( (CMND.CmndRealVal(4) .lt. 0.) .and. 
     &              (CMND.CmndRealVal(4) .gt. 100.) ) then
            write(6,160) CMND.CmndRealVal(4)
            if ( OF.ToLog ) write(3,160) CMND.CmndRealVal(4)
          else
            FRC_COND.trig_percent= CMND.CmndRealVal(4)
          end if ! interpret trigger percentage
          
        else if ( CMND.CmndText(3) .eq. 'HST' ) then
          if ( .not. CMND.CmndNumOK(4) ) then
            write(6,150) CMND.CmndText(4)
            if ( OF.ToLog ) write(3,150) CMND.CmndText(4)
          else if ( (CMND.CmndRealVal(4) .lt. 0.) .and. 
     &              (CMND.CmndRealVal(4) .gt. 100.) ) then
            write(6,160) CMND.CmndRealVal(4)
            if ( OF.ToLog ) write(3,160) CMND.CmndRealVal(4)
          else
            FRC_COND.HS_tol_percent= CMND.CmndRealVal(4)
          end if ! interpret Heelstrike tolerance percent
                                            
        else
          write(6,170) CMND.CmndText(3)
          if ( OF.ToLog ) write(3,170) CMND.CmndText(3)
170       format(' Error- ',a3,' is an invalid OPT FRC command.'/
     &		 '        Valid commands are: ',
     &		 'IDLe% idleFRames TRIgger%'/
     &           '                            HSTolerance%.')
        end if ! FRC command                
        
      else  
        write(6,200) CMND.CmndText(2)
        if ( OF.ToLog) write(3,200) CMND.CmndText(2)
200     format(' Error- ',a3,' is an invalid OPTion command.'/
     &         '        Valid commands are: GEN FRC')
      end if
      return

1000  write(6,1005) 
      if ( OF.ToLog ) write(3,1005) 
1005  format(' Error- There must be at least 3 command entries.'/
     &       '        Valid second commands are: GEN FRC')
      return

1010  write(6,1015) error,filename
      if ( OF.ToLog ) write(3,1015) error,filename
1015  format(' Error- Error #',i4,' occured while opening ',a40/
     &       '        as the session log file.')
      return
      end
c
c
c                                                      
c
c     Copyright by Dwight Meglan 1990
c
c     Purpose: Toggle logical flag from true to false or false to true
c
      subroutine FlipLogical( Flag )
      implicit none

      logical*4 flag

      if ( flag ) then
        flag= .false.
      else
        flag= .true.
      end if
      return
      end
c                                             
c         
c
c
c     Copyright by Dwight Meglan 1990
c
c     Purpose: Get descriptive information about the person whose activity is
c              being analyzed. Note that weight and height may be given in metric
c              US units by indicating the units after the number. Units are presumed
c              to be US unless they are given. These are stored in metric units. Ex:
c              PAT WEI 100     - means 100 pounds
c              PAT WEI 100 LBS - means 100 pounds
c              PAT WEI 100 KG  - means 100 kilograms
c              PAT HEI 72      - means 72  inches
c              PAT HEI 72 IN   - means 72  inches
c              PAT HEI 1.2 M   - means 1.2 meters
c
c   Routines called:
c       None
c
c	Common Block Variables USED by routine:
c	Block Name		Variable Name
c
c	Common Block Variables MODIFIED by routine:
c	Block Name		Variable Name
c      Param          GP.name
c      Param          GP.comment
c      Param          GP.age
c      Param          GP.Sex
c      Param          GP.weight
c      Param          GP.height
c
      subroutine GetPatientInfo( CMND,OF )
      implicit none
      include 'a_const.inc'

      include 'a_struct.inc'
      include 'a_prm.inc'

      record /CmndLine/    CMND
      record /option_flag/ OF

      integer*4 i,j,num_char
      real*4    scalefactor                

      if ( CMND.NumCmnd .lt. 3 ) goto 1000 ! error
      if ( CMND.CmndText(2) .eq. 'NAM' ) then
        i= 80
        do while ( CMND.Text(1)(i:i) .eq. ' ' )
          i= i - 1
        end do
        num_char= i - CMND.CmndStart(3) + 1
        do j= num_char+1, 40
          GP.name(j:j)= ' '
        end do
        i= CMND.CmndStart(3)-1
        do j= 1, num_char
          GP.name(j:j)= CMND.Text(1)(i+j:i+j)
        end do
        
      else if ( CMND.CmndText(2) .eq. 'COM' ) then
        num_char= 80 - CMND.CmndStart(3) + 1
        do j= num_char+1, 80
          GP.comment(j:j)= ' '
        end do
        i= CMND.CmndStart(3)-1
        do j= 1, num_char
          GP.comment(j:j)= CMND.Text(1)(i+j:i+j)
        end do
        
      else if ( CMND.CmndText(2) .eq. 'AGE' ) then
        if ( CMND.CmndNumOK(3) ) then
          GP.age= CMND.CmndIntVal(3)
        else
          write(6,100) CMND.CmndText(3)
          if ( OF.ToLog ) write(3,100) CMND.CmndText(3)
100       format(' Error- ',a3,' is not a valid patient age.')
        end if
        
      else if ( CMND.CmndText(2) .eq. 'SEX' ) then
        if ( CMND.CmndText(3)(1:1) .eq. 'F' ) then
          GP.Sex= 'F'
        else if ( CMND.CmndText(3)(1:1) .eq. 'M' ) then
          GP.Sex= 'M'
        else
          write(6,103) CMND.CmndText(3)
          if ( OF.ToLog ) write(3,103) CMND.CmndText(3)
103	  format(' Error- ',a3,
     &		 ' is not a valid patient sex designator'/
     &           '        Only Female and Male are possible')
        end if

      else if ( CMND.CmndText(2) .eq. 'WEI' ) then
        scalefactor= 2.2209
        if ( CMND.NumCmnd .eq. 4 ) then ! determine units of weight lbs or kg
          if ( CMND.CmndText(4) .eq. 'KG ' ) then
            scalefactor= 1.0
          else if ( CMND.CmndText(4) .ne. 'LBS' ) then
            write(6,110) CMND.CmndText(4)
            if ( OF.ToLog ) write(3,110) CMND.CmndText(4)
110         format(' Error- ',a3,' is an invalid weight unit.'/
     &             '        Unit is assumed to be lbs.')
          end if ! what type of weight unit
        end if ! is weight unit present
        if ( CMND.CmndNumOK(3) ) then
          GP.weight= CMND.CmndRealVal(3)/scalefactor
        else
          write(6,120) CMND.CmndText(3)
          if ( OF.ToLog ) write(3,120) CMND.CmndText(3)
120       format(' Error- ',a3,' is not a valid patient weight.')
        end if
        
      else if ( CMND.CmndText(2) .eq. 'HEI' ) then
        scalefactor= .0254
        if ( CMND.NumCmnd .eq. 4 ) then ! determine units of height in or m
          if ( CMND.CmndText(4) .eq. 'M ' ) then
            scalefactor= 1.0
          else if ( CMND.CmndText(4) .ne. 'IN ' ) then
            write(6,130) CMND.CmndText(4)
            if ( OF.ToLog ) write(3,130) CMND.CmndText(4)
130         format(' Error- ',a3,' is an invalid height unit.'/
     &             '        Unit is assumed to be inches.')
          end if ! what type of height unit
        end if ! is height unit present
        if ( CMND.CmndNumOK(3) ) then
          GP.height= CMND.CmndRealVal(3)*scalefactor
        else
          write(6,140) CMND.CmndText(3)
          if ( OF.ToLog ) write(3,140) CMND.CmndText(3)
140       format(' Error- ',a3,' is not a valid patient height.')
        end if
        
      else
        write(6,150) CMND.CmndText(2)
        if ( OF.ToLog ) write(3,150) CMND.CmndText(2)
150     format(' Error- ',a3,' is not a valid patient command.'/
     &	       '        Valid commands are: ',
     &	       'NAMe COMment AGE WEIght HEIght SEX')
      end if ! what type of patient command
      return
      
1000  write(6,1005) CMND.NumCmnd
      if ( OF.ToLog ) write(3,1005) CMND.NumCmnd
1005  format(' Error- There must be at least 3 command entries.'/
     &       '        Only ',i1,' was/were found.'/
     &	       '      Valid commands are: ',
     &	     'NAMe COMment AGE WEIght HEIght SEX')
      return
      end
