subroutine find(set,line,error)
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>find
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ public
  ! CLASS Support routine for command
  !    FIND [APPEND|NEW_DATA|UPDATE]
  !  1       [/ALL]
  !  2       [/LINE]
  !  3       [/NUMBER]
  !  4       [/SCAN]
  !  5       [/OFFSET]
  !  6       [/SOURCE]
  !  7       [/RANGE]
  !  8       [/QUALITY]
  !  9       [/TELESCOPE]
  ! 10       [/SUBSCAN]
  ! 11       [/ENTRY]
  ! 12       [/OBSERVED]
  ! 13       [/REDUCED]
  ! 14       [/FREQUENCY]
  ! 15       [/SECTION]
  ! 16       [/USER]
  ! 17       [/MASK]
  ! 18       [/POSITION]
  !  Find a set of observations according to setup search rules and
  ! command options.
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set    !
  character(len=*),    intent(in)    :: line   ! Command line
  logical,             intent(inout) :: error  ! Error status
  ! Local
  character(len=*), parameter :: rname='FIND'
  integer(kind=entry_length) :: cxnext0
  character(len=80) :: mess
  character(len=14) :: argum
  logical :: new_argum,upd_argum,app_argum
  logical :: new_wanted,upd_wanted,app_wanted
  integer(kind=4), parameter :: mvocab=3
  character(len=12) :: vocab(mvocab),keywor
  integer(kind=4) :: nc,nkey,iarg,ier
  integer(kind=entry_length) :: nfound,erange(2)
  integer(kind=entry_length) :: indmin,indmax,i,j,k
  ! Data
  data vocab/'APPEND','NEW_DATA','UPDATE'/
  !
  if (.not.filein_opened(rname,error))  return
  !
  call find_setup(set,line,error)
  if (error)  return
  !
  ! APPEND|NEW_DATA|UPDATE arguments
  app_argum = .false.  ! append to previous CX
  new_argum = .false.  ! find in new entries only
  upd_argum = .false.  ! update IX before FIND
  do iarg=1,sic_narg(0)
     call sic_ke (line,0,iarg,argum,nc,.false.,error)
     if (error) return
     call sic_ambigs(rname,argum,keywor,nkey,vocab,mvocab,error)
     if (error) return
     select case (nkey)
     case(1)
        app_argum = .true.
     case(2)
        new_argum = .true.
     case(3)
        upd_argum = .true.
     end select
  enddo
  if ((app_argum.and.new_argum) .or.  &   ! Useless, this is UPDATE
      (app_argum.and.upd_argum) .or.  &   ! Useless / no-sense
      (new_argum.and.upd_argum)) then     ! Exclusive
    call class_message(seve%e,rname,  &
      'Arguments APPEND, NEW_DATA and UPDATE are exclusive')
    error = .true.
    return
  endif
  !
  app_wanted = app_argum
  new_wanted = new_argum
  upd_wanted = upd_argum.or.set%fupda
  !
  ! Update index
  if (upd_wanted) then
     call ix_update(error)
     if (error) return
  endif
  !
  ! Zeroes the current index by default, except if APPEND
  if (.not.app_wanted) then
     cx%next = 1
     knext = 0
  endif
  cxnext0 = cx%next
  !
  if (new_wanted) then
    ! Look in IX for new entries and restrict the search to this 'entry range'
    call eix_newdata(erange(1),erange(2),error)
    if (error) return
    call fix(set,ix,cx,nfound,error,erange)
    if (error)  return
  else
    ! Search in all IX entries
    call fix(set,ix,cx,nfound,error)
    if (error)  return
  endif
  if (nfound.eq.0) then
    call class_message(seve%w,rname,'Nothing found')
    goto 999
  endif
  !
  if (cxnext0.gt.1 .and. cx%next.gt.cxnext0) then
     ! There was already entries in CX and we added more: compress CX
     k = cxnext0
     do i=cxnext0, cx%next-1
        do j=1, cxnext0-1
           if (cx%ind(j).eq.cx%ind(i)) goto 100
        enddo
        call optimize_tooptimize(cx,i,cx,k,.true.,error)
        if (error)  goto 999
        k = k+1
