/**
 *
 * sglgal (modification of galeqd) to compute galactic coordinates
 *  from supergalactic coordinates.  j.bennett  30oct-05nov90
 *
 * inputs:
 * @param xb = supergalactic latitude  (SGB)  (-90. to + 90. deg). double precision.
 * @param xl = supergalactic longitude (SGL)  (0-360. deg). double precision.
 * @return {{ra: (number), dec: (number)}}
 * returned: rad =  gal lon (l) in degrees. double precision.
 *           decd = gal lat (b) in degrees. double precision.
 *
 *  Computed values of rotation used for the Eulerian angles:
 *   phi = 137.37 deg.;  theta = 83.68 deg.;  psi = 0. deg.
 *    Based on gal l,b = 137.37, 0 deg. at sg SGL,SGB = 0., 0. and
 *         SG North Pole (0,+90) at gal l,b = 47.37, +6.32 deg.
 *
 * References:
 * de Vaucouleurs,G., A. de Vaucouleurs, and G.H.Corwin,
 *  Second Reference Catalog of Bright Galaxies, (1976), p.8
 *
 * Tully,B., Nearby Galaxies Catalog, (1988) p. 1,4-5
 *
 *    Note: de Vaucouleurs gives gal l,b 137.29, 0 for SGL,SGB= 0,0;
 *          this is not 90 degrees from Galactic North Pole.- used
 *          Tully's value of 137.37, 0 deg.
 *
 *  gal <==> equ equations from tom soifer.  see also:
 *   Classical Mechanics by Herbert Goldstein (Addison-Wesley Publ.Co.,
 *     c.1950, 7th printing 1965) Section 4-4 on Eulerian Angles
 *     (p.107-109)
 *    note: such equations also appropriate for gal <==> sgl .
 *          See code below for def. of arrays a,b,c.
 *  x = cos(sgb)*cos(sgl)
 *  y = sin(sgl)*cos(sgb)
 *  z = sin(sgb)
 *  eq1 = sin(lat)          =   a(1)*x +  a(2)*y +  a(3)*z
 *  eq2 = cos(lat)*cos(lon) =   b(1)*x +  b(2)*y +  b(3)*z
 *  eq3 = cos(lat)*sin(lon) =   c(1)*x +  c(2)*y +  c(3)*z
 *  sgb = arsin(sin(lat))
 *  cos(lat) = sqrt(1.-sin(lat)*sin(lat))
 *  cos(lon) = eq2/cos(lat)
 *  sin(lon) = eq3/cos(lat)
 *  lon = atan2(sin(lon)/cos(lon): if(lon.lt.0) lon = lon+2*pi if radians.
 *
 */


/**
 *
 * 23feb91 updated some comments.
 * 22feb91 to make sure pa is 0 to 360 (i.e.never < 0 )in sub jbelpt.
 * 19feb91 jbposa2.f  to allow 0 to 360 deg pa
 *  26,29oct90 to add pole test to jbposa sub.
 *
 * 28sep90 to include slightly modified ipac prec. routines
 * 26sep90 to improve comments & use smaller value for value variable small.
 * 10sep90 jbposa modification of ned version of jbdist to return pa
 *   (0 - 180 deg. E of N) if distd < 90 deg.
 * jbposa finds distance between 2 positions & (if distd <90.deg) finds
 *   position angle (pa) of (xlon1,xlat1) with respect to (xlon0,xlat0)
 *
 * all non-integer args in double precision degrees.distd,pa,ipf returned.
 *
 * for discussion of xlon1, etc. see pa explanation below.
 *
 * distd is distance between 2 positions on sky - results in degrees.
 *
 * pa is position angle (degrees E of N) -  0 to 180 deg. returned and
 *  is valid only if distd < 90. deg.
 *  pa is sensitive to what is called xlon1,xlat1 and what is called
 *  xlon0,xlat0.
 *   for use w/ ellipse  xlon1,xlat1 is pt on ellipse;
 *                       xlon0,xlat0 is center of ellipse.
 *
 * ipf is integer flag for pa compution: 0 = not computed; 1 = computed;
 *      2=computed and one of points treated as though exactly at pole.
 *      if ipf = 0, and distd .ne. 0, distd was computed.
 *
 * NOTE: reference for the equations used:
 *   A Compendium of Spherical Astronomy by Simon Newcomb
 *    Section 56 (page 111)
 *
 *  where s is distance (in degrees), p is position angle (in degrees)
 *        dela = alpha' - alpha
 *     sin(s)*sin(p) =                           cos(d')*sin(dela)
 *     sin(s)*cos(p) = cos( d)*sin(d') - sin( d)*cos(d')*cos(dela)
 *            cos(s) = sin( d)*sin(d') + cos( d)*cos(d')*cos(dela)
 *        Therefore:
 *          s = acos(cos(s))
 *          p = atan2(sin(p) , cos(p))
 *      p is counted from the meridian passing north through position
 *        at (alpha,d)  toward the east.
 *
 * NOTE: maximum precision in distd is .01" on machine with a 64-bit
 *       double precision word. On cyber, with 128-bit double precision
 *       word, precision may exceed .00001" .  The worst case for distd
 *       is near the poles.
 *       Precision for posangle is within .5 degree which is usually
 *       considered, astronomically speaking, more than satisfactory.
 *       Actual test cases have indicated pa is within 1.2d-06" on
 *       a UNIX machine (i.e. 64-bit double precision)- however not
 *       all possible cases have been tested.
 *
 */


/**
 *
 * finds pt on end of ellipse given center xlonin & xlatin, posang (pa)
 *    and major axis semi-diameter (distd). Returns xlonp,xlatp & iflg).
 *    all non-integer args are double precision degrees.
 * @return xlonp,xlatp
 * @return   iflg indicates processing: 1 completely "normal"
 *        0 = distd too small (new pt = old pt on return)
 *        2 = posang too small (treated as though pa= 0.)
 *            ( note 3 can override iflg=2)
 *        3 = treated xlonin,xlatin as pole:  e.g. dabs(xlatin) close
 *            to 90.deg, treated as + or - 90 & xlonin was not 0 on
 *            input, but was treated as though zero.
 *             Note: test for pole used here is that any position with
 *                   dabs(xlatin) > 89.99999d0 (89d59'59.964") is at the
 *                   pole  and is treated as pole with xlon = 0 deg. and
 *                   xlat as -90. or + 90. deg as appropriate.
 *        4 = xlonp,xlatp should be treated as pole, however computed
 *            pos has not been revised. Calling prog. may want to revise pos.
 *
 * NOTE: reference for the equations used:
 *   A Compendium of Spherical Astronomy by Simon Newcomb
 *    Section 56 (page 111)
 *
 */


/**
 *  26mar-01apr92 j.bennett
 *  This updated version, aug92, is totally restructured in order to
 *    handle the addition of ecliptic of date; also problems in the pre-release
 *    version have been fixed. (Pre-release version failed to produce
 *    accurate results if input was Bess. equ (isys1 =1) with equinox other
 *    than 1950.0d0 and output was Julian equatorial (isys2 =0) with equinox
 *    2000.0d0 (e.g. B1975 to J2000 conversion was wrong).  Also,
 *    when isys1  was 2,3,or 4 (galactic,ecliptic,supergalactic) and
 *    isys2  =1 (Bess. equ) and equinox not 1950.0d0, result was wrong).
 *
 *  jcnvc2 is version of jcnvcd that can handle J2000 input and output and
 *         do appropriate conversions before/after calling ecl,gal,sgl conv.
 *         routines.
 *         E-term removal/replacement assumed in B1950 <==>J2000 conversions.
 *
 *  16Sep92 to comment out write on unit 0
 *  24aug92 updated comments only.
 *  11-13,20aug92 to implement ecliptic of date capability.
 *
 *    calls gtjul2, unjul2, nwcprc, fk5prc
 *    calls ecleqx,equecx,equgad,galeqd,galsgl,sglgal
 *     the new subroutines compute(the first time thru & store) values for
 *     the galactic <==> equatorial conversion matrices from the
 *     actual angles so that maximum precision may be maintained for
 *     the machine being used for computation. Also better agreement is
 *     obtained when returning to input coord system from output values.
 *
 *    Also radian to deg., etc. computed using machine functions (i.e.
 *     radian-to-deg = datan(1.0d0) / 45.0d0 )
 *    If |dec| or |lat| = 90.0d0, the corresponding ra or lon = 0.0d0.
 *
 * @param x0,y0     = input lon and lat in degrees,
 * @param y0
 * @param xnew,ynew = DUMMY FROM CONVERSION output lon and lat in degrees.
 * @param ynew
 * @param epoki,epoko input output equinox (used if jsys1,jsys2 0, 1, 3, 11,or 13).
 * @param epoko
 *    epok_ ignored for galactic (jsys_=2) and supergalactic (isys_=4).
 *    If epok_ input as 0.0d0, then 1950.0d0 used if isys_ is 1 or 3;
 *                                  2000.0d0 used if isys_ is 0,11 or 13.
 * @param isys1  = input coordinate system#;  isys2 = output system#.
 *     0 = equ(Jul. ),     1 = equ(Bess),
 *     2 = gal,            3 = ecl(Bess),     4 = supergalactic (sgl)
 *     11= equ(Jul.),      13= ecl(Jul.)
 * @param isys2
 * @param tobsin is observation epoch used when B1950 <==> J2000 conversions required.
 *   Note:gal and sgl conversions require B1950 as input, give B1950 as output
 *   when working with the original subroutines. jcnvc2 will convert between
 *   B1950 and J2000 as needed and as appropriate.
 *
 */


/**
 * 31jul92 - changes to jrmvet,jaddet; substituted more general purpose
 *     subs jgtobq,ecleqx,equec2 for limited- purpose subs gtoblq,ecleq2,equec2
 * 23jul92 to call nwcprc/nwcprp instead of jprecj.
 * 02jul92 - re; routines with propermotions:
 *    gtjulp will assume eqx,epoch B1950 in and yield eqx,epoch J2000 out.
 *    unjulp will assume eqx,epoch J2000 in and yield eqx,epoch B1950 out.
 * 30jun92 to apply fk5-fk4 sys. corr. to eqx B1950 position before any other
 *   corrections.
 * 05,06mar92 to use astron. suppl 1984 & 1961 e-term removal equations
 *    (in subs gtjul2,gtjulp,unjul,unjulp)
 * 13-15jan92 updated to reflect method described in FK5 Part I. Catalog
 * author:   judy bennett
 *
 * to precess old besselian equinox positions to equator and equinox of
 *   J2000.0.
 *
 *   Calls subroutines nwcprc ("old" Newcomb constants) and fk5prc and fk5prp
 *      ("new" Julian precession formulas).
 *
 *  Source of method:
 *    Fifth Fundamental Catalogue (FK5) Part I (1988, but not avail. till 1992)
 *     Section 8. (page 9)
 *     Summary of order:
 *  1.  Precess each object (using precessional values adopted in that cat-
 *        i.e. usually Newcomb) from the catalogue equinox to the mean equinox
 *        at the object's mean epoch (i.e. observation date).
 *  2.  The mean positions in all star catalogues published prior to 1984
 *        contain the terms of elliptic aberration (E-terms). These terms need
 *        to be removed from the star's mean position.
 *  3.  The equinox correction and the systematic correction FK5-FK4
 *       (given in the FK5 cat), computed for the object's mean epoch, need to
 *       be applied. Note: program applies fk5-fk4 sys.corr. at B1950 which
 *       seems consistent with procedure actually described in the FK5.
 *  4.  The corrected position has to be precessed to the new standard equinox
 *       J2000.0 using the precessional quantities as adopted in the IAU(1976)
 *       System of Astronomical Constants (also see Astronomical Almanac 1984,
 *       pages S34,S36)
 *
 *  NOTE: these routines apply the fk5-fk4 correction at B1950.
 *        if no fk5-fk4 systematic correction required, the user should
 *        include the following statements in his program:
 *  (a value of 0 for japply specifies no corrections; anything else uses corr.)
 *        external jfk5bd
 *        common /fkappl/ japply
 *        japply = 0
 *
 * ****************************************************************************
 *   All arguments are double precision, except ieflg which is integer.
 *  Input values:
 * @param eqxin is the equinox of the input position (if negative, absolute val.used)
 * @param ra    is right ascension (decimal degrees) at eqx
 * @param dec   is declination (decimal degrees) at eqx
 * @param tobsin is the year of observation (i.e. when the object was observed at
 *         this position (e.g. 1983.5d0) ; if 0.0d0, value of eqxin is used.
 * @param ieflg is flag allowing removal of E-terms of aberration if any (usually
 *        they are present, therefore ieflg should = +1):
 *         ieflg = -1 do not remove E-terms (there none).
 *         ieflg = any value except -1 indicates  E-terms are present and
 *                 are to be removed.
 * @return {{ra: number, dec: number}}
 * raout  is right ascension at equator and equinox of J2000.0
 * decout is declination at equator and equinox of J2000.0
 *
 * ****************************************************************************
 *
 * Files required: gtjul2.f (includes gtjul2,gtjulp,unjul2,unjulp,gtecle,
 *                           gtetrm,itere,iterec,jaddet,jclpos,jrmvet)
 *                 ecleqx.f (includes ecleqx,equecx,jgtobq)
 *                 fk5prc.f (includes fk5prc,fk5prp)
 *                 nwcprc.f (includes nwcprc,nwcprp)
 *                 jgtfkc.f (includes jgtfkc,junfkc,jnitfk.jfk5bd,dintrp,dintr2)
 *
 * ****************************************************************************
 */


