module class_parameter
  use classic_params
  !
  integer(kind=4), parameter :: obsnum_length=entry_length
  integer(kind=4), parameter :: xdata_kind=8
  integer(kind=4), parameter :: plot_length=4
  !
  integer(kind=4), parameter :: mx_sec=64        ! Maximum range of section number
  ! A padding is required in "header" if mx_sec is even.
  integer(kind=4), parameter :: class_sec_user_id=0     ! User sections
  integer(kind=4), parameter :: class_sec_com_id=-1     ! Comment
  integer(kind=4), parameter :: class_sec_gen_id=-2     ! General
  integer(kind=4), parameter :: class_sec_pos_id=-3     ! Position
  integer(kind=4), parameter :: class_sec_spe_id=-4     ! Spectroscopy
  integer(kind=4), parameter :: class_sec_bas_id=-5     ! Baseline
  integer(kind=4), parameter :: class_sec_his_id=-6     ! History
  integer(kind=4), parameter :: class_sec_plo_id=-7     ! Plots
  integer(kind=4), parameter :: class_sec_swi_id=-8     ! Phase description
  integer(kind=4), parameter :: class_sec_gau_id=-9     ! Gauss fit
  integer(kind=4), parameter :: class_sec_dri_id=-10    ! Drift Continuum section
  integer(kind=4), parameter :: class_sec_bea_id=-11    ! Beam Switch
  integer(kind=4), parameter :: class_sec_she_id=-12    ! Shell fit
  integer(kind=4), parameter :: class_sec_hfs_id=-13    ! HFS/NH3 fit
  integer(kind=4), parameter :: class_sec_abs_id=-18    ! Absorption fit
  integer(kind=4), parameter :: class_sec_cal_id=-14    ! Calibration
  integer(kind=4), parameter :: class_sec_poi_id=-15    ! Continuum fit results
  integer(kind=4), parameter :: class_sec_sky_id=-16    ! Skydip description
  integer(kind=4), parameter :: class_sec_xcoo_id=-17   ! Irregularly sampled X coordinates
  integer(kind=4), parameter :: class_sec_assoc_id=-19  ! Associated Arrays
  integer(kind=4), parameter :: class_sec_her_id=-20    ! Herschel Space Observatory
  integer(kind=4), parameter :: class_sec_res_id=-21    ! Resolution (beam)
  integer(kind=4), parameter :: class_sec_desc_id=-30   ! Old OTF format description (kept for backward compatibility)
  !
  ! Windows and Masks
  integer(kind=4), parameter :: mwind1=100
  integer(kind=4), parameter :: mmask1=100
  integer(kind=4), parameter :: setnwind_default=-1  ! SET WINDOW /DEFAULT (e.g. at startup)
  integer(kind=4), parameter :: setnwind_polygon=-2  ! SET WINDOW /POLYGON
  integer(kind=4), parameter :: setnwind_assoc  =-3  ! SET WINDOW /ASSOCIATED
  integer(kind=4), parameter :: setnwind_auto   =-4  ! SET WINDOW AUTO (take from data)
  integer(kind=4), parameter :: basnwind_assoc  =-1  ! Associated Array LINE was used for BASE
  !
  ! Support for SET VARIABLE
  integer(kind=4), parameter :: setvar_read=1
  integer(kind=4), parameter :: setvar_write=2
  integer(kind=4), parameter :: setvar_off=3
  integer(kind=4), parameter :: setvar_mmodes=3
  character(len=5), parameter :: setvar_modes(setvar_mmodes) = (/ 'READ ', 'WRITE', 'OFF  ' /)
  !
  ! Parameters that can be modified
  integer(kind=entry_length) :: class_idx_size  ! Default size for Class indexes
  !
  ! Quality of data
  integer(kind=4), parameter :: qual_unknown=0
  integer(kind=4), parameter :: qual_excellent=1
  integer(kind=4), parameter :: qual_good=2
  integer(kind=4), parameter :: qual_fair=3
  integer(kind=4), parameter :: qual_average=4
  integer(kind=4), parameter :: qual_poor=5
  integer(kind=4), parameter :: qual_bad=6
  integer(kind=4), parameter :: qual_awful=7
  integer(kind=4), parameter :: qual_worst=8
  integer(kind=4), parameter :: qual_deleted=9
  !
  ! Velocity direction
  integer(kind=4), parameter :: vdire_unk = 0  ! Unknown or other (reference position, middle of the scan...)
  integer(kind=4), parameter :: vdire_act = 1  ! Actual spectrum position (i.e. taking offsets into account)
  !
  ! Y scale unit
  integer(kind=4), parameter :: myunit=6  ! Number of Y scale units supported
  ! Codes:
  integer(kind=4), parameter :: yunit_unknown=0
  integer(kind=4), parameter :: yunit_K_Tas=1       ! [K] T_A*
  integer(kind=4), parameter :: yunit_K_Tmb=2       ! [K] T_mb
  integer(kind=4), parameter :: yunit_Jyperbeam=3   ! [Jy/beam]
  integer(kind=4), parameter :: yunit_mJyperbeam=4  ! [mJy/beam]
  integer(kind=4), parameter :: yunit_Jypersr=5     ! [Jy/sr]
  integer(kind=4), parameter :: yunit_mJypersr=6    ! [mJy/sr]
  ! Strings (e.g. for plot labeling)
  character(len=8), parameter :: yunit_strings(0:myunit) = (/  &
    'Unknown ','K (Ta*) ','K (Tmb) ','Jy/beam ','mJy/beam','Jy/sr   ','mJy/sr  ' /)
  ! Keywords (e.g. for command line parsing). Note they need to be uppercase
  ! even the m for milli...
  character(len=8), parameter :: yunit_keys(0:myunit) = (/  &
    '*       ','TA*     ','TMB     ','JY/BEAM ','MJY/BEAM','JY/SR   ','MJY/SR  ' /)
  !
  real(kind=4), parameter :: class_bad=-1000.0
  real(kind=8), parameter :: ut_null=-1.d0         ! Means unset value
  real(kind=8), parameter :: image_null=0.d0       ! Means unset value
  real(kind=8), parameter :: parang_null=-1000.d0  ! Means unset value
end module class_parameter
!
module class_user
  use gildas_def
  !
  type :: userhook_t
    character(len=12) :: owner
    character(len=12) :: title
    procedure(), nopass, pointer :: toclass        => null()
    procedure(), nopass, pointer :: dump           => null()
    procedure(), nopass, pointer :: setvar         => null()
    procedure(), nopass, pointer :: find           => null()
    procedure(), nopass, pointer :: fix            => null()
    procedure(), nopass, pointer :: varidx_fill    => null()
    procedure(), nopass, pointer :: varidx_defvar  => null()
    procedure(), nopass, pointer :: varidx_realloc => null()
  end type userhook_t
  !
  integer(kind=4), parameter :: muserhooks=5  ! Maximum number of known user hooks
  integer(kind=4)            :: nuserhooks=0  ! Current number of known user hooks
  integer(kind=4)            :: cuserhooks=0  ! Current user hooks in use
  type(userhook_t), save     :: userhooks(muserhooks)  ! All the user hooks
  !
  integer(kind=4) :: usub  ! The User Subsection number the hooks are defined for
  !