100     continue
     enddo
     cx%next = k
     nindex = cx%next-1
  endif
  !
  ! Sort index (after compression and extraction)
  if (set%do_sort) call sort_index(set,'C',error)
  !
  ! /ENTRY option: Extract entry numbers if needed. Parsing is done here
  ! because execution is not done in FIX...
  call find_by_entry(set,line,indmin,indmax,error)
  if (error)  return
  if (flg%ind) then
     k = 1
     do i=indmin,min(indmax,cx%next-1)
        call optimize_tooptimize(cx,i,cx,k,.true.,error)
        if (error)  return
        k = k+1
     enddo
     cx%next = k
     nindex  = cx%next-1
     nfound  = nindex
  endif
  !
  if (error) return
  !
  if (nfound.eq.1) then
     call class_message(seve%i,rname,'1 observation found')
  elseif (nfound.ne.0) then
     write(mess,'(I0,A)') cx%next-1,' observations found'
     call class_message(seve%i,rname,mess)
  endif
  !
999 continue
  ! Time when index is filled
  ier = gag_time(cx%time)
  if (ier.ne.0) then
    call class_message(seve%e,rname,'Error getting current time')
    error = .true.
    if (error)  return
  endif
  !
  ! Check whether current index contains old format observations
  if (cx%next.gt.1) then
     cx%has_old_fmt = minval(cx%subscan(1:cx%next-1)).eq.0
     if (cx%has_old_fmt) &
        call class_message(seve%w,rname,'Current index contains old format data')
  else
     cx%has_old_fmt = .false.
  endif
  !
  ! Reset the IDX% Sic structure
  call class_variable_index_reset(error)
  if (error) return
  !
  ! Index has changed: Reset consistency and range information
  call consistency_defaults(set,cx%cons)
  cx%ranges%done = .false.
  call index_ranges(cx,error)
  !