/**
 * author: judy bennett
 * 01jul92
 * 26jun92 to allow removal of fk5-fk4 systematic corrections
 * 17jan92
 * 05feb92 to use fk5prc instead of hcprec.
 *
 * unjul2 reverses what gtjul2  did - i.e. unjul2 precesses accurately
 *    back to the original besselian input.
 *
 * to precess new Julian  equinox positions (J2000.0)back to input besselian
 *   equinox positions (B1950.0).
 *
 *   Calls subroutines nwcprc ("old" Newcomb constants) and fk5prc ("new"
 *      Julian prec.formulas).
 *
 *  Source of method:
 *   See comments in gtjul2.
 *
 * ****************************************************************************
 *   All arguments are double precision, except ieflg which is integer.
 *  Input values:
 * @param rain is right ascension (decimal degrees) at J2000.0
 * @param decin is declination (decimal degrees) at J2000.0
 * @param tobsin is the year of observation (i.e. when the object was assigned this pos)
 *         if 0.0d0, eqxbou is used.
 * @param ieflg is flag allowing restore of E-terms of aberration if any (usually
 *        they are present; ieflg should usually = + 1).
 *         ieflg =-1 do not replace E-terms (there none).
 *         ieflg = anything but -1 indicates  E-terms are to be present
 *             and are to be replaced. Usually they are to be replaced.
 * @param eqxbou is output equinox (besselian): if 0.0d0, 1950.0d0 is used.
 * @return {{ra: number, dec: number}}
 * raout  is right ascension at besselian equinox of eqxbou.
 * decout is declination at besselian equinox of eqxbou.
 *
 * ****************************************************************************
 */


/**
 * 27jul92 to allow pmain,pmdin =0.0d0 to be processed as any other
 *         source with given proper motions (User must use gtjul2
 *         if proper motions are "intrinsically" zero (e.g. radio source)
 *         or if no proper motions are given for the object).
 * 02jul92 to apply fk5-fk4 systematic corrections at B1950.
 *  eqxin will be ignored; jgtjulp assumes equinox,epoch B1950 for inputs.
 * 24jun92 to apply fk5-fk4 systematic corrections if desired.
 * 05feb92 like gtjul2, except for objects with proper motions etc.
 *
 * author: judy bennett
 *
 * to precess old besselian equinox positions to equator, equinox and epoch
 *   of J2000.0.
 *
 *  Source of method:
 *    Fifth Fundamental Catalogue (FK5) Part I (1988, but not avail. till 1992)
 *     Section 8. (page 9) + discussion in FK5
 *
 * ****************************************************************************
 *   All arguments are double precision, except ieflg which is integer.
 *  Input values:
 * @param eqxin is ignored (assumes 1950.0d0);
 *       is the equinox & epoch of input position
 * @param rain  is right ascension (decimal degrees) at equinox & epoch of B1950
 * @param decin is declination (decimal degrees) at equinox & epoxh of B1950
 * @param pmain is proper motion in ra in seconds of time per tropical century
 * @param pmdin is proper motion in dec in seconds of arc per tropical century
 * @param pin is parallax in arc seconds.
 * @param vin is radial velocity in km/sec
 * @param ieflg is flag allowing removal of E-terms of aberration if any (usually
 *        E-terms are present; therefore, ieflg should = +1)
 *         ieflg = -1 do not remove E-terms (there none).
 *         ieflg = anything except -1 indicates  E-terms are present and
 *                 are to be removed.
 *  Returned values:
 * @return raout  is right ascension at epoch, equator and equinox of J2000.0
 * @return decout is declination at epoch, equator and equinox of J2000.0
 * @return pmaout is proper motion in seconds of time per Julian century.
 * @return pmdout is proper motion in seconds of arc per Julian century.
 * @return {{ra: number, dec: number, pmra: number, pmdec: number}}
 *
 * ****************************************************************************
 *
 */


/**
 * 27jul92 to allow pmain,pmdin =0.0d0 to be processed as any other
 *         source with given proper motions (User must use unjul2
 *         if proper motions are "intrinsically" zero (e.g. radio source)
 *         or if no proper motions are given for the object).
 * 02jul92-eqxbou is ignored (assumed to be equinox,epoch B1950.0d0 for outputs)
 * 26jun92 to allow removal for fk5-fk4 correction.
 * author:  judy bennett
 *
 * unjulp reverses what gtjulp  did - i.e. unjulp precesses accurately
 *    back to the original besselian input ( B1950).
 *
 * to precess new Julian  equinox positions (J2000.0)back to input besselian
 *   equinox positions (B1950.0).
 *
 *  Source of method:
 *   See comments in gtjul2.
 *
 * ****************************************************************************
 *   All arguments are double precision, except ieflg which is integer.
 *  Input values:
 * @param rain is right ascension (decimal degrees) at epoch & equinox of J2000.0
 * @param decin is declination (decimal degrees) at epoch & equinox of J2000.0
 * @param pmain is proper motion in ra in seconds of time per Julian century.
 * @param pmdin is proper motion in dec in seconds of arc per Julian century.
 * @param pin is parallax in arc seconds.   (0.0d0 if unknown)
 * @param vin is radial velocity in km/sec. (0.0d0 if unknown)
 * @param ieflg is flag allowing restore of E-terms of aberration. Usually ieflg
 *   should = +1 (to restore the E-terms to the B1950 position).
 *         ieflg =-1 do not replace E-terms (there none).
 *         ieflg = anything but -1 indicates  E-terms are to be present
 *             and are to be replaced.
 * @param eqxbou is ignored (assumed to be 1950.0d0);
 *        is output equinox (besselian):
 * @return {{ra: number, dec: number, pmra: number, pmdec: number}}
 * raout  is right ascension (decimal degrees) at equinox,epoch B1950.
 * decout is declination (decimal degrees) at equinox,epoch B1950.
 * pmaout  is proper motion in ra in seconds of time per tropical century.
 * pmdout  is proper motion in dec in seconds of arc per tropical century.
 *
 * ****************************************************************************
 *
 */


/**
 *for adding E-term back (note: w/ supp. formulas, edela,edeld are added to
 *
 * @param ra and dec to remove the E-term; therefore subtract here.
 * @param dec
 * @return {{ra: number, dec: number}}
 */


/**
 *  from Suppl. to Astron. Alman. 1984 (also 1961 supp. page 144)
 *    see also, Standish, A&A 115, 20-22 (1982)
 *
 * compute E-terms to be removed for  object at ra and dec.
 *  all args. double precision and in decimal degrees)
 *
 *  Since the E-terms (terms of elliptic aberration) change so slowly
 *    (Smart,Textbook on Spherical Astronomy, Sixth Ed. Section 108,p186)
 *     these values do not require t as input and will be valid in the
 *     1950 to 2000 time span we are dealing with.
 *
 *  The 1961 supp called these equations an approximation and stated that
 *  small errors in this procedure are usually negligible. However, they
 *  did not explain what lead up to the procedure:  "The form of the equations
 *  of condition and their solution are not discussed here."
 *
 * @return {{ra: number, dec: number}}
 *
 */


/**
 *
 * compute E-terms at epoch for ecliptic lambda, beta input (returned in dela,
 *  deld (degrees).
 *  epoch in years (e.g. 1950.000), lambda,beta,,dela,deld in decimal degrees.
 *  All arguments double precision.
 *
 * E-term formulas from ASTRONOMICAL ALGORITHMS by Jean Meeus (1991) ch.22
 *   Note: equations as presented are for computing E-terms from position
 *         that does not contain E-terms.  To get better answer (when
 *         splitting hairs), iterate to get best E-term (for position that
 *         has E-terms) to be removed. Subroutine iterec may be called to
 *         to do the iteration.
 *   Note 2: these formulas for E-terms, as function of ecliptic lon and lat,
 *           also appear in  Spherical Astronomy by R.Green (1985),page 192;
 *           and in Textbook on Spherical Astronomy, Sixth Ed.,by Smart (1977),
 *           page 186.
 *
 *   To remove E-terms, subtract dela & deld from lamba & beta, respectively,
 *   in the calling program.
 *   To add back E-terms, add dela & deld to lambda & beta, respectively, in
 *   the calling program.
 *
 * @return {{ra: number, dec: number}}
 *
 */


/**
 *
 * @param tobsj
 * @param lambda
 * @param beta
 * @return {{ra: number, dec: number}}
 */


/** Remove E-terms:
 *  31jul92 update to use equecx and ecleqx instead of equec2 and ecleq2.
 * @param tobsj
 * @param rat
 * @param dect
 * @return {{ra: number, dec: number}}
 */


/** Add back  E-terms:
 *  31jul92 update to use equecx and ecleqx instead of equec2 and ecleq2.
 * @param tobsj
 * @param rat
 * @param dect
 * @return {{ra: number, dec: number}}
 */


/** to put ra into 0 to 360 and dec into -90 to +90 ranges.*/


/**
 * j.bennett - for Besselian (aka Newcomb) precession:
 *              using constants from herget general precession (jprecj;
 *              also see p.6 of Publ.Cincinnati Obs. No.24)
 *
 *  allows precession of proper motion values (also will make use of
 *    parallax and radial velocity if not zero.
 *
 * All arguments are double precision:
 *  @param eqx1 is equinox of input position (in year - e.g. 1950.0d0)
 *  @param rain, decin is input position in decimal degrees at eqx1.
 *  @param decin
 *  @param pmain is proper motion in ra in seconds of time per Tropical century.
 *  @param pmdin is proper motion in dec in seconds of arc per Tropical century.
 *  @param pin is parallax in arc seconds (0.0d0 if none)
 *  @param vin is radial velocity in km/sec (0.0d0 if none)
 *  @param eqx2 is eqinox of output position (in year - e.g. 1992.0d0)
 *  @return raou, decou is position in decimal degrees at eqx2.
 *  @return pmaou is proper motion in ra in seconds of time per Tropical century for eqx2
 *  @return pmdou is proper motion in dec in seconds of arc per Tropical century for eqx2
 *
 *******************************************************************************
 * method from Fricke,W.,Schwan,H.,Lederle,T.,1988,Fifth Fundamental Catalogue
 *     (FK5) Part I. (pages 10-11)
 *******************************************************************************
 */


