subroutine get(set,line,r,error,user_function)
  use gildas_def
  use gbl_constant
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>get
  use class_parameter
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ public
  ! CLASS Support routine for command
  !      GET Number|NEXT|FIRST|LAST|PREVIOUS [Version]
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set            !
  character(len=*),    intent(in)    :: line           ! Command line
  type(observation),   intent(inout) :: r              !
  logical,             intent(inout) :: error          ! Error flag
  logical,             external      :: user_function  !
  ! Local
  character(len=*), parameter :: rname='GET'
  logical :: endof
  integer(kind=entry_length) :: kx
  integer(kind=obsnum_length) :: nnn
  integer(kind=4) :: mmm,nc,nfound
  character(len=varname_length) :: argum,found
  character(len=message_length) :: mess
  integer, parameter :: nkey=5
  character(len=12) :: keys(nkey)
  ! Data
  data keys / 'FIRST','LAST','NEXT','PREVIOUS','ZERO' /
  !
  ! Initialization
  endof = .false.
  !
  ! Verify if any input file
  if (.not.filein_opened(rname,error))  return
  !
  if (.not.sic_present(0,1)) then
    ! No argument: Take last selected entry
    kx = last_xnum
    if (kx.eq.0) then
      call class_message(seve%e,rname,'No R spectrum in memory')
      error = .true.
      return
    endif
    if (kx.le.0 .or. kx.ge.ix%next) then
      write(mess,'(A,I0)') 'Non-existant index entry #',kx
      call class_message(seve%e,rname,mess)
      error = .true.
      return
    endif
    call get_it(set,r,kx,user_function,error)
    !
  else
    call sic_ke (line,0,1,argum,nc,.true.,error)
    if (error) return
    !
    ! 'sic_ambigs_sub' will return nfound=0 without complaining if
    ! argum is not in the list of known keywords (except if the known
    ! keywords have ambiguities)
    call sic_ambigs_sub(rname,argum,found,nfound,keys,nkey,error)
    if (error)  return
    !
    select case (nfound)
    case(1)  ! FIRST
      if (cx%next.le.1) then
        call class_message(seve%e,rname,'Index is empty')
        error = .true.
        return
      endif
      call get_first(set,r,user_function,error)
      !
    case(2)  ! LAST
      if (cx%next.le.1) then
        call class_message(seve%e,rname,'Index is empty')
        error = .true.
        return
      endif
      call get_last(set,r,user_function,error)
      !
    case(3)  ! NEXT
      call get_next(set,r,endof,user_function,error)
      if (endof) then
        call class_message(seve%e,rname,'End of current index encountered')
        error = .true.
        return
      endif
     !
    case(4)  ! PREVIOUS
      if (knext.le.1) then
        call class_message(seve%e,rname,'Beginning of index encountered')
        error = .true.
        return
      endif
      knext = knext-1
      kx = cx%ind(knext)
      call get_it(set,r,kx,user_function,error)
      !
    case(5)  ! ZERO
      knext = 0
      return  ! Nothing more to do
      !
    case(0)  ! Not a known keyword
      call sic_i8 (line,0,1,nnn,.false.,error)
      if (error) return
      mmm = 0
      call sic_i4 (line,0,2,mmm,.false.,error)
      if (error) return
      call get_num(set,r,nnn,mmm,user_function,error)
      !
    case default
      call class_message(seve%e,rname,'Internal error: argument not understood')
      error = .true.
      return
    end select
  endif
  if (error)  return
  !
  ! User feedback
  write(mess,'(a,i0,a,i0,a,i0)')  'Observation ',r%head%gen%num,'; Vers ',  &
    r%head%gen%ver,' Scan ',r%head%gen%scan
  call class_message(seve%i,rname,mess)
  if (r%head%gen%qual.eq.qual_deleted)  &
    call class_message(seve%w,rname,'Observation marked for deletion')
  !
  ! Initialize X,Y,Z
  call newdat(set,r,error)
  call newdat_assoc(set,r,error)
  call newdat_user(set,r,error)
  !
  last_xnum = r%head%xnum
end subroutine get
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine get_first(set,obs,user_function,error)
  use gildas_def
  use classcore_interfaces, except_this=>get_first
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Get the first index entry
  ! An index must exist
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set            !
  type(observation),   intent(inout) :: obs            ! Current observation
  logical,             external      :: user_function  !
  logical,             intent(inout) :: error          ! Error flag
  ! Local
  integer(kind=entry_length) :: kx
  !
  knext = 1
  kx = cx%ind(knext)
  obs%head%des%rec = 1
  call get_it(set,obs,kx,user_function,error)