end subroutine find
!
subroutine find_setup(set,line,error)
  use gbl_constant
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>find_setup
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Parse the command line and setup the smin%, smax% and flg%
  ! structures for later use by subroutine FIX.
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set    !
  character(len=*),    intent(in)    :: line   !
  logical,             intent(inout) :: error  !
  ! Local
  character(len=*), parameter :: rname='FIND'
  integer(kind=4) :: nc
  character(len=14) :: argum1,argum2,argum3
  character(len=argument_length) :: expr1,expr2
  real(kind=4) :: any
  real(kind=8) :: dummy
  integer(kind=4), parameter :: mini2=-32768
  integer(kind=4), parameter :: maxi2=32767
  integer(kind=4), parameter :: maxi4=2147483647_4
  integer(kind=8), parameter :: maxi8=9223372036854775807_8
  !
  call chtoby('ANY ',any,4)
  !
  flg%last=.not.sic_present(1,0)  ! Only last version unless specified
  flg%ver=.false.                 ! No version specified
  !
  !***************** Obs. Type (no option) **************
  if (set%kind.eq.kind_any) then
    flg%kind = .false.
  else
    flg%kind = .true.
    smin%kind = set%kind
  endif
  !
  !*********************** /LINE ***********************
  if (sic_present(2,0)) then
    smin%cline = '*'
    call sic_ch(line,2,1,smin%cline,nc,.false.,error)
    if (error) return
  else ! SET LINE
    smin%cline = set%line
  endif
  call sic_upper(smin%cline)
  flg%line = smin%cline.ne.'*'
  flg%iline = index(smin%cline,'*')
  !
  !*********************** /NUMBER ***********************
  flg%num=.false.
  smin%num=0
  smax%num=maxi8
  if (sic_present(3,0)) then
    argum1= '*'
    call sic_ke (line,3,1,argum1,nc,.false.,error)
    if (error) return
    argum2= ' '
    call sic_ke (line,3,2,argum2,nc,.false.,error)
    if (error) return
    if (argum1(1:1).eq.'*') then
      smin%num=1
    else
      call sic_i8 (line,3,1,smin%num,.false.,error)
      if (error) return
      flg%num=.true.
    endif
    if (argum2(1:1).eq.' ') then
      smax%num=smin%num
    elseif (argum2.ne.'*') then
      call sic_i8 (line,3,2,smax%num,.false.,error)
      if (error) return
      flg%num=.true.
    endif
    ! SET NUMBER
  elseif (set%nume1.ne.0 .or. set%nume2.ne.maxi8) then
    flg%num=.true.
    smin%num=set%nume1
    smax%num=set%nume2
  endif
  !
  !*********************** /OBSERVED ***********************
  flg%dobs=.false.
  if (sic_present(12,0)) then
    argum1  = '*'
    call sic_ke (line,12,1,argum1,nc,.false.,error)
    if (error) return
    argum2 = '*'
    call sic_ke (line,12,2,argum2,nc,.false.,error)
    if (error) return
    smin%dobs = mini2
    call gag_fromdate(argum1,smin%dobs,error)
    smax%dobs = maxi2
    call gag_fromdate(argum2,smax%dobs,error)
    if (error) return
    if (smax%dobs.ne.maxi2.or.smin%dobs.ne.mini2) flg%dobs=.true.
  else  ! SET OBSERVED
    if (set%obse1.ne.mini2 .or. set%obse2.ne.maxi2) then
      flg%dobs=.true.
      smin%dobs=set%obse1
      smax%dobs=set%obse2
    else
      flg%dobs=.false.
      smin%dobs=mini2
      smax%dobs=maxi2
    endif
  endif
  !
  !*********************** /SCAN ***********************
  flg%scan=.false.
  smin%scan=0
  smax%scan=maxi8
  if (sic_present(4,0)) then
    argum1= '*'
    call sic_ke (line,4,1,argum1,nc,.false.,error)
    if (error) return
    argum2= ' '
    call sic_ke (line,4,2,argum2,nc,.false.,error)
    if (error) return
    if (argum1(1:1).eq.'*') then
      smin%scan = 0
    else
      call sic_i8 (line,4,1,smin%scan,.false.,error)
      if (error) return
      flg%scan=.true.
    endif
    if (argum2(1:1).eq.' ') then
      smax%scan=smin%scan
    elseif (argum2.ne.'*') then
      call sic_i8 (line,4,2,smax%scan,.false.,error)
      if (error) return
      flg%scan=.true.
    endif
    ! SET SCAN
  elseif (set%scan1.ne.0 .or. set%scan2.ne.maxi8) then
    flg%scan=.true.
    smin%scan=set%scan1
    smax%scan=set%scan2
  endif
  !
  !*********************** /OFFSET ***********************
  if (sic_present(5,0)) then
    argum2 = ' '  ! Default current angle unit
    call sic_ke(line,5,3,argum2,nc,.false.,error)
    if (error)  return
    !
    expr1= '*'
    call sic_ke (line,5,1,expr1,nc,.false.,error)
    if (error) return
    if (expr1(1:1).ne.'*') then
      call coffse(set,rname,expr1,argum2,smin%off1,error)
      if (error) return
      flg%off1=.true.
      smax%off1=smin%off1+set%tole
      smin%off1=smin%off1-set%tole
    endif
    !
    expr1= '*'
    call sic_ke (line,5,2,expr1,nc,.false.,error)
    if (error) return
    if (expr1(1:1).ne.'*') then
      call coffse(set,rname,expr1,argum2,smin%off2,error)
      if (error) return
      flg%off2=.true.
      smax%off2=smin%off2+set%tole
      smin%off2=smin%off2-set%tole
    endif
  endif
  !
  !*********************** /SOURCE ***********************
  if (sic_present(6,0)) then
    smin%csour = '*'
    call sic_ch(line,6,1,smin%csour,nc,.false.,error)
    if (error) return
  else ! SET SOURCE
    smin%csour = set%sourc
  endif
  call sic_upper(smin%csour)
  flg%sourc = smin%csour.ne.'*'
  flg%isourc = index(smin%csour,'*')
  !
  !***********************  /RANGE ***********************
  if (sic_present(7,0)) then
    flg%off1=.false.
    flg%off2=.false.
    smin%off1=any
    smin%off2=any
    smax%off1=any
    smax%off2=any
    !
    argum3 = ' '  ! Default current angle unit
    call sic_ke(line,7,5,argum3,nc,.false.,error)
    if (error)  return
    !
    expr1= '*'
    call sic_ke (line,7,1,expr1,nc,.false.,error)
    if (error) return
    if (expr1(1:1).ne.'*') then
      call coffse(set,rname,expr1,argum3,smin%off1,error)
      if (error) return
      flg%off1=.true.
      smin%off1=smin%off1-set%tole
    endif
    !
    expr2= '*'
    call sic_ke (line,7,2,expr2,nc,.false.,error)
    if (error) return
    if (expr2(1:1).ne.'*') then
      call coffse(set,rname,expr2,argum3,smax%off1,error)
      if (error) return
      flg%off1=.true.
      smax%off1=smax%off1+set%tole
    endif
    !
    expr1= '*'
    call sic_ke (line,7,3,expr1,nc,.false.,error)
    if (error) return
    if (expr1(1:1).ne.'*') then
      call coffse(set,rname,expr1,argum3,smin%off2,error)
      if (error) return
      flg%off2=.true.
      smin%off2=smin%off2-set%tole
    endif
    !
    expr2= '*'
    call sic_ke (line,7,4,expr2,nc,.false.,error)
    if (error) return
    if (expr2(1:1).ne.'*') then
      call coffse(set,rname,expr2,argum3,smax%off2,error)
      if (error) return
      flg%off2=.true.
      smax%off2=smax%off2+set%tole
    endif
    !
  else ! SET OFFSET or SET RANGE
    if (.not.flg%off1 .and.  &
        (set%offs1.ne.any .or. set%offl1.ne.any)) then
      flg%off1=.true.
      smin%off1=set%offs1
      if (smin%off1.ne.any) smin%off1 = smin%off1-set%tole
      smax%off1=set%offl1
      if (smax%off1.ne.any) smax%off1 = smax%off1+set%tole
    endif
    if (.not.flg%off2.and.(set%offs2.ne.any .or. set%offl2.ne.any)) then
      flg%off2=.true.
      smin%off2=set%offs2
      if (smin%off2.ne.any) smin%off2 = smin%off2-set%tole
      smax%off2=set%offl2
      if (smax%off2.ne.any) smax%off2 = smax%off2+set%tole
    endif
  endif
  !
  !*********************** /QUALITY ***********************
  smin%qual = set%qual2
  if (sic_present(8,0)) then
    call sic_i4 (line,8,1,smin%qual,.false.,error)
    if (error) return
    if (smin%qual.lt.0 .or. smin%qual.gt.9) then
      call class_message(seve%e,rname,'Quality out of range 0-9')
      error = .true.
      return
    endif
  endif
  !
  !*********************** /REDUCED ***********************
  flg%dred=.false.
  if (sic_present(13,0)) then
    argum1  = '*'
    call sic_ke (line,13,1,argum1,nc,.false.,error)
    if (error) return
    argum2 = '*'
    call sic_ke (line,13,2,argum2,nc,.false.,error)
    if (error) return
    smin%dred = mini2
    call gag_fromdate(argum1,smin%dred,error)
    if (error) return
    smax%dred = maxi2
    call gag_fromdate(argum2,smax%dred,error)
    if (error) return
    if (smax%dred.ne.maxi2.or.smin%dred.ne.mini2) flg%dred=.true.
  else ! SET REDUCED
    if (set%redu1.ne.mini2 .or. set%redu2.ne.maxi2) then
      flg%dred=.true.
      smin%dred=set%redu1
      smax%dred=set%redu2
    else
      flg%dred=.false.
      smin%dred=mini2
      smax%dred=maxi2
    endif
  endif
  !
  !*********************** /TELESCOPE ***********************
  if (sic_present(9,0)) then
    smin%ctele= '*'
    call sic_ch(line,9,1,smin%ctele,nc,.false.,error)
    if (error) return
  else
    smin%ctele = set%teles
  endif
  call sic_upper(smin%ctele)
  flg%teles = smin%ctele.ne.'*'
  flg%iteles = index(smin%ctele,'*')
  !
  !*********************** /SUBSCAN ***********************
  flg%subscan=.false.
  smin%subscan=0
  smax%subscan=maxi4
  if (sic_present(10,0)) then
    argum1= '*'
    call sic_ke (line,10,1,argum1,nc,.false.,error)
    if (error) return
    argum2= ' '
    call sic_ke (line,10,2,argum2,nc,.false.,error)
    if (error) return
    if (argum1(1:1).eq.'*') then
      smin%subscan = 0
    else
      call sic_i4  (line,10,1,smin%subscan,.false.,error)
      if (error) return
      flg%subscan=.true.
    endif
    if (argum2(1:1).eq.' ') then
      smax%subscan=smin%subscan
    elseif (argum2.ne.'*') then
      call sic_i4 (line,10,2,smax%subscan,.false.,error)
      if (error) return
      flg%subscan=.true.
    endif
    ! SET SUBSCAN
  elseif (set%sub1.ne.0 .or. set%sub2.ne.maxi4) then
    flg%subscan=.true.
    smin%subscan=set%sub1
    smax%subscan=set%sub2
  endif
  !
  !*********************** SET POSANGLE ***********************
  if (set%kind.eq.kind_cont) then
    if (set%posa1.ne.-1e7 .or. set%posa2.ne.+1e7) then
      flg%posa=.true.
      smin%posa=set%posa1
      smax%posa=set%posa2
    else
      flg%posa=.false.
    endif
  endif
  !
  !**************************** /FREQUENCY *****************************
  if (sic_present(14,0)) then
    if (set%kind.ne.kind_spec) then
      call class_message(seve%e,rname,  &
        'FIND /FREQUENCY is allowed only with spectroscopic data')
      error = .true.
      return
    endif
    !
    call setfrequency('FIND /FREQUENCY',line,14,1,flg%freqmin,flg%freqmax,  &
      flg%freqsig,error)
    if (error)  return
    !
  else  ! SET FREQUENCY
    if (set%kind.eq.kind_spec) then
      flg%freqmin = set%freqmin
      flg%freqmax = set%freqmax
      flg%freqsig = set%freqsig
    else
      ! Ignore
      flg%freqmin = -1.d0
      flg%freqmax = -1.d0
      flg%freqsig = .true.
    endif
  endif
  !
  flg%freq = flg%freqmin.gt.0.d0 .or. flg%freqmax.gt.0.d0
  !
  ! Sort here to ease later computations
  if (flg%freq) then
    ! Frequency selection is in use
    if (flg%freqmin.gt.0.d0 .and. flg%freqmax.gt.0.d0) then
      ! Both values are set
      if (flg%freqmax.lt.flg%freqmin) then
        ! Values are misordered. Swap.
        dummy = flg%freqmin
        flg%freqmin = flg%freqmax
        flg%freqmax = dummy
      endif
    endif
  endif
  !
  !************************** /SECTION **************************
  call find_setup_section(line,error)
  if (error)  return
  !
  !************************** /USER *****************************
  flg%user = sic_present(16,0)
  if (flg%user) then
    call user_sec_find(line,error)
    if (error)  return
  endif
  !
  !************************** /MASK *****************************
  call find_setup_mask(line,error)
  if (error)  return
  !
  !************************ /POSITION ***************************
  call find_setup_position(line,error)
  if (error)  return
  !