/**
 * do the conversion when there is no proper motion
 * in_sys and out_sys should be on of the final int defined in this class.
 * @param {number} in_sys one of {EQUATORIAL_J, EQUATORIAL_B, GALACTIC, ECLIPTIC_B, SUPERGALACTIC, ECLIPTIC_J}
 * @param {number} in_equinox
 * @param {number} in_lon
 * @param {number} in_lat
 * @param {number} out_sys one of {EQUATORIAL_J, EQUATORIAL_B, GALACTIC, ECLIPTIC_B, SUPERGALACTIC, ECLIPTIC_J}
 * @param {number} out_equinox
 * @param {number} tobs
 * @return {{lon: number, lat: number}}
 */


/**
 * only handles the Proper Motion conversion from Equatorial B1950 to J2000, or vice versa.
 * proper motion unit: arcsec/year
 * @param {boolean} fromB1950ToJ2000
 * @param {number} in_lon
 * @param {number} in_lat
 * @param {number} in_pmlon
 * @param {number} in_pmlat
 * @return {{ra: number, dec: number, raPM: number, decPM: number}}
 */


/**
 *
 *       ALL FLOATING POINT ARGS ARE DOUBLE PRECISION
 *
 * @param eqxin is the equinox(besselian) of the input position.
 * @param ra,dec is input position in decimal degrees at equinox eqxin.
 * @param dec
 * @param pab  = input position angle (0 to 360.0d0 deg.) at eqxin.
 * @param tobsin is year of observation (e.g. 1983.5 for iras sources)
 *         if 0.0d0, then tobsin is treated as though equal to eqxin.
 * @param ieflg  of -1 indicate to not remove E-terms from position in computing
 *             position angle (any other value allows E-term removal)
 * @return raout,decout is output position in decimal degrees at J2000.0
 * @return paj is output position angle (0 to 360.0d0 deg.) for J2000.0
 *         if ierr = 0 ( garbage otherwise).
 * @return ierr = 0 for normal return. -1 if paj could not be computed.
 *
 * NOTE:
 * This routine assumes input pos angle & input position are in the equatorial
 *    coordinate system.
 *
 * calls jbposa,jbelpt,gtjul2
 *
 */


/**
 *
 *       ALL FLOATING POINT ARGS ARE DOUBLE PRECISION
 *
 * @param ra,dec is input position in decimal degrees at J2000.0
 * @param dec
 * @param paj  = input position angle (0 to 360.0d0 deg.) at J2000.0
 * @param tobsin is year of observation (e.g. 1983.5 for iras sources)
 *         if 0.0d0, then tobsin is treated as though equal to eqxin.
 * @param ieflg  of -1 indicates to not add back E-terms
 *           +1  (any val other than -1) indicates E-terms are to be replaced.
 * @param eqxbou is the equinox(besselian) of the output position & position angle.
 * @return raout,decout is output position in decimal degrees at eqxbou.
 * @return pab is output position angle (0 to 360.0d0 deg.) for eqxbou;
 *         if ierr = 0 ( garbage otherwise).
 * @return ierr = 0 for normal return. -1 if paou could not be computed.
 *
 * NOTE:
 * This routine assumes input pos angle & input position are in the equatorial
 *    coordinate system.
 *
 * calls jbposa,jbelpt,unjul2
 *
 */


/**
 *
 *       ALL FLOATING POINT ARGS ARE DOUBLE PRECISION
 *
 * @param eqxin is the equinox(besselian) of the input position & position angle.
 * @param ra,dec is input position in decimal degrees at equinox eqxin.
 * @param dec
 * @param pab  = input position angle (0 to 360.0d0 deg.) at eqxin.
 * @param pma is proper motion in ra in seconds per tropical century.
 * @param pmd is proper motion in dec in seconds of arc per tropical century.
 * @param pin is parallax in arc seconds.
 * @param vin is radial velocity in km/sec
 * @param ieflg  of -1 indicate to not remove E-terms from position in computing
 *             position angle (any other value allows E-term removal)
 * @return raout,decout is output position in decimal degrees at J2000.0
 * @return paj is output position angle (0 to 360.0d0 deg.) for J2000.0
 *         if ierr = 0 ( garbage otherwise).
 * @return pmaout is proper motion in seconds of time per Julian century.
 * @return pmdout is proper motion in seconds of arc per Julian century.
 * @return ierr = 0 for normal return. -1 if paj could not be computed.
 *
 * NOTE:
 * This routine assumes input pos angle & input position are in the equatorial
 *    coordinate system.
 *
 * calls jbposa,jbelpt,gtjulp,gtjul2
 *
 */


/**
 *       ALL FLOATING POINT ARGS ARE DOUBLE PRECISION
 *
 * @param ra,dec is input position in decimal degrees at J2000.0
 * @param dec
 * @param paj  = input position angle (0 to 360.0d0 deg.) at J2000.0
 * @param pma is proper motion in ra in seconds per Julian century.
 * @param pmd is proper motion in dec in seconds of arc per Julian century.
 * @param pin is parallax in arc seconds.
 * @param vin is radial velocity in km/sec
 * @param ieflg  of -1 indicates to not add back E-terms
 *           +1  (any val other than -1) indicates E-terms are to be replaced.
 * @param eqxbou is the equinox(besselian) of the output position & position angle.
 * @return raout,decout is output position in decimal degrees at eqxbou.
 * @return pab is output position angle (0 to 360.0d0 deg.) for eqxbou;
 *         if ierr = 0 ( garbage otherwise).
 * @return pmaout is proper motion in seconds of time per tropical century.
 * @return pmdout is proper motion in seconds of arc per tropical century.
 * @return ierr = 0 for normal return. -1 if paou could not be computed.
 *
 * NOTE:
 * This routine assumes input pos angle & input position are in the equatorial
 *    coordinate system.
 *
 * calls jbposa,jbelpt,unjulp,unjul2
 *
 */


/** 18sep92 just to remove redundant type spec. for dintrp in func. dintrp and
 *     for dintr2 in func. dintr2 so it can be compile on apc3 also.
 * 27jul92 to add   common/fk5way/
 * updated 23jul92 to clean up.
 *  j.bennett  jun92
 * gets systematic fk5-fk4 corrections for b1950 to j2000 conversions
 *  @param ain is b1950 ra in degrees;
 *  @param d is b1950 dec in degrees;
 *  @param dmag is photometric magnitude (used only if between 1.0 and 7.0
 *  @param epoch is normally 1950.0 and provides for an adjustment if it is not
 *     1950.  At 1950, there is no additional adjustment.
 *  @param corra,corrd are the corrections to ra and dec, in degrees, such that they
 *      may be added to a and d to obtain the corrected position.
 *   @param corrd
 *  @param corrpa is correction for proper motion in ra in seconds of time per century.
 *  @param corrpd is correction for proper motion in dec in seconds of arc per century.
 *
 */


/**
 * find, by iteration, fk5-fk4 systematic corrections to subtract from
 *   ra and dec when returning position back to B1950/FK4 system.
 *
 */


/**
 *      block data jfk5bd
 *
 *  updated 27jul92 to add common/fk5way/iway so jgtfkc can check for "pole"
 *    value when correction will be added in calling program (iway >=0) or
 *    will be removed in calling program (iway < 0) and return fk5-fk4
 *    correction values of 0. when too close to pole for valid corr or
 *    reproducibility problems.
 *  updated 22jun92 to add common/fkappl/japply  so user may change
 *   default application of systematic corrections by including common/fkappl/
 *    and setting japply  (japply .ne. 0 to apply corr - i.e. add when going
 *     from B1950 to J2000, subtract when going from J2000 to b1950;
 *     japply = 0 to not apply corr.-allows calling program a central info.
 *       location to determine application desires (however, if jgtfkc is
 *       called, corr. factors will be returned and calling program
 *       must make decision (based on japply)  whether to apply them.
 *
 * Note: common/fkappl/ is used in gtjulX/unjulX routines and may be used/reset
 *                      in any user subroutine.
 *       common/fk5way/ is set to -1 in junfkc, but returned to previous value
 *                      on return; is used in junfkc and jgtfkc.
 *
 *       See subroutine jnitfk for explanation of values in common/fk5cc2/
 *
 */


/**
 * for Julian precession.
 * fk5prc to have simpler arg list when no proper motions are present.
 * calls fk5prp.  See fk5prp for comments on method.
 *
 * @param {number} eqx1
 * @param {number} rain
 * @param {number} decin
 * @param {number} eqx2
 * @return {number} raou
 * @return {number} decou
 * @return {{raou:number,decou:number}}
 */


/**
 *  j.bennett (1992) - for Julian precession:
 *              using IAU (1976) System of Astronomical Constants
 *
 *  allows precession of proper motion values (also will make use of
 *    parallax and radial velocity if not zero.
 *
 * All arguments are double precision:
 *  @param {number} eqx1 is equinox of input position (in year - e.g. 2000.0d0)
 *  @param {number} rain, decin is input position in decimal degrees at eqx1.
 *  @param {number} decin
 *  @param {number} pmain is proper motion in ra in seconds of time per Julian century.
 *  @param {number} pmdin is proper motion in dec in seconds of arc per Julian century.
 *  @param {number} pin is parallax in arc seconds (0.0d0 if none)
 *  @param {number} vin is radial velocity in km/sec (0.0d0 if none)
 *  @param {number} eqx2 is eqinox of output position (in year - e.g. 1992.0d0)
 *                 (or 1949.99979d0 if quick and dirty approx of B1950 desired)
 *  @return {number} raou, decou is position in decimal degrees at eqx2.
 *  @return {number} decou
 *  @return {number} pmaou is proper motion in ra in seconds of time per Julian century for eqx2.
 *  @return {number} pmdou is proper motion in dec in seconds of arc per Julian century for eqx2.
 *  @return {{raou:number,decou:number,pmaou:number,pmdou:number}}
 *
 *******************************************************************************
 * method from Fricke,W.,Schwan,H.,Lederle,T.,1988,Fifth Fundamental Catalogue
 *     (FK5) Part I. (pages 10-11)
 *******************************************************************************
 */


/**
 *
 * updated 09jun92 to test costh ( to prevent acos error message when
 *   round off near theta = 0. or 180.deg creates a dabs(cos(theta)) slightly
 *   greater than 1.0d0)
 * \ned\jbdist.f  28feb91  like prev. versions except does not call
 *     fdtor2/frtod2
 * f77 -c jbdist.f
 * for vax, dacos is used instead of darcos.
 * all args in double precision degrees.
 *
 * @param {number} xlon1
 * @param {number} xlat1
 * @param {number} xlon2
 * @param {number} xlat2
 * @return {number} distd is distance between 2 positions on sky - results in degrees
 *
 */


/**
 * filter on the selected rows
 * @param {string} tbl_id  table ID
 * @param {number[]} selected  array of selected row indices.
 */


/* modified to only reset columns selection */


/**
 *
 * @param {TableHpxData} hpxIndexData
 * @param {Number} idx
 * @return {WorldPt}
 */


/**
 * convenience function to create the serialized string representation of SortInfo
 * @param {string|array} colName one column's name or multiple columns' names
 * @param {boolean} [isAscending=true] false for descending order, otherwise it's default to ascending.
 */