end subroutine get_first
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine get_next(set,obs,endof,user_function,error)
  use gildas_def
  use classcore_interfaces, except_this=>get_next
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Get next index entry
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set            !
  type(observation),   intent(inout) :: obs            ! Current observation
  logical,             intent(out)   :: endof          ! End of index
  logical,             external      :: user_function  !
  logical,             intent(inout) :: error          ! Error flag
  ! Local
  integer(kind=entry_length) :: kx
  !
  if (knext.ge.cx%next-1) then
    endof = .true.
    return
  endif
  knext=knext+1
  !
  kx = cx%ind(knext)
  obs%head%des%rec = 1
  call get_it(set,obs,kx,user_function,error)
end subroutine get_next
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine get_last(set,obs,user_function,error)
  use gildas_def
  use classcore_interfaces, except_this=>get_last
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Get the last index entry
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set            !
  type(observation),   intent(inout) :: obs            ! Current observation
  logical,             external      :: user_function  !
  logical,             intent(inout) :: error          ! Error flag
  ! Local
  integer(kind=entry_length) :: kx
  !
  knext = cx%next-1
  kx = cx%ind(knext)
  obs%head%des%rec = 1
  call get_it(set,obs,kx,user_function,error)
end subroutine get_last
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine get_num(set,obs,nnn,mmm,user_function,error)
  use gildas_def
  use gbl_message
  use classic_api
  use classcore_interfaces, except_this=>get_num
  use class_parameter
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! CLASS internal routine
  ! Get VERSION mmm of ENTRY nnn
  ! First look for in the Current Index
  ! If not in Current Index, search in File
  !---------------------------------------------------------------------
  type(class_setup_t),         intent(in)    :: set            !
  type(observation),           intent(inout) :: obs            ! Current observation
  integer(kind=obsnum_length), intent(in)    :: nnn            ! Entry number
  integer(kind=4),             intent(in)    :: mmm            ! Version number
  logical,                     external      :: user_function  !
  logical,                     intent(out)   :: error          ! Error flag
  ! Local
  character(len=*), parameter :: rname='GET'
  integer(kind=entry_length) :: kx
  character(len=20) :: nombr1
  logical :: found
  !
  error = .false.
  !
  ! Search first in Current Index
  call get_num_cx(nnn,mmm,found,kx,error)
  if (error)  return
  !
  if (.not.found) then
    ! Else, search in Input Index (input file)
    call get_num_ix(set,nnn,mmm,found,kx,error)
    if (error) return
  endif
  !
  if (.not.found) then
     ! Nothing found...
     if (mmm.gt.0) then
        write(nombr1,'(I0,A,I0)' ) nnn,'; ',mmm
     else
        write(nombr1,'(I0)') nnn
     endif
     call class_message(seve%e,rname,'Observation #'//trim(nombr1)//' not found')
     error = .true.
     return
  endif
  !
  obs%head%des%rec = 1
  call get_it(set,obs,kx,user_function,error)
end subroutine get_num
!
subroutine get_num_cx(num,ver,found,kx,error)
  use gildas_def
  use gbl_message
  use classic_api
  use classcore_interfaces, except_this=>get_num_cx
  use class_parameter
  use class_index
  !---------------------------------------------------------------------
  ! @ private
  ! Get VERSION ver of ENTRY num. Look in Current Index
  !---------------------------------------------------------------------
  integer(kind=obsnum_length), intent(in)    :: num    ! Observation number
  integer(kind=4),             intent(in)    :: ver    ! Version number
  logical,                     intent(out)   :: found  !
  integer(kind=entry_length),  intent(out)   :: kx     ! Entry number
  logical,                     intent(inout) :: error  ! Error flag
  ! Local
  integer(kind=entry_length) :: i,ifound
  integer(kind=4) :: cver
  !
  found = .false.
  kx = 0
  ifound = 0
  cver = 0
  !
  if (ver.le.0) then
     ! Search for last version
     do i=1,cx%next-1
        if (cx%num(i).eq.num) then
           if (cx%ver(i).ge.0) then
              found = .true.
              knext = i
              kx = cx%ind(i)
              return
           elseif (cx%ver(i).lt.cver) then
              ifound = i
              cver = cx%ver(i)
           endif
        endif
     enddo
     if (ifound.ne.0) then
        found = .true.
        knext = ifound
        kx = cx%ind(ifound)
        return
     endif
  else
     ! Search for given version
     do i=1,cx%next-1
        if (cx%num(i).eq.num) then
           cver = iabs(cx%ver(i))
           if (cver.eq.ver) then
              found = .true.
              kx = cx%ind(i)
              knext = i
              return
           endif
        endif
     enddo
  endif
end subroutine get_num_cx
!
subroutine get_num_ix(set,num,ver,found,kx,error)
  use gildas_def
  use gbl_message
  use classic_api
  use classcore_interfaces, except_this=>get_num_ix
  use class_index
  use class_parameter
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Get VERSION ver of ENTRY num. Search in the Input File Index
  !---------------------------------------------------------------------
  type(class_setup_t),         intent(in)    :: set    !
  integer(kind=obsnum_length), intent(in)    :: num    ! Observation number
  integer(kind=4),             intent(in)    :: ver    ! Version number
  logical,                     intent(out)   :: found  !
  integer(kind=entry_length),  intent(out)   :: kx     ! Entry number
  logical,                     intent(inout) :: error  ! Error flag
  ! Local
  type(optimize), save :: mycx  ! See call to FIX below
  integer(kind=entry_length) :: nfound,more
  !
  found = .false.
  kx = 0
  !
  ! Tune the searching flags used by subroutine FIX. NB: the other flags
  ! have been reset at the end of previous call to FIX.
  flg%num=.true.
  smin%num=num
  smax%num=num
  if (ver.le.0) then
    flg%last=.true.
    flg%ver=.false.
  else
    flg%last=.false.
    flg%ver=.true.
    smin%ver=ver
    smax%ver=ver
  endif
  !
  ! Prepare the local CX to be filled by FIX
  mycx%next = 1  ! This index is marked empty
  more = 1  ! We will store only 1 more entry is this index. This avoids
            ! allocating a huge index (size of IX) while we know we are
            ! searching for 1 entry.
  !
  call fix(set,ix,mycx,nfound,error,more=more)
  if (error)  return
  if (nfound.eq.0)  return
  !
  found = .true.
  kx = mycx%ind(1)
  !
end subroutine get_num_ix
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine get_it(set,obs,kx,user_function,error)
  use gildas_def
  use gbl_message
  use gbl_constant
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>get_it
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Get observation (header+data) number KX into observation structure OBS
  !---------------------------------------------------------------------
  type(class_setup_t),        intent(in)    :: set            !
  type(observation),          intent(inout) :: obs            ! Observation structure
  integer(kind=entry_length), intent(in)    :: kx             ! Entry number
  logical,                    external      :: user_function  ! intent(in)
  logical,                    intent(out)   :: error          ! Error flag
  ! Local
  character(len=*), parameter :: rname='GET_IT'
  character(len=message_length) :: mess
  integer(kind=4) :: ndata,ldata,ier,nchan,nrec
  logical :: notok
  real(kind=4), allocatable :: loc_buffer(:)
  logical :: readsec(-mx_sec:0)  ! Which section are to be read
  !
  error = .false.
  !
  ! Should use subroutine 'rheader' (which all reads all the available
  ! sections), but what about 'rzero' with the 'NULL' code?
  ! 'rzero' must come before 'robs', which partially fills the header.
  call rzero(obs,'NULL',user_function)
  !
  ! ROBS has 2 purposes:
  ! 1) read the sections informations (addresses, lengths, etc).
  !    Note that it is important to have an up-to-date User or X
  !    coordinate section length because we always read them from
  !    file
  ! 2) read the index block, in particular OBS%DESC%LDATA which we need
  !    for reading the data
  ! Call to ROBS is factorized here because:
  ! 1) we do not want to call it twice (one time when reading the
  !    header from file, again when reading the data from file)
  ! 2) ROBS copies the index block duplicate values in the header
  !    (is this really needed?), which is not satisfying because
  !    we can update e.g. the POSITION information (convert_pos)
  !    after reading the header and before reading the data
  call robs(obs,kx,error)
  if (error) return
  !
  ! --- HEADER reading ---
  ndata = 0
  if (set%verbose) then
    write(mess,*) 'Get header for obs: ',kx
    call class_message(seve%i,rname,mess)
  endif
  !
  obs%head%xnum = 0
  !
  ! Read all (the available) sections
  readsec(:) = .true.
  call rheader_sub(set,obs,readsec,error)
  if (error)  return
  !
  if (obs%head%gen%kind.eq.kind_sky) then
    ! Skydips
    obs%head%xnum = kx
    ndata = 0
    return
    !
  elseif (obs%head%gen%kind.eq.kind_spec) then
    ! Spectroscopic data
    ndata = obs%head%spe%nchan
    !
  elseif (obs%head%gen%kind.eq.kind_cont .or.  &
          obs%head%gen%kind.eq.kind_onoff) then
    ! Continuum drift or ONOFF
    ndata = obs%head%dri%npoin
  endif
  !
  ! Read User Defined section
  notok = user_function('GET')
  if (notok)  call class_message(seve%w,rname,'Error reading user sections')
  !
  obs%head%xnum = kx
  !
  ! --- HEADER update ---
  ! Convert coordinates
  call convert_pos(set,obs%head,error)
  if (error)  return
  ! Convert velocity type
  call convert_vtype(set,obs%head,error)
  if (error)  return
  !
  ! --- DATA reading ---
  if (set%verbose) then
     ! Debugging message
     write(mess,*) 'Get data for obs: ',kx,ndata
     call class_message(seve%i,rname,mess)
  endif
  ! Enlarge data space when needed
  call reallocate_obs(obs,ndata,error)
  if (error) return
  ! Additional allocation for old OTF format
  if (obs%is_otf) then
     nchan = obs%head%spe%nchan
     nrec  = obs%head%des%ndump
     ! Deallocate first? *** JP
     allocate(obs%data2(nchan,nrec),stat=ier)
     if (failed_allocate(rname,'data2',ier,error))  return
     allocate(obs%dap(nrec),stat=ier)
     if (failed_allocate(rname,'dap',ier,error))  return
  endif
  ! Now read irregular X axis if present
  if (obs%head%presec(class_sec_xcoo_id)) then
     call rxcoo(set,obs,error)
     error = .false.
  endif
  !
  ! OBS%DESC%LDATA already read with ROBS
  ! Should we enable this test (this can happen if data is not correctly
  ! written at the telescope)? Or is it a waste of time?
  ! if (ndata.ne.obs%desc%ldata) then
  !   write (mess,'(3(A,I0))')  &
  !     'Spurious data for observation #',kx,': expected ',ndata, &
  !     ' values, found ',obs%desc%ldata
  !   call class_message(seve%e,rname,mess)
  !   error = .true.
  !   return
  ! endif
  !
  ! Read data from file to obs
  ldata = obs%desc%ldata  ! Store into INTEGER*4
  if (obs%is_otf) then
    ! Allocate local buffer
    allocate(loc_buffer(obs%desc%ldata),stat=ier)
    if (failed_allocate(rname,'local buffer',ier,error))  return
    ! Read into local buffer
    call rdata(set,obs,ldata,loc_buffer,error)
    if (error) then
      call class_message(seve%e,rname,'Reading data from file')
      return
    endif
    ! Fill obs%dap and obs%data2 from loc_buffer
    call extract_otf(loc_buffer,obs%head%des%ldump,obs%dap,obs%data2,nchan,nrec)
    ! Not saved in the virtual buffer (useless/not available)
  else
    call rdata(set,obs,ldata,obs%data1,error)
    if (error) then
      call class_message(seve%e,rname,'Reading data from file')
      return
    endif
  endif
  ! Deallocate loc_buffer if needed
  if (obs%is_otf) deallocate(loc_buffer)
  !
  if (obs%is_otf) then
     ! Copy record #1 into OBS structure
     call get_rec(obs,1,error)
     if (error) return
  else
     ! Initialize these for compatibility
     obs%cnchan         = ndata
     obs%head%des%ndump = 1
     obs%head%des%ldump = 0
     obs%head%des%ldpar = 0
     obs%head%des%ldatl = 0
     obs%head%des%rec = 1
     obs%spectre => obs%data1
  endif
  !
  ! --- DATA update ---
  call convert_drop(set,obs,error)  ! Drop edge channels if needed
  if (error)  return
  call convert_scale(set,obs,.true.,error)  ! Rescale the Y data to desired unit
  if (error)  return
  !
  ! Not here: depends on calling program
  ! call newdat(set,obs,error)
