//
// globs.h (global things we want...)
//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//
//
//
//
//
//
//

#ifndef GLOBS_H

#define GLOBS_H

#include <time.h>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <math.h>
#include <stdarg.h>   // ANSI version, not UNIX varargs.h
#include "mt64.h"



#ifdef _WIN32
#include <process.h>
#include <windows.h>  // for FILETIME struct
#define SLASH '\\'
#define OTHER_SLASH '/'

#else
#define SLASH '/'
#define OTHER_SLASH '\\'

#endif // !_WIN32

#ifdef _WIN32

#define NEWF_FLAGS (_O_WRONLY | _O_CREAT | _O_BINARY)
#define OLDF_FLAGS (_O_RDONLY            | _O_BINARY)

#else

#define NEWF_FLAGS (O_WRONLY | O_CREAT )
#define OLDF_FLAGS (O_RDONLY           )

#endif // !_WIN32



#ifdef FROM_GLOB
#define EXTERN 
#define GLOB_INIT(x)      x
#define GLOB_INI2(x,y)    x,y
#define GLOB_INI3(x,y,z)  x,y,z
#else
#define EXTERN extern
#define GLOB_INIT(x)
#define GLOB_INI2(x,y)
#define GLOB_INI3(x,y,z)
#endif


#ifdef CAUSES_PROBLEMS
   #define CR (13)
   #undef  LF
   #define LF (10)
#endif // CAUSES_PROBLEMS


void jassert(int iBOOL);                                 // 01-14-00
inline void jassert(void *pVoid) {jassert(pVoid != NULL);}
// #define JASSERT(iBOOL)  (jassert(iBOOL); assert(iBOOL))  // 01-14-00
#define JASSERT(iBOOL)  jassert(iBOOL); assert(iBOOL)

#define PI            (3.14159265358979)
#define TWO_PI        (6.283185307179586)
#define DEG_PER_RAD (57.2957795147199)
#define RAD_PER_DEG (1.0/DEG_PER_RAD)

#define TWO_15    (32768)
#define TWO_16    (65536)

#define MIN_SHORT (-32768)
#define MAX_SHORT (+32767)

#define MIN_SCHAR (-128)
#define MAX_SCHAR (+127)

#define MAX_CBUF   (2048)

#define BIG_POS_INT (+2147483647)
#define BIG_NEG_INT (-2147483648)
#define BIG_U32     (4294967296ULL)
#define LIL_U32     (unsigned int)BIG_U32

#define TINY_DOUB   (0.000000000000000001)

#define ME_WRITE     (0200)    /* octal... */

#define CASE_SAME  (0)
#define CASE_UPPER (1)
#define CASE_LOWER (2)

#define fnDThalf      (1000)  // msec for volume memory to cut in half
#define fnDriftHalf   (1000)  // msec for drift to fall to half`
#define fnKslide   (0.0010)      // 10-17-99: still less...
#define fnKgood    (0.0001)
#define fnKdrift   (0.000001)    // 10-16-99
#define fnKcontPainFact (10.0)   // 10-17-99; MORE
#define fnKextraCredit  (1.1)    // 10-13-99 (was hard-coded) pickATuse()
#define fnDTmaxPSE  (64)         // 11-09-99: LATE making this a param!
#define fnKrampGood   (100.0)    // 02-06-00: factor between old tch and new tsp.
#define fnKrampSlide  (400.0)    // 01-21-00: factor between old tch and new tsp.
#define fnKrampDrift  (1000.0)   // 01-15-00: factor between old tch and new tsp.
#define fnSRFfact     (0.5)      // 01-30-00: power reduction of stress reduction factor (old behavior: 1.0: no reduction in reduction)
#define fnHighNote    (1.0)      // 01-30-00: 0.0 no extra credit; 1.0 double
#define fnVolFlatn    (0.5)      // 01-30-00: 1.0 as before; 0.0 full flatten
#define fnKeyedTunable (1.0)     // 01-11-01: 1.0 fully; 0.0 COFT
#define fnRmelody      (0.00125) // 06-14-01: 1% of "nominal" .125
#define fnStretchExp   (0.0)     // 05-24-01; 06-16-01
#define fnStretchLin   (0.0)     // 06-16-01
#define fnOffcent      (0.0)     // 06-17-01
#define fnMaxGrDev     (7.0)     // 09-05-01: max grounding deviation.
#define fnVolAdjCtr    (64.0)    // 11-01-01: volume that is unchanged
#define fnVolAdjSlope  (1.0)     // 11-01-01: slope of volume mapping




#define TWELVT    (12)
#define THIRTY1   (31)
#define NADA      (-1)
#define NAD2      (-2)
#define NAD3      (-3)
#define DADA      (-1.0)
static const double BIG_NEG = -1.0E+20;
static const double BIG_POS = +1.0E+20;
static const double LIL_NEG = -1.0E-20;
static const double LIL_POS = +1.0E-20;
static const double tol_cents = .001;
static const double tol_vol   = .001;
static const double tol_sprng = .001;     // 01-29-00
static const double tol_pain  = .001;     // 01-30-00

#define BU_PER_CENT (81.92)   // when instrument has +-1 semitone range
#define CENT_PER_BU (1.0/BU_PER_CENT)
#define CENT_PER_SEMI (100.0)
#define SEMI_PER_CENT (1.0/CENT_PER_SEMI)
#define SEMI_PER_OCT  (TWELVT)
#define OCT_PER_SEMI  (1.0/SEMI_PER_OCT)
#define CENT_PER_OCT  (CENT_PER_SEMI * SEMI_PER_OCT)
#define OCT_PER_CENT  (1.0/CENT_PER_OCT)
#define MSEC_PER_SEC  (1000.)

#define MIN_THIRD     (315.641287)
#define MAJ_THIRD     (386.313714)
#define PE_FOURTH     (498.044999)

// 02-05-04:
#define DEF_BMP_IN    ("blahIn.bmp")
#define DEF_BMP_OUT   ("blahOut.bmp")


class Vol12Base;
class MevBase;
class MevAnch;
class Bufin;


// newer than above lower case; 09-30-98; see useful.dat...

#ifndef MAX
#define MAX(A, B)         ((A) > (B) ? (A) : (B))
#define MA3(A, B, C)      (MAX((MAX((A),(B))),(C)))
#define MA4(A, B, C, D)   (MAX((MAX((A),(B))),(MAX((C),(D)))))
#define MIN(A, B)         ((A) < (B) ? (A) : (B))
#define MI3(A, B, C)      (MIN((MIN((A),(B))),(C)))
#define MI4(A, B, C, D)   (MIN((MIN((A),(B))),(MIN((C),(D)))))
#endif

#ifndef ABS
#define ABS(x)    (((x) >= 0) ? (x) : (-(x)))
#endif
#ifndef SGN
#define SGN(x)    (((x) > 0) ? (1) : (((x) < 0) ? (-1) : (0)))
#endif


#ifndef RANGE
#define RANGE(val, minn, maxx) (MIN(MAX((val), (minn)), (maxx)))
#define RANG84F(val)  (RANGE((val), -99.999, 999.999))
#define IN_RANGE(val, minn, maxx) (((val) < (minn)) ? (false) : (((val) > (maxx)) ? (false) : (true)))
#endif

#define LOG_2(x)     (log(x)/log(2.0))
#define CPS_TO_MID(freq)  (69.0 + 12.0 * LOG_2((freq) / 440.0))
#define MID_TO_CPS(dmid)  (440.0 * pow(2.0, (dmid - 69.0)/12.0))
#define ADDR_ZEROTH(veccy)    ((veccy.size() > 0) ? (&veccy[0]) : (NULL))


#define SMARTA(name, closs, nElem, nam2)   closs *name = new closs[nElem]; SmartParr<closs> nam2(name);
#define SMART1(name, closs,        nam2)   closs *name = new closs;        SmartPtr<closs>  nam2(name);
#define SMART1p(name, closs, param, nam2)  closs *name = new closs(param); SmartPtr<closs>  nam2(name);