/**
     * returns the sortInfo of the next toggle state.
     * @param {string[]} cnames an array of the column(s) to sort
     * @returns {SortInfo}
     */


/**
 * This function convert the selected rows into its associated ROW_IDX, add it as a filter, then
 * dispatch it to tableFilter for processing.
 * @param {Action} action
 * @returns {function}
 */


/**
 * Convert a meta data entry description the coordinate column to an CoordColsDescription object. The meta data entry is
 * a string with two or three parts separated by a semicolon. examples- as 'ra;dec;J2000' or 'lon3;lat3;Gal'.
 * The first element of the string is optional it could be 'ra;dec' and it will default to J2000.
 *
 * @param def
 * @param {TableModel} table - used to look up column information
 * @return {CoordColsDescription|null}
 */


/**
 * return [column_name, operator, value] triplet.
 * @param {string} input
 * @param {object} options
 * @prop {boolean} options.removeQuotes  remove double-quotes from column name if present
 * @returns {string[]}
 */


/**
     * parse the given filterString into a FilterInfo
     * @param filterString
     * @returns {FilterInfo}
     */


/**
     * given a list of filters separated by condition separator,
     * transform them into valid filters if they are not already so.
     * @param filterInfo
     * @param columns
     * @returns {string}
     */


/**
     * validate the conditions
     * @param conditions
     * @returns {boolean}
     */


/**
     * validator for column's filter.  it validates only the condition portion of the filter.
     * @param conditions
     * @param tbl_id
     * @param cname
     * @returns {{valid: boolean, value: (string|*), message: string}}
     */


/**
     * validate the filterInfo string
     * @param {string} filterInfo
     * @param {TableColumn[]} columns array of column definitions
     * @returns {Array.<boolean, string>} isValid plus an error message if isValid is false.
     */


/**
     * validator for free-form filters field
     * @param {TableColumn[]} columns array of column definitions
     * @param {string} filterInfo
     * @returns {{valid: boolean, value: (string|*), message: string}}
     */


/**
     * returns a comparator function that takes a row(string[]) as parameter.
     * This comparator will returns true if the given row passes the given filterStr.
     * @param {string} filterStr
     * @param {TableModel} tableModel
     * @returns {function(): boolean}
     */


/**
 * convert sql like condition to RegExp, the following character cases in like condition are changed
 * - usage of special characters for regular expression
 * - usage of wildcard, % & _, escape wildcard, \% and \_,
 * - usage of \\ is kept same in regular expression
 * @param text
 * @returns {RegExp}
 */


// r1 is the replacement for w, r2 is the replacement for \w


/**
 * Attempt to auto-correct the given condition(s).
 * @param {string} conditions  one or more conditions, separated by COND_SEP
 * @param {string} tbl_id   table ID.
 * @param {string} cname    column name.
 * @returns {string}
 */


/**
 * auto correction on filter string in case it is not a valid sql statement.
 * the correction following the rules as follows
 * op : case 1: 'not' specified or 'like' (for text column)
 *              if the value part is not enclosed by single quotes:
 *                  convert %, _, | to be \%, \_ or \\. (escape the wildcard and escape character)
 *                  enclose the string by '%' and then by single quotes.
 *                  ex: abc% => '%abc\%%' after auto-correction.
 *              not specified (for numeric column)
 *                  set op to be '=', no correction on value.
 *      case 2: 'in',
 *              enclose each value in signle quotes in case they are missing (for text column only)
 *              enclose the entire value string in braces, (), if they area missing (for all kinds of columns)
 *              ex: in a, b  => in ('a', 'b') after auto=correction for text column
 *              ex: in a, b  => in (a, b) after auto-correction for numeric column
 *     case 3: other operaters, >, <, >=, <=, =, !=
 *              enclose value in single quotes if they are missing (for text Columns and non-numeric values)
 *              ex: =abc => ='abc' after auto-correction for text column
 *                  =abc => =abc   after auto-correction for numeric column
 *
 * @param v     filter expression
 * @param col   column to operate on
 * @returns {*}
 */


/**
 * returns a comparator for a single, simple `column operator value` filter
 * @param filterStr
 * @param tableModel
 * @returns {function(): boolean}
 */


/**
     * lodash isEqual is really slow when comparing huge Set and maybe array as well.
     * This is a custom isEqual of the SelectInfos that perform reasonably well.
     * @param si1  a SelectInfo data
     * @param si2  another SelectInfo data to compare with
     * @returns {boolean}
     */


/**
     * Destructing of the SelectInfo's data.
     * @param {Object}  p
     * @param {number} p.rowCount   IMPORTANT!!. Total number of rows in the table. defaults to zero.
     * @param {boolean} [p.selectAll] Indicates selectAll mode. defaults to false.
     * @param {Set}     [p.exceptions] A set of exceptions based on selectAll mode.
     * @param {number} [offset]     All indices passed into this class's function will be offsetted by this given value.
     * @returns {SelectInfo}
     */


/**
 *
 * @param tbl_ui_id
 * @param uiData
 * @return {boolean} returns true if column preferences were applied
 */


/**
 * clear this table preferences
 * @param {string} tbl_ui_id
 */


/**
 * @param {TableColumn} col
 * @param {COL_TYPE} type
 * @returns true if col is of the given type
 */


/**
 * returns true is there is data within the given range.  this is needed because
 * of paging table not loading the full table.
 * @param {number} startIdx
 * @param {number} endIdx
 * @param {TableModel} tableModel
 * @returns {boolean}
 * @func isTblDataAvail
 * @memberof firefly.util.table
 */


/**
 * returns the table group name given a tbl_id.  it will return undefined if
 * the given tbl_id is not in a group.
 * @param {string} tbl_id    table id
 * @returns {String}
 * @public
 * @memberof firefly.util.table
 * @func findGroupByTblId
 */


/**
 * Returns the first index of the found row.  It will search the table on the client first.
 * If none is found and the table is partially loaded, it will search the server-side as well.
 * @param {string} tbl_id the tbl_id of the table to search on.
 * @param {string} filterInfo filter info string used to find the first row that matches it.
 * @returns {Promise.<number>} Returns the index of the found row, else -1.
 * @func findIndex
 * @memberof firefly.util.table
 */


/**
 * Fold 1d array value according to column's arraySize specification.
 * For example, if `col.arraySize` is `'2x3'` and `val` is `[1,2,3,4,5,6]`, the result will be `[[1,2],[3,4],[5,6]]`.
 * @param {TableColumn} col
 * @param {Object} val
 * @returns {*} array value with right dimensions, if a column is an array, or an unchanged value
 */


/**
 * Firefly has 3 column meta that affect the formatting of the column's data.  They are
 * listed below in order of highest to lowest precedence.
 *
 * fmtDisp		: A Java format string.  It can be used to format any type.  i.e.  "cost $%.2f"
 * format		: Same as fmtDisp
 * precision	: This only applies to floating point numbers.
 *                A string Tn where T is either F, E, G, HMS, or DMS
 *                When T is F or E, n is the number of significant figures after the decimal point.
 *                When T is G, n is the number of significant digits
 *                When T is HMS or DMS, n is ignored

 * @param {TableColumn} col
 * @param {Object} val
 * @return {string}
 * @public
 * @func formatValue
 * @memberof firefly.util.table
 */


/**
 * return true if the given table is fully loaded.
 * @param {TableModel} tableModel
 * @returns {boolean}
 * @memberof ffirefly.util.table
 * @func isTableLoaded
 */


/**
 * This function merges the source object into the target object
 * by traversing and comparing every like path.  If a value was
 * merged at any data node in the data graph, the node and all of its
 * parent nodes will be shallow cloned and returned.  Otherwise, the target's value
 * will be returned.
 * @param {Object} target
 * @param {Object} source
 * @returns {Object}
 * @public
 * @memberof firefly.util.table
 * @func smartMerge
 */


/**
 * sort table data in-place.
 * @param {TableData} tableData
 * @param {TableColumn[]} columns
 * @param {string} sortInfoStr
 * @returns {TableData}
 * @public
 * @memberof firefly.util.table
 * @func sortTableData
 */


/**
 * filter the given table.  This function update the table data in-place.
 * @param {TableModel} table
 * @param {string} filterInfoStr filters are separated by comma(',').
 * @memberof firefly.util.table
 * @func filterTable
 */


/**
 *
 * @param {TableModel|String} tableOrId - parameters accepts the table model or tha table id
 * @param {number} rowIdx - rowIdx to check
 * @param {number} [hlRowIdx] - highlighted row index, defaults to tableModel.highlightedRow
 * @return {boolean} true if it is sub-highlight
 */


/**
 * convert this table into IPAC format
 * @param tableModel
 * @returns {string}
 */


/**
 * returns a details view of the highlightedRow in a form of a tableModel
 * with columns Name, Value, Type, Units, and Description
 * @param {string} tbl_id             tbl_id of the table
 * @param {number} highlightedRow     the row to generate the details for
 * @param {string} details_tbl_id     tbl_id of the details table.  defaults to tbl_id + '_details'
 */


/**
 * There are some inconsistencies in how a request is created.
 * This fixes any of the inconsistencies it finds.
 * @param request
 */


/**
 * create a unique table id (tbl_id)
 * @returns {string}
 * @public
 * @memberof firefly.util.table
 * @func uniqueTblId
 */


/**
 * create a unique table UI id (tbl_ui_id)
 * @returns {string}
 * @public
 * @memberof firefly.util.table
 * @func uniqueTblUiId
 */


/**
 *  This function provides a patch until we can reliably determine that the ra/dec columns use radians or degrees.
 * @param {TableModel} table the table model
 * @param {Array.<String>} [columnNames]
 * @memberof firefly.util.table
 * @func isTableUsingRadians
 *
 */


/**
 * this function invoke the given callback when the given actions occur.
 * @param {Object}   actions  an array of actions to watch
 * @param {function} accept  a function used to filter incoming actions.  if not given, it will accept all.
 * @param {function} callback  callback to execute when action occurs.
 * @param {string} [watcherId] action watcher id to be used
 * @return {function} returns a function used to cancel
 */


/**
 * If input is '"x"', outputs 'x', but if input is '"x"+"y"' or 'log("x")' output is the same as input
 * @param s
 * @returns {*}
 */


/**
 * @param afterLoaded   if true, watch for TABLE_LOADED, then resolve
 * @param tbl_id        table to watch
 */


/**
 * Creates a table request object for the given id.
 * @param {string} id       required.  SearchProcessor ID.
 * @param {string} [title]  title to display with this table.
 * @param {object} [params] the parameters to include with this request.
 * @param {TableRequest} [options] more options.  see TableRequest for details.
 * @returns {TableRequest}
 * @public
 * @func  makeTblRequest
 * @memberof firefly.util.table
 */


/**
 * Creates a table request for tabular data from a file or url.  Source of file may be
 * from a url or an absolute path on the server.
 * @param {string} [title]      title to display with this table.
 * @param {string} source       required; location of the ipac table. url or file path.
 * @param {string} [alt_source] use this if source does not exists.
 * @param {TableRequest} [options]  more options.  see TableRequest for details.
 * @returns {TableRequest}
 * @public
 * @func makeFileRequest
 * @memberof firefly.util.table
 */


/**
 * Creates a table request for tabular data from IRSA workspace.
 * Source should be an IRSA workspace path.  i.e value returned from WorkspaceViewer
 * @param {string} source       required; IRSA workspace path.
 * @param {string} [title]      title to display with this table.
 * @param {TableRequest} [options]  more options.  see TableRequest for details.
 * @returns {TableRequest}
 * @public
 * @func makeIrsaWorkspaceRequest
 * @memberof firefly.util.table
 */