end module class_user
!
module class_types
  use gildas_def
  use image_def
  use class_parameter
  use classic_api
  !
  ! Section 0
  ! USER: User defined sections
  type class_user_sub_t  ! Type for each user subsection
     character(len=12)        :: owner    ! Owner of the subsection
     character(len=12)        :: title    ! Title of the subsection
     integer(kind=4)          :: version  ! Version of the subsection
     integer(kind=4)          :: ndata    ! Length of the data(:) array
     integer(kind=4), pointer :: data(:)  ! Place holder for information
  end type class_user_sub_t
  !
  type class_user_t  ! Type for all user subsections
     integer(kind=4)                      :: n       ! Number of user subsections
     type (class_user_sub_t), allocatable :: sub(:)  ! Array of subsections
  end type class_user_t
  !
  ! Section -2 /CRPAR/
  ! GENERAL: General parameters, always present.
  integer(kind=4), parameter :: class_sec_gen_len_v1=9
  integer(kind=4), parameter :: class_sec_gen_len_v2_1=9
  integer(kind=4), parameter :: class_sec_gen_len_v2_2=11  ! 10/03/2023 Added parallactic angle
  integer(kind=4), parameter :: class_sec_gen_len_max=class_sec_gen_len_v2_2
  integer(kind=4), parameter :: class_sec_gen_len_full=21  ! Not for Class Data Format
  type class_general_t
     sequence  ! Because of SEQUENCE, character strings are moved at the end of
               ! the type. Use integer arrays at the place they are found on disk.
     ! Written in the index on disk
     integer(kind=obsnum_length) :: num        ! [         ] Observation number
     integer(kind=4)             :: ver        ! [         ] Version number
     integer(kind=4)             :: telpad(3)  ! [         ] Unused
     integer(kind=4)             :: dobs       ! [MJD-60549] Date of observation
     integer(kind=4)             :: dred       ! [MJD-60549] Date of reduction
     integer(kind=4)             :: kind       ! [     code] Type of data
     integer(kind=4)             :: qual       ! [     code] Quality of data
     integer(kind=obsnum_length) :: scan       ! [         ] Scan number
     integer(kind=4)             :: subscan    ! [         ] Subscan number
     integer(kind=4)             :: align_1    !
     ! Written in the section on disk
     real(kind=8)                :: ut       !  1- 2 [  rad] UT of observation
     real(kind=8)                :: st       !  3- 4 [  rad] LST of observation
     real(kind=4)                :: az       !  5    [  rad] Azimuth
     real(kind=4)                :: el       !  6    [  rad] Elevation
     real(kind=4)                :: tau      !  7    [neper] Opacity
     real(kind=4)                :: tsys     !  8    [    K] System temperature
     real(kind=4)                :: time     !  9    [    s] Integration time
     integer(kind=4)             :: align_2  !       [     ] Alignment padding
     real(kind=8)                :: parang   ! 10-11 [  rad] Parallactic angle
     ! Memory only, not written on disk
     integer(kind=4)             :: yunit    ! [ code] Y scale unit
     ! Not in this section on disk
     integer(kind=4)             :: xunit    ! [ code] X unit (if X coordinates section is present)
     ! NOT in data ---
     character(len=12)           :: cdobs    ! [string] Duplicate of dobs
     character(len=12)           :: cdred    ! [string] Duplicate of dred
     character(len=12)           :: teles    ! [string] Duplicate of indx%ctele
     integer(kind=4)             :: align_3  ! [      ] Alignment padding
  end type class_general_t
  !
  ! Section -3
  ! POSITION: Position information.
  integer(kind=4), parameter :: class_sec_pos_len_v1=17
  integer(kind=4), parameter :: class_sec_pos_len_v2=14
  integer(kind=4), parameter :: class_sec_pos_len_max=class_sec_pos_len_v1
  type class_position_t
     sequence  ! Because of SEQUENCE, character strings are moved at the end of
               ! the type. Use integer arrays at the place they are found on disk.
     integer(kind=4)   :: soupad(3)  !  1- 3 [    ] Unused
     integer(kind=4)   :: system     !     4 [code] Coordinate system
     real(kind=4)      :: equinox    !     5 [    ] Equinox of coordinates
     integer(kind=4)   :: proj       !     6 [code] Projection system
     real(kind=8)      :: lam        !  7- 8 [ rad] Lambda of projection center
     real(kind=8)      :: bet        !  9-10 [ rad] Beta of projection center
     real(kind=8)      :: projang    ! 11-12 [ rad] Projection angle
     real(kind=4)      :: lamof      !    13 [ rad] Offset in Lambda
     real(kind=4)      :: betof      !    14 [ rad] Offset in Beta
     ! SEQUENCE not guaranteed below
     character(len=12) :: sourc      !       [ str] Source name
     integer(kind=4)   :: align_1    !       [    ] Alignment padding
     ! NOT in data ---
     real(kind=4)      :: rx_off     !       [current angle unit] Duplicate of lamof
     real(kind=4)      :: ry_off     !       [current angle unit] Duplicate of betof
  end type class_position_t
  !
  ! Section -4
  ! SPECTRO: Spectroscopic information (for spectra).
  integer(kind=4), parameter :: class_sec_spe_len_v1_1=15  ! Old spectro section
                                                           ! (without SKYFR and VTELES)
  integer(kind=4), parameter :: class_sec_spe_len_v1_2=18  ! Old spectro section
                                                           ! (with SKYFR and VTELES)
  integer(kind=4), parameter :: class_sec_spe_len_v1_3=17  ! Spectro section with Doppler added
  integer(kind=4), parameter :: class_sec_spe_len_v3  =22  ! Latest version with double precision
                                                           ! and velocity parameters
  integer(kind=4), parameter :: class_sec_spe_len_max=class_sec_spe_len_v3
  type class_spectro_t
     sequence  ! Needed for VIRTUAL buffer (starts->ends). Because of SEQUENCE,
               ! character strings are moved at the end of the type. Use
               ! integer arrays at the place they are found on disk.
     integer(kind=4) :: linpad(3) ! [    ] Unused
     integer(kind=4) :: nchan     ! [    ] Number of channels
     real(kind=8)    :: restf     ! [ MHz] Rest frequency
     real(kind=8)    :: image     ! [ MHz] Image frequency
     real(kind=8)    :: doppler   ! [    ] Doppler correction -V/c (CLASS convention)
     real(kind=8)    :: rchan     ! [    ] Reference channel
     real(kind=8)    :: fres      ! [ MHz] Frequency resolution
     real(kind=8)    :: vres      ! [km/s] Velocity resolution
     real(kind=8)    :: voff      ! [km/s] Velocity at reference channel
     real(kind=4)    :: bad       ! [    ] Blanking value
     integer(kind=4) :: vtype     ! [code] Type of velocity
     integer(kind=4) :: vconv     ! [code] Velocity convention (optical, radio, ...)
     integer(kind=4) :: vdire     ! [code] Velocity direction for Doppler
     ! SEQUENCE not guaranteed below
     character(len=12) :: line    ! [ str] Line name (use this one)
     integer(kind=4)   :: align   ! [    ] Alignment padding
  end type class_spectro_t
  !
  ! Section -5
  ! BASE: Baseline information (for spectra or drifts).
  integer(kind=4), parameter :: mdeg=100
  integer(kind=4), parameter :: mwind=100
  integer(kind=4), parameter :: class_sec_bas_len=8+2*mwind
  type class_base_t
     sequence
     integer(kind=4) :: deg         ! [          ] Degree of last baseline
     real(kind=4)    :: sigfi       ! [Same as RY] Sigma
     real(kind=4)    :: aire        ! [Int.  unit] Area under windows
     integer(kind=4) :: nwind       ! [          ] Number of line windows
     real(kind=4)    :: w1(mwind)   ! [      km/s] Lower limits of windows
     real(kind=4)    :: w2(mwind)   ! [      km/s] Upper limits of windows
     real(kind=4)    :: sinus(3)    ! [          ] Sinus baseline results
     integer(kind=4) :: padding     ! [          ] Alignment padding
  end type class_base_t
  !
  ! Section -6
  ! HISTORY: Scan numbers of initial observations.
  integer(kind=4), parameter :: mseq=100
  integer(kind=4), parameter :: class_sec_his_len=2*mseq+1
  type class_history_t
     sequence
     integer(kind=4) :: nseq        ! Number of sequences
     integer(kind=4) :: start(mseq) ! Start can number of seq.
     integer(kind=4) :: end(mseq)   ! End scan number of seq.
     integer(kind=4) :: pad         ! Alignment padding
  end type class_history_t
  !
  ! Section -7
  ! PLOT: Default plotting limits.
  integer(kind=4), parameter :: class_sec_plo_len=4
  type class_plot_t
     sequence
     real(kind=4) :: amin  ! [Int. unit] Min Y value plotted
     real(kind=4) :: amax  ! [Int. unit] Max Y value plotted
     real(kind=4) :: vmin  ! [     km/s] Min X value plotted
     real(kind=4) :: vmax  ! [     km/s] Max X value plotted
  end type class_plot_t
  !
  ! Section -8
  ! SWITCH: Switching information (for spectra).
  integer(kind=4), parameter :: mxphas=8
  integer(kind=4), parameter :: class_sec_swi_len=2+6*mxphas
  type class_switch_t
     sequence
     integer(kind=4) :: align           ! [    ] Padding
     integer(kind=4) :: nphas           ! [    ] Number of phases
     real(kind=8)    :: decal(mxphas)   ! [ MHz] Frequency offsets
     real(kind=4)    :: duree(mxphas)   ! [   s] Time per phase
     real(kind=4)    :: poids(mxphas)   ! [    ] Weight of each phase
     integer(kind=4) :: swmod           ! [code] Switching mode (frequency, position...)
     real(kind=4)    :: ldecal(mxphas)  ! [ rad] Lambda offsets
     real(kind=4)    :: bdecal(mxphas)  ! [ rad] Beta offsets of each phase
     integer(kind=4) :: pad
  end type class_switch_t
  !
  ! Section -14
  ! CALIBRATION: Calibration parameters.
  integer(kind=4), parameter :: class_sec_cal_len=25
  type class_calib_t
     sequence
     integer(kind=4) :: align    ! [     ] Padding
     real(kind=4)    :: beeff    ! [     ] Beam efficiency
     real(kind=4)    :: foeff    ! [     ] Forward efficiency
     real(kind=4)    :: gaini    ! [     ] Image/Signal gain ratio
     real(kind=4)    :: h2omm    ! [   mm] Water vapor content
     real(kind=4)    :: pamb     ! [  hPa] Ambient pressure
     real(kind=4)    :: tamb     ! [    K] Ambient temperature
     real(kind=4)    :: tatms    ! [    K] Atmosphere temp. in signal band
     real(kind=4)    :: tchop    ! [    K] Chopper temperature
     real(kind=4)    :: tcold    ! [    K] Cold load temperature
     real(kind=4)    :: taus     ! [neper] Opacity in signal band
     real(kind=4)    :: taui     ! [neper] Opacity in image band
     real(kind=4)    :: tatmi    ! [    K] Atmosphere temp. in image band
     real(kind=4)    :: trec     ! [    K] Receiver temperature
     integer(kind=4) :: cmode    ! [ code] Calibration mode
     real(kind=4)    :: atfac    ! [     ] Applied calibration factor (Tcal)
     real(kind=4)    :: alti     ! [    m] Site elevation
     real(kind=4)    :: count(3) ! [count] Power of Atm., Chopp., Cold
     real(kind=4)    :: lcalof   ! [  rad] Longitude offset for sky measurement
     real(kind=4)    :: bcalof   ! [  rad] Latitude offset for sky measurement
     real(kind=8)    :: geolong  ! [  rad] Geographic longitude of observatory
     real(kind=8)    :: geolat   ! [  rad] Geographic latitude of observatory
  end type class_calib_t
  !
  ! Section -16
  ! SKYDIP: For Skydips observations. No associated data.
  integer(kind=4), parameter :: msky=10
  integer(kind=4), parameter :: class_sec_sky_len=10+4*msky
  type class_skydip_t
     sequence
     integer(kind=4) :: align_1     ! [     ] Alignment padding
     integer(kind=4) :: linpad(3)   ! [     ] Unused
     real(kind=8)    :: restf       ! [  MHz] Rest frequency
     real(kind=8)    :: image       ! [  MHz] Image frequency
     integer(kind=4) :: nsky        ! [     ] Number of points on sky
     integer(kind=4) :: nchop       ! [     ]   -   -    -    - chopper
     integer(kind=4) :: ncold       ! [     ]   -   -    -    - cold load
     real(kind=4)    :: elev(msky)  ! [  rad] Elevations
     real(kind=4)    :: emiss(msky) ! [    ?] Power on sky
     real(kind=4)    :: chopp(msky) ! [    ?] Power on chopper
     real(kind=4)    :: cold(msky)  ! [    ?] Power on cold load
     integer(kind=4) :: align_2     ! [     ] Alignment padding
     ! SEQUENCE not guaranteed below
     character(len=12) :: line      ! [string] Line name
     integer(kind=4)   :: align_3   ! [     ] Alignment padding
  end type class_skydip_t
  !
  ! Section -9  /CRGAUS/
  ! GAUSS: Gauss fit results (for spectra or drifts).
  integer(kind=4), parameter :: mgauslin=10 ! Max number of lines in section
  integer(kind=4), parameter :: ngauspar=3  ! Number of parameters per line
  integer(kind=4), parameter :: mgausfit=ngauspar*mgauslin
  type class_gauss_t
     sequence
     integer(kind=4) :: nline           ! [            ] Number of components
     real(kind=4)    :: sigba           ! [   Int. unit] Sigma on base
     real(kind=4)    :: sigra           ! [   Int. unit] Sigma on line
     real(kind=4)    :: nfit(mgausfit)  ! [area,v0,fwhm] Fit results
     real(kind=4)    :: nerr(mgausfit)  ! [area,v0,fwhm] Errors
     real(kind=4)    :: pad             ! [            ] Alignement padding
  end type class_gauss_t
  !
  ! Section -12   /CRSHEL/
  ! SHELL: "Stellar shell" profile fit results (for spectra).
  integer(kind=4), parameter :: mshelllin=10 ! Max number of lines in section
  integer(kind=4), parameter :: nshellpar=4  ! Number of parameters per line
  integer(kind=4), parameter :: mshellfit=nshellpar*mshelllin
  type class_shell_t
     sequence
     integer(kind=4) :: nline            ! [] Number of components
     real(kind=4)    :: sigba            ! [] Sigma on base
     real(kind=4)    :: sigra            ! [] Sigma on line
     real(kind=4)    :: nfit(mshellfit)  ! [] Fit results
     real(kind=4)    :: nerr(mshellfit)  ! [] Errors
     real(kind=4)    :: pad              ! [] Alignement padding
  end type class_shell_t
  !
  ! Section -13 /CRNH3/
  ! HFS: "Hyperfine Structure" profile fit results (e.g. NH3, HCN, for spectra).
  integer(kind=4), parameter :: mhfslin=10 ! Max number of lines in section
  integer(kind=4), parameter :: nhfspar=4  ! Number of parameters per line
  integer(kind=4), parameter :: mhfsfit=nhfspar*mhfslin
  type class_hfs_t
     sequence
     integer(kind=4) :: nline          ! Number of components
     real(kind=4)    :: sigba          ! Sigma on base
     real(kind=4)    :: sigra          ! Sigma on line
     real(kind=4)    :: nfit(mhfsfit)  ! Fit results
     real(kind=4)    :: nerr(mhfsfit)  ! Errors
     real(kind=4)    :: pad            ! Alignement
  end type class_hfs_t
  !
  ! Section -18 /CRABS/
  ! ABS: "Hyperfine Structure" absorption profile fit results (e.g. NH3, HCN, for spectra).
  integer(kind=4), parameter :: mabslin=10 ! Max number of lines in section
  integer(kind=4), parameter :: nabspar=3  ! Number of parameters per line
  integer(kind=4), parameter :: mabsfit=1+nabspar*mabslin  ! First is continuum
  type class_absorption_t
     sequence
     integer(kind=4) :: nline          ! Number of components
     real(kind=4)    :: sigba          ! Sigma on base
     real(kind=4)    :: sigra          ! Sigma on line
     real(kind=4)    :: nfit(mabsfit)  ! Fit results
     real(kind=4)    :: nerr(mabsfit)  ! Errors
     real(kind=4)    :: pad            ! Alignement
  end type class_absorption_t
  !
  ! Section -10 /CRCONT/
  ! DRIFT: Continuum drift description (for drifts).
  integer(kind=4), parameter :: class_sec_dri_len=16
  type class_drift_t
     sequence
     real(kind=8)    :: freq    ! [MHz] Rest frequency
     real(kind=4)    :: width   ! [MHz] Bandwidth
     integer(kind=4) :: npoin   ! [   ] Number of data points
     real(kind=4)    :: rpoin   ! [   ] Reference point
     real(kind=4)    :: tref    ! [  ?] Time at reference
     real(kind=4)    :: aref    ! [rad] Angular offset at ref.
     real(kind=4)    :: apos    ! [rad] Position angle of drift
     real(kind=4)    :: tres    ! [  ?] Time resolution
     real(kind=4)    :: ares    ! [rad] Angular resolution
     real(kind=4)    :: bad     ! [   ] Blanking value
     integer(kind=4) :: ctype   ! [code] Type of offsets
     real(kind=8)    :: cimag   ! [MHz] Image frequency
     real(kind=4)    :: colla   ! [] Collimation error Az
     real(kind=4)    :: colle   ! [] Collimation error El
  end type class_drift_t
  !
  ! Section -11
  ! BEAM: Beam-switching parameters (for spectra or drifts).
  integer(kind=4), parameter :: class_sec_bea_len=5
  type class_beam_t
     sequence
     real(kind=4)    :: cazim   ! [ rad] Azimuth of observation
     real(kind=4)    :: celev   ! [ rad] Elevation of observation
     real(kind=4)    :: space   ! [ rad] Beam spacing
     real(kind=4)    :: bpos    ! [ rad] Position angle of beams
     integer(kind=4) :: btype   ! [code] System for angle
     integer(kind=4) :: pad     ! [    ] Alignment padding
  end type class_beam_t
  !
  ! Section -15 /CRPOINT/
  ! CONTINUUM: Double gaussian and baseline fit results (for drifts).
  integer(kind=4), parameter :: mpoifit=8
  integer(kind=4), parameter :: class_sec_poi_len=3+2*mpoifit
  type class_pointing_t
     sequence
     integer(kind=4) :: nline          ! Number of components
     real(kind=4)    :: sigba          ! Sigma on base
     real(kind=4)    :: sigra          ! Sigma on line
     real(kind=4)    :: nfit(mpoifit)  ! Fit results
     real(kind=4)    :: nerr(mpoifit)  ! Errors
     integer(kind=4) :: pad            ! Alignment padding
  end type class_pointing_t
  !
  ! Section -19
  ! Associated Arrays
  integer(kind=4), parameter :: fmt_b2=-101  ! 2 bits value (disk only)
  type class_assoc_sub_t
    ! Description of data (on disk)
    character(len=12) :: name    ! [    ] Name describing content of array
    character(len=12) :: unit    ! [    ] Unit for data
    integer(kind=4)   :: dim2    ! [    ] Second dimension, 0 for 1D only
    integer(kind=4)   :: fmt     ! [code] Data format of array
    ! Description of data (memory only, for easier bookkeeping)
    integer(kind=4)   :: status  ! [code] Pointer status (null, associated, allocated)
    integer(kind=4)   :: dim1    ! [    ] First dimension, should be Nchan
    ! Data
    integer(kind=4)          :: badi4    ! Blanking value for I4 array
    integer(kind=4), pointer :: i4(:,:)  !
    real(kind=4)             :: badr4    ! Blanking value for R4 array
    real(kind=4),    pointer :: r4(:,:)  !
  end type class_assoc_sub_t
  type class_assoc_t
     integer(kind=4) :: n      ! Number of Associated Arrays in section
     type(class_assoc_sub_t), allocatable :: array(:)  ! The Associated Arrays
  end type class_assoc_t
  !
  ! Section -20
  ! Herschel Space Observatory section
  integer(kind=4), parameter :: class_sec_her_len=96
  type class_herschel_t
    sequence
    integer(kind=8)   :: obsid       !  1- 2  [----] Observation id
    integer(kind=4)   :: pad01(2)    !  3- 4  [str ] Room for instrument
    integer(kind=4)   :: pad02(6)    !  5-10  [str ] Room for proposal
    integer(kind=4)   :: pad03(17)   ! 11-27  [str ] Room for aor
    integer(kind=4)   :: operday     !    28  [day ] Operational day number
    integer(kind=4)   :: pad04(7)    ! 29-35  [str ] Room for dateobs
    integer(kind=4)   :: pad05(7)    ! 36-42  [str ] Room for dateend
    integer(kind=4)   :: pad06(10)   ! 43-52  [str ] Room for obsmode
    real(kind=4)      :: vinfo       !    53  [km/s] Informative source velocity in LSR frame
    real(kind=4)      :: zinfo       !    54  [----] Informative target redshift
    real(kind=8)      :: posangle    ! 55-56  [rad ] Spacecraft pointing position angle
    real(kind=8)      :: reflam      ! 57-58  [rad ] Sky reference (a.k.a. OFF), lambda coordinate
    real(kind=8)      :: refbet      ! 59-60  [rad ] Sky reference (a.k.a. OFF), beta coordinate
    real(kind=8)      :: hifavelam   ! 61-62  [rad ] ON average H and V coordinate (HIFI), lambda coordinate
    real(kind=8)      :: hifavebet   ! 63-64  [rad ] ON average H and V coordinate (HIFI), beta coordinate
    real(kind=4)      :: etamb       !    65  [----] Main beam efficiency used when applying doAntennaTemp
    real(kind=4)      :: etal        !    66  [----] Forward efficiency used when applying doAntennaTemp
    real(kind=4)      :: etaa        !    67  [----] Telescope aperture efficiency
    real(kind=4)      :: hpbw        !    68  [rad ] Azimuthally-averaged half-power beam width
    integer(kind=4)   :: pad07(2)    ! 69-70  [str ] Room for tempscal
    real(kind=8)      :: lodopave    ! 71-72  [MHz ] Average LO frequency Doppler corrected to freqFrame (SPECSYS)
    real(kind=4)      :: gim0        !    73  [----] Sideband gain polynomial coeff 0 applied
    real(kind=4)      :: gim1        !    74  [----] Sideband gain polynomial coeff 1 applied
    real(kind=4)      :: gim2        !    75  [----] Sideband gain polynomial coeff 2 applied
    real(kind=4)      :: gim3        !    76  [----] Sideband gain polynomial coeff 3 applied
    real(kind=4)      :: mixercurh   !    77  [mA  ] Calibrated mixer junction current, horizontal
    real(kind=4)      :: mixercurv   !    78  [mA  ] Calibrated mixer junction current, vertical
    integer(kind=4)   :: pad08(7)    ! 79-85  [str ] Room for datehcss
    integer(kind=4)   :: pad09(6)    ! 86-91  [str ] Room for hcssver
    integer(kind=4)   :: pad10(4)    ! 92-95  [str ] Room for calver
    real(kind=4)      :: level       !    96  [----] Pipeline level
    ! SEQUENCE not guaranteed below
    character(len=8)  :: instrument  !        [str ] Instrument name
    character(len=24) :: proposal    !        [str ] Proposal name
    character(len=68) :: aor         !        [str ] Astronomical Observation Request
    character(len=28) :: dateobs     !        [str ] Start date (ISO date)
    character(len=28) :: dateend     !        [str ] End date (ISO date)
    character(len=40) :: obsmode     !        [str ] Observing mode
    character(len=8)  :: tempscal    !        [str ] Temperature scale in use
    character(len=28) :: datehcss    !        [str ] Processing date (ISO date)
    character(len=24) :: hcssver     !        [str ] HCSS version
    character(len=16) :: calver      !        [str ] Calibration version
  end type class_herschel_t
  !
  ! Section -21
  ! BEAM: Beam description
  integer(kind=4), parameter :: class_sec_res_len=3
  type class_res_t
    sequence
    real(kind=4)    :: major   ! 1  [rad] Major axis
    real(kind=4)    :: minor   ! 2  [rad] Minor axis
    real(kind=4)    :: posang  ! 3  [rad] Position angle
    integer(kind=4) :: pad     !          Memory alignment padding
  end type class_res_t
  !
  ! Section -30
  ! Data Section Descriptor.
  ! (Old OTF data format, kept for backward compatibility).
  integer(kind=4), parameter :: class_sec_desc_len=4  ! ???
  type class_descriptor_t
     sequence
     integer(kind=4) :: ndump   ! Number of records
     integer(kind=4) :: ldpar   ! Length of data header (longwords)
     integer(kind=4) :: ldatl   ! length of line data      (")
     integer(kind=4) :: ldump   ! length of record         (")
     integer(kind=4) :: rec     ! Current Record Number
     integer(kind=4) :: pad     ! Alignment padding
  end type class_descriptor_t
  !
  integer(kind=4), parameter :: class_sec_comm_len=256  ! ???
  type class_comment_t
     sequence
     integer(kind=4)     :: ltext  ! Length of comment
     integer(kind=4)     :: pad    ! Alignment padding
     character(len=1024) :: ctext  ! Comment string
  end type class_comment_t
  !
  ! Observation Header
  type header
     sequence
     integer(kind=4)          :: start(2)
     !
     type(class_general_t)    :: gen
     type(class_position_t)   :: pos
     type(class_spectro_t)    :: spe
     type(class_res_t)        :: res
     type(class_base_t)       :: bas
     type(class_history_t)    :: his
     type(class_plot_t)       :: plo
     type(class_switch_t)     :: swi
     !
     type(class_calib_t)      :: cal
     type(class_skydip_t)     :: sky
     type(class_gauss_t)      :: gau
     type(class_shell_t)      :: she
     type(class_hfs_t)        :: hfs
     type(class_absorption_t) :: abs
     !
     type(class_drift_t)      :: dri
     type(class_beam_t)       :: bea
     type(class_pointing_t)   :: poi
     !
     type(class_herschel_t)   :: her
     !
     type(class_descriptor_t) :: des
     type(class_comment_t)    :: com
     !
     logical                    :: presec(-mx_sec:0) ! Which section are presents
     integer(kind=4)            :: padding           ! If mx_sec is even
     integer(kind=entry_length) :: xnum              ! Origin of spectrum (fit/model/absent/data)
     !
     integer(kind=4)  :: ends(2)
  end type header
  !
  ! Data additional parameters
  ! (Old OTF data format, kept for backward compatibility)
  type dapotf
     integer(kind=4) :: irec   ! Record number
     real(kind=4)    :: az     ! Azimut
     real(kind=4)    :: el     ! Elevation
     real(kind=4)    :: st     ! LST
     real(kind=4)    :: ut     ! UT
     real(kind=4)    :: lamof  ! Offset in Lambda
     real(kind=4)    :: betof  ! Offset in Beta
     integer(kind=4) :: feed   ! Mutli-beam feed number
  end type dapotf
  !
  ! Support for CONSISTENCY
  type :: consistency_section_t
     logical                     :: check ! [ ] Check this section?
     logical                     :: done  ! [ ] Already checked?
     logical                     :: prob  ! [ ] Inconsistent?
     logical                     :: mess  ! [ ] Output message?
     integer(kind=obsnum_length) :: num   ! [ ] Observation number of inconsistent spectrum
  end type consistency_section_t
  !
  type :: consistency_t
     logical :: check       ! [ ] Anything left to be done?
     logical :: prob        ! [ ] Is there a consistency problem?
     !
     type(consistency_section_t) :: gen ! [ ] Generalities
     type(consistency_section_t) :: sou ! [ ] Source name
     type(consistency_section_t) :: lin ! [ ] Line name
     type(consistency_section_t) :: pos ! [ ] Position information
     type(consistency_section_t) :: off ! [ ] Offset positions
     type(consistency_section_t) :: spe ! [ ] Spectroscopy information
     type(consistency_section_t) :: cal ! [ ] Calibration information
     type(consistency_section_t) :: swi ! [ ] Switching information
     type(consistency_section_t) :: dri ! [ ] Drift informations
     !
     real(kind=8) :: ctole  ! [chan] Channel tolerance
     real(kind=8) :: ptole  ! [rad]  Position tolerance
     real(kind=8) :: atole  ! [rad]  Position angle tolerance
     !
     type(header) :: head ! The header against which consistency is checked
  end type consistency_t
  !
  type :: class_observation_fft_t
    ! X axis description
    integer(kind=4) :: nx,ny       ! [     ] Size of datay
    integer(kind=4) :: nchan       ! [chan ]
    real(kind=4)    :: xref        ! [chan ]
    real(kind=4)    :: xval        ! [MHz-1]
    real(kind=4)    :: xinc        ! [MHz-1]
    ! Possibly 2D array for index
    real(kind=4),    allocatable :: datax(:)    ! [MHz-1] Inverse frequency
    real(kind=4),    allocatable :: datay(:,:)  ! [     ] Intensities
  end type class_observation_fft_t
  !
  integer(kind=4), parameter :: vobs_stable=2
  type observation
     type(classic_entrydesc_t) :: desc           ! Entry Descriptor (read-only for Class)
     type(header)              :: head           ! Observation Header
     type(class_comment_t)     :: note
     integer(kind=4)           :: cimin,cimax    ! First and last channel displayed
     integer(kind=4)           :: cnchan         ! Number of data points
     real(kind=4)              :: cbad           ! Bad value
     logical                   :: is_R           ! Is this the R buffer (for Class internal use only!)
     logical                   :: is_otf         ! Is an old OTF scan?
     ! Abscissa (see comments in subroutine 'abscissa')
     real(kind=xdata_kind), pointer :: datax (:) ! Current X abscissa
     real(kind=xdata_kind), pointer :: datas (:) ! Signal frequencies
     real(kind=xdata_kind), pointer :: datai (:) ! Image frequencies
     real(kind=xdata_kind), pointer :: datav (:) ! Velocities
     ! Values
     real(kind=4), pointer :: data1 (:)   ! 1D Values
     real(kind=4), pointer :: dataw (:)   ! Weights
     real(kind=4), pointer :: data2 (:,:) ! 2D Values
     real(kind=4), pointer :: spectre (:) ! Y Values
     type(dapotf), pointer :: dap(:)      ! OTF daps
     ! FFT, computed by FFT command
     type(class_observation_fft_t) :: fft
     ! User section
     type(class_user_t) :: user
     ! Associated Arrays
     type(class_assoc_t) :: assoc
  end type observation
  !
  !
  ! INDEX VERSION 1
  integer(kind=4), parameter :: vind_v1=1          ! Index version
  integer(kind=4), parameter :: lind_v1=32         ! Index length, in words
  integer(kind=4), parameter :: lind_unused_v1=10  ! Number of unused words
  integer(kind=4), parameter :: dobs_v1_old=-6813  ! Assume V1 uses "old" data format before 01-JAN-2006
  type indx_v1_t
     sequence
     integer(kind=4)   :: bloc     !  1   : block read from index
     integer(kind=4)   :: num      !  2   : number read
     integer(kind=4)   :: ver      !  3   : version read from index
     character(len=12) :: csour    !  4- 6: source read from index
     character(len=12) :: cline    !  7- 9: line read from index
     character(len=12) :: ctele    ! 10-12: telescope read from index
     integer(kind=4)   :: dobs     ! 13   : date obs. read from index
     integer(kind=4)   :: dred     ! 14   : date red. read from index
     real(kind=4)      :: off1     ! 15   : read offset 1
     real(kind=4)      :: off2     ! 16   : read offset 2
     integer(kind=4)   :: type     ! 17   : type of read offsets
     integer(kind=4)   :: kind     ! 18   : type of observation
     integer(kind=4)   :: qual     ! 19   : Quality read from index
     integer(kind=4)   :: scan     ! 20   : Scan number read from index
     real(kind=4)      :: posa     ! 21   : Position angle
     integer(kind=4)   :: subscan  ! 22   : Subscan number (not available in "old" data format)
     integer(kind=4)   :: pad(10)  ! 23-32: Pad to 32 words
  end type indx_v1_t
  !
  ! INDEX VERSION 2 (use same type and subroutines as V3)
  integer(kind=4), parameter :: vind_v2=2         ! Index version
  integer(kind=4), parameter :: lind_v2=26        ! Index length, in words
  integer(kind=4), parameter :: lind_unused_v2=0  ! Number of unused words
  !
  ! INDEX VERSION 3 (current default in memory)
  integer(kind=4), parameter :: vind_v3=3         ! Index version
  integer(kind=4), parameter :: lind_v3=28        ! Index length, in words
  integer(kind=4), parameter :: lind_unused_v3=0  ! Number of unused words
  type indx_t  ! indx_v3_t
     ! No sequence. Because of memory padding (implicit by the compiler, or
     ! explicit by the programmer), we write the elements one by one
     integer(kind=8)   :: bloc     !  1- 2: record where observation is to be found
     integer(kind=4)   :: word     !  3   : word where obs. is to be found in the record
     integer(kind=8)   :: num      !  4- 5: number read
     integer(kind=4)   :: ver      !  6   : version read from index
     character(len=12) :: csour    !  7- 9: source read from index
     character(len=12) :: cline    ! 10-12: line read from index
     character(len=12) :: ctele    ! 13-15: telescope read from index
     integer(kind=4)   :: dobs     ! 16   : date obs. read from index
     integer(kind=4)   :: dred     ! 17   : date red. read from index
     real(kind=4)      :: off1     ! 18   : read offset 1
     real(kind=4)      :: off2     ! 19   : read offset 2
     integer(kind=4)   :: type     ! 20   : type of read offsets
     integer(kind=4)   :: kind     ! 21   : type of observation
     integer(kind=4)   :: qual     ! 22   : Quality read from index
     real(kind=4)      :: posa     ! 23   : Position angle
     integer(kind=8)   :: scan     ! 24-25: Scan number read from index
     integer(kind=4)   :: subscan  ! 26   : Subscan number
     real(kind=8)      :: ut       ! 27-28: UT of observation
  end type indx_t
  !
  type ranges_t
     logical                     :: done   ! Already done or not
     integer(kind=obsnum_length) :: scan1  ! First scan number
     integer(kind=obsnum_length) :: scan2  ! Last  scan number
     integer(kind=4)             :: dobs1  ! Minimum OBS date
     integer(kind=4)             :: dobs2  ! Maximum OBS date
     integer(kind=4)             :: dred1  ! Minimum RED date
     integer(kind=4)             :: dred2  ! Maximum RED date
     real(kind=4)                :: lam1   ! Minimum Lambda offset
     real(kind=4)                :: lam2   ! Maximum Lambda offset
     real(kind=4)                :: bet1   ! Minimum Beta   offset
     real(kind=4)                :: bet2   ! Maximum Beta   offset
  end type ranges_t
  !
  type optimize_sorting_t
     ! Support arrays for sorted index. There are several kinds of sorting
     ! 1) Sorting by observation numbers
     integer(kind=entry_length)           :: nsort              !
     integer(kind=obsnum_length), pointer :: number(:)=>null()  ! Sorted observation numbers
     integer(kind=entry_length),  pointer :: entry(:) =>null()  ! Associated entry numbers
     ! 2) Sorting by Date, then Time, then Telescope
     integer(kind=entry_length),  pointer :: dtt(:)   =>null()  ! Sorting array
  end type optimize_sorting_t
  !
  type optimize
     logical                    :: has_old_fmt  ! .true. if (at least one) subscan=0
     integer(kind=8)            :: time         ! Time when index is filled (nanosecond)
     integer(kind=entry_length) :: mobs         ! Maximum number of observations in index (size of allocation)
     integer(kind=entry_length) :: next         ! Number of observations in index + 1
     type(consistency_t)        :: cons         ! Consistency checks, tolerances and results
     type(ranges_t)             :: ranges       ! Ranges of the INDEX
     integer(kind=entry_length),  pointer :: ind(:)    =>null()  ! Index values (C)
     integer(kind=obsnum_length), pointer :: num(:)    =>null()  ! Observation numbers (I/O/C)
     integer(kind=8),             pointer :: bloc(:)   =>null()  ! Bloc numbers (I/O/C)
     integer(kind=4),             pointer :: word(:)   =>null()  ! Word positions (I/O/C)
     integer(kind=4),             pointer :: ver(:)    =>null()  ! Version numbers (I/O/C)
     integer(kind=4),             pointer :: kind(:)   =>null()  ! Kinds (I/C)
     integer(kind=4),             pointer :: qual(:)   =>null()  ! Qualities (I/C)
     integer(kind=obsnum_length), pointer :: scan(:)   =>null()  ! Scan numbers (I/C)
     integer(kind=4),             pointer :: dobs(:)   =>null()  ! Observation dates (I/C)
     real(kind=4),                pointer :: off1(:)   =>null()  ! Lambda Offset (I/C)
     real(kind=4),                pointer :: off2(:)   =>null()  ! Beta Offset (I/C)
     integer(kind=4),             pointer :: subscan(:)=>null()  ! Subscan number (I/C)
     character(len=12),           pointer :: csour(:)  =>null()  ! Source name (I/C)
     character(len=12),           pointer :: cline(:)  =>null()  ! Line name (I/C)
     character(len=12),           pointer :: ctele(:)  =>null()  ! Backend name (I/C)
     real(kind=8),                pointer :: ut(:)     =>null()  ! UT of observation (I/O/C)
     real(kind=4),                pointer :: posa(:)   =>null()  ! Drift position angle (I/C)
     ! Sorted index. An implementation with different ordering may be faster
     type(optimize_sorting_t)             :: sort                ! Sorting arrays (O)
  end type optimize
  !
  type flag_t
     logical         :: kind     ! by obs. type
     logical         :: last     ! only last version
     logical         :: ind      ! by entry number
     logical         :: num      ! by observation number
     logical         :: ver      ! by version
     logical         :: sourc    ! by source name
     integer(kind=4) :: isourc   ! (first wildcard position)
     logical         :: line     ! by line name
     integer(kind=4) :: iline    ! (first wildcard position)
     logical         :: teles    ! by backend
     integer(kind=4) :: iteles   ! (first wildcard position)
     logical         :: dobs     ! by observation date
     logical         :: dred     ! by reduction date
     logical         :: off1     ! by offset 1
     logical         :: off2     ! by offset 2
     logical         :: scan     ! by scan number
     logical         :: subscan  ! by subscan number
     logical         :: posa     ! by position angle
     ! Other criteria which do not rely on the index:
     logical         :: sect     ! by section present
     integer(kind=4) :: sectval  ! section identifier
     logical         :: freq     ! by frequency
     real(kind=8)    :: freqmin  ! frequency range: minimal value
     real(kind=8)    :: freqmax  ! frequency range: maximal value
     logical         :: freqsig  ! Signal or image frequency selection?
     logical         :: user     ! by user hook
     logical         :: domask   ! by position-position mask
     type(gildas)    :: mask     ! the mask array
     logical         :: dopos    ! by absolute position
     real(kind=8)    :: poslam   ! [rad] Position lambda
     real(kind=8)    :: posbet   ! [rad] Position beta
     integer(kind=4) :: possys   ! [code] Position system of coordinates
     real(kind=4)    :: posequ   ! [year] Position equinox (if relevant for system)
     logical         :: doswitch ! by switching mode
     integer(kind=4) :: switch   ! [code] Switching code
     logical         :: dodri    ! by drift angle
     real(kind=4)    :: driang   ! [rad] Drift position angle
     logical         :: dodir    ! by direction angle
     real(kind=4)    :: dirang   ! [rad] Direction angle
  end type flag_t
  !
  ! Support for SET FORMAT
  type class_title_t
     logical :: position
     logical :: quality
     logical :: spectral
     logical :: calibration
     logical :: atmosphere
     logical :: origin
     logical :: continuum
  end type class_title_t
  !
  ! Support for SET [NO]CHECK
  type class_setup_check_t
    logical :: sou
    logical :: pos
    logical :: off
    logical :: lin
    logical :: spe
    logical :: cal
    logical :: swi
  end type class_setup_check_t
  !
  type class_setup_t
     ! This type is OBSOLESCENT and should be transfered to the new
     ! module 'class_setup_new' with proper put/get API
   ! real(kind=8)   :: fangle           ! Transfered to class_setup_new
     real(kind=8)   :: freqmin,freqmax  ! Frequency range for command FIND
     logical        :: freqsig          ! Signal or image frequency selection?
     real(kind=4)   :: offs1, offs2     ! Offset Min Max (E-W)
     real(kind=4)   :: offl1, offl2     ! Offset Min Max (N-S)
     real(kind=4)   :: tole             ! Tolerance on position checks
     real(kind=4)   :: beamt, gaint     ! Tolerance on BeamEff and GainImage
     real(kind=4)   :: wind1(mwind1)    ! Windows definition
     real(kind=4)   :: wind2(mwind1)    ! Windows definition
     real(kind=4)   :: mask1(mmask1)    ! Masks definition
     real(kind=4)   :: mask2(mmask1)    ! Masks definition
     real(kind=4)   :: equinox          ! Default equinox
     real(kind=4)   :: posa1, posa2     ! Position angle
     integer(kind=entry_length)  :: entr1, entr2  ! Entry numbers
     integer(kind=obsnum_length) :: nume1, nume2  ! Observation Numbers
     integer(kind=obsnum_length) :: scan1, scan2  ! Scan Numbers
     integer(kind=4) :: sub1,sub2       ! Subscan numbers
     integer(kind=4) :: base            ! Baseline degree (-1 = Sinus)
     integer(kind=4) :: nwind           ! Window number
     integer(kind=4) :: nmask           ! Mask number
     integer(kind=4) :: kind            ! 0 Line, 1 Continuum
     integer(kind=4) :: obse1, obse2    ! Observing dates
     integer(kind=4) :: redu1, redu2    ! Reduction dates
     integer(kind=4) :: coord           ! Coordinate Type
     integer(kind=4) :: veloc           ! Velocity Type
     integer(kind=4) :: lbase           ! Last Baseline degree
     integer(kind=4) :: qual1, qual2    ! Quality of data
     integer(kind=4) :: slev, flev      ! Output message priorities (screen and file)
     integer(kind=4) :: drop(2)         ! Drop edge channels at reading
     integer(kind=4) :: scale           ! Rescale RY to new unit at read time
     logical :: write_r8                ! Write Irregularly sampled data as Real*8
     logical :: match                   ! Position checking
     logical :: mapcl                   ! clear in MAP
     logical :: fupda                   ! FIND UPDATE mode
     logical :: do_sort                 ! SORT index
     logical :: do_scan                 ! SCAN Mode for PLOT, BASE, FOLD, ...
     logical :: origin                  ! List the history ?
     logical :: verbose                 ! Verbose printout
     logical :: fft                     ! Fourier space (True) or Direct space
     logical :: uniqueness              ! Check observations uniqueness at WRITE time?
     logical :: chase_nan               ! Deeply track NaN while reading
     character(len=12) :: sort_name     ! Sort key name
     !
     character(len=12) :: line      ! Line Name
     character(len=12) :: sourc     ! Source Name
     character(len=12) :: teles     ! Telescope Name
     character(len=12) :: method    ! Fit Method
     character(len=32) :: defext    ! Default Extension
   ! character(len=3) :: angle      ! Transfered to class_setup_new
     character(len=1) :: heade      ! Header type
     character(len=1) :: modex      ! Plot Mode
     character(len=1) :: modey      ! Plot Mode
     character(len=1) :: modez      ! Plot Mode
     character(len=1) :: plot       ! Plot Type (normal, histogram)
     character(len=1) :: unitx(2)   ! Abscissae axis unit (lower and upper)
     character(len=1) :: weigh      ! Summation Weight
     character(len=1) :: bad        ! Bad checking
     character(len=1) :: action     ! Index or Observation
     character(len=1) :: box        ! Box orientation (L or P)
     character(len=1) :: align
     character(len=1) :: alig2
     !
     character(len=24) :: obs_name  ! []    Observatory name for compute_doppler
     real(kind=8)      :: obs_long  ! [deg] Observatory longitude for compute_doppler
     real(kind=8)      :: obs_lati  ! [deg] Observatory latitude for compute_doppler
     real(kind=8)      :: obs_alti  ! [km]  Observatory altitude for compute_doppler
     !
     type(class_setup_check_t) :: check
     type(class_title_t)       :: title                 ! SET FORMAT
     real(kind=4), allocatable :: window_polygon(:,:)   ! SET WINDOW (polygon mode)
     integer(kind=4)           :: varpresec(-mx_sec:0)  ! SET VARIABLE: activation mode for each section
  end type class_setup_t
  !
  ! Support for EXTRACT et al.
  type :: extract_t
    character(len=12) :: rname
    ! User request (in any unit), if needed
    real(kind=8)     :: xa    ! X range (value 1)
    real(kind=8)     :: xb    ! X range (value 2)
    character(len=1) :: unit  ! X range unit
    ! Channel range (used for actual extraction)
    integer(kind=4) :: c1  ! X range (left channel)
    integer(kind=4) :: c2  ! X range (right channel)
    integer(kind=4) :: nc  ! Number of channels
  end type extract_t
  !
  type :: resampling ! Definition of a regularly sampled X-axis
     integer(kind=4)  :: nchan ! Number of channels
     real(kind=8)     :: ref   ! Reference channel
     real(kind=8)     :: val   ! Value at reference channel
     real(kind=8)     :: inc   ! Increment
     character(len=1) :: unit  ! Unit (i.e. frequency or velocity)
     character(len=8) :: shape ! Convolution kernel kind
     real(kind=4)     :: width ! Convolution kernel width
  end type resampling
  !