#define BACK_SLASH  ('\\')
#define FRWD_SLASH  ('/')
#define DOUB_QUOTE  ('"')
#define POUND_CHAR  ('#')
#define UNDER_CHAR  ('_')
#define ASCII_TAB   (9)
#define ESC         (27)
#define COPYRIGHT_CHAR (0xA9)
#define ARROW_UP    (0xE048)
#define ARROW_DOWN  (0xE050)
#define ARROW_RIGHT (0xE04D)
#define ARROW_LEFT  (0xE04B)




#define BMP_EXT0  "bmp"
#define BMP_EXT1 ".bmp"

#define JPG_EXT0  "jpg"
#define JPG_EXT1 ".jpg"

#define PNG_EXT0  "png"
#define PNG_EXT1 ".png"





inline int bitTest(int n, int ibit) {return ((n >> ibit) & 1);}
inline int bitTest(unsigned int n, int ibit) {return ((n >> ibit) & 1);}
inline int bitTest(long long n, int ibit) {return ((n >> ibit) & 1);}
inline int bitTest(unsigned long long n, int ibit) {return ((n >> ibit) & 1);}






// qxonePair

struct onePair {
   int numer;
   int denom;

   onePair(int n=0, int d=0) : numer(n), denom(d) {}
   onePair(const onePair &rs) : numer(rs.numer), denom(rs.denom) {}
   ~onePair() {}

   const onePair &operator=(const onePair &rs) {
      if(&rs != this) {
         numer = rs.numer;
         denom = rs.denom;
      } // if(&rs != this)

      return *this;
   } // const onePair &operator=(const onePair &rs)

   bool operator<(const onePair &rs) const  {return (((long long)rs.denom * (long long)numer) < ((long long)rs.numer * (long long)denom));}
}; // struct onePair





// qxtwoPairs

struct twoPairs {
   onePair main;
   onePair back;

   twoPairs(int mn=0, int md=0, int bn=0, int bd=0) : main(mn, md), back(bn, bd) {}
   twoPairs(const twoPairs &rs): main(rs.main), back(rs.back) {}
   ~twoPairs() {}

   const twoPairs &operator=(const twoPairs &rs) {
      if(&rs != this) {
         main = rs.main;
         back = rs.back;
      } // if(&rs != this)

      return *this;
   } // const twoPairs &operator=(const twoPairs &rs)
}; // struct twoPairs



// for Steg2:
//
// qxstegInfo
//

struct stegInfo {
   bool bDoStop;
   bool bDidStop;
   int  maxBits;                                    // 0: unrestricted; higher: no more than this in each date byte.
   int  widDesired;                                 // desired stuffed file width, pixels.
   int  hgtDesired;                                 // desired stuffed file height, pixels.
   int  fszDesired;                                 // desired file size, bytes.
   int  noWrite;                                    // don't rewrite someName.txt
   int  nNumer;                                     // stuffing numerator override.
   int  nDenom;                                     // stuffing denominator override.
   int  doDbg;                                      // 1: never; 0: look elsewhere; 1: always.
   int  doBmp;                                      // 1: write stuffed .bmp file.
   int  doPng;                                      // 1: write stuffed .png file.
   int  useScatter;                                 // -1: !bScatter; 1: bScatter; 0: under user control.
   int  lastScatter;                                // if useScatter == 0, we seed lastScatter.
   int  nDigitsSafe;                                // detection difficulty (safety) display: number of digits after "."
   int  embFolder;                                  // if 1, seed folder embed rather than individual file(s) embed.
   bool bShuffle;                                   // makes iShiftOff less fully random.
   bool bConserv;                                   // fewer calls to MT64 when !bShuffle.
   bool bTrim;                                      // 1.09 improvement to 1.08.
   bool bPassHint;                                  // (default true): show hint from password.
   double      difDesired;                          // desired detection difficulty.
   double      factRed;                             // default 1.0; less means red is less embedded.
   double      factGrn;                             // default 1.0; less means grn is less embedded.
   double      factBlu;                             // default 1.0; less means blu is less embedded.
   std::string ssName;                              // thread watches for this & opens explorer on it.
   std::string ssExtractCold;                       // extract folder before embed.
   std::string ssExtractWarm;                       // extract folder after  embed.
   std::string ssWrapperLoc;                        // where we last opened a wrapper file.
   std::string ssEmbedLoc;                          // where we last opened embed file(s).
   std::string ssEmbedFoldr;                        // where we last opened embed folder.
   std::string ssMessageLoc;                        // where we last saved a message.
   std::vector<onePair> vcBackRatEmb;               // ratios to use when embeding
   std::vector<onePair> vcBackRatExt;               // (more extensive) ratios to try when extracting.
   std::vector<onePair> vcBackRatOld;               // Just has 1 / 16, for use without 100,000 scrambles.
   std::vector<std::string> vcSsBlahNames;          // places we might copy blah.dbg after closing.

   stegInfo() : bDoStop(false), bDidStop(false), maxBits(0), widDesired(0), hgtDesired(0), fszDesired(0), noWrite(0), nNumer(0), nDenom(0), doDbg(0), doBmp(0), doPng(1), difDesired(-1.0), factRed(1.0), factGrn(1.0), factBlu(1.0), useScatter(1), lastScatter(1), nDigitsSafe(2), embFolder(0), bShuffle(true), bConserv(true), bTrim(true), bPassHint(true) {}
}; // struct stegInfo



EXTERN FILE *fp_dbg GLOB_INIT(= NULL) ;
EXTERN FILE *fp_db2 GLOB_INIT(= NULL) ;   // 12-29-00
EXTERN FILE *fp_std GLOB_INIT(= NULL) ;   // 05-30-04 (from $bg): takes place of hard-coded stdout's.
EXTERN int  jdebug  GLOB_INIT(= 0) ;

EXTERN long sn_cookd  GLOB_INIT(= 0) ;  // 06-28-01

// note: modifying this should be accompanied w/ change in sn.h:
EXTERN const char *cp_vers  GLOB_INIT(= "2005_May_01") ;


const char *getBipMeat(Bufin *bip);

int NADAfunc(const char *pcMessage=NULL, int onlyIf=0);
int NADAfnc2(const char * const pc, ...);
int is_a_num(const char *cdata);
int is_a_flag(const char *cdata);

int jsubstr(const char *str_in, int from, int to, char *str_out);
int jcalcstr(char *str_in, long *val_out, long *div_out);
double rcalcstr(char *str_in);

int trim_sp(const char *str_in, char *str_out);
int trim_sp(const std::string &ssIn, char *str_out);
int trim_sp(const char *str_in, std::string &ssOut);
int trim_sp(const std::string &ssIn, std::string &ssOut);

int replace_char(const char *str_in, char *str_out, int char0, int char1);
int replace_string(const char *str_in, char *str_out, const char *cold, const char *cnew, int ntries);
int non_space_count(const char *str_in);
long str_to_long(const char *str_in, int col1, int col2);
double str_to_doub(const char *str_in, int col1, int col2, double err_return=DADA);
unsigned int str_to_hexi(const char *str_in, int col1, int col2);  // 07-25-04
unsigned int iHash(const std::vector<unsigned char> &vcData);
const unsigned char *scrambledHash(const unsigned char *cNamePlusFive, int lenPlusFive);
int isCombinedKeyValid(const unsigned char *cBoth, int lenBoth);
int retrieveCombinedKey(unsigned char *cBoth, int &lenBoth);       // 07-14-06 (jdl)
int hasValidLicenseFile(void);                                     // 07-28-04 (jdl)
const char *licenseName();                                         // 10-02-04 (jdl)
int writeLicenseFile(const unsigned char *cBoth, int lenBoth);     // 07-28-04 (jdl)
const char *arg_extract(int argc, const char **argv, int *which_arg);

inline int sgn_tol(double val_in, double tol) {
   if(val_in > tol) return 1;
   if(val_in < -tol) return -1;
   return 0;
} /* end of sgn_tol() */

// in mio.cpp:
int playSequence(MevAnch *pMa, int doHpBuffer, long MaxDt);
int recordSequence(MevAnch *pMa, int doEcho);

int dbgOpen(int iAppend=1);
int dbgClose();
char *strjncpy(char *dest, const char *src, size_t count);