/**
 * creates the request to query IRSA catalogs.
 * @param {string} title    title to be displayed with this table result
 * @param {string} project
 * @param {string} catalog  the catalog name to search
 * @param {ConeParams|BoxParams|ElipParams} params   one of 'Cone','Eliptical','Box','Polygon','Table','AllSky'.
 * @param {TableRequest} [options]
 * @returns {TableRequest}
 * @public
 * @func makeIrsaCatalogRequest
 * @memberof firefly.util.table
 */


/**
 * creates the request to query VO using ConeSearchByURL or another vo provider Search processor
 * @param {string} title    title to be displayed with this table result
 * @param {ConeParams|BoxParams|ElipParams} params   one of 'Cone','Eliptical','Box','Polygon','Table','AllSky'.
 * @param {TableRequest} [options]
 * @returns {TableRequest}
 * @func makeVOCatalogRequest
 * @memberof firefly.util.table
 * @see edu.caltech.ipac.firefly.server.persistence.QueryByConeSearchURL.java
 */


/**
 * private function to handle Resource related actions
 * @param {object} p                function parameters
 * @param {ResourceInfo} p.resource resource information
 * @param {string} [p.title]        title to display with this table.
 * @param {TableRequest} [p.options] table request options.  see TableRequest for details.
 * @param {string} p.action one of 'query', 'create', 'delete'.  defautls to 'query'.
 *                          when action is 'create' or 'delete', it will submit the request.
 *                          no further action is needed.
 */


/**
 * create a deep clone of the given request.  tbl_id is removed from the cloned request.
 * @param {TableRequest}        request  the original request to clone
 * @param {Object} params       additional parameters to add to the cloned request
 * @param {boolean} createTblId when true, create a new unique tbl_id for this request
 * @returns {TableRequest}
 * @public
 * @func cloneRequest
 * @memberof firefly.util.table
 */


/**
 * create a request which will perform a function on the given searchRequest
 * @param {TableRequest} searchRequest  required. the table's request this function should operate on
 * @param {string} id                   required.  SearchProcessor ID.
 * @param {string} [title]              title to display with this table.
 * @param {object} [params]             the parameters to include with this request.
 * @param {TableRequest} [options]      more options.  see TableRequest for details.
 * @returns {TableRequest}
 * @public
 * @func makeTableFunctionRequest
 * @memberof firefly.util.table
 */


/**
 * create a request which will perform a sub query on the given searchRequest
 * @param {TableRequest} searchRequest  required. the table's request this function should operate on
 * @param {string} [title]              title to display with this table.
 * @param {object} [params]             the parameters to include with this request.
 * @param {TableRequest} [options]      more options.  see TableRequest for details.
 * @returns {TableRequest}
 * @public
 * @func makeSubQueryRequest
 * @memberof firefly.util.table
 */


/*---------------------------- COLUMN HEADER RENDERERS ----------------------------*/


/* Applies ObsCore's related logic to the table before it's placed into the store */


/**
 * Make a simple color map array of no more than 10 entries.  Map goes from darker to brighter.
 * @param baseColor
 * @param mapSize
 * @param reverse
 * @return {*}
 */


/**
 * parse the given string into the resolver.
 * Returns true if the string is a valid position.
 * @param s
 * @return {*}
 */


/**
 * Determine the type of input.
 * The input is a position if any of the following test are true
 *

 *
name: the first character is not a digit, a '+', or a decimal point
 *
position: first string is numeric or is a parse-able lon
 *

 * @param s the crunched input string
 * @return the Input type
 */


/**
 * given a partial url and a rootPath, create a full url, if not rootPath the use document.URL for the rootpath
 * @param {string} url
 * @param {string} rootPath
 * @return {string}
 */


/**
 * return true if the string is a valid full url
 * @param url
 * @return {boolean}
 */


/**
 * load a js script by dynamically adding a script tag.
 * @param scriptName
 * @return {Promise} when the script is loaded or failed to load
 */


/**
 * Create a function that caches last N (up to 20) function call results
 * This is better for functions that take immutable objects. it compare every argument using ===
 * This cache size has to be smaller (<29=0) since if must iterate though all the last results.
 * @param fn - the function to wrap
 * @param {number} [cacheSize=1] the number of saved calls with a maximum of 20
 * @return {function}
 */


/**
 * Create a function that caches function call result
 * This function is better use for call types that do heavy computations that take number or string as all the parameters.
 * If you are wrapping a function that takes an object you should pass a makeKey function.
 * @param fn - the function to wrap
 * @param {number} [maxMapSize=5000] when the cache number goes over 5000 the map is cleared
 * @param {function} [makeKey] - make a cache key from the function arguments call with the arguments as an array as makeKey(args). Defaults to calling joint on the arguments
 * @return {function}
 */


/**
 * Create an image with a promise that resolves when the image is loaded
 * @param {string} src the source of the image typically a url or local image data
 * @return {Promise} a promise that will resolved with the loaded image object
 */


/**
 * Return a promise that resolves when document is ready
 * @return {Promise<void>}
 */


/**
 * Create an image with a promise and a cancel function.  The promise resolves when the image is loaded.
 * @param {string} src the source of the image typically a url or local image data
 * @return {{promise:Promise, cancelImageLoad:Function}} an object with the promise and the cancel function
 */


/**
 * returns an array of {name, value} pairs based on the given params object.
 * If the value in the params object is an array, it will be flatten into multiple
 * name-value pairs based on the same key.
 * @param params
 * @returns {string}
 */


/**
 * Copy the content of the string to the clipboard
 * @param str
 */


/**
 * Diff the the two objects and prints differences to console
 * @param o1
 * @param o2
 * @param p the title
 * @param collapsed show the differences collapsed
 */


/**
 * This is a wrapper of React update's $set for use with deep object update.
 * *Syntax is similar to lodash set.
 * @param object (Object): The object to modify.
 * @param path (Array|string): The path of the property to set.
 * @param value (*): The value to set.
 */


/**
 * This is a wrapper of React update's $merge for use with deep object update.
 * *Syntax is similar to as lodash set.
 * @param object (Object): The object to modify.
 * @param path (Array|string): The path of the property to merge.
 * @param value (*): The value to merge.
 */


/**
 * This is a generic wrapper of React's update for use with deep object update.
 * Command can be on of:
 * {$push: array}, {$unshift: array}, {$splice: array of arrays}, {$set: any}, {$apply: function}
 * see React's update for details.
 * *Syntax is similar to as lodash set.
 * @param object (Object): The object to modify.
 * @param path (Array|string): The path of the property to apply the function to.
 * @param command (*): The command portion of react's update.
 */


/**
 * similar to deep merge, except when a value is an array, it will replace the value instead of merging.
 * @param {Object|undefined} target  - the target or destination object
 * @param {Object|undefined} sources - the source objects
 */


/**
 *
 * Return a function that will only do a search once.
 * The function that takes 2 parameters:
 *       validateSearch:Function|boolean,
 *       doSearch:Function|undefined
 *       [id]: string, optional
 * When validateSearch search returns true then doSearch is called and search is considered done for that id
 * To mark the search as done without actually doing it then just pass true as first parameter
 * makeSearchOnce is similar to lodash once but includes a validate as a way to make it done.
 * It also includes an id so that it runs once per id
 * Note that the execution of the doSearch function is deferred.
 * @param {boolean } [defer] - if true run the search deferred
 * @return {Function} a function with the signature f(validateSearch,doSearch)
 */


/**
 * A strict version of parseInt.  Anything that is not an integer will return NaN, i.e '12xx34'
 * @param value
 * @returns {number} a number or NaN if it cannot be parse into an interger
 */


/**
 * return true if val is boolean true, or 'true' case-insensitive
 * @param val the value to convert.
 * @param def return def if val is undefined
 * @param {Array.<String>} [trueList] - a case-insensitive list of string the will parse to true, default is just ['true']
 * @returns {boolean}
 */


/**
 * replace or add and extension to a filename
 * @param {string} filename
 * @param {string} ext
 * @return {string} the new filename
 */


/**
 *
 * @param object
 * @param prefix - prefix to use for all object properties
 * @param testFunc - test function to decide which entries should be flattened.  defaults to isPlainObject
 * @returns {*}
 */


/**
 * trim a string on one of several ways.
 *

 *
middle - both end are preserver middle has an ellipsis

 *
bothEnds - middle is preserved both ends have an ellipsis

 *
complex - middle and ends are preserved with ellipsis between the parts

 *
startMiddle - start and middle are preserved with ellipsis between the parts

 *
start - start is preserved ellipsis at end

 *
end - end is preserved ellipsis at start

 *

 * @param s - the string to trim
 * @param maxLength - max length of the string
 * @param trimType - either- 'middle', 'bothEnds', 'complex', 'start', 'end', 'startMiddle', default to 'middle'
 * @return {string}
 */


/**
 * Unless you have reason don't call this function directly, call fetchUrl in fetch.js
 * @param {String} url
 * @param {Object} options
 * @param {boolean} doValidation
 * @param loggerFunc
 * @return {Promise<Response>}
 */


/**
 * Process through an array or list and acting on each element. Return a promise that will return true if
 * interation successfully completes
 *
 * @param {object} params
 * @param params.iterator - iterator through an array or list
 * @param {function} params.processValue - function to act on the next value of the interator
 * @param {number} [params.intervalBreak] - how ofter the stop looping
 * @param {function} [params.percentUpdate] - will call with percentage every 5 percent
 * @param {number} [params.length] - length of the data being processed, only required if using percentUpdate
 * @param {function} [params.shouldAbort] - call occasionally - return true if should abort, promise will return false
 * @return {Promise<Boolean>}
 */


/**
 * returns a Logger with the given tag
 * @param tag   a tag associate with this logger.
 * @returns {Logger}
 */


/**
 * @param ua user agent string
 * @param key
 * @return {{majorVersion: number, minorVersion: number}}
 */


/**
 * parse s_region description and covert the description to DrawObj object or
 * find the corners of the area covering the region described by s_region string
 * for position and polygon region, the points in the description are collected
 * for box, circle region, the four corners covering the region are collected
 * the parsing is based on the syntax described in section 6 Simple STC-S BNF of TAP 1.0.pdf
 * @param sRegionVal s_region description
 * @param unit  unit set in s_region column
 * @param isCorners get corners or get DrawObj
 * @returns {object}
 */


/**
 * This function supports doing multiple of the same call and forcing them to all take the first calls results.
 * Any call that has the same pKey is considered the same call
 * This function is best used when your code is calling something more than one time with the same data very close together.
 * It will guarantee that only one call if made and all the calls (with the same pKey) will get the same result.
 *
 * @param {string} pKey - the promise key for this call. This first call with the key will be the result of every call that is made while the first is running
 * @param {Function} asyncFunction - a functino that returns a promise. This is the function that does the work
 * @return {Promise<unknown>}
 */


/**
 * If a call is running associated the pKey then return a promise for the results. If no call is running then return
 * a Promise.resolve().
 * using async/await this call can be used to block until the promise fulfils
 * <code>
 *    await blockWhileAsyncIdWaiting('someKey');
 * </code>
 *
 * @param {string} pKey
 * @return {Promise<unknown>}
 */


/**
 * A wrapper for the underlying window.fetch function.
 * see https://github.com/github/fetch for usage.
 * see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API for current status on the API
 * see https://fetch.spec.whatwg.org/ for official standard
 *
 * This function applies default behaviors before fetching.
 *
 * @param {string} url the URL to connect
 * @param {Object} options
 * @param {Object} options.params a parameter map to send along with the request.  It does not need to
 *                                  be encoded.  Base on the method used, it will be handled internally.
 * @param {string} options.method can be one of get, post, or multipart
 *                                when 'multipart', it will post with 'multipart/form-data' encoding.
 * @param {boolean} doValidation
 * @param {boolean} [enableDefOptions= true]
 * @return {Promise} a promise of the response when successful, or reject with an Error.
 */