end module class_types
!
module class_averaging
  use class_types
  !
  ! Alignment parameters
  integer(kind=4), parameter :: align_auto=0
  integer(kind=4), parameter :: align_velo=1
  integer(kind=4), parameter :: align_freq=2
  integer(kind=4), parameter :: align_imag=3
  integer(kind=4), parameter :: align_posi=4
  character(len=*), parameter :: align_name(4) =  &
    (/ 'Velocity ','Frequency','Image    ','Position ' /)
  character(len=*), parameter :: align_unit(4) =  &
    (/ 'km/s','MHz ','MHz ','    ' /)
  !
  ! Resampling parameters
  integer(kind=4), parameter :: resample_no=0     ! No resampling
  integer(kind=4), parameter :: resample_auto=1   ! Automatic resampling
  integer(kind=4), parameter :: resample_user=2   ! User's resampling
  !
  ! Weighting modes
  integer(kind=4), parameter :: weight_equal=1
  integer(kind=4), parameter :: weight_time=2
  integer(kind=4), parameter :: weight_sigma=3
  integer(kind=4), parameter :: weight_assoc=4
  !
  ! Composition modes
  integer(kind=4), parameter :: composite_inter=-1  ! Force intersection
  integer(kind=4), parameter :: composite_user = 0  ! Let user decision
  integer(kind=4), parameter :: composite_union=+1  ! Force union ("composition" in Class nomenclature)
  !
  ! Range type
  type :: average_range_t
    character(len=1) :: unit  ! Unit
    real(kind=8)     :: xmin  ! Xmin range value
    real(kind=8)     :: xmax  ! Xmax range value
  end type average_range_t
  !
  type :: average_comm_t
    character(len=20) :: rname         ! Calling command name
    logical           :: nomatch       ! /NOMATCH invoked?
    logical           :: resample      ! /RESAMPLE invoked?
    integer(kind=4)   :: optresample   ! /RESAMPLE option number
    logical           :: nocheck       ! /NOCHECK invoked?
    integer(kind=4)   :: optnocheck    ! /NOCHECK option number
    integer(kind=4)   :: optweight     ! /WEIGHT option number
    logical           :: stitch        ! Stitch mode?
    logical           :: stitch_image  ! STITCH in image frequencies?
    logical           :: rms           ! Perform the rms instead of average?
  end type average_comm_t
  !
  type :: average_do_t
    character(len=20)     :: rname        ! Calling command name
    integer(kind=4)       :: kind         ! Kind of data
    integer(kind=4)       :: resampling   ! Desired resampling mode
    integer(kind=4)       :: alignment    ! Desired unit for alignment
    character(len=1)      :: weight       ! [Letter] Desired weighting
    integer(kind=4)       :: composition  ! Desired composition mode
    type(resampling)      :: axis         ! Desired resampling axis, if relevant
    logical               :: range        ! Is a cut by range desired?
    type(average_range_t) :: rangeval     ! Desired range cut, if relevant
    logical               :: modfreq      ! Is a MODIFY FREQUENCY desired?
    real(kind=8)          :: restf        ! New Restf frequency, if relevant
    logical               :: modvelo      ! Is a MODIFY VELOCITY desired?
    real(kind=8)          :: voff         ! New Velocity, if relevant
  end type average_do_t
  !
  type :: average_done_t
    logical          :: kind_is_spec  ! Kind of data is spectroscopy
    logical          :: resample      ! Is resampling effectively needed?
    integer(kind=4)  :: align         ! Effective unit for the alignment
    logical          :: composite     ! Is composition mode 'composite'?
    integer(kind=4)  :: weight        ! [code] Weighting
    type(resampling) :: axis          ! The effective resampling axis
    integer(kind=4)  :: nchanmax      ! Size of largest spectrum encountered
  end type average_done_t
  !
  type :: average_t
    type(average_comm_t) :: comm  ! Command line description
    type(average_do_t)   :: do    ! User and command inputs
    type(average_done_t) :: done  ! Averaging parameters
  end type average_t
  !