end subroutine find_setup
!
subroutine index_ranges(windex,error)
  use class_parameter
  use class_types
  use class_index
  !---------------------------------------------------------------------
  ! @ private
  ! Computes ranges of LAMBDA BETA SCAN DOBS (DRED)
  !---------------------------------------------------------------------
  type(optimize), intent(inout) :: windex  !
  logical,        intent(out)   :: error   !
  ! Local
  integer(kind=entry_length) :: i,inum
  real(kind=4) :: min_loff,max_loff,min_boff,max_boff
  integer(kind=obsnum_length) :: min_scan,max_scan
  integer(kind=4) :: min_dobs,max_dobs
  !
  ! If already done, don't do it
  if (windex%ranges%done) return
  if (windex%next.le.1) return  ! Empty index case...
  !
  ! Initialization
  error = .true.
  inum     = windex%ind(1)
  min_loff = ix%off1(inum)
  max_loff = ix%off1(inum)
  min_boff = ix%off2(inum)
  max_boff = ix%off2(inum)
  min_scan = ix%scan(inum)
  max_scan = ix%scan(inum)
  min_dobs = ix%dobs(inum)
  max_dobs = ix%dobs(inum)
  !
  ! Loop on entries
  do i=1,windex%next-1
     inum = windex%ind(i)
     min_loff = min(min_loff,ix%off1(inum))
     max_loff = max(max_loff,ix%off1(inum))
     min_boff = min(min_boff,ix%off2(inum))
     max_boff = max(max_boff,ix%off2(inum))
     min_scan = min(min_scan,ix%scan(inum))
     max_scan = max(max_scan,ix%scan(inum))
     min_dobs = min(min_dobs,ix%dobs(inum))
     max_dobs = max(max_dobs,ix%dobs(inum))
  enddo
  !
  windex%ranges%lam1  = min_loff
  windex%ranges%lam2  = max_loff
  windex%ranges%bet1  = min_boff
  windex%ranges%bet2  = max_boff
  windex%ranges%scan1 = min_scan
  windex%ranges%scan2 = max_scan
  windex%ranges%dobs1 = min_dobs
  windex%ranges%dobs2 = max_dobs
  windex%ranges%dred1 = 0
  windex%ranges%dred2 = 0
  !
  windex%ranges%done = .true.
  error = .false.