/**
 * return the filename from the Content-Disposition header or undefined
 * @param resp - fetch response
 * @return {string|undefined}
 */


/**
 * create the default download filename
 * @param {String} root - should be one of 'image', 'HiPS', 'table', 'chart'  (we can add to this list as appropriate)
 * @param {String} [title] - the title associated with the visualizer, if falsy then the name is build without a title
 * @param {String} [ext] - the extensionn (without the dot). i.e. 'fits', 'png', 'cvs', etc
 * @return {string}
 */


/*
     * @param {number} i
     * @return {number}
     */


/**
     * Adjust the set of allowed variables: create it (if not yet
     * existent) and add optVariable (if it's nonnull).  If the
     * allowed-variable set exists, the parser will reject input
     * strings that use any other variables.
     *
     * @param optVariable the variable to be allowed, or null
     */


/*
     * @param {Variable} v - variable
      */


/**
 * Make an expression that applies a nullary operator (no arguments).
 * @param {number} rator (int) a code for a nullary operator
 * @return an expression meaning rator()
 */


/**
 * Make an expression that applies a unary operator to an operand.
 * @param {number} rator (int) a code for a unary operator
 * @param rand operand (Expr)
 * @return an expression meaning rator(rand)
 */


/**
 * Make an expression that applies a binary operator to two operands.
 * @param {number} rator - a code for a binary operator
 * @param {Expr} rand0 - left operand
 * @param {Expr} rand1  right operand
 * @return an expression meaning rator(rand0, rand1)
 */


/**
 * Make an expression that applies a ternary operator to three operands.
 * @param {number} rator - a code for a binary operator
 * @param {Expr} rand0 - first operand
 * @param {Expr} rand1  second operand
 * @param {Expr} rand2  third operand
 * @return an expression meaning rator(rand0, rand1, rand2)
 */


/**
 * Make an expression that applies a n-ary operator to n operands.
 * @param {number} rator - a code for a binary operator
 * @param {Array.<Expr>} randAry - operands
 * @return an expression meaning rator(...randAry)
 */


/**
 * Make a conditional expression.
 * @param test (Expr) `if' part
 * @param consequent (Expr) `then' part
 * @param alternative (Expr) `else' part
 * @return an expression meaning `if test, then consequent, else alternative'
 */


//Token(int ttype, double nval, String input, int start, int end)


/**
 * Convenience function to quote variable name if it's not alphanumeric
 * (if the name is not alphanumeric, it needs to be quoted in expressions)
 * @param name
 * @returns {*}
 */


/**
 * Return a unique variable named `name'.  There can be only one
 * variable with the same name returned by this method; that is,
 * makeVariable(s1) === makeVariable(s2) if and only if s1===s2.
 * @param {String} name the variable's name
 * @return the variable; create it initialized to 0 if it doesn't
 *         yet exist */


/**
 * The Regrid class shrinks or expands the size of an array by an  arbitrary amount.
 *
 * NOTE: this implementation is one dimension only.
 *
 *  The algorithm is the same as IDL CONGRID with MINUS_ONE is set to true and extrapolation=false by default
 *
 *        When MINUS_ONE is true, I enforced the new coordinate at newDim -1 is
 *          the same as oldDim-1.   Mathematically,
 *             RegridFact = (oldDim - 1) / (newDim - 1);
 *             new_coordinate(i) =   i * RegridFact
 *             when i = newDim -1, new_coordinate(newDim-1) = oldDim -1.
 *             But due to the numerically error, there may be some small detla value introduced.
 *             Therefore, I need to enforce it to oldDim -1
 *
 */


/**
 * For any input data, for example,
 *
 *   inData = [d0, d1, d2, d3], the coordinate corresponding to the data is coord=[0, 1, 2, 3].
 *   If we express it using a function expression,we have
 *     di = f(coord*i)
 *     d0=f(0)
 *     d1=f(1)
 *
 *     ...
 *
 *
 *
 *  When we make a new coordinate for the new out array, the coordinate needs to be satisfy that
 *
 *   d_dim = f(coord) when dim=inData.length-1, d_dim = the last element of inData.
 *   when dim=0, d_0 = the first element of the inData
 *
 * @param inData
 * @param outArraySize
 * @param allowExtrapolation
 * @returns {Array}
 */


/**
 * This FireflyViewer is a generic application with some configurable behaviors.
 * The application is separated into these major parts:  banner, menu, searches, and results.
 * The props below allow you to alter their default behaviors.
 *
 * Props
 *
title:  This title will appears at center top of the results area. Defaults to 'FFTools'.

 *
menu:  menu is an array of menu items {label, action, icon, desc, type}.  Leave type blank for dropdown.  If type='COMMAND', it will fire the action without triggering dropdown.

 *
appTitle:  The title of the FireflyViewer.  It will appears at top left of the banner. Defaults to 'Firefly'.

 *
appIcon:  A react element rendered at where appIcon should appear.

 *
footer:   A react elements to place on the footer when the menu drop down.

 *
dropdownPanels:  An array of additional react elements which are mapped to a menu item's action.

 *
views:  The type of result view.  Choices are 'images', 'tables', and 'xyPlots'.  They can be combined with ' | ', i.e.  'images | tables'

 *
 */


/**
 * this manager manages what main components get display on the screen.
 * These main components are image plots, charts, tables, dropdown panel, etc.
 * This manager implements the default firefly viewer's requirements.
 * Because it may differs between applications, it is okay to have a custom layout manager if needed.
 * @param {object} p
 * @param {string} [p.title] title to display
 * @param {string} [p.views] defaults to tri-view if not given.
 */


/**
 * This event manager is custom made for HydraViewer.
 */


/**
 * handle logic when a new search is initiated.
 * should go and clean up all previous state.
 * @param {object} layoutInfo layoutInfo
 * @param {string} action
 * @returns {Object} the new layoutInfo
 */


/**
 * remove the previous results
 */


/**
 * this manager manages what main components get display on the screen.
 * These main components are image plots, charts, tables, dropdown panel, etc.
 * This manager implements the default firefly viewer's requirements.
 * Because it may differs between applications, it is okay to have a custom layout manager if needed.
 * @param {Action} action
 * @param {Function} cancelSelf
 * @param {Object} params
 */


/**
 * @summary construct table fetch request based on exist request and new column sort info.
 * @param colToSort
 */


/**
 * This event manager is custom made for light curve viewer.
 * @param {LCMissionConverter} params
 */


/**
 * @summary handle value change on time, flux, cutout size
 * @param {object} layoutInfo
 * @param {object} action
 * @returns {*}
 */


/**
 * @summary highlight the table row & chart after change the active plot view
 * @param layoutInfo
 * @param action
 * @returns {*}
 */


/**
 * handle logic when a new search is initiated.
 * @param {object} layoutInfo layoutInfo
 * @param {string} action
 * @returns {Object} the new layoutInfo
 */


/*
 * field group, LC_VIEWER_FINDER, includes fieldKey from missionEntries & generalEntries
 * missionEntries & generalEntries is mission specific, more detail to be fixed after raw table metadata is defined. -- TO DO
 */


/**
 * @summary handle on loaded table, update period and periodogram field groups, update chart
 * @param layoutInfo
 * @param action
 * @returns {*}
 */


/**
 * @summary handle on changing the active table, update image and chart
 * @param layoutInfo
 * @param action
 * @returns {*}
 */


/**
 * @summary upload phase table with the column arranged as needed
 * @param {TableModel} tbl
 * @param {string} flux
 */


/**
 * @summary adding phase column to raw table
 * @param {string} flux flux column name
 * @param {string} time time column name
 * @param {string} period periodt  value
 * @param {string} tzero zero time value
 * @return {TableModel} phase table
 */


/**
 * @summary create a table model with phase column
 * @param {TableModel} tbl
 * @param {string} timeName
 * @param {string} tzero
 * @param {string} period
 * @returns {TableModel}
 */


/**
 * @summary change the content of each row of the table by relocating some columns
 *          to be after or replace certain column
 * @param {TableModel} tbl
 * @param {array|string} srcCols -- a string or an array of strings
 * @param {number|string} targetCol -- a string indicating column name or a number indicating column index
 * @param {number} position 1: after the target columm, -1: before the target column, 0: at the target column
 */


/**
 * @summary duplicate the phase cycle to the phase folded table
 * @param {TableModel} phaseTable
 */


/**
 * @param {WebPlotRequest} inWpr
 * @param {string} title
 * @param {WorldPt} wp
 * @returns {WebPlotRequest}
 */


/**
 * Return true if the user inputs make sense to show images in result layout
 * @param {object} layoutInfo
 * @return {bool}
 */


/**
 * make a list of plot request for wise. This function works with ConverterFactory.
 * @param table
 * @param rowIdx
 * @param {Number} cutoutSize
 * @return {{}}
 */


/**
 *  This is specialized for PTF download.
 *  Gets the download option panel for PTF with specific file processor id 'PtfDownload'
 * @param mission
 * @param cutoutSizeInDeg
 * @returns {XML}
 */


/**
 *  This is specialized for ZTF download.
 *  Gets the download option panel for ZTF with specific file processor id 'ZtfDownload'
 * @param mission
 * @param cutoutSizeInDeg
 * @returns {XML}
 */


/**
 *
 * @param tableModel
 * @param hlrow
 * @param size
 * @param cutoutSize
 * @param params object attribute match the ztfManage#getImagePlotParams()
 * @returns {WebPlotRequest}
 */


/**
 * Returns a function to use in pseudos for :enabled/:disabled
 * @param {Boolean} disabled true for :disabled; false for :enabled
 */


// Implement the identical functionality for filter and not


// Prefer a tbody over its parent table for containing new rows


// a vendor prefixed property.


// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport


// Create a reducing function iterating left or right.


// in the main function will deoptimize the, see #1991.


// Generator function to create the indexOf and lastIndexOf functions


/**
 * Change the quicklook images when the user changes the extension.
 * @param {String} type - The image type (e.g. "rate", "uncal", etc.)
 * @param {String} file_root - The rootname of the file
 * @param {String} inst - The instrument for the given file
 */


/**
 * Change the filetype for all displayed images
 * @param {String} type - The image type (e.g. "rate", "uncal", etc.)
 * @param {String} group_root - The rootname of the file group
 * @param {Dict} num_ints - A dictionary whose keys are suffix types and whose
 *                          values are the number of integrations with an associated
 *                          preview image for that suffix
 * @param {Dict} available_ints - A dictionary whose keys are suffix types and whose
 *                                values are the integration numbers of the available
 *                                jpgs for that suffix
 * @param {Dict} total_ints - A dictionary whose keys are suffix types and whose
 *                                values are the total number of integrations for that
 *                                filetype.
 * @param {String} inst - The instrument for the given file
 */


/**
 * Change the filetype of the displayed image
 * @param {String} type - The image type (e.g. "rate", "uncal", etc.)
 * @param {String} file_root - The rootname of the file
 * @param {Dict} num_ints - A dictionary whose keys are suffix types and whose
 *                          values are the number of integrations with an associated
 *                          preview image for that suffix
 * @param {Dict} available_ints - A dictionary whose keys are suffix types and whose
 *                                values are the integration numbers of the available
 *                                jpgs for that suffix
 * @param {Dict} total_ints - A dictionary whose keys are suffix types and whose
 *                                values are the total number of integrations for that
 *                                filetype.
 * @param {String} inst - The instrument for the given file
 */