// a collection of nice utilities:
int break_file_name(const char *file_in, char *body_out, char *dot_out, char *ext_out);
int break_file_name(const char *file_in, std::string &ssBodOut, std::string &ssDotOut, std::string &ssExtOut);
int cut_file_name(const char *name_in, char *dir_out, char *file_out);
int cut_file_name(const char *name_in, std::string &ssDirOut, std::string &ssFilOut);
int make_full_name(const char *cdir, const char *cfil, char *cful);

std::string vschToSs(const std::vector<signed char> &vSc);    // converts vector of signed char to std::string.


// qxis_slash()

inline int is_slash(int c) {
   if(c == SLASH) return 1;
   if(c == OTHER_SLASH) return 1;
   return 0;
} // end of is_slash()

// 08-06-99: from recurse.c; INT_32 -> int...
int case_change(char *cp_in_out, int which_case);

// 09-17-99:
const char *msecToMinSec(int msecIn, char *cbufIn=NULL);

// 12-17-00
const char *noteToColon(int noteIn, char *cbufIn=NULL);

// 06-14-00:
int nToRight(double rawVal, int totWidth);

// 10-09-00:
int compress_78(const unsigned char *data_in, int n_in, unsigned char *data_out);
int expand_87(const unsigned char *data_in, int n_in, unsigned char *data_out);

// 10-11-00, from jca.cpp:
int is_a_hex_num(const char *cdata);
double jatof(const char *cdata);
int intify(double dVal);
int jatoi(const char *cdata);

// 06-15-00:
int isKeyPending(void);
int suckKeysPending(void);
int waitForKey(void);

// 11-21-00:
int calcDecay(double y0, double y1, double y2, double &k1, double &k2, double &k3);

// 03-18-01:
int showArgs(int argc, const char **argv, FILE *fp_in);

// 11-03-01:
double centsToJI(double centsIn, int limit, int &numOut, int &denOut);

// 12-31-01:
int format_one(time_t time_val, char *cbufOut);
int rmlf(char *str_in);
int fileDate(const char *fileToRead, char *cbufOut);

// 01-26-02:
long file_t(const char *file_name, bool bDirectoryOK=false);
long  file_t4(const char *file_name, short *exists, short *is_dir, short *is_prot);
int is_a_dir(const char *file_name);

int do_proc_time(FILE *fp1=NULL, FILE *fp2=NULL);
int intersectLines(double xa0, double ya0, double xa1, double ya1, double xb0, double yb0, double xb1, double yb1, double &xOut, double &yOut);
int dropToLine(double xa0, double ya0, double xa1, double ya1, double xp, double yp, double &xOut, double &yOut);
double dist2d(double x0, double y0, double x1, double y1);
double dist2d_sq(double x0, double y0, double x1, double y1);    // 03-18-04
double dot2d(double dx0, double dy0, double dx1, double dy1);

// 02-05-04:
int isBmpName(const char *cFile);
int isJpgName(const char *cFile);   // either .jpg or .jpeg
int isJpsName(const char *cFile);   // short: .jpg
int isJplName(const char *cFile);   // long: .jpeg
int isPngName(const char *cFile);

// 07-21-06: from tstamp.c:
int tstamp3(time_t new_time_t, char *file_to);
int tstamp4(time_t delta_time_t, char *file_to);

// 01-30-10: from jnob:
int byte_cmp(char *str1, char *str2, signed long lenn);
int byte_cpy(const char *str1, char *str2, signed long lenn);

// 02-20-10, for rw:
int solveQuadratic(double x0, double y0, double x1, double y1, double x2, double y2, double &a, double &b, double &c, double &xMaxMin, double &yMaxMin);

// 09-11-10 (taken from $bg)
int roundy(double rawVal);

// 10-02-10 (jdl): brand new:
int solveSimultaneous(const std::vector<std::vector<double> > &coeffsIn, std::vector<double> &unknownsOut, FILE *fp_wrt=NULL);
int semiSolve(const std::vector<std::vector<double> > &voicePeaks, const std::vector<double> &targetPeaks, std::vector<double> &Fout, std::vector<double> &targetAchieved, double *pPainFract=NULL);
int semiSolveNoNeg(const std::vector<std::vector<double> > &voicePeaks, const std::vector<double> &targetPeaks, std::vector<double> &Fout, std::vector<double> &targetAchieved, double *pPainFract=NULL);
int normalizevd(std::vector<double> &vd);

// 12-28-10 (jdl):
int semiSolveCubic(const std::vector<double> &yValuesIn, std::vector<double> &coeffsOut);

// 03-18-11 (jdl):
int semiSolveQuadratic(const std::vector<double> &yValuesIn, std::vector<double> &coeffsOut);
int semiSolveLinear(const std::vector<double> &yValuesIn, std::vector<double> &coeffsOut);

// 09-21-11 (jdl):
int atond(const char *cdata, int &iNumerOut, int &iDenomOut);
int nBitsAvail(signed short isVal, int nGuard=0, int maxEmbBits=0);

// 10-08-11 (jdl) (moved from egrid.cpp):
short shortify(double dVal);
short shortifi(int iVal);

int arcMeSimple(const char * filename);

int qprintf(FILE * const fp , const char * const pc , ...);
int qflush(FILE *fp);

long long fileSize(const char *file_name);
int arcMeDotty(const char * filename);

int nDigits(const char *pDigs);
int arcMe3num(const char *fileName, std::string *pSSout=NULL, bool bJustTell=false);



//
//
//
// 06-19-24: hold FILE ** in case outside code closes and NULLs the actual guy.
//
// qxfileCloser

class fileCloser {
private:
   FILE **m_fp;
   int    m_iReport;
   std::string m_ssInfo;
public:
   fileCloser(FILE **fpIn=NULL, int ir=0, std::string ss="") : m_fp(fpIn), m_iReport(ir), m_ssInfo(ss) {}
   ~fileCloser() {
      if((m_fp != NULL) && (*m_fp != NULL)) {
         if((m_iReport & 1) != 0)
            qprintf(*m_fp, "fileCloser is closing your file \"%s\" for you.\n", m_ssInfo.c_str());

         if((m_iReport & 2) != 0)
            qprintf(stdout, "fileCloser is closing your file \"%s\" for you.\n", m_ssInfo.c_str());

         fclose(*m_fp); *m_fp=NULL;
      } else {
         if((m_iReport & 2) != 0)
            qprintf(stdout, "fileCloser can't close your file \"%s\" for you.\n", m_ssInfo.c_str());
      }
   }
};



// qxBitSrc

class BitSrc {
private:
   unsigned long long m_bitsies;
   int                m_bitnext;

public:
   BitSrc() : m_bitsies(0), m_bitnext(64) {}

   // qxgetBit()
   int getBit(MT64 *pMT=NULL, bool bPeek=false) {
      if(m_bitnext >= 64) {
         m_bitnext = 0;
         if(pMT != NULL)
            m_bitsies = pMT->genrand64_int64();
      } // if(m_bitnext >= 64)

      int iRet = (m_bitsies >> m_bitnext) & 1;

      if(!bPeek)
         m_bitnext++;

      return iRet;
   } // int getBit()...

   // qxgetNbits()
   int getNbits(int nBits, MT64 *pMT=NULL) {
      if(m_bitnext >= 64) {
         m_bitnext = 0;
         if(pMT != NULL)
            m_bitsies = pMT->genrand64_int64();
      } // if(m_bitnext >= 64)

      int mask = (1 << nBits) - 1;

      int iRet = (m_bitsies >> m_bitnext) & mask;
      m_bitnext += nBits;

      if(m_bitnext > 64) {
         m_bitnext -= 64;
         if(pMT != NULL)
            m_bitsies = pMT->genrand64_int64();

         int mask2 = (1 << m_bitnext) - 1;
         int ival2 = m_bitsies & mask2;
         int ishft = nBits - m_bitnext;
         iRet     += (ival2 << ishft);
      } // if(m_bitnext > 64)

      return iRet;
   } // int getNbits(int nBits, MT64 *pMT=NULL)
}; // class BitSrc