end subroutine index_ranges
!
subroutine find_by_entry(set,line,indmin,indmax,error)
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>find_by_entry
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Support routine for command
  !    FIND /ENTRY
  !  Parse the command line for the FIND /ENTRY arguments
  !---------------------------------------------------------------------
  type(class_setup_t),        intent(in)    :: set
  character(len=*),           intent(in)    :: line
  integer(kind=entry_length), intent(out)   :: indmin
  integer(kind=entry_length), intent(out)   :: indmax
  logical,                    intent(inout) :: error
  ! Local
  character(len=*), parameter :: rname='FIND'
  integer(kind=4) :: nc
  character(len=14) :: argum1,argum2
  integer(kind=entry_length) :: indtmp
  integer(kind=8), parameter :: maxi8=9223372036854775807_8
  !
  flg%ind=.false.
  if (sic_present(11,0)) then
    !
    argum1= '*'
    call sic_ke (line,11,1,argum1,nc,.false.,error)
    if (error) return
    argum2= '*'
    call sic_ke (line,11,2,argum2,nc,.false.,error)
    if (error) return
    !
    if (argum1(1:1).eq.'*') then
      indmin = 1
    else
      call sic_i8(line,11,1,indmin,.true.,error)
      if (error) return
      flg%ind=.true.
    endif
    !
    if (argum2(1:1).eq.'*') then
      indmax = ix%mobs
    else
      call sic_i8(line,11,2,indmax,.false.,error)
      if (error) return
      flg%ind=.true.
    endif
    ! Check consistency
    if (indmin.gt.indmax) then
      call class_message(seve%i,rname,'Swap ENTRY arguments')
      indtmp = indmin
      indmin = indmax
      indmax = indtmp
    else if (indmin.le.0) then
      call class_message(seve%e,rname,'Entry number must be > 0')
      error = .true.
      return
    endif
    !
  elseif (set%entr1.ne.0 .or. set%entr2.ne.maxi8) then
    flg%ind = .true.
    indmin = set%entr1
    indmax = set%entr2
  endif
  !