/**
 * Change the integration number of the displayed image
 * @param {String} file_root - The rootname of the file
 * @param {Dict} num_ints - A dictionary whose keys are suffix types and whose
 *                          values are the number of integrations for that suffix
 * @param {Dict} available_ints - A dictionary whose keys are suffix types and whose
 *                                values are the integration numbers of the available
 *                                jpgs for that suffix
 * @param {String} method - How the integration change was initialized, either "button" or "slider"
 * @param {String} direction - The direction to switch to, either "left" (decrease) or "right" (increase).
 *                             Only relevant if method is "button".
 */


/**
 * Clean garbage characters in input dictionary parameters passed as strings.
 * @param {String} param_value - The parameter value to clean
 * @returns {String} cleaned - The cleaned parameter value
 */


/**
 * Determine whether the page is archive or unlooked
 * @param {String} instrument - The instrument of interest
 * @param {Integer} proposal - The proposal of interest
 */


/**
 * Determine whether the page is archive or unlooked
 * @param {String} instrument - The instrument of interest
 * @param {Integer} proposal - The proposal of interest
 * @param {Integer} observation - The observation number of interest
 */


/**
 * Populate a user provided html table from a dictionary
 * @param {Object} dictionary - Python style dictionary
 * @param {String} table_name - The table name in that will be updated
 * @param {Integer} nr_paired_columns - How many paired columns per row.  One "paired column" is 2 columns (1 key, 1 value)
 */


/**
 * Interprets number of integrations/groups for the selected extension and disables input for calculating difference accordingly
 * @param {Dict} integrations - A dictionary whose keys are extensions and whose
 *                              values are the number of integrations for that suffix
 * @param {Dict} groups - A dictionary whose keys are extensions and whose
 *                              values are the number of groups for that suffix
 */


/**
 * Group thumbnail display by exposure or file, save group type in session
 * @param {String} group_type - The group type
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Hide an image viewer
 * @param {String} detector - The detector name for the image viewer
 */


/**
 * Show an image viewer
 * @param {String} detector - The detector name for the image viewer
 */


/**
 * Insert thumbnail images inside existing HTML img tags
 * @param {List} updates - A list of updates to make, as [thumbnail_id, jpg_path].
 */


/**
 * Parse observation information from a JWST file name.
 * @param {String} filename - The file or group root name to parse
 * @returns {Object} parsed - Dictionary containing 'proposal', 'obs_id', 'visit_id', 'program'
 */


/**
 * Reset the integration slider for a new file
 * @param {Int} num_integration - The number of integration images available
 * @param {Int} total_integration - The total number of integrations to display
 */


/**
 * If an image is not found, replace with temporary image sized to thumbnail
 */


/**
 * Perform a search of images and display the resulting thumbnails
 */


/**
 * Limit the displayed thumbnails based on filter criteria
 * @param {String} filter_type - The filter type.
 * @param {Integer} value - The filter value
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Sort thumbnail display by proposal number
 * @param {String} sort_type - The sort type (e.g. "asc", "desc")
 */


/**
 * Sort thumbnail display by a given sort type, save sort type in session for use in previous/next buttons
 * @param {String} sort_type - The sort type by file name
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 *
 * This function is used to sort query page results
*/


/**
 * Sort thumbnail display on observation level page by a given sort type, save sort type
 * in session for use in previous/next buttons
 * @param {String} sort_type - The sort type by file name
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 *
 * This function is used to sort thumbnails on observation level pages.
*/


/**
 * Toggle a viewed button when pressed.
 * Ajax call to update RootFileInfo model with toggled value
 *
 * @param {String} file_root - The rootname of the file corresponding to the thumbnail
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Set the viewed status for a group of files.
 * Ajax call to update RootFileInfo model with toggled value
 *
 * @param {String} group_root - The rootname of the exposure group
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Download filtered data report
 * @param {String} inst - The instrument in use
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Updates various components on the archive page
 * @param {String} inst - The instrument of interest (e.g. "FGS")
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Updates various components on the MSATA page
 * @param {String} inst - The instrument of interest (e.g. "FGS")
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Updates various components on the WATA page
 * @param {String} inst - The instrument of interest (e.g. "FGS")
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Updates various components on the thumbnails page
 * @param {String} inst - The instrument of interest (e.g. "FGS")
 * @param {String} file_root - The rootname of the file corresponding to the instrument (e.g. "JW01473015001_04101_00001_MIRIMAGE")
 * @param {String} filetype - The type to be viewed (e.g. "cal" or "rate").
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 * @param {Boolean} do_opt_args - Flag to calculate and send optional arguments in URL
 */


/**
 * Updates the thumbnail-filter div with filter options
 * @param {Object} data - The data returned by the update_thumbnails_page AJAX method
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 * @param {String} thumbnail_class - the class name of the thumbnails that will be filtered
 */


/**
 * Updates the group-by-exposure div
 * @param {Object} data - The data returned by the update_thumbnails_page AJAX method
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Change the header extension displayed
 * @param {String} extension - The extension of the header selected
  * @param {String} num_extensions - The total number of extensions
 */


/**
 * Updates the obs-list div with observation number options
 * @param {Object} data - The data returned by the update_thumbnails_page AJAX method
 * @param {String} inst - Instrument name
 * @param {String} prop - Proposal ID
 * @param {List} obslist - List of observation number strings
 */


/**
 * Update the pagination div with navigation links
 * @param {Object} data - The data returned by the query_submit AJAX method
 */


/**
 * Updates the img_show_count component
 * @param {Integer} count - The count to display
 * @param {String} type - The type of the count (e.g. "activities")
 */


/**
 * Updates the thumbnail-sort div with sorting options
 * @param {Object} data - The data returned by the update_thumbnails_page AJAX method
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 */


/**
 * Updates the thumbnail divs with interactive images of thumbnails
 * @param {Object} data - The data returned by the update_thumbnails_per_observation_page AJAX methods
 *
 * This is used when working with observation-level pages. update_thumbnail_array below works
 * with the query results page.
 */


/**
 * Updates the thumbnail-array div with interactive images of thumbnails
 * @param {Object} data - The data returned by the update_thumbnails_query_page AJAX methods
 *
 * This is used when working with query page results. update_thumbnail_array_all_obs() above
 * works with the observation-level pages.
 */


/**
 * Updates various components on the thumbnails page
 * @param {String} inst - The instrument of interest (e.g. "FGS")
 * @param {String} proposal - The proposal number of interest (e.g. "88660")
 * @param {String} observation - The observation number within the proposal (e.g. "001")
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 * @param {String} sort - Sort method string saved in session data image_sort
 * @param {String} group - Group method string saved in session data image_group
 */


/**
 * Updates various components on the thumbnails anomaly query page
 * @param {String} base_url - The base URL for gathering data from the AJAX view.
 * @param {Int} page - Page number to load
 */


/**
 * Construct the URL for viewing/exploring a selected image on the exposure page
 */


/**
 * Construct the URL corresponding to a specific GitHub release
 * @param {String} version_string - The x.y.z version number
 */


// Cloud masking for Landsat 8.


// Define a function that scales and masks Landsat 8 surface reflectance images.


// Set the label to the result of the mean reduction.


// A function to make buttons labeled by position.


// Define a function to scale the data and mask unwanted pixels.


// and adds an NDVI band.


// Scales and masks Landsat 8 surface reflectance images.


// Function to create the legend image.


// Create a function to render a map layer configured by the user inputs.


// Define function to get and rename bands of interest from OLI.


// Define function to get and rename bands of interest from ETM+.


// Define function to apply harmonization transformation.


// Define function to mask out clouds and cloud shadows.


// Define function to prepare OLI images.


// Define function to prepare ETM+ images.


// Define function to apply OLS ETM+ to OLI transformation.


// Define function to apply OLS OLI to ETM+ transformation.


// Define function to apply RMA OLI to ETM+ transformation.


// Define function to apply RMA ETM+ to OLI transformation.


/**
 * Adds CSS class name to the target DOM element.
 * @param {DOMElement} target Target DOM element.
 * @param {String} className New CSS class to add.
 */


/**
 * Converts the source to array object. Mostly used for function arguments and
 * lists returned by getElementsByTagName() which aren't Array objects.
 * @param {List} source Source list.
 * @return {Array} Returns array.
 */


/**
 * Looks for a child or parent node which has specified classname.
 * Equivalent to jQuery's $(container).find(".className")
 * @param {Element} target Target element.
 * @param {String} search Class name or node name to look for.
 * @param {Boolean} reverse If set to true, will go up the node tree instead of down.
 * @return {Element} Returns found child or parent element on null.
 */


/**
 * Finds an index of element in the array.
 * @ignore
 * @param {Object} searchElement
 * @param {Number} fromIndex
 * @return {Number} Returns index of element if found; -1 otherwise.
 */


/**
 * Merges two objects. Values from obj2 override values in obj1.
 * Function is NOT recursive and works only for one dimensional objects.
 * @param {Object} obj1 First object.
 * @param {Object} obj2 Second object.
 * @return {Object} Returns combination of both objects.
 */


/**
 * Attempts to convert string to boolean.
 * @param {String} value Input string.
 * @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise.
 */


/**
 * Opens up a centered popup window.
 * @param {String} url		URL to open in the window.
 * @param {String} name		Popup name.
 * @param {int} width		Popup width.
 * @param {int} height		Popup height.
 * @param {String} options	window.open() options.
 * @return {Window}			Returns window instance.
 */


/**
 * Adds event handler to the target object.
 * @param {Object} obj		Target object.
 * @param {String} type		Name of the event.
 * @param {Function} func	Handling function.
 */


/**
 * Finds a brush by its alias.
 *
 * @param {String} alias		Brush alias.
 * @param {Boolean} showAlert	Suppresses the alert if false.
 * @return {Brush}				Returns bursh constructor if found, null otherwise.
 */


/**
 * Executes a callback on each line and replaces each line with result from the callback.
 * @param {Object} str			Input string.
 * @param {Object} callback		Callback function taking one string argument and returning a string.
 */


/**
 * Parses key/value pairs into hash object.
 *
 * Understands the following formats:
 * - name: word;
 * - name: [word, word];
 * - name: "string";
 * - name: 'string';
 *
 * For example:
 *   name1: value; name2: [value, value]; name3: 'value'
 *
 * @param {String} str    Input string.
 * @return {Object}       Returns deserialized object.
 */


/**
 * Wraps each line of the string into <code/> tag with given style applied to it.
 *
 * @param {String} str   Input string.
 * @param {String} css   Style name to apply to the string.
 * @return {String}      Returns input string with each line surrounded by <span/> tag.
 */


/**
 * Pads number with zeros until it's length is the same as given length.
 *
 * @param {Number} number	Number to pad.
 * @param {Number} length	Max string length with.
 * @return {String}			Returns a string padded with proper amount of '0'.
 */


/**
 * Replaces tabs with spaces.
 *
 * @param {String} code		Source code.
 * @param {Number} tabSize	Size of the tab.
 * @return {String}			Returns code with all tabs replaces by spaces.
 */


/**
 * Replaces tabs with smart spaces.
 *
 * @param {String} code    Code to fix the tabs in.
 * @param {Number} tabSize Number of spaces in a column.
 * @return {String}        Returns code with all tabs replaces with roper amount of spaces.
 */


/**
 * Performs various string fixes based on configuration.
 */


/**
 * Unindents a block of text by the lowest common indent amount.
 * @param {String} str   Text to unindent.
 * @return {String}      Returns unindented text block.
 */