end subroutine get_it
!
subroutine get_it_subset(set,obs,kx,extr,user_function,error)
  use gbl_message
  use gbl_constant
  use classic_api
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>get_it_subset
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! *** (Much) simplified duplicate of 'get_it', combined with ***
  ! *** partial duplicate of 'do_extract'                      ***
  ! - Get observation (header + SUBSET of data) number KX, FROM FILE
  ! (always), into observation structure OBS.
  ! - No support for OTF data, no use of the virtual buffers, no
  ! annoying message, no DROP support
  !---------------------------------------------------------------------
  type(class_setup_t),        intent(in)    :: set            !
  type(observation),          intent(inout) :: obs            ! Observation structure
  integer(kind=entry_length), intent(in)    :: kx             ! Entry number
  type(extract_t),            intent(inout) :: extr           ! Extraction description
  logical,                    external      :: user_function  !
  logical,                    intent(inout) :: error          ! Error flag
  ! Local
  character(len=*), parameter :: rname='GET_IT_SUB'
  integer(kind=data_length) :: ifirst,ilast,nv
  integer(kind=4) :: ofirst,olast,old_nchan
  real(kind=4) :: bad
  logical :: notok
  logical :: readsec(-mx_sec:0)  ! Which section are to be read
  !
  ! Should use subroutine 'rheader' (which all reads all the available
  ! sections), but what about 'rzero' with the 'NULL' code?
  ! 'rzero' must come before 'robs', which partially fills the header.
  call rzero(obs,'NULL',user_function)
  !
  call robs(obs,kx,error)
  if (error) return
  !
  ! Now read irregular X axis if present
  if (obs%head%presec(class_sec_xcoo_id)) then
    call class_message(seve%e,rname,'Irregularly spaced data not yet supported')
    error = .true.
    return
  elseif (obs%head%presec(class_sec_desc_id)) then
    call class_message(seve%e,rname,'Old OTF data not supported here')
    error = .true.
    return
  endif
  !
  ! --- HEADER reading ---
  obs%head%xnum = kx
  !
  ! Read all (the available) sections
  readsec(:) = .true.
  call rheader_sub(set,obs,readsec,error)
  if (error)  return
  !
  ! Set up extraction for header and data (comes after header reading)
  call do_extract_units(obs,extr,error)
  if (error)  return
  !
  ! Special treatment for Associated Arrays
  if (obs%head%presec(class_sec_assoc_id)) then
    call extract_assoc(obs%assoc,extr,error)
    if (error)  return
  endif
  !
  ! Read User Defined section
  notok = user_function('GET')
  if (notok)  call class_message(seve%w,rname,'Error reading user sections')
  !
  ! --- HEADER update ---
  ! Convert coordinates
  call convert_pos(set,obs%head,error)
  if (error)  return
  ! Convert velocity type
  call convert_vtype(set,obs%head,error)
  if (error)  return
  !
  ! --- DATA reading ---
  !
  ! Enlarge data space when needed
  call reallocate_obs(obs,extr%nc,error)
  if (error) return
  !
  ! Reading algorithm made efficient:
  ! 1) avoid filling data1(:) beyond extr%nc
  ! 2) avoid initializing with blanks everywhere before overwriting with real data
  ! 3) read only the needed part from file
  if (obs%head%gen%kind.eq.kind_spec) then
    bad = obs%head%spe%bad
    old_nchan = obs%head%spe%nchan
  else
    bad = obs%head%dri%bad
    old_nchan = obs%head%dri%npoin
  endif
  !
  if (extr%c1.le.0) then
    ifirst = 1_8         ! First channel read from input array
    ofirst = -extr%c1+2  ! First channel written in output array
    obs%data1(1:ofirst-1) = bad
  else
    ifirst = extr%c1
    ofirst = 1
  endif
  if (extr%c2.gt.old_nchan) then
    ilast = old_nchan            ! Last channel read from input array
    olast = old_nchan-extr%c1+1  ! Last channel written in output array
    obs%data1(olast+1:extr%nc) = bad
  else
    ilast = extr%c2
    olast = extr%c2-extr%c1+1
  endif
  nv = ilast-ifirst+1_8  ! Number of values to read from file
  !
  ! Read data from file to obs
  call rdata_sub(set,obs,ifirst,ilast,nv,obs%data1(ofirst:),error)
  if (error) then
    call class_message(seve%e,rname,'Reading data from file')
    return
  endif
  !
  ! Update the header. Easy: just change Nchan and shift Rchan
  if (obs%head%gen%kind.eq.kind_spec) then
    obs%head%spe%nchan = extr%nc
    obs%head%spe%rchan = obs%head%spe%rchan-extr%c1+1.d0
  else
    obs%head%dri%npoin = extr%nc
    obs%head%dri%rpoin = obs%head%dri%rpoin-extr%c1+1
  endif
  !
  ! Disable PLOT section. We can also choose to update the Vmin-Vmax values
  ! but we don't want to recompute the Ymin-Ymax in order to save time
  obs%head%presec(class_sec_plo_id) = .false.
  !
  ! Initialize these for old OTF compatibility
  obs%cnchan         = extr%nc
  obs%head%des%ndump = 1
  obs%head%des%ldump = 0
  obs%head%des%ldpar = 0
  obs%head%des%ldatl = 0
  obs%head%des%rec = 1
  obs%spectre => obs%data1
  !
  ! --- DATA update ---
  call convert_scale(set,obs,.true.,error)  ! Rescale the Y data to desired unit
  if (error)  return
  !