end subroutine find_by_entry
!
subroutine find_setup_section(line,error)
  use gkernel_interfaces
  use class_index
  !---------------------------------------------------------------------
  ! @ private
  ! Support routine for command FIND /SECTION FOO
  ! If required, turn on the FIND flags for a by-section search.
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Input command line
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=32) :: argum,sname
  integer(kind=4) :: nc,sval
  integer(kind=4), parameter :: vocf=-18,vocl=0
  integer(kind=4), parameter :: nvoc=vocl-vocf+1
  character(len=12) :: vocab(nvoc)
  ! Data
  ! Use same names as SET VARIABLE
  data vocab /'ABS',      '',            'SKYDIP',     &  ! -18:-16
              '',         'CALIBRATION', 'NH3',        &  ! -15:-13
              'SHELL',    'BEAM',        'CONTINUUM',  &  ! -12:-10
              'GAUSS',    'SWITCH',      'PLOT',       &  !  -9:-7
              '',         'BASE',        'SPECTRO',    &  !  -6:-4
              'POSITION', 'GENERAL',     'COMMENT',    &  !  -3:-1
              'USER'/                                     !   0
  !
  flg%sectval = 1  ! No section has a positive identifier
  if (sic_present(15,0)) then
    call sic_ke(line,15,1,argum,nc,.true.,error)
    if (error) return
    call sic_ambigs('FIND',argum,sname,sval,vocab,nvoc,error)
    if (error)  return
    flg%sectval = vocf+sval-1
  endif
  flg%sect = flg%sectval.le.0
  !