// qxShuffled

class Shuffled {
private:
   std::vector<int>       m_vcSchuf;
   int                    m_walk;
   int                    m_nAdvance;
   int                    m_nReshuf;
   bool                   m_bOneForAll;
   bool                   m_bRestrict;
   bool                   m_bOnesCompl;
   std::vector<int>       m_vcBitOrder;

public:

   Shuffled(int nEntries=0, MT64 *pMT=NULL, bool bOne=false, bool bRestr=false, const std::vector<int> *pvcBitOrder=NULL, bool bOnes=false);
   Shuffled(const Shuffled &rs);
   ~Shuffled();

   const Shuffled &operator=(const Shuffled &rs);

   int setSize(int nEntries, MT64 *pMT=NULL);
   int doShuf(MT64 *pMT);
   int getCurrent(MT64 *pMT=NULL, bool bPeek=false);
   static int makeVec(int nNumer, int nDenom, std::vector<int> &vcBitOrderOut, bool bTrim=false, int mostestBits=-1);

}; // class Shuffled.



// qxShufWrap

class ShufWrap {
private:
   std::vector<Shuffled>    m_vcShffl;

public:
   ShufWrap(MT64 *pMT=NULL) {
      m_vcShffl.resize(8);
      for(int i=0; i<8; i++) {
         int nElem = 1 << i;
         m_vcShffl[i].setSize(nElem, pMT);
      } // for(int i=0; i<8; i++)
   } // ShufWrap()

   ShufWrap(const ShufWrap &rs) : m_vcShffl(rs.m_vcShffl) {}

   const ShufWrap &operator=(const ShufWrap &rs) {
      if(&rs != this) {
         m_vcShffl = rs.m_vcShffl;
      } // if(&rs != this)

      return *this;
   } // const ShufWrap &operator=(const ShufWrap &rs)

   // qxgetCurrenw()
   int getCurrenw(int nBits, MT64 *pMT=NULL, bool bPeek=false) {
      if((nBits < 0) || (nBits >= 8))
         return NADA;

      int iRet = m_vcShffl[nBits].getCurrent(pMT, bPeek);

      return iRet;
   } // int getCurrenw(int nBits, MT64 *pMT=NULL, bool bPeek=false)
}; // class ShufWrap





// qxzeroAr()

template <typename T> void zeroAr(T *pT, int nElem, int stufVal=0) {
   for(int i=0; i<nElem; i++)
      pT[i] = stufVal;

   return;
} // template <typename T> void zeroAr(T *pT, int nElem, int stufVal=0) {




// qxzeroMe()

template <typename T> void zeroMe(T &ssOrVec, int stufVal=0) {
   int nElAct = (int)ssOrVec.size();

   for(int i=0; i<nElAct; i++)
      ssOrVec[i] = stufVal;

   return;
} // template <typename T> void zeroMe(T &ssOrVec) 



// qxzeroVc()

template <typename T> void zeroVc(std::vector<T> &vcSsOrVec, int stufVal=0) {
   int nElAct = (int)vcSsOrVec.size();

   for(int i=0; i<nElAct; i++)
      zeroMe(vcSsOrVec[i], stufVal);

   return;
} // template <typename T> void zeroVc()...





// qxzeroVv()

template <typename T> void zeroVv(std::vector<std::vector<T>> &vcVcSsOrVec, int stufVal=0) {
   int nElAct = (int)vcVcSsOrVec.size();

   for(int i=0; i<nElAct; i++)
      zeroVc(vcVcSsOrVec[i], stufVal);

   return;
} // template <typename T> void zeroVv()...





// qxbIsInSet()

template <typename T> inline bool bIsInSet(const std::set<T> &theSet, T key) {
   typename std::set<T>::const_iterator it = theSet.find(key);

   return (it != theSet.end());
} // bIsInSet()



// qxsigmaSize()

template <typename T> inline size_t sigmaSize(const std::vector<std::vector<T>> &theVcVc) {
   size_t sum = 0;
   for(int i=0; i<(int)theVcVc.size(); i++)
      sum += theVcVc[i].size();

   return sum;
} // sigmaSize()




// qxbIsInMap()

template <typename T, typename U> bool bIsInMap(const std::map<T, U> &theMap, const T key) {
   typename std::map<T, U>::const_iterator it = theMap.find(key);

   return (it != theMap.end());
} // bIsInMap()







// qxmapValuu()

template <typename T> T *mapValuu(const std::map<T *, T *> &theMap, T *pKey, T *pError) {
   if(pKey == NULL) 
      return NULL;      // NULL never gets translated to anything else.

   typename std::map<T *, T *>::const_iterator it = theMap.find(pKey);
   if(it == theMap.end()) {
      // fprintf(stdout, "pKey not in map in mapValuu().\n");
      // qprintf(fp_dbg, "pKey not in map in mapValuu().\n");
      return pError;
   } // if(it == theMap.end())

   return it->second;
} // template <typename T> T *mapValuu(const std::map<const T *, T *> &theMap, const T *pKey, T *pError)




// qxmapValuu()

template <typename T> T *mapValuu(const std::map<const T *, T *> &theMap, const T *pKey, T *pError) {
   if(pKey == NULL) 
      return NULL;      // NULL never gets translated to anything else.

   typename std::map<const T *, T *>::const_iterator it = theMap.find(pKey);
   if(it == theMap.end()) {
      // fprintf(stdout, "pKey not in map in mapValuu().\n");
      // qprintf(fp_dbg, "pKey not in map in mapValuu().\n");
      return pError;
   } // if(it == theMap.end())

   return it->second;
} // template <typename T> T *mapValuu(const std::map<const T *, T *> &theMap, const T *pKey, T *pError)




// qxmapValuu()

template <typename T> const T *mapValuu(const std::map<const T *, const T *> &theMap, const T *pKey, const T *pError) {
   if(pKey == NULL) 
      return NULL;      // NULL never gets translated to anything else.

   typename std::map<const T *, const T *>::const_iterator it = theMap.find(pKey);
   if(it == theMap.end()) {
      // fprintf(stdout, "pKey not in map in mapValuu().\n");
      // qprintf(fp_dbg, "pKey not in map in mapValuu().\n");
      return pError;
   } // if(it == theMap.end())

   return it->second;
} // template <typename T> T *mapValuu(const std::map<const T *, T *> &theMap, const T *pKey, T *pError)




//
// returns value (copy).  Neither T nor U by reference.
//
//
//
//
// qxmapValu2()
//

template <typename T, typename U> U mapValu2(const std::map<T, U> &theMap, const T key, U error) {

   typename std::map<T, U>::const_iterator it = theMap.find(key);
   if(it == theMap.end()) {
      // fprintf(stdout, "pKey not in map in mapValuu().\n");
      // qprintf(fp_dbg, "pKey not in map in mapValuu().\n");
      return error;
   } // if(it == theMap.end())

   return it->second;
}



//
// returns non-const reference.  U but not T by reference.
//
//
//
//
// qxmapValu3v()

template <typename T, typename U> U &mapValu3v(std::map<T, U> &theMap, const T key, U &error) {

   typename std::map<T, U>::iterator it = theMap.find(key);
   if(it == theMap.end())
      return error;

   return it->second;
}



//
// returns const reference.  U but not T by reference.
//
//
//
//
// qxmapValu3c()

template <typename T, typename U> const U &mapValu3c(const std::map<T, U> &theMap, const T key, const U &error) {

   typename std::map<T, U>::const_iterator it = theMap.find(key);
   if(it == theMap.end())
      return error;

   return it->second;
}





//
// returns non-const reference.  Both T and U by reference.
//
//
//
//
// qxmapValu4v()

template <typename T, typename U> U &mapValu4v(std::map<T, U> &theMap, const T &key, U &error) {

   typename std::map<T, U>::iterator it = theMap.find(key);
   if(it == theMap.end())
      return error;

   return it->second;
}



//
// returns const reference.  Both T and U by reference.
//
//
//
//
// qxmapValu4c()