end subroutine get_it_subset
!
subroutine get_rec(obs,ir,error)
  use gildas_def
  use gbl_message
  use classcore_interfaces, except_this=>get_rec
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Copy record IR into OBS structure
  ! The content of DAPS in CLASS old OTF format
  !     type      number      content
  !     Real*4    1           RAZ           Azimuth in radians
  !     Real*4    1           REL           Elevation in radians
  !     Real*4    1           R4ST          LST       in radians
  !     Real*4    1           R4UT          UT        in radians
  !     Real*4    1           RLAMOF        Lambda offset in radians
  !     Real*4    1           RBETOF        Beta   offset in radians
  !     Integer*4 1           RFEED         feed number of array rec.
  !---------------------------------------------------------------------
  type (observation), intent(inout) :: obs    ! Current observation
  integer,            intent(in)    :: ir     ! Record number
  logical,            intent(out)   :: error  ! Error flag
  ! Local
  character(len=13) :: ch
  !
  if (.not.obs%is_otf) return
  !
  if (ir.lt.1 .or. ir.gt.obs%head%des%ndump) then
     write (ch,'(i6,a,i6)') ir,'/',obs%head%des%ndump
     call class_message(seve%f,'GET_REC','Invalid record '//ch(1:13))
     error = .true.
     return
  endif
  !
  obs%spectre => obs%data2(:,ir)
  !
  ! Data Associated Parameters
  obs%head%gen%az    = obs%dap(ir)%az
  obs%head%gen%el    = obs%dap(ir)%el
  obs%head%gen%st    = obs%dap(ir)%st
  obs%head%gen%ut    = obs%dap(ir)%ut
  obs%head%pos%lamof = obs%dap(ir)%lamof
  obs%head%pos%betof = obs%dap(ir)%betof
  obs%head%des%rec = ir
end subroutine get_rec
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine extract_otf(raw,ndat,dap,datotf,nchan,nrec)
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  ! Separate spectral intensities from DAPS for an old OTF format scan
  !---------------------------------------------------------------------
  integer(kind=4), intent(in)  :: ndat                ! nchan+ndaps
  integer(kind=4), intent(in)  :: nrec                ! Nb of records
  real(kind=4),    intent(in)  :: raw(ndat,nrec)      ! Complete data array
  type (dapotf),   intent(out) :: dap(nrec)           ! DAPs array
  integer(kind=4), intent(in)  :: nchan               ! Nb of channels
  real(kind=4),    intent(out) :: datotf(nchan,nrec)  ! Spectral data array
  ! Local
  integer(kind=4) :: i,j
  !
  do j=1,nrec
     call r4tor4 (raw(1,j),datotf(1,j),nchan)
     i = ndat-19
     dap(j)%irec = j
     i = i+1
     dap(j)%az = raw(i,j)
     i = i+1
     dap(j)%el = raw(i,j)
     i = i+1
     dap(j)%st = raw(i,j)
     i = i+1
     dap(j)%ut = raw(i,j)
     i = i+1
     dap(j)%lamof = raw(i,j)
     i = i+1
     dap(j)%betof = raw(i,j)
  enddo
end subroutine extract_otf
!
subroutine copy_header(in,out)
  use class_types
  !---------------------------------------------------------------------
  ! @ private-mandatory (because symbol is used elsewhere)
  ! Copy the header of IN into OUT
  !---------------------------------------------------------------------
  type(header), intent(in)  :: in   !
  type(header), intent(out) :: out  !
  out = in
end subroutine copy_header