end subroutine find_setup_section
!
subroutine find_setup_mask(line,error)
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>find_setup_mask
  use class_common
  use class_index
  !---------------------------------------------------------------------
  ! @ private
  ! Support routine for command FIND /MASK Name
  ! If required, turn on the FIND flags for a mask search
  ! Name is assumed a file name
  ! We could also support variables in the future
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Input command line
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='FIND'
  integer(kind=4), parameter :: optmask=17
  integer(kind=4) :: nc,ier
  character(len=message_length) :: mess
  logical :: error2
  !
  ! Clean previous mask
  if (flg%mask%loca%islo.ne.0) then
    error2 = .false.
    call gdf_close_image(flg%mask,error2)
    if (error2) then
      error = .true.
      return
    endif
    if (associated(flg%mask%r2d))  deallocate(flg%mask%r2d)
  endif
  !
  flg%domask = sic_present(optmask,0)
  if (.not.flg%domask)  return
  !
  call gildas_null(flg%mask)
  !
  ! Get mask file name
  if (filein_isvlm) then
    ! Default same as FILE IN VLM with extension .wei
    nc = len_trim(filein_vlmhead%file)
    flg%mask%file = filein_vlmhead%file(1:nc-4)//'.wei'
  elseif (.not.sic_present(optmask,1)) then
    call class_message(seve%e,rname,'No default file name for /MASK')
    error = .true.
    return
  endif
  call sic_ch(line,optmask,1,flg%mask%file,nc,.false.,error)
  if (error) return
  !
  ! Read only the header. The data will be read after we ensured
  ! everything is correct
  call gdf_read_header(flg%mask,error)
  if (error)  return
  !
  if (flg%mask%gil%ndim.ne.2) then
    write(mess,'(A,I0,A)')  'Mask must have 2 dimensions (got ',flg%mask%gil%ndim,')'
    call class_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  if (flg%mask%gil%xaxi*flg%mask%gil%yaxi.ne.2) then
    ! Ensure that the ref/val/inc axes are spatial i.e. they can be used
    ! with the Class lamof/betof.
    call class_message(seve%e,rname,  &
      'The mask dimensions does not appear to be spatial dimensions')
    error = .true.
    return
  endif
  !
  ! Read the data as a flat array (easier use later on)
  allocate(flg%mask%r2d(flg%mask%gil%dim(1),flg%mask%gil%dim(2)),stat=ier)
  if (failed_allocate(rname,'mask r2d',ier,error))  return
  call gdf_read_data(flg%mask,flg%mask%r2d,error)
  if (error)  return
  !
end subroutine find_setup_mask
!
subroutine find_setup_position(line,error)
  use gbl_constant
  use gbl_message
  use phys_const
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>find_setup_position
  use class_index
  !---------------------------------------------------------------------
  ! @ private
  ! Support routine for command
  !    FIND /POSITION A0 D0 System [Equinox]
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: line   ! Input command line
  logical,          intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='FIND'
  integer(kind=4), parameter :: optpos=18
  integer(kind=4) :: nc,ikey
  character(len=24) :: argum,keyw
  character(len=message_length) :: mess
  character(len=10), parameter :: syst(2) = (/ 'EQUATORIAL','GALACTIC  ' /)
  !
  flg%dopos = sic_present(optpos,0)
  if (.not.flg%dopos)  return
  !
  call sic_ch(line,optpos,1,argum,nc,.true.,error)
  if (error)  return
  call sic_sexa(argum,nc,flg%poslam,error)
  if (error)  return
  !
  call sic_ch(line,optpos,2,argum,nc,.true.,error)
  if (error)  return
  call sic_sexa(argum,nc,flg%posbet,error)
  if (error)  return
  !
  call sic_ke(line,optpos,3,argum,nc,.true.,error)
  if (error)  return
  call sic_ambigs(rname,argum,keyw,ikey,syst,2,error)
  if (keyw.eq.'EQUATORIAL') then
    flg%poslam = flg%poslam*rad_per_hang
    flg%posbet = flg%posbet*rad_per_deg
    flg%possys = type_eq
    call sic_r4(line,optpos,4,flg%posequ,.true.,error)
    if (error)  return
  else
    flg%poslam = flg%poslam*rad_per_deg
    flg%posbet = flg%posbet*rad_per_deg
    flg%possys = type_ga
    flg%posequ = equinox_null
  endif
  !
end subroutine find_setup_position
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
subroutine sort_index(set,key,error)
  use classcore_interfaces, except_this=>sort_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Sort the index using the quicksort algorithm.
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)  :: set    !
  character(len=1),    intent(in)  :: key    ! Index: I, O, Current (default)
  logical,             intent(out) :: error  ! Error status
  select case(key)
  case('I')
     call sort_ix(set,error)
  case('O')
     return
  case default
     call sort_cx(set,error)
  end select