template <typename T, typename U> const U &mapValu4c(const std::map<T, U> &theMap, const T &key, const U &error) {

   typename std::map<T, U>::const_iterator it = theMap.find(key);
   if(it == theMap.end())
      return error;

   return it->second;
}





// the following from $95/smartPtr.cpp 08-06-20 (after changes there):

//
// for array values.
//
//
//
//
// qxRefCarr

template <typename T> class RefCarr {
private:
   T   *m_pData;
   int  m_refCt;
public:
   RefCarr(T *pDat=NULL) : m_pData(pDat), m_refCt(1) {}
   ~RefCarr() {if(m_pData!=NULL) delete [] m_pData;}

   int bumpCount() {m_refCt++; return m_refCt;}
   int decrCount() {
      int ict=--m_refCt;
      if(m_refCt<=0) {
         delete this;
      } // if(m_refCt<=0)
      return ict;
   }
   int getCt() const {return m_refCt;}
   int newData(T *pNuu) {
      if(pNuu != m_pData) {
         if(m_pData!=NULL) delete [] m_pData;
         m_pData = pNuu;
      } // if(pNuu != m_pData)
      return m_refCt;
   }
   int release() {
      int iRet = (m_pData!=NULL);
      m_pData = NULL;
      return iRet;
   }

   operator T *()             {return  m_pData;}
   operator T &()             {return *m_pData;}
   operator const T *() const {return  m_pData;}
   operator const T &() const {return *m_pData;}
   operator void *()          {return  (void *)m_pData;}
}; // template <typename T> class RefCarr




//
// Note: use only for ARRAY of T (else delete [] may barf)
//
//
//
// qxSmartParr
//

template <typename T> class SmartParr {
private:
   RefCarr<T> *m_pReffie;

public:
   SmartParr(T *pDat=NULL) : m_pReffie(new RefCarr<T>(pDat)) {}
   SmartParr(const SmartParr<T> &rs) : m_pReffie(rs.m_pReffie) {m_pReffie->bumpCount();}
   ~SmartParr() {m_pReffie->decrCount();}

   const SmartParr<T> &operator=(const SmartParr<T> &rs) {
      if(rs.m_pReffie != m_pReffie) {
         m_pReffie->decrCount();
         m_pReffie = rs.m_pReffie;
         m_pReffie->bumpCount();
      } // if(rs.m_pReffie != m_pReffie)

      return *this;
   }

   bool operator==(const SmartParr<T> &rs) const {return (rs.m_pReffie == m_pReffie);}
   bool operator!=(const SmartParr<T> &rs) const {return !operator==(rs);}

   int getCt() const    {return m_pReffie->getCt();}
   int newData(T *pNuu) {return m_pReffie->newData(pNuu);}
   int release()        {return m_pReffie->release();}

   operator T *()             {return  (T       *)(*m_pReffie);}     // not an error: member function of RefCarr<T>.
   operator T &()             {return  (T       &)(*m_pReffie);}
   operator const T *() const {return  (const T *)(*m_pReffie);}
   operator const T &() const {return  (const T &)(*m_pReffie);}
   operator void *()          {return  (void    *)(*m_pReffie);}

   bool operator<(const SmartParr<T> &rs) const  {return (((const T *)(*this)) < ((const T *)rs));}
}; // class SmartParr






//
// for scalar values.
//
//
//
//
// qxRefCt

template <typename T> class RefCt {
private:
   T   *m_pData;
   int  m_refCt;
public:
   RefCt(T *pDat=NULL) : m_pData(pDat), m_refCt(1) {}
   ~RefCt() {if(m_pData!=NULL) delete m_pData;}

   int bumpCount() {m_refCt++; return m_refCt;}
   int decrCount() {
      int ict=--m_refCt;
      if(m_refCt<=0) {
         delete this;
      } // if(m_refCt<=0)
      return ict;
   }
   int getCt() const {return m_refCt;}
   int newData(T *pNuu) {
      if(pNuu != m_pData) {
         if(m_pData!=NULL) delete m_pData;
         m_pData = pNuu;
      } // if(pNuu != m_pData)
      return m_refCt;
   }
   int release() {
      int iRet = (m_pData!=NULL);
      m_pData = NULL;
      return iRet;
   }

   operator T *()             {return  m_pData;}
   operator T &()             {return *m_pData;}
   operator const T *() const {return  m_pData;}
   operator const T &() const {return *m_pData;}
   operator void *()          {return  (void *)m_pData;}
}; // template <typename T> class RefCt




//
// Note: use only for single instance (not array) of T (else delete may barf)
//
//
//
// qxSmartPtr
//

template <typename T> class SmartPtr {
private:
   RefCt<T> *m_pReffie;

public:
   SmartPtr(T *pDat=NULL) : m_pReffie(new RefCt<T>(pDat)) {}
   SmartPtr(const SmartPtr<T> &rs) : m_pReffie(rs.m_pReffie) {m_pReffie->bumpCount();}
   ~SmartPtr() {m_pReffie->decrCount();}

   const SmartPtr<T> &operator=(const SmartPtr<T> &rs) {
      if(rs.m_pReffie != m_pReffie) {
         m_pReffie->decrCount();
         m_pReffie = rs.m_pReffie;
         m_pReffie->bumpCount();
      } // if(rs.m_pReffie != m_pReffie)

      return *this;
   }

   bool operator==(const SmartPtr<T> &rs) const {return (rs.m_pReffie == m_pReffie);}
   bool operator!=(const SmartPtr<T> &rs) const {return !operator==(rs);}

   int getCt() const    {return m_pReffie->getCt();}
   int newData(T *pNuu) {return m_pReffie->newData(pNuu);}
   int release()        {return m_pReffie->release();}


   operator T *()             {return  (T       *)(*m_pReffie);}     // not an error: member function of RefCt<T>.
   operator T &()             {return  (T       &)(*m_pReffie);}
   operator const T *() const {return  (const T *)(*m_pReffie);}
   operator const T &() const {return  (const T &)(*m_pReffie);}
   operator void *()          {return  (void    *)(*m_pReffie);}

   bool operator<(const SmartPtr<T> &rs) const  {return (((const T *)(*this)) < ((const T *)rs));}
}; // class SmartPtr






//
// new 04-13-18.  Possible substitute for operator==() for vetSet, etc.
//
//
//
//
//
// qxequivee()
//

template <typename T> bool equivee(const T &t1, const T &t2) {
   if(t1 < t2)
      return false;

   if(t2 < t1)
      return false;

   return true;
} // template <typename T> bool equivee(const T &t1, const T &t2)





//
// new 04-13-18.  Possible substitute for operator==() for vetSet, etc.  Direct version (use for int, pointers, etc.)
//
//
//
//
//
// qxequived()
//

template <typename T> bool equived(const T t1, const T t2) {
   if(t1 < t2)
      return false;

   if(t2 < t1)
      return false;

   return true;
} // template <typename T> bool equived(const T t1, const T t2)




//
// template for a vector-set pair.  Useful when we want no duplicates but also want to preserve order of entry.
// A vector by itself is slow for searching, but a set is fast (log(n)).
//
// Note: for pointers, vepSet, below, is more efficient.
//
//
//
//
// qxvetSet
//