end module class_averaging
!
module class_sicidx
  use class_parameter
  !---------------------------------------------------------------------
  ! Support module for
  !  Sic structure  IDX%HEAD%
  !  Command        VARIABLE Section /INDEX
  !---------------------------------------------------------------------
  !
  type class_general_arr_t
    ! Also in the index
    integer(kind=obsnum_length), allocatable :: num(:)      ! Observation number
    integer(kind=4),             allocatable :: ver(:)      ! Version number
    character(len=12),           allocatable :: teles(:)    ! Telescope name
    integer(kind=4),             allocatable :: dobs(:)     ! Date of observation
    integer(kind=4),             allocatable :: dred(:)     ! Date of reduction
    integer(kind=4),             allocatable :: kind(:)     ! Type of data
    integer(kind=4),             allocatable :: qual(:)     ! Quality of data
    integer(kind=4),             allocatable :: subscan(:)  ! Subscan number
    integer(kind=obsnum_length), allocatable :: scan(:)     ! Scan number
    ! In the section only
    real(kind=8),                allocatable :: ut(:)       ! UT of observation
    real(kind=8),                allocatable :: st(:)       ! LST of observation
    real(kind=4),                allocatable :: az(:)       ! Azimuth
    real(kind=4),                allocatable :: el(:)       ! Elevation
    real(kind=4),                allocatable :: tau(:)      ! Opacity
    real(kind=4),                allocatable :: tsys(:)     ! System temperature
    real(kind=4),                allocatable :: time(:)     ! Integration time
    real(kind=8),                allocatable :: parang(:)   ! Parallactic angle
    integer(kind=4),             allocatable :: xunit(:)    ! X unit (if X coordinates section is present)
    ! Duplicates
    ! character(len=12),           allocatable :: cdobs(:)    ! Date of observation
    ! character(len=12),           allocatable :: cdred(:)    ! Date of reduction
  end type class_general_arr_t
  !
  type class_position_arr_t
    character(len=12), allocatable :: sourc(:)    ! Source name
    integer(kind=4),   allocatable :: system(:)   ! Coordinate system
    real(kind=4),      allocatable :: equinox(:)  ! Equinox of coordinates
    integer(kind=4),   allocatable :: proj(:)     ! Projection system
    real(kind=8),      allocatable :: lam(:)      ! Lambda
    real(kind=8),      allocatable :: bet(:)      ! Beta
    real(kind=8),      allocatable :: projang(:)  ! Projection angle
    real(kind=4),      allocatable :: lamof(:)    ! Offset in Lambda
    real(kind=4),      allocatable :: betof(:)    ! Offset in Beta
  end type class_position_arr_t
  !
  type class_spectro_arr_t
    character(len=12), allocatable :: line(:)     ! Line name
    real(kind=8),      allocatable :: restf(:)    ! Rest frequency
    integer(kind=4),   allocatable :: nchan(:)    ! Number of channels
    real(kind=8),      allocatable :: rchan(:)    ! Reference channels
    real(kind=8),      allocatable :: fres(:)     ! Frequency resolution
    real(kind=8),      allocatable :: vres(:)     ! Velocity resolution
    real(kind=8),      allocatable :: voff(:)     ! Velocity at reference channel
    real(kind=4),      allocatable :: bad(:)      ! Blanking value
    real(kind=8),      allocatable :: image(:)    ! Image frequency
    integer(kind=4),   allocatable :: vtype(:)    ! Type of velocity
    integer(kind=4),   allocatable :: vconv(:)    ! Velocity convention
    integer(kind=4),   allocatable :: vdire(:)    ! Velocity direction
    real(kind=8),      allocatable :: doppler(:)  ! Doppler factor = -V/c (CLASS convention)
  end type class_spectro_arr_t
  !
  type class_res_arr_t
    real(kind=4), allocatable :: major(:)   !  [rad] Major axis
    real(kind=4), allocatable :: minor(:)   !  [rad] Minor axis
    real(kind=4), allocatable :: posang(:)  !  [rad] Position angle
  end type class_res_arr_t
  !
  type class_base_arr_t
    integer(kind=4), allocatable :: deg(:)      ! Degree of last baseline
    real(kind=4),    allocatable :: sigfi(:)    ! Sigma
    real(kind=4),    allocatable :: aire(:)     ! Area under windows
    integer(kind=4), allocatable :: nwind(:)    ! Number of line windows
    real(kind=4),    allocatable :: w1(:,:)     ! Lower limits of windows
    real(kind=4),    allocatable :: w2(:,:)     ! Upper limits of windows
    real(kind=4),    allocatable :: sinus(:,:)  ! Sinus baseline results
  end type class_base_arr_t
  !
  type class_history_arr_t
    integer(kind=4), allocatable :: nseq(:)     ! Number of sequences
    integer(kind=4), allocatable :: start(:,:)  ! Start can number of seq.
    integer(kind=4), allocatable :: end(:,:)    ! End scan number of seq.
  end type class_history_arr_t
  !
  type class_plot_arr_t
    real(kind=4), allocatable :: amin(:)  ! Min Y value plotted
    real(kind=4), allocatable :: amax(:)  ! Max Y value plotted
    real(kind=4), allocatable :: vmin(:)  ! Min X value plotted
    real(kind=4), allocatable :: vmax(:)  ! Max X value plotted
  end type class_plot_arr_t
  !
  type class_switch_arr_t
    integer(kind=4), allocatable :: nphas(:)     ! Number of phases
    real(kind=8),    allocatable :: decal(:,:)   ! Frequency offsets
    real(kind=4),    allocatable :: duree(:,:)   ! Time per phase
    real(kind=4),    allocatable :: poids(:,:)   ! Weight of each phase
    integer(kind=4), allocatable :: swmod(:)     ! Switching mode (frequency, position...)
    real(kind=4),    allocatable :: ldecal(:,:)  ! Lambda offsets
    real(kind=4),    allocatable :: bdecal(:,:)  ! Beta offsets of each phase
  end type class_switch_arr_t
  !
  type class_calib_arr_t
    real(kind=4),    allocatable :: beeff(:)    ! Beam efficiency
    real(kind=4),    allocatable :: foeff(:)    ! Forward efficiency
    real(kind=4),    allocatable :: gaini(:)    ! Image/Signal gain ratio
    real(kind=4),    allocatable :: h2omm(:)    ! Water vapor content
    real(kind=4),    allocatable :: pamb(:)     ! Ambient pressure
    real(kind=4),    allocatable :: tamb(:)     ! Ambient temperature
    real(kind=4),    allocatable :: tatms(:)    ! Atmosphere temp. in signal band
    real(kind=4),    allocatable :: tchop(:)    ! Chopper temperature
    real(kind=4),    allocatable :: tcold(:)    ! Cold load temperature
    real(kind=4),    allocatable :: taus(:)     ! Opacity in signal band
    real(kind=4),    allocatable :: taui(:)     ! Opacity in image band
    real(kind=4),    allocatable :: tatmi(:)    ! Atmosphere temp. in image band
    real(kind=4),    allocatable :: trec(:)     ! Receiver temperature
    integer(kind=4), allocatable :: cmode(:)    ! Calibration mode
    real(kind=4),    allocatable :: atfac(:)    ! Applied calibration factor
    real(kind=4),    allocatable :: alti(:)     ! Site elevation
    real(kind=4),    allocatable :: count(:,:)  ! Power of Atm., Chopp., Cold
    real(kind=4),    allocatable :: lcalof(:)   ! Longitude offset for sky measurement
    real(kind=4),    allocatable :: bcalof(:)   ! Latitude offset for sky measurement
    real(kind=8),    allocatable :: geolong(:)  ! Geographic longitude of observatory
    real(kind=8),    allocatable :: geolat(:)   ! Geographic latitude of observatory
  end type class_calib_arr_t
  !
  type class_skydip_arr_t
  ! character(len=12), allocatable :: line      ! Line name
    real(kind=8),    allocatable :: restf(:)    ! Rest frequency
    real(kind=8),    allocatable :: image(:)    ! Image frequency
    integer(kind=4), allocatable :: nsky(:)     ! Number of points on sky
    integer(kind=4), allocatable :: nchop(:)    !   -   -    -    - chopper
    integer(kind=4), allocatable :: ncold(:)    !   -   -    -    - cold load
    real(kind=4),    allocatable :: elev(:,:)   ! Elevations
    real(kind=4),    allocatable :: emiss(:,:)  ! Power on sky
    real(kind=4),    allocatable :: chopp(:,:)  ! Power on chopper
    real(kind=4),    allocatable :: cold(:,:)   ! Power on cold load
  end type class_skydip_arr_t
  !
  type class_gauss_arr_t
    integer(kind=4), allocatable :: nline(:)   ! Number of components
    real(kind=4),    allocatable :: sigba(:)   ! Sigma on base
    real(kind=4),    allocatable :: sigra(:)   ! Sigma on line
    real(kind=4),    allocatable :: nfit(:,:)  ! Fit results
    real(kind=4),    allocatable :: nerr(:,:)  ! Errors
  end type class_gauss_arr_t
  !
  type class_shell_arr_t
    integer(kind=4), allocatable :: nline(:)   ! Number of components
    real(kind=4),    allocatable :: sigba(:)   ! Sigma on base
    real(kind=4),    allocatable :: sigra(:)   ! Sigma on line
    real(kind=4),    allocatable :: nfit(:,:)  ! Fit results
    real(kind=4),    allocatable :: nerr(:,:)  ! Errors
  end type class_shell_arr_t
  !
  type class_hfs_arr_t
    integer(kind=4), allocatable :: nline(:)   ! Number of components
    real(kind=4),    allocatable :: sigba(:)   ! Sigma on base
    real(kind=4),    allocatable :: sigra(:)   ! Sigma on line
    real(kind=4),    allocatable :: nfit(:,:)  ! Fit results
    real(kind=4),    allocatable :: nerr(:,:)  ! Errors
  end type class_hfs_arr_t
  !
  type class_absorption_arr_t
    integer(kind=4), allocatable :: nline(:)   ! Number of components
    real(kind=4),    allocatable :: sigba(:)   ! Sigma on base
    real(kind=4),    allocatable :: sigra(:)   ! Sigma on line
    real(kind=4),    allocatable :: nfit(:,:)  ! Fit results
    real(kind=4),    allocatable :: nerr(:,:)  ! Errors
  end type class_absorption_arr_t
  !
  type class_drift_arr_t
    real(kind=8),    allocatable :: freq(:)   ! Rest frequency
    real(kind=4),    allocatable :: width(:)  ! Bandwidth
    integer(kind=4), allocatable :: npoin(:)  ! Number of data points
    real(kind=4),    allocatable :: rpoin(:)  ! Reference point
    real(kind=4),    allocatable :: tref(:)   ! Time at reference
    real(kind=4),    allocatable :: aref(:)   ! Angular offset at ref.
    real(kind=4),    allocatable :: apos(:)   ! Position angle of drift
    real(kind=4),    allocatable :: tres(:)   ! Time resolution
    real(kind=4),    allocatable :: ares(:)   ! Angular resolution
    real(kind=4),    allocatable :: bad(:)    ! Blanking value
    integer(kind=4), allocatable :: ctype(:)  ! Type of offsets
    real(kind=8),    allocatable :: cimag(:)  ! Image frequency
    real(kind=4),    allocatable :: colla(:)  ! Collimation error Az
    real(kind=4),    allocatable :: colle(:)  ! Collimation error El
  end type class_drift_arr_t
  !
  type class_beam_arr_t
    real(kind=4),    allocatable :: cazim(:)  ! Azimuth of observation
    real(kind=4),    allocatable :: celev(:)  ! Elevation of observation
    real(kind=4),    allocatable :: space(:)  ! Beam spacing
    real(kind=4),    allocatable :: bpos(:)   ! Position angle of beams
    integer(kind=4), allocatable :: btype(:)  ! System for angle
  end type class_beam_arr_t
  !
  type class_pointing_arr_t
    integer(kind=4), allocatable :: nline(:)   ! Number of components
    real(kind=4),    allocatable :: sigba(:)   ! Sigma on base
    real(kind=4),    allocatable :: sigra(:)   ! Sigma on line
    real(kind=4),    allocatable :: nfit(:,:)  ! Fit results
    real(kind=4),    allocatable :: nerr(:,:)  ! Errors
  end type class_pointing_arr_t
  !
  type class_herschel_arr_t
    integer(kind=8),   allocatable :: obsid(:)       !  [----] Observation id
    character(len=8),  allocatable :: instrument(:)  !  [str ] Instrument name
    character(len=24), allocatable :: proposal(:)    !  [str ] Proposal name
    character(len=68), allocatable :: aor(:)         !  [str ] Astronomical Observation Request
    integer(kind=4),   allocatable :: operday(:)     !  [day ] Operational day number
    character(len=28), allocatable :: dateobs(:)     !  [str ] Start date (ISO date)
    character(len=28), allocatable :: dateend(:)     !  [str ] End date (ISO date)
    character(len=40), allocatable :: obsmode(:)     !  [str ] Observing mode
    real(kind=4),      allocatable :: vinfo(:)       !  [km/s] Informative source velocity in LSR frame
    real(kind=4),      allocatable :: zinfo(:)       !  [----] Informative target redshift
    real(kind=8),      allocatable :: posangle(:)    !  [rad ] Spacecraft pointing position angle
    real(kind=8),      allocatable :: reflam(:)      !  [rad ] Sky reference (a.k.a. OFF), lambda coordinate
    real(kind=8),      allocatable :: refbet(:)      !  [rad ] Sky reference (a.k.a. OFF), beta coordinate
    real(kind=8),      allocatable :: hifavelam(:)   !  [rad ] ON average H and V coordinate (HIFI), lambda coordinate
    real(kind=8),      allocatable :: hifavebet(:)   !  [rad ] ON average H and V coordinate (HIFI), beta coordinate
    real(kind=4),      allocatable :: etamb(:)       !  [----] Main beam efficiency used when applying doAntennaTemp
    real(kind=4),      allocatable :: etal(:)        !  [----] Forward efficiency used when applying doAntennaTemp
    real(kind=4),      allocatable :: etaa(:)        !  [----] Telescope aperture efficiency
    real(kind=4),      allocatable :: hpbw(:)        !  [rad ] Azimuthally-averaged half-power beam width
    character(len=8),  allocatable :: tempscal(:)    !  [str ] Temperature scale in use
    real(kind=8),      allocatable :: lodopave(:)    !  [MHz ] Average LO frequency Doppler corrected to freqFrame (SPECSYS)
    real(kind=4),      allocatable :: gim0(:)        !  [----] Sideband gain polynomial coeff 0 applied
    real(kind=4),      allocatable :: gim1(:)        !  [----] Sideband gain polynomial coeff 1 applied
    real(kind=4),      allocatable :: gim2(:)        !  [----] Sideband gain polynomial coeff 2 applied
    real(kind=4),      allocatable :: gim3(:)        !  [----] Sideband gain polynomial coeff 3 applied
    real(kind=4),      allocatable :: mixercurh(:)   !  [mA  ] Calibrated mixer junction current, horizontal
    real(kind=4),      allocatable :: mixercurv(:)   !  [mA  ] Calibrated mixer junction current, vertical
    character(len=28), allocatable :: datehcss(:)    !  [str ] Processing date (ISO date)
    character(len=24), allocatable :: hcssver(:)     !  [str ] HCSS version
    character(len=16), allocatable :: calver(:)      !  [str ] Calibration version
    real(kind=4),      allocatable :: level(:)       !  [----] Pipeline level
  end type class_herschel_arr_t
  !
  type class_comment_arr_t
    integer(kind=4),     allocatable :: ltext(:)  ! Length of comment
    character(len=1024), allocatable :: ctext(:)  ! Comment string
  end type class_comment_arr_t
  !
  ! Header (array)
  type class_header_arr_t
    logical, allocatable :: presec(:,:)  ! Which section are presents
    !
    type(class_general_arr_t)    :: gen
    type(class_position_arr_t)   :: pos
    type(class_spectro_arr_t)    :: spe
    type(class_res_arr_t)        :: res
    type(class_base_arr_t)       :: bas
    type(class_history_arr_t)    :: his
    type(class_plot_arr_t)       :: plo
    type(class_switch_arr_t)     :: swi
    type(class_calib_arr_t)      :: cal
    type(class_skydip_arr_t)     :: sky
    type(class_gauss_arr_t)      :: gau
    type(class_shell_arr_t)      :: she
    type(class_hfs_arr_t)        :: hfs
    type(class_absorption_arr_t) :: abs
    type(class_drift_arr_t)      :: dri
    type(class_beam_arr_t)       :: bea
    type(class_pointing_arr_t)   :: poi
    type(class_herschel_arr_t)   :: her
    type(class_comment_arr_t)    :: com
  end type class_header_arr_t
  !
  ! Support variable for command "SET VARIABLE Section /INDEX"
  type(class_header_arr_t), save :: idxhead
  !
end module class_sicidx
!
! Others..
!
module sinus_parameter
  integer(kind=4), parameter :: mxline=5
  !
  ! Initial values and Dependency codes
  real(kind=4) , dimension(mxline) :: spar
  real(kind=4)                     :: deltav
  ! Weights for minimization
  integer(kind=4)              :: mxcan
  integer(kind=4), allocatable :: wfit(:)
  ! Common containing results and errors
  real(kind=4) , dimension(mxline) :: par     ! Parameters
  real(kind=4)                     :: sigbas  ! rms on baseline
  real(kind=4)                     :: sigrai  ! rms on area under line
end module sinus_parameter
!
module class_buffer
  use classic_params
  !
  integer(kind=4) :: header_length
  integer(kind=4), allocatable :: iwork(:)  ! Buffer for standard sections
  !
  integer(kind=8), save :: jlen=0
  integer(kind=4), allocatable :: jwork(:)  ! Buffer for X coordinates section
  !
  integer(kind=4), allocatable :: uwork(:)  ! Buffer for User Section
  integer(kind=data_length) :: unext        ! Next element to write in uwork
  !
end module class_buffer
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