/**
 * Callback method for Array.sort() which sorts matches by
 * index position and then by length.
 *
 * @param {Match} m1	Left object.
 * @param {Match} m2    Right object.
 * @return {Number}     Returns -1, 0 or -1 as a comparison result.
 */


/**
 * Turns all URLs in the code into <a/> tags.
 * @param {String} code Input code.
 * @return {String} Returns code with </a> tags.
 */


/**
 * Strips <![CDATA[]]> from <SCRIPT /> content because it should be used
 * there in most cases for XHTML compliance.
 * @param {String} original	Input code.
 * @return {String} Returns code without leading <![CDATA[]]> tags.
 */


/**
 * Quick code mouse double click handler.
 */


/**
 *
 * @param {string} url the URL of the firefly API
 * @param {boolean} loadNow retrieve the API immediately
 * @return {initFirefly~getFireflyAPI} a function to call that will return a promise with the FireflyAPI
 */


// Create the production build and print the deployment instructions.


// Adjusts the three.js standard shader to include batchid highlight


// resize the renderer


// append structural metadata information table


// function for writing rows


// update raycasting to find hovered mesh features


// Update the mesh feature material and meta data table displays


// render and animate


// before compile can be used to chain shader adjustments. Returns the added uniforms used for fading.


// function for calculating the positioning of topographic lines at a given world position


/**
	 *
	 * @param buffer
	 * @return {Subtree}
	 */


/**
	 * Determine which buffer views need to be loaded into memory. This includes:
	 *
	 *

	 *
The tile availability bitstream (if a bitstream is defined)

	 *
The content availability bitstream(s) (if a bitstream is defined)

	 *
The child subtree availability bitstream (if a bitstream is defined)

	 *

	 *
	 *

	 * This function modifies the buffer view headers' isActive flags in place.
	 *

	 *
	 * @param {JSON} subtreeJson The JSON chunk from the subtree
	 * @param {BufferViewHeader[]} bufferViewHeaders The preprocessed buffer view headers
	 * @private
	 */


/**
	 * Go through the list of buffers and gather all the active ones into
	 * a dictionary.
	 *

	 * The results are put into a dictionary object. The keys are indices of
	 * buffers, and the values are Uint8Arrays of the contents. Only buffers
	 * marked with the isActive flag are fetched.
	 *

	 *

	 * The internal buffer (the subtree's binary chunk) is also stored in this
	 * dictionary if it is marked active.
	 *

	 * @param {BufferHeader[]} bufferHeaders The preprocessed buffer headers
	 * @param {ArrayBuffer} internalBuffer The binary chunk of the subtree file
	 * @returns {object} buffersU8 A dictionary of buffer index to a Uint8Array of its contents.
	 * @private
	 */


/**
	 * Go through the list of buffer views, and if they are marked as active,
	 * extract a subarray from one of the active buffers.
	 *
	 * @param {BufferViewHeader[]} bufferViewHeaders
	 * @param {object} buffersU8 A dictionary of buffer index to a Uint8Array of its contents.
	 * @returns {object} A dictionary of buffer view index to a Uint8Array of its contents.
	 * @private
	 */


/**
	 * Iterate over the list of buffers from the subtree JSON and add the isActive field for easier parsing later.
	 * This modifies the objects in place.
	 * @param {Object[]} [bufferHeaders=[]] The JSON from subtreeJson.buffers.
	 * @returns {BufferHeader[]} The same array of headers with additional fields.
	 * @private
	 */


/**
	 * Iterate the list of buffer views from the subtree JSON and add the
	 * isActive flag. Also save a reference to the bufferHeader.
	 *
	 * @param {Object[]} [bufferViewHeaders=[]] The JSON from subtree.bufferViews.
	 * @param {BufferHeader[]} bufferHeaders The preprocessed buffer headers.
	 * @returns {BufferViewHeader[]} The same array of bufferView headers with additional fields.
	 * @private
	 */


/**
	 * Parse the three availability bitstreams and store them in the subtree.
	 *
	 * @param {Subtree} subtree The subtree to modify.
	 * @param {Object} subtreeJson The subtree JSON.
	 * @param {Object} bufferViewsU8 A dictionary of buffer view index to a Uint8Array of its contents.
	 * @private
	 */


/**
	 * Given the JSON describing an availability bitstream, turn it into an
	 * in-memory representation using an object. This handles bitstreams from a bufferView.
	 *
	 * @param {Object} availabilityJson A JSON object representing the availability.
	 * @param {Object} bufferViewsU8 A dictionary of buffer view index to its Uint8Array contents.
	 * @param {number} lengthBits The length of the availability bitstream in bits.
	 * @returns {object}
	 * @private
	 */


/**
	 * Expand a single subtree tile. This transcodes the subtree into
	 * a tree of {@link SubtreeTile}. The root of this tree is stored in
	 * the placeholder tile's children array. This method also creates
	 * tiles for the child subtrees to be lazily expanded as needed.
	 *
	 * @param {Object | SubtreeTile} subtreeRoot The first node of the subtree.
	 * @param {Subtree} subtree The parsed subtree.
	 * @private
	 */


/**
	 * Transcode the implicitly defined tiles within this subtree and generate
	 * explicit {@link SubtreeTile} objects. This function only transcodes tiles,
	 * child subtrees are handled separately.
	 *
	 * @param {Object | SubtreeTile} subtreeRoot The root of the current subtree.
	 * @param {Subtree} subtree The subtree to get availability information.
	 * @returns {Array} The bottom row of transcoded tiles. This is helpful for processing child subtrees.
	 * @private
	 */


/**
	 * Given a parent tile and information about which child to create, derive
	 * the properties of the child tile implicitly.
	 * <p>
	 * This creates a real tile for rendering.
	 * </p>
	 *
	 * @param {Subtree} subtree The subtree the child tile belongs to.
	 * @param {Object | SubtreeTile} parentTile The parent of the new child tile.
	 * @param {number} childBitIndex The index of the child tile within the tile's availability information.
	 * @param {number} childMortonIndex The morton index of the child tile relative to its parent.
	 * @returns {SubtreeTile} The new child tile.
	 * @private
	 */


/**
	 * Determine what child subtrees exist and return a list of information.
	 *
	 * @param {Object} subtree The subtree for looking up availability.
	 * @param {Array} bottomRow The bottom row of tiles in a transcoded subtree.
	 * @returns {[]} A list of identifiers for the child subtrees.
	 * @private
	 */


/**
	 * Replaces placeholder tokens in a URI template with the corresponding tile properties.
	 *
	 * The URI template should contain the tokens:
	 * - `{level}` for the tile's subdivision level.
	 * - `{x}` for the tile's x-coordinate.
	 * - `{y}` for the tile's y-coordinate.
	 * - `{z}` for the tile's z-coordinate.
	 *
	 * @param {Object} tile - The tile object containing properties __level, __x, __y, and __z.
	 * @param {string} uri - The URI template string with placeholders.
	 * @returns {string} The URI with placeholders replaced by the tile's properties.
	 */


/**
	 * Generates the full external buffer URI for a tile by combining an implicit URI with a buffer URI.
	 *
	 * First, it parses the implicit URI using the tile properties and the provided template. Then, it creates a new URL
	 * relative to the tile's base path, removes the last path segment, and appends the buffer URI.
	 *
	 * @param {Object} tile - The tile object that contains properties:
	 *   - __level: the subdivision level,
	 *   - __x, __y, __z: the tile coordinates,
	 * @param {string} uri - The URI template string with placeholders for the tile (e.g., `{level}`, `{x}`, `{y}`, `{z}`).
	 * @param {string} bufUri - The buffer file name to append (e.g., "0_1.bin").
	 * @returns {string} The full external buffer URI.
	 */


// Returns whether or not the cache has reached the maximum size


// Maybe call it "cleanup" or "unloadToMinSize"


// returns whether tasks are queued or actively running


// per frame, initially queuing a new call for the next frame.


// Checks whether this tile was last used on the given frame.


// Resets the frame frame information for the given tile


// Recursively mark tiles used down to the next layer, skipping external tile sets


// Recursively traverses to the next tiles with unloaded renderable content to load them


// Mark a tile as being used by current view


// Returns whether the tile can be traversed to the next layer of children by checking the tile metrics


// traversal will end early.


// Determine which tiles are used by the renderer given the current camera configuration


// Traverse and mark the tiles that are at the leaf nodes of the "used" tree.


// Skip past tiles we consider unrenderable because they are outside the error threshold.


// Final traverse to toggle tile visibility.


/**
 * Traverses the ancestry of the tile up to the root tile.
 */


// force a recalculation of the tile or all tiles if no tile is provided


// add and remove cameras used for sorting


// run the given item index if possible


// register query callbacks


// dispose of everything


// checks if the first level of object key-values are equal


// Helper for using an object as a dependency in a useEffect or useMemo array


// return true if the given key is for registering an event


// Recursively assigns a set of options to an object, interpreting dashes as periods


// Assigns a set of options to an object shallowly, interpreting dashes as periods


// assign a give target to the set of refs


// current position in addition to adjusting the height.


// disable rotation once we're outside the control transition


// tilt the camera to align with north


// tilt the camera to look at the center of the globe


// returns the perspective camera transition distance can move to based on globe size and fov


// returns the max distance the perspective camera can move to based on globe size and fov


// returns the transition threshold for orthographic zoom based on the globe size and camera settings


// returns the minimum allowed orthographic zoom based on the globe size and camera settings


// in space and derive a reasonable "up" value.


// helper function for constructing a matrix for rotating around a point


// get the three.js pointer coords from an event


// the surface intersection if they collide.


// find the closest ray on the horizon when the ray passes above the sphere


// updates the camera to position it based on the constraints of the controls


// update the point being zoomed in to based on the zoom direction


// returns the point below the camera


// update the drag action


// sets the "up" axis for the current surface of the tile set


// tilt the camera to align with the provided "up" value


// clamp rotation to the given "up" vector


// about pointer movement


// Returns the estimated number of bytes used by the object


// Returns the closest hit when traversing the tree


/**
 * Decode an octahedron-encoded normal (as a pair of 8-bit unsigned numbers) into a Vector3.
 *
 * Resources:
 * - https://stackoverflow.com/a/74745666/2704779
 * - https://knarkowicz.wordpress.com/2014/04/16/octahedron-normal-vector-encoding/
 * @param {number} x The unsigned 8-bit X coordinate on the projected octahedron.
 * @param {number} y The unsigned 8-bit Y coordinate on the projected octahedron.
 * @param {Vector3} [target] The target vector.
 */


/**
	 * Clamps the given point within the bounds of this OBB
	 * @param {Vector3} point
	 * @param {Vector3} result
	 * @returns {Vector3}
	 */


/**
	 * Returns the distance from any edge of this OBB to the specified point.
	 * If the point lies inside of this box, the distance will be 0.
	 * @param {Vector3} point
	 * @returns {number}
	 */


// returns boolean indicating whether the ray has intersected the obb


// Returns "null" if no intersection found.


// of that shape to determine whether the OBB is intersected with.


// Solve a system of equations to find the point where the three planes intersect


// Checks if the given tile is available


// initialize the groups for displaying helpers, register events, and initialize existing tiles


// API for updating and shapes to flatten the vertices


// reset the vertex positions and remove the update callback


// override the parse to mesh logic to support a region mesh


// function for marking and releasing images in the given overlay


// returns the total number of tiles that will be drawn for the provided range


// initialize the overlay to use the right fetch options, load all data for existing tiles


// wrap all materials in the given scene wit the overlay material shader


// does not need to be awaited for use since it's just locking textures which are awaited later.


// initialize the scene meshes


// helper for processing the buffer into a texture


// fetch the item with the given key fields