template <typename T> class vetSet {
private:
   std::set<T>       m_sett;
   std::vector<T>    m_vecc;
public:
   vetSet()  {}
   vetSet(const vetSet &rs) : m_sett(rs.m_sett), m_vecc(rs.m_vecc) {}
   ~vetSet() {this->clear();}

   bool operator==(const vetSet &rs) const {
      if(m_sett != rs.m_sett)
         return false;
      if(m_vecc != rs.m_vecc)
         return false;

      return true;
   } // bool operator==(const vetSet &rs) const

   bool operator!=(const vetSet &rs) const {return !operator==(rs);}

   const vetSet &operator=(const vetSet &rs) {
      if(&rs != this) {
         m_sett = rs.m_sett;
         m_vecc = rs.m_vecc;
      } // if(&rs != this)
      return *this;
   } // const vetSet &operator=(const vetSet &rs)

   const vetSet &operator=(const std::vector<T> &rs) {    // <=== cross operator=().  Note that duplicates will be eaten!
      this->clear();
      for(int i=0; i<(int)rs.size(); i++)
         this->inserd(rs[i]);
      return *this;
   } // const vetSet &operator=(const vetSet &rs)

   void clear() {m_sett.clear(); m_vecc.clear();}

   int inserd(T tNew, int iSlot=-1) {          // "direct", not by reference.  insert(6) barfs. 
      return insert(tNew, iSlot);
   } // int inserd(T tNew)

   int insert(const T &tNew, int iSlot=-1) {
      int iRet = -1;

      if(m_sett.find(tNew) == m_sett.end()) {
         m_sett.insert(tNew);
         if(iSlot < 0) {
            m_vecc.push_back(tNew);
            iRet = (int)m_vecc.size() - 1;   // index of newly inserted element.
         } else {
//          unsigned int isiz = (unsigned int)m_vecc.size();
            int isiz = (int)m_vecc.size();
            m_vecc.resize(isiz+1);

            // push zero or more current entries down/up to make room for the new guy:
            int jSlot = MIN(iSlot, isiz);
            for(int i=isiz; i>jSlot; i--)
               m_vecc[i] = m_vecc[i-1];

            m_vecc[jSlot] = tNew;

            iRet = jSlot;              // index of newly inserted element.
         } // if(iSlot < 0)
      } else {
         iRet = -1;  // signal it was already there.
      } // !if(m_sett.find(pNew) == m_sett.end())

      return iRet;
   } // int insert()

   bool bIsIn(const T &tThis) const {return (m_sett.find(tThis) != m_sett.end());}
   bool bIsId(T  tThis) const {return (m_sett.find(tThis) != m_sett.end());}
// int  nIn()  const {return m_vecc.size();}
   size_t  size() const {return m_vecc.size();}
   const T &getIth(int ith) const {
      const static T statT;     // a default instance of class T

      if((ith < 0) || (ith >= (int)size()))
         return statT;

      return m_vecc[ith];
   } // getIth(int ith)

   const T &operator[](int ith) const {return getIth(ith);}
// T &operator[](int ith) {return (T &)((const vetSet<T> *)this)->getIth(ith);} // would allow for corruption between vector and set.

   const std::set<T>    &getSet() const {return m_sett;}
   const std::vector<T> &getVec() const {return m_vecc;}

   int erasd(T tDelMe) {          // "direct", not by reference.  erase(6) barfs.  More efficient if T is a pointer
      return erase(tDelMe);
   } // int erasd(T tDelMe) {

   int erase(T &tDelMe) {
      if(!bIsIn(tDelMe))
         return -1;

      bool bDidIt = false;
      for(int i=0; i<(int)size(); i++) {
//       if(tDelMe == m_vecc[i]) {        // danger?  operator==() may not be same as "equivalent" using operator<().
         if(equivee(tDelMe, m_vecc[i])) { 
            // found it.  Move everybody else down and resize:
            for(int j=i+1; j<(int)size(); j++) {
               m_vecc[j-1] = m_vecc[j];
            } // for(int j=i+1; j<(int)size(); j++)
            m_vecc.resize(size() - 1);
            bDidIt = true;
            break;
         } // if(pDelMe == m_vecc[i])
      } // for(int i=0; i<(int)size(); i++)
      if(bDidIt) {
         // expected
         m_sett.erase(tDelMe);
      } else {
         // some horrible problem.
         return -2;
      } // !if(bDidIt)

      return 0;
   } // int erase()

   int replace(int indx, T &tNuu) {
      if(bIsIn(tNuu))
         return -1;                              // this class doesn't allow duplicates

      if((indx < 0) || (indx >= (int)size()))
         return -2;

      m_sett.erase(m_vecc[indx]);
      m_vecc[indx] = tNuu;
      m_sett.insert(m_vecc[indx]);

      return 0;
   } // int replace(int indx, T &tNuu)

   int findd(T tFindMe) {          // "direct", not by reference.  erase(6) barfs.  More efficient if T is a pointer
      return find(tFindMe);
   } // int erasd(T tDelMe) {

   int find(T &tFindMe) const {
      if(!bIsIn(tFindMe))
         return -1;

      for(int i=0; i<(int)size(); i++) {
         if(equivee(tFindMe, m_vecc[i]))
            return i;                           // found it.
      } // for(int i=0; i<(int)size(); i++)

      return -2;   // some horrible problem: corruption.
   } // int find(T &tFindMe) const

}; // class vetSet






//
// new 10-13-17.  Like vetSet but specifically tailored for pointers.
//
// template for a vector-set pair.  Useful when we want no duplicates but also want to preserve order of entry.
// A vector by itself is slow for searching, but a set is fast (log(n)).
//
//
//
//
//
// 12-20-19 (jdl): m_bNullForbid.
//
// qxvepSet
//

template <typename T> class vepSet {
private:
   std::set<T *>       m_sett;
   std::vector<T *>    m_vecc;
   bool                m_bNullForbid;
public:
   vepSet(bool bnf=false) : m_bNullForbid(bnf)  {}
   vepSet(const vepSet &rs) : m_sett(rs.m_sett), m_vecc(rs.m_vecc), m_bNullForbid(rs.m_bNullForbid) {}
   ~vepSet() {this->clear();}

   bool operator==(const vepSet &rs) const {
      if(m_sett != rs.m_sett)
         return false;
      if(m_vecc != rs.m_vecc)
         return false;
      if(m_bNullForbid != rs.m_bNullForbid)
         return false;

      return true;
   } // bool operator==(const vepSet &rs) const

   bool operator!=(const vepSet &rs) const {return !operator==(rs);}

   const vepSet &operator=(const vepSet &rs) {
      if(&rs != this) {
         m_sett = rs.m_sett;
         m_vecc = rs.m_vecc;
         m_bNullForbid = rs.m_bNullForbid;
      } // if(&rs != this)

      return *this;
   } // const vepSet &operator=(const vepSet &rs)

   const vepSet &operator=(const std::vector<T *> &rs) {   // <=== cross operator=().  Note that duplicates will be eaten!
      this->clear();
      for(int i=0; i<(int)rs.size(); i++)
         this->insert(rs[i]);
      return *this;
   } // const vepSet &operator=(const vepSet &rs)

   void clear() {m_sett.clear(); m_vecc.clear(); m_bNullForbid=false;}

   int insert(T *tNew, int iSlot=-1) {
      int iRet = -1;
      if((tNew == NULL) && m_bNullForbid)
         return -2;

      if(m_sett.find(tNew) == m_sett.end()) {
         m_sett.insert(tNew);
         if(iSlot < 0) {
            m_vecc.push_back(tNew);
            iRet = (int)m_vecc.size() - 1;   // index of newly inserted element.
         } else {
            int isiz = (int)m_vecc.size();
            m_vecc.resize(isiz+1);

            // push zero or more current entries down/up to make room for the new guy:
            int jSlot = MIN(iSlot, isiz);
            for(int i=isiz; i>jSlot; i--)
               m_vecc[i] = m_vecc[i-1];

            m_vecc[jSlot] = tNew;

            iRet = jSlot;              // index of newly inserted element.
         } // if(iSlot < 0)
      } else {
         iRet = -1;  // signal it was already there.
      } // !if(m_sett.find(pNew) == m_sett.end())

      return iRet;
   } // int insert()

   bool bIsIn(const T *pThis) const {return (m_sett.find((T *)pThis) != m_sett.end());}
   size_t  size() const {return m_vecc.size();}
   const T *getIth(int ith) const {
      if((ith < 0) || (ith >= (int)size()))
         return NULL;

      return m_vecc[ith];
   } // getIth(int ith)

   const T *operator[](int ith) const {return getIth(ith);}
   T *operator[](int ith)             {return (T *)((const vepSet<T> *)this)->getIth(ith);}

   const std::set<T *>    &getSet() const {return m_sett;}
   const std::vector<T *> &getVec() const {return m_vecc;}

   int erase(T *pDelMe) {
      if(!bIsIn(pDelMe))
         return -1;

      bool bDidIt = false;
      for(int i=0; i<(int)size(); i++) {
//       if(pDelMe == m_vecc[i]) {        // danger?  operator==() may not be same as "equivalent" using operator<().
         if(equived(pDelMe, m_vecc[i])) { 
            // found it.  Move everybody else down and resize:
            for(int j=i+1; j<(int)size(); j++) {
               m_vecc[j-1] = m_vecc[j];
            } // for(int j=i+1; j<(int)size(); j++)
            m_vecc.resize((int)size() - 1);
            bDidIt = true;
            break;
         } // if(pDelMe == m_vecc[i])
      } // for(int i=0; i<(int)size(); i++)
      if(bDidIt) {
         // expected
         m_sett.erase(pDelMe);
      } else {
         // some horrible problem.
         return -2;
      } // !if(bDidIt)

      return 0;
   } // int erase()

   int replace(int indx, T *pNuu) {
      if(bIsIn(pNuu))
         return -1;                              // this class doesn't allow duplicates

      if((indx < 0) || (indx >= (int)size()))
         return -2;

      m_sett.erase(m_vecc[indx]);
      m_vecc[indx] = pNuu;
      m_sett.insert(m_vecc[indx]);

      return 0;
   } // int replace(int indx, T *pNuu)

   int find(T *pFindMe) const {
      if(!bIsIn(pFindMe))
         return -1;

      for(int i=0; i<(int)size(); i++) {
         if(equived(pFindMe, m_vecc[i]))
            return i;                           // found it.
      } // for(int i=0; i<(int)size(); i++)

      return -2;   // some horrible problem: corruption.
   } // int find(T &tFindMe) const

}; // class vepSet