end subroutine sort_index
!
subroutine sort_cx(set,error)
  use classcore_interfaces, except_this=>sort_cx
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Sort the index using the quicksort algorithm.
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set    !
  logical,             intent(inout) :: error  ! Error status
  ! Local
  integer(kind=entry_length) :: ix_iobs, cx_iobs
  !
  if (cx%next.le.2) return
  !
  select case (set%sort_name)
  case ('BLOC')
     call quicksort(set,cx%ind,cx%next-1,ix_bloc_gt,ix_bloc_ge,error)
  case ('NUMBER')
     call quicksort(set,cx%ind,cx%next-1,ix_num_gt,ix_num_ge,error)
  case ('VERSION')
     call quicksort(set,cx%ind,cx%next-1,ix_ver_gt,ix_ver_ge,error)
  case ('OBSERVED')
     call quicksort(set,cx%ind,cx%next-1,ix_dobs_gt,ix_dobs_ge,error)
  case ('LAMBDA')
     call quicksort(set,cx%ind,cx%next-1,ix_off1_gt,ix_off1_ge,error)
  case ('BETA')
     call quicksort(set,cx%ind,cx%next-1,ix_off2_gt,ix_off2_ge,error)
  case ('SCAN')
     call quicksort(set,cx%ind,cx%next-1,ix_scan_gt,ix_scan_ge,error)
  case ('SUBSCAN')
     call quicksort(set,cx%ind,cx%next-1,ix_subscan_gt,ix_subscan_ge,error)
  case ('KIND')
     call quicksort(set,cx%ind,cx%next-1,ix_kind_gt,ix_kind_ge,error)
  case ('QUALITY')
     call quicksort(set,cx%ind,cx%next-1,ix_qual_gt,ix_qual_ge,error)
  case ('SOURCE')
     call quicksort(set,cx%ind,cx%next-1,ix_csour_gt,ix_csour_ge,error)
  case ('LINE')
     call quicksort(set,cx%ind,cx%next-1,ix_cline_gt,ix_cline_ge,error)
  case ('TELESCOPE')
     call quicksort(set,cx%ind,cx%next-1,ix_ctele_gt,ix_ctele_ge,error)
  case ('TOC')
     call quicksort(set,cx%ind,cx%next-1,ix_toc_default_gt,ix_toc_default_ge,error)
  case ('NONE')
     return
  end select
  if (error) return
  !
  do cx_iobs=1,cx%next-1
     ix_iobs = cx%ind(cx_iobs)
     call optimize_tooptimize(ix,ix_iobs,cx,cx_iobs,.true.,error)
     if (error)  return
  enddo
end subroutine sort_cx
!
subroutine sort_ix(set,error)
  use classcore_interfaces, except_this=>sort_ix
  use class_index
  use class_types
  !---------------------------------------------------------------------
  ! @ private
  !  Sort the input file index using the quicksort algorithm.
  !---------------------------------------------------------------------
  type(class_setup_t), intent(in)    :: set    !
  logical,             intent(inout) :: error  ! Error status
  ! Local
  integer(kind=entry_length) :: nobs
  !
  if (ix%next.le.2) return
  nobs = ix%next-1
  !
  select case (set%sort_name)
  case ('BLOC')
     call quicksort(set,ix%ind,nobs,ix_bloc_gt,ix_bloc_ge,error)
  case ('NUMBER')
     call quicksort(set,ix%ind,nobs,ix_num_gt,ix_num_ge,error)
  case ('VERSION')
     call quicksort(set,ix%ind,nobs,ix_ver_gt,ix_ver_ge,error)
  case ('OBSERVED')
     call quicksort(set,ix%ind,nobs,ix_dobs_gt,ix_dobs_ge,error)
  case ('LAMBDA')
     call quicksort(set,ix%ind,nobs,ix_off1_gt,ix_off1_ge,error)
  case ('BETA')
     call quicksort(set,ix%ind,nobs,ix_off2_gt,ix_off2_ge,error)
  case ('SCAN')
     call quicksort(set,ix%ind,nobs,ix_scan_gt,ix_scan_ge,error)
  case ('SUBSCAN')
     call quicksort(set,ix%ind,nobs,ix_subscan_gt,ix_subscan_ge,error)
  case ('KIND')
     call quicksort(set,ix%ind,nobs,ix_kind_gt,ix_kind_ge,error)
  case ('QUALITY')
     call quicksort(set,ix%ind,nobs,ix_qual_gt,ix_qual_ge,error)
  case ('SOURCE')
     call quicksort(set,ix%ind,nobs,ix_csour_gt,ix_csour_ge,error)
  case ('LINE')
     call quicksort(set,ix%ind,nobs,ix_cline_gt,ix_cline_ge,error)
  case ('TELESCOPE')
     call quicksort(set,ix%ind,nobs,ix_ctele_gt,ix_ctele_ge,error)
  case ('TOC')
     call quicksort(set,ix%ind,nobs,ix_toc_default_gt,ix_toc_default_ge,error)
  case ('NONE')
     return
  end select
  if (error) return
end subroutine sort_ix