//
// new 12-30-17, from vepMap.  Like vepMap but without pointer req. 
//
// template for a vector-map pair.  Useful when we want no duplicates but also want to preserve order of entry.
// A vector by itself is slow for searching, but a map is fast (log(n)).
//
//
//
//
//
//
// qxvetMap
//

template <typename T, typename U> class vetMap {
private:
   std::map<T, U>    m_mapp;
   std::vector<T>    m_vecc;
public:
   vetMap()  {}
   vetMap(const vetMap &rs) : m_mapp(rs.m_mapp), m_vecc(rs.m_vecc) {}
   ~vetMap() {this->clear();}

   bool operator==(const vetMap &rs) const {
      if(m_mapp != rs.m_mapp)
         return false;
      if(m_vecc != rs.m_vecc)
         return false;

      return true;
   } // bool operator==(const vetMap &rs) const

   bool operator!=(const vetMap &rs) const {return !operator==(rs);}

   const vetMap &operator=(const vetMap &rs) {
      if(&rs != this) {
         m_mapp = rs.m_mapp;
         m_vecc = rs.m_vecc;
      } // if(&rs != this)

      return *this;
   } // const vetMap &operator=(const vetMap &rs)

   void clear() {m_mapp.clear(); m_vecc.clear();}

   int insert(const T &tNew, const U &uNew, int iSlot=-1) {
      int iRet = -1;

      if(m_mapp.find(tNew) == m_mapp.end()) {
         m_mapp[tNew] = uNew;

         if(iSlot < 0) {
            m_vecc.push_back(tNew);
            iRet = (int)m_vecc.size() - 1;   // index of newly inserted element.
         } else {
            int isiz = (int)m_vecc.size();
            m_vecc.resize(isiz+1);

            // push zero or more current entries down/up to make room for the new guy:
            int jSlot = MIN(iSlot, isiz);
            for(int i=isiz; i>jSlot; i--)
               m_vecc[i] = m_vecc[i-1];

            m_vecc[jSlot] = tNew;

            iRet = jSlot;              // index of newly inserted element.
         } // if(iSlot < 0)
      } else {
         iRet = -1;  // signal it was already there.
      } // !if(m_mapp.find(pNew) == m_mapp.end())

      return iRet;
   } // int insert()

   int update(const T &tOld, const U &uNew) {
      if(!bIsIn(tOld))
         return -1;

      m_mapp[tOld] = uNew;

      return 0;
   } // int update()...

   bool bIsIn(const T &tThis) const {return (m_mapp.find(tThis) != m_mapp.end());}
   size_t  size() const {return m_vecc.size();}

   const T &getIth(int ith) const {
      const static T statT;     // a default instance of class T

      if((ith < 0) || (ith >= (int)size()))
         return statT;

      return m_vecc[ith];
   } // getIth(int ith)

   const U &getUth(const T &tT, const U &uError) const {
      typename std::map<T, U>::const_iterator it = m_mapp.find(tT);
      if(it == m_mapp.end()) {
         return uError;
      } else {
         return it->second;
      } // if(it == m_mapp.end())
   } // getUth(int ith)


   const U &getUth(const T &tT) const {
      const static U uError;

      return getUth(tT, uError);

#ifdef DEAD_CODE
      std::map<T, U>::const_iterator it = m_mapp.find(tT);
      if(it == m_mapp.end()) {
         return uError;   // qxl: what??
      } else {
         return it->second;
      } // if(it == m_mapp.end())
#endif // DEAD_CODE
   } // getUth(int ith)

   // non-const (creates entry if necessary, as does a plain std::map):
   U &getUtnc(T &tT) {
      typename std::map<T, U>::iterator it = m_mapp.find(tT);
      if(it == m_mapp.end()) {
         U uDummy;
         this->insert(tT, uDummy);
      } // if(it == m_mapp.end())

      return m_mapp[tT];
   } // getUtnc(int ith)

#ifdef CHANGED_MY_MIND
// const T &operator[](int ith) const {return getIth(ith);}
// T &operator[](int ith)             {return (T &)((const vetMap<T, U> *)this)->getIth(ith);}

   const U &operator[](const T &tT) const {return getUth(tT);}
   U &operator[](T &tT)                   {return getUtnc(tT);}
#endif // CHANGED_MY_MIND

   const T &operator[](int ith) const {return getIth(ith);}
// T &operator[](int ith)             {return (T &)((const vetMap<T, U> *)this)->getIth(ith);} // would allow for corruption between vector and map.

// const U &operator[](const T &tT) const {return getUth(tT);}
// U &operator[](T &tT)                   {return getUtnc(tT);}

   const std::map<T, U>   &getMap() const {return m_mapp;}
   const std::vector<T>   &getVec() const {return m_vecc;}

   int erase(T &tDelMe) {
      if(!bIsIn(tDelMe))
         return -1;

      bool bDidIt = false;
      for(int i=0; i<(int)size(); i++) {
//       if(tDelMe == m_vecc[i]) {        // danger?  operator==() may not be same as "equivalent" using operator<().
         if(equivee(tDelMe, m_vecc[i])) { 
            // found it.  Move everybody else down and resize:
            for(int j=i+1; j<(int)size(); j++) {
               m_vecc[j-1] = m_vecc[j];
            } // for(int j=i+1; j<(int)size(); j++)
            m_vecc.resize((int)size() - 1);
            bDidIt = true;
            break;
         } // if(tDelMe == m_vecc[i])
      } // for(int i=0; i<(int)size(); i++)
      if(bDidIt) {
         // expected
         m_mapp.erase(tDelMe);
      } else {
         // some horrible problem.
         return -2;
      } // !if(bDidIt)

      return 0;
   } // int erase()

   int findd(T tFindMe) {          // "direct", not by reference.  erase(6) barfs.  More efficient if T is a pointer
      return find(tFindMe);
   } // int erasd(T tDelMe) {

   int find(T &tFindMe) const {
      if(!bIsIn(tFindMe))
         return -1;

      for(int i=0; i<(int)size(); i++) {
         if(equivee(tFindMe, m_vecc[i]))
            return i;                           // found it.
      } // for(int i=0; i<(int)size(); i++)

      return -2;   // some horrible problem: corruption.
   } // int find(T &tFindMe) const

}; // class vetMap






//
// new 12-13-17, from vepSet.  Like vepSet but with a map.
//
// template for a vector-map pair.  Useful when we want no duplicates but also want to preserve order of entry.
// A vector by itself is slow for searching, but a map is fast (log(n)).
//
//
//
//
//
// 12-20-19 (jdl): m_bNullForbid.
//
// qxvepMap
//

template <typename T, typename U> class vepMap {
private:
   std::map<T *, U>    m_mapp;
   std::vector<T *>    m_vecc;
   bool                m_bNullForbid;
public:
   vepMap(bool bnf=false) : m_bNullForbid(bnf)  {}
   vepMap(const vepMap &rs) : m_mapp(rs.m_mapp), m_vecc(rs.m_vecc), m_bNullForbid(rs.m_bNullForbid) {}
   ~vepMap() {this->clear();}

   bool operator==(const vepMap &rs) const {
      if(m_mapp != rs.m_mapp)
         return false;
      if(m_vecc != rs.m_vecc)
         return false;
      if(m_bNullForbid != rs.m_bNullForbid)
         return false;

      return true;
   } // bool operator==(const vepMap &rs) const

   bool operator!=(const vepMap &rs) const {return !operator==(rs);}

   const vepMap &operator=(const vepMap &rs) {
      if(&rs != this) {
         m_mapp = rs.m_mapp;
         m_vecc = rs.m_vecc;
         m_bNullForbid = rs.m_bNullForbid;
      } // if(&rs != this)

      return *this;
   } // const vepMap &operator=(const vepMap &rs)

   void clear() {m_mapp.clear(); m_vecc.clear(); m_bNullForbid=false;}

   int insert(T *tNew, const U &uNew, int iSlot=-1) {
      int iRet = -1;
      if((tNew == NULL) && m_bNullForbid)
         return -2;

      if(m_mapp.find(tNew) == m_mapp.end()) {
         m_mapp[tNew] = uNew;

         if(iSlot < 0) {
            m_vecc.push_back(tNew);
            iRet = (int)m_vecc.size() - 1;   // index of newly inserted element.
         } else {
            int isiz = (int)m_vecc.size();
            m_vecc.resize(isiz+1);

            // push zero or more current entries down/up to make room for the new guy:
            int jSlot = MIN(iSlot, isiz);
            for(int i=isiz; i>jSlot; i--)
               m_vecc[i] = m_vecc[i-1];

            m_vecc[jSlot] = tNew;

            iRet = jSlot;              // index of newly inserted element.
         } // if(iSlot < 0)
      } else {
         iRet = -1;  // signal it was already there; caller should use update() to modify an existing entry.
      } // !if(m_mapp.find(pNew) == m_mapp.end())

      return iRet;
   } // int insert()

   int update(T *tOld, const U &uNew) {
      if(!bIsIn(tOld))
         return -1;

      m_mapp[tOld] = uNew;

      return 0;
   } // int update()...

   bool bIsIn(const T *pThis) const {return (m_mapp.find((T *)pThis) != m_mapp.end());}
   size_t  size() const {return m_vecc.size();}

   const T *getIth(int ith) const {
      if((ith < 0) || (ith >= (int)size()))
         return NULL;

      return m_vecc[ith];
   } // getIth(int ith)

   const U &getUth(const T *pT) const {
      const static U uError;

      typename std::map<T *, U>::const_iterator it = m_mapp.find((T *)pT);
      if(it == m_mapp.end()) {
         return uError;   // qxl: what??
      } else {
         return it->second;
      } // if(it == m_mapp.end())
   } // getUth(int ith)

   // non-const (creates entry if necessary, as does a plain std::map):
   U &getUtnc(T *pT) {
      typename std::map<T *, U>::iterator it = m_mapp.find(pT);
      if(it == m_mapp.end()) {
         U uDummy;
         this->insert(pT, uDummy);
      } // if(it == m_mapp.end())

      return m_mapp[pT];
   } // getUtnc(int ith)

   const T *operator[](int ith) const {return getIth(ith);}
   T *operator[](int ith)             {return (T *)((const vepMap<T, U> *)this)->getIth(ith);}

   const U &operator[](const T *pT) const {return getUth(pT);}
   U &operator[](T *pT)                   {return getUtnc(pT);}

   const std::map<T *, U> &getMap() const {return m_mapp;}
   const std::vector<T *> &getVec() const {return m_vecc;}

   int erase(T *pDelMe) {
      if(!bIsIn(pDelMe))
         return -1;

      bool bDidIt = false;
      for(int i=0; i<(int)size(); i++) {
//       if(pDelMe == m_vecc[i]) {        // danger?  operator==() may not be same as "equivalent" using operator<().
         if(equived(pDelMe, m_vecc[i])) { 
            // found it.  Move everybody else down and resize:
            for(int j=i+1; j<(int)size(); j++) {
               m_vecc[j-1] = m_vecc[j];
            } // for(int j=i+1; j<(int)size(); j++)
            m_vecc.resize(size() - 1);
            bDidIt = true;
            break;
         } // if(pDelMe == m_vecc[i])
      } // for(int i=0; i<(int)size(); i++)
      if(bDidIt) {
         // expected
         m_mapp.erase(pDelMe);
      } else {
         // some horrible problem.
         return -2;
      } // !if(bDidIt)

      return 0;
   } // int erase()

   int find(T *pFindMe) const {
      if(!bIsIn(pFindMe))
         return -1;

      for(int i=0; i<(int)size(); i++) {
         if(equived(pFindMe, m_vecc[i]))
            return i;                           // found it.
      } // for(int i=0; i<(int)size(); i++)

      return -2;   // some horrible problem: corruption.
   } // int find(T &tFindMe) const


}; // class vepMap



const unsigned char *getUpc();
const unsigned char *getLwc();
const unsigned char *getSmc();

int doLwc(std::string &ssInOut);


std::string ksprintf(const char *ckorm, double dVal);
std::string formatMode(int mode, bool bRaw);

int match(const char *pattern, const char *candidate, const unsigned char *pArrCmp);
int match(const unsigned char *pattern, const unsigned char *candidate, const unsigned char *pArrCmp);
char *date_format(time_t time_in, char *string_out);


int mkdirWrap(const char *pcDestDir, FILE *fp_inf=NULL);

int cutLineIntoTokens(const char *lineIn, std::vector<std::string> &vecTokensOut);
int cutLineIntoTokens(const char *lineIn, const std::string &ssSeparators, std::vector<std::string> &vecTokensOut, bool bTrimSp=false, bool bLankFieldsOK=false);

int unAbsify(const std::string &ssAbsIn, std::string &ssRelOut);
int fixSlashes(const std::string &ssIn, std::string &ssOut);

char *comma_me(int int_in, char *cbuf, int len_s);
char *comma_me(long long ll_in, char *cbuf, int len_s);

std::string rmCr(const std::string &ssIn);
std::string adCr(const std::string &ssIn);
std::string ssVcToSs(const std::vector<std::string> &vcSsIn, bool bCr);
int countCrLf(const char *pcIn, int &nCrOut, int &nLfOut);
int vcUcToSs(const std::vector<unsigned char> &vcIn, std::string &ssOut);
int vcSsToSs(const std::vector<std::string> &vcIn, std::string &ssOut);
int findDenom(double dRat, int denomLo, int denomTooHi);
int findNumDenom(double dRat, int denomLo, int denomTooHi, int &numOut, int &denOut);
const char *fnPlural(int n, const char *cpPlural=NULL, const char *cpSingular=NULL);


#ifdef _WIN32
unsigned long long getProccyTime();
unsigned long long getProccyTime(std::vector<unsigned long long> &vcAppend);

inline unsigned long long combineFiletime(const FILETIME &combineMe) {
   return (((unsigned long long)combineMe.dwHighDateTime) << 32) + (unsigned long long)combineMe.dwLowDateTime;
}
#endif // _WIN32


#ifndef _WIN32

char getch(void);
int kbhit();
void set_keypress(void);
void reset_keypress(void);

#endif // !_WIN32

int jcpp(const char *file_from, const char *file_to);
std::string ReplaceExtension(const char *pcOldName, const char *pcNewExtension);

signed long long timeGetTime64();



int getSeedFromPwd(std::vector<unsigned long long> &fillMe);
int getSeedFromPwd(std::vector<unsigned long long> &fillMe, std::vector<unsigned long long> &fillM2, int nCycle);




#endif // GLOBS_H







