#include "SUMA_suma.h"
#include "../thd_brainormalize.h"
#include "../rickr/r_new_resam_dset.h"
#undef STAND_ALONE

#if defined SUMA_BrainWrap_STANDALONE
#define STAND_ALONE 
#endif

#ifdef STAND_ALONE
/* these global variables must be declared even if they will not be used by this main */
SUMA_SurfaceViewer *SUMAg_cSV = NULL; /*!< Global pointer to current Surface Viewer structure*/
SUMA_SurfaceViewer *SUMAg_SVv = NULL; /*!< Global pointer to the vector containing the various Surface Viewer Structures 
                                    SUMAg_SVv contains SUMA_MAX_SURF_VIEWERS structures */
int SUMAg_N_SVv = 0; /*!< Number of SVs realized by X */
SUMA_DO *SUMAg_DOv = NULL;   /*!< Global pointer to Displayable Object structure vector*/
int SUMAg_N_DOv = 0; /*!< Number of DOs stored in DOv */
SUMA_CommonFields *SUMAg_CF = NULL; /*!< Global pointer to structure containing info common to all viewers */
#else
extern SUMA_CommonFields *SUMAg_CF;
extern SUMA_DO *SUMAg_DOv;
extern SUMA_SurfaceViewer *SUMAg_SVv;
extern int SUMAg_N_SVv; 
extern int SUMAg_N_DOv;  
#endif

#ifdef SUMA_BrainWrap_STANDALONE
void usage_SUMA_BrainWrap (SUMA_GENERIC_ARGV_PARSE *ps)
   {
      static char FuncName[]={"usage_SUMA_BrainWrap"};
      char * s = NULL, *sio=NULL, *st = NULL, *sts = NULL;
      int i;
      s = SUMA_help_basics();
      sio  = SUMA_help_IO_Args(ps);
      sts = SUMA_help_talk(ps);
      printf ( "\n"
               "Usage: A program to extract the brain from surrounding.\n"
               "  tissue from MRI T1-weighted images. The fully automated\n"
               "  process consists of three steps:\n"
               "  1- Preprocessing of volume to remove gross spatial image \n"
               "  non-uniformity artifacts and reposition the brain in\n"
               "  a reasonable manner for convenience.\n"
               "  2- Expand a spherical surface iteratively until it envelopes\n"
               "  the brain. This is a modified version of the BET algorithm:\n"
               "     Fast robust automated brain extraction, \n"
               "      by Stephen M. Smith, HBM 2002 v 17:3 pp 143-155\n"
               "    Modifications include the use of:\n"
               "     . outer brain surface\n"
               "     . expansion driven by data inside and outside the surface\n"
               "     . avoidance of eyes and ventricles\n"
               "     . a set of operations to avoid the clipping of certain brain\n"
               "       areas and reduce leakage into the skull in heavily shaded\n"
               "       data\n"
               "     . two additional processing stages to ensure convergence and\n"
               "       reduction of clipped areas.\n"
               "     . use of 3d edge detection, see Deriche and Monga references\n"
               "       in 3dedge3 -help.\n"
               "  3- The creation of various masks and surfaces modeling brain\n"
               "     and portions of the skull\n"
               "\n"
               "  Common examples of usage:\n"
               "  -------------------------\n"
               "  o 3dSkullStrip -input VOL -prefix VOL_PREFIX\n"
               "     Vanilla mode, should work for most datasets.\n"
               "  o 3dSkullStrip -input VOL -prefix VOL_PREFIX -push_to_edge\n"
               "     Adds an agressive push to brain edges. Use this option\n"
               "     when the chunks of gray matter are not included. This option\n"
               "     might cause the mask to leak into non-brain areas.\n"
               "  o 3dSkullStrip -input VOL -surface_coil -prefix VOL_PREFIX -monkey\n"
               "     Vanilla mode, for use with monkey data.\n"
               "  o 3dSkullStrip -input VOL -prefix VOL_PREFIX -ld 30\n"
               "     Use a denser mesh, in the cases where you have lots of \n"
               "     csf between gyri. Also helps when some of the brain is clipped\n"
               "     close to regions of high curvature.\n"
               "\n"
               "  Tips:\n"
               "  -----\n"
               "     I ran the program with the default parameters on 200+ datasets.\n"
               "     The results were quite good in all but a couple of instances, here\n"
               "     are some tips on fixing trouble spots:\n"  
               "\n"
               "     Clipping in frontal areas, close to the eye balls:\n"
               "        + Try -push_to_edge option first.\n"
               "          Can also try -no_avoid_eyes option.\n"
               "     Clipping in general:\n"
               "        + Try -push_to_edge option first.\n"
               "          Can also use lower -shrink_fac, start with 0.5 then 0.4\n"
               "     Problems down below:\n"
               "        + Piece of cerbellum missing, reduce -shrink_fac_bot_lim \n"
               "          from default value.\n"
               "        + Leakage in lower areas, increase -shrink_fac_bot_lim \n"
               "          from default value.\n"
               "     Some lobules are not included:\n"
               "        + Use a denser mesh. Start with -ld 30. If that still fails,\n"
               "        try even higher density (like -ld 50) and increase iterations \n"
               "        (say to -niter 750). Expect the program to take much longer in that case.\n"
               "        + Instead of using denser meshes, you could try blurring the data \n"
               "        before skull stripping. Something like -blur_fwhm 2 did\n"
               "        wonders for some of my data with the default options of 3dSkullStrip\n"
               "        Blurring is a lot faster than increasing mesh density.\n"
               "        + Use also a smaller -shrink_fac is you have lots of CSF between gyri.\n"
               "     Massive chunks missing:\n"
               "        + If brain has very large ventricles and lots of CSF between gyri, the\n"
               "        ventricles will keep attracting the surface inwards. In such cases, use\n"
               "        the -visual option to see what is happening and try these options to \n"
               "        reduce the severity of the problem:\n"
               "            -blur_fwhm 2 -use_skull\n"
               "\n" 
               "  Eye Candy Mode: \n"
               "  ---------------\n"
               "  You can run BrainWarp and have it send successive iterations\n"
               " to SUMA and AFNI. This is very helpful in following the\n"
               " progression of the algorithm and determining the source\n"
               " of trouble, if any.\n"
               "  Example:\n"
               "     afni -niml -yesplugouts &\n"
               "     suma -niml &\n"
               "     3dSkullStrip -input Anat+orig -o_ply anat_brain -visual\n"
               "\n"
               "  Help section for the intrepid:\n"
               "  ------------------------------\n" 
               "  3dSkullStrip  < -input VOL >\n"
               "             [< -o_TYPE PREFIX >] [< -prefix VOL_PREFIX >] \n"
               "             [< -spatnorm >] [< -no_spatnorm >] [< -write_spatnorm >]\n"
               "             [< -niter N_ITER >] [< -ld LD >] \n"
               "             [< -shrink_fac SF >] [< -var_shrink_fac >] \n"
               "             [< -no_var_shrink_fac >] [< -shrink_fac_bot_lim SFBL >]\n"
               "             [< -pushout >] [< -no_pushout >] [< -exp_frac FRAC]\n"
               "             [< -touchup >] [< -no_touchup >]\n"
               "             [< -fill_hole R >] [< -NN_smooth NN_SM >]\n"
               "             [< -smooth_final SM >] [< -avoid_vent >] [< -no_avoid_vent >]\n"
               "             [< -use_skull >] [< -no_use_skull >] \n"
               "             [< -avoid_eyes >] [< -no_avoid_eyes >] \n"
               "             [< -use_edge >] [< -no_use_edge >] \n"
               "             [< -push_to_edge >] [<-no_push_to_edge>]\n"
               "             [< -perc_int PERC_INT >] \n"
               "             [< -max_inter_iter MII >] [-mask_vol | -orig_vol | -norm_vol]\n"
               "             [< -debug DBG >] [< -node_debug NODE_DBG >]\n"
               "             [< -demo_pause >]\n"
               "             [< -monkey >] [<-rat>]\n"  
               "\n"
               "  NOTE: Please report bugs and strange failures\n"
               "        to saadz@mail.nih.gov\n"
               "\n"
               "  Mandatory parameters:\n"
               "     -input VOL: Input AFNI (or AFNI readable) volume.\n"
               "                 \n"
               "\n"
               "  Optional Parameters:\n"
               "     -monkey: the brain of a monkey.\n"
               "     -rat: the brain of a rat.\n"
               "           By default, no_touchup is used with the rat.\n"
               "     -surface_coil: Data acquired with a surface coil.\n"
               "     -o_TYPE PREFIX: prefix of output surface.\n"
               "        where TYPE specifies the format of the surface\n"
               "        and PREFIX is, well, the prefix.\n"
               "        TYPE is one of: fs, 1d (or vec), sf, ply.\n"
               "        More on that below.\n"
               "     -skulls: Output surface models of the skull.\n"
               "     -4Tom:   The output surfaces are named based\n"
               "             on PREFIX following -o_TYPE option below.\n"
               "     -prefix VOL_PREFIX: prefix of output volume.\n"
               "        If not specified, the prefix is the same\n"
               "        as the one used with -o_TYPE.\n"
               "        The output volume is skull stripped version\n"
               "        of the input volume. In the earlier version\n"
               "        of the program, a mask volume was written out.\n" 
               "        You can still get that mask volume instead of the\n"
               "        skull-stripped volume with the option -mask_vol . \n"
               "        NOTE: In the default setting, the output volume does not \n"
               "              have values identical to those in the input. \n"
               "              In particular, the range might be larger \n"
               "              and some low-intensity values are set to 0.\n"
               "              If you insist on having the same range of values as in\n"
               "              the input, then either use option -orig_vol, or run:\n"
               "         3dcalc -nscale -a VOL+VIEW -b VOL_PREFIX+VIEW \\\n"
               "                -expr 'a*step(b)' -prefix VOL_SAME_RANGE\n"
               "              With the command above, you can preserve the range\n"
               "              of values of the input but some low-intensity voxels would still\n"
               "              be masked. If you want to preserve them, then use -mask_vol\n"
               "              in the 3dSkullStrip command that would produce \n"
               "              VOL_MASK_PREFIX+VIEW. Then run 3dcalc masking with voxels\n"
               "              inside the brain surface envelope:\n"
               "         3dcalc -nscale -a VOL+VIEW -b VOL_MASK_PREFIX+VIEW \\\n"
               "                -expr 'a*step(b-3.01)' -prefix VOL_SAME_RANGE_KEEP_LOW\n"
               "     -norm_vol: Output a masked and somewhat intensity normalized and \n"
               "                thresholded version of the input. This is the default,\n"
               "                and you can use -orig_vol to override it.\n"
               "     -orig_vol: Output a masked version of the input AND do not modify\n"
               "                the values inside the brain as -norm_vol would.\n"
               "     -mask_vol: Output a mask volume instead of a skull-stripped\n"
               "                volume.\n"
               "                The mask volume containes:\n"
               "                 0: Voxel outside surface\n"
               "                 1: Voxel just outside the surface. This means the voxel\n"
               "                    center is outside the surface but inside the \n"
               "                    bounding box of a triangle in the mesh. \n"
               "                 2: Voxel intersects the surface (a triangle), but center\n"
               "                    lies outside.\n"
               "                 3: Voxel contains a surface node.\n"
               "                 4: Voxel intersects the surface (a triangle), center lies\n"
               "                    inside surface. \n"
               "                 5: Voxel just inside the surface. This means the voxel\n"
               "                    center is inside the surface and inside the \n"
               "                    bounding box of a triangle in the mesh. \n"
               "                 6: Voxel inside the surface. \n"
               "     -spat_norm: (Default) Perform spatial normalization first.\n"
               "                 This is a necessary step unless the volume has\n"
               "                 been 'spatnormed' already.\n"
               "     -no_spatnorm: Do not perform spatial normalization.\n"
               "                   Use this option only when the volume \n"
               "                   has been run through the 'spatnorm' process\n"
               "     -spatnorm_dxyz DXYZ: Use DXY for the spatial resolution of the\n"
               "                          spatially normalized volume. The default \n"
               "                          is the lowest of all three dimensions.\n"
               "                          For human brains, use DXYZ of 1.0, for\n"
               "                          primate brain, use the default setting.\n"
               "     -write_spatnorm: Write the 'spatnormed' volume to disk.\n"
               "     -niter N_ITER: Number of iterations. Default is 250\n"
               "        For denser meshes, you need more iterations\n"
               "        N_ITER of 750 works for LD of 50.\n"
               "     -ld LD: Parameter to control the density of the surface.\n"
               "             Default is 20 if -no_use_edge is used,\n"
               "             30 with -use_edge. See CreateIcosahedron -help\n"
               "             for details on this option.\n"
               "     -shrink_fac SF: Parameter controlling the brain vs non-brain\n"
               "             intensity threshold (tb). Default is 0.6.\n"
               "              tb = (Imax - t2) SF + t2 \n"
               "             where t2 is the 2 percentile value and Imax is the local\n"
               "             maximum, limited to the median intensity value.\n"
               "             For more information on tb, t2, etc. read the BET paper\n"
               "             mentioned above. Note that in 3dSkullStrip, SF can vary across \n"
               "             iterations and might be automatically clipped in certain areas.\n"
               "             SF can vary between 0 and 1.\n"
               "             0: Intensities < median inensity are considered non-brain\n"
               "             1: Intensities < t2 are considered non-brain\n" 
               "     -var_shrink_fac: Vary the shrink factor with the number of\n"
               "             iterations. This reduces the likelihood of a surface\n"
               "             getting stuck on large pools of CSF before reaching\n"
               "             the outer surface of the brain. (Default)\n"
               "     -no_var_shrink_fac: Do not use var_shrink_fac.\n"
               "     -shrink_fac_bot_lim SFBL: Do not allow the varying SF to go\n"
               "             below SFBL . Default 0.65, 0.4 when edge detection is used. \n"
               "             This option helps reduce potential for leakage below \n"
               "             the cerebellum.\n"
               "             In certain cases where you have severe non-uniformity resulting\n"
               "             in low signal towards the bottom of the brain, you will need to reduce\n"
               "             this parameter.\n"
/*               "     -shrink_fac_bias SHRINK_BIAS_FILE: A file containing bias \n"
               "                      factors to apply to the shrink_fac at certain nodes.\n"
               "                      This option is experimental at the moment.\n"
               "                      Column 0 has node indices, Col. 1 has the bias factors\n" */
               "     -pushout: Consider values above each node in addition to values\n"
               "               below the node when deciding on expansion. (Default)\n"
               "     -no_pushout: Do not use -pushout.\n"
               "     -exp_frac FRAC: Speed of expansion (see BET paper). Default is 0.1.\n"
               "     -touchup: Perform touchup operations at end to include\n"
               "               areas not covered by surface expansion. \n"
               "               Use -touchup -touchup for aggressive makeup.\n"
               "               (Default is -touchup)\n"
               "     -no_touchup: Do not use -touchup\n"
               "     -fill_hole R: Fill small holes that can result from small surface\n"
               "                   intersections caused by the touchup operation.\n"
               "                   R is the maximum number of pixels on the side of a hole\n"
               "                   that can be filled. Big holes are not filled.\n"
               "                   If you use -touchup, the default R is 10. Otherwise \n"
               "                   the default is 0.\n"
               "                   This is a less than elegant solution to the small\n"
               "                   intersections which are usually eliminated\n"
               "                   automatically. \n"
               "     -NN_smooth NN_SM: Perform Nearest Neighbor coordinate interpolation\n"
               "                       every few iterations. Default is 72\n"
               "     -smooth_final SM: Perform final surface smoothing after all iterations.\n"
               "                       Default is 20 smoothing iterations.\n"
               "                       Smoothing is done using Taubin's method, \n"
               "                       see SurfSmooth -help for detail.\n"
               "     -avoid_vent: avoid ventricles. Default.\n"
               "     -no_avoid_vent: Do not use -avoid_vent.\n"
               "     -init_radius RAD: Use RAD for the initial sphere radius.\n"
               "                       For the automatic setting, there is an\n"
               "                       upper limit of 80mm for humans.\n"
               "     -avoid_eyes: avoid eyes. Default\n"
               "     -no_avoid_eyes: Do not use -avoid_eyes.\n"
               "     -use_edge: Use edge detection to reduce leakage into meninges and eyes.\n"
               "                Default.\n"
               "     -no_use_edge: Do no use edges.\n"
               "     -push_to_edge: Perform aggressive push to edge at the end.\n"
               "                    This option might cause leakage.\n"
               "     -no_push_to_edge: (Default).\n"
               "     -use_skull: Use outer skull to limit expansion of surface into\n"
               "                 the skull due to very strong shading artifacts.\n"
               "                 This option is buggy at the moment, use it only \n"
               "                 if you have leakage into skull.\n"
               "     -no_use_skull: Do not use -use_skull (Default).\n"
               "     -send_no_skull: Do not send the skull surface to SUMA if you are\n"
               "                     using  -talk_suma\n" 
               "     -perc_int PERC_INT: Percentage of segments allowed to intersect\n"
               "                         surface. Ideally this should be 0 (Default). \n"
               "                         However, few surfaces might have small stubborn\n"
               "                         intersections that produce a few holes.\n"
               "                         PERC_INT should be a small number, typically\n"
               "                         between 0 and 0.1\n. A -1 means do not do\n"
               "                         any testing for intersection.\n"
               "     -max_inter_iter N_II: Number of iteration to remove intersection\n"
               "                           problems. With each iteration, the program\n"
               "                           automatically increases the amount of smoothing\n"
               "                           to get rid of intersections. Default is 4\n"
               "     -blur_fwhm FWHM: Blur dset after spatial normalization.\n"
               "                      Recommended when you have lots of CSF in brain\n"
               "                      and when you have protruding gyri (finger like)\n"
               "                      Recommended value is 2..4. \n"
               "     -interactive: Make the program stop at various stages in the \n"
               "                   segmentation process for a prompt from the user\n"
               "                   to continue or skip that stage of processing.\n"
               "                   This option is best used in conjunction with options\n"
               "                   -talk_suma and -feed_afni\n"
               "     -demo_pause: Pause at various step in the process to facilitate\n"
               "                  interactive demo while 3dSkullStrip is communicating\n"
               "                  with AFNI and SUMA. See 'Eye Candy' mode below and\n"
               "                  -talk_suma option. \n"
               "\n"
               "%s"
               "     -visual: Equivalent to using -talk_suma -feed_afni -send_kth 5\n"
               "\n"
               "     -debug DBG: debug levels of 0 (default), 1, 2, 3.\n"
               "        This is no Rick Reynolds debug, which is oft nicer\n"
               "        than the results, but it will do.\n"
               "     -node_debug NODE_DBG: Output lots of parameters for node\n"
               "                         NODE_DBG for each iteration.\n"
               "     The next 3 options are for specifying surface coordinates\n"
               "     to keep the program from having to recompute them.\n"
               "     The options are only useful for saving time during debugging.\n"
               "     -brain_contour_xyz_file BRAIN_CONTOUR_XYZ.1D\n"
               "     -brain_hull_xyz_file BRAIN_HULL_XYZ.1D\n"
               "     -skull_outer_xyz_file SKULL_OUTER_XYZ.1D\n"
               "\n"
               /*
               "     -sm_fac SMFAC: Smoothing factor (Default is 1)\n"
               "     -d1 D1: Distance to search inward (Default 20 mm)\n"
               "     -t2 T2: Force t2 to be T2 (Default automated)\n"
               "     -t T: Force t to be T (Default automated)\n"
               "     -tm TM: Force tm to be TM (Default automated)\n"
               "     -t98 T98: Force t98 to be T98 (Default automated)\n"
               */
               "%s"
               "\n", sio,  s);
       SUMA_free(s); s = NULL; SUMA_free(st); st = NULL; SUMA_free(sio); sio = NULL; SUMA_free(sts); sts = NULL;         
       s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
       printf("       Ziad S. Saad SSCC/NIMH/NIH saadz@mail.nih.gov     \n");
       exit (0);
   }
/*!
   \brief parse the arguments for SurfSmooth program
   
   \param argv (char *)
   \param argc (int)
   \return Opt (SUMA_GENERIC_PROG_OPTIONS_STRUCT *) options structure.
               To free it, use 
               SUMA_free(Opt->out_name); 
               SUMA_free(Opt);
*/
SUMA_GENERIC_PROG_OPTIONS_STRUCT *SUMA_BrainWrap_ParseInput (char *argv[], int argc, SUMA_GENERIC_ARGV_PARSE *ps)
{
   static char FuncName[]={"SUMA_BrainWrap_ParseInput"}; 
   SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt=NULL;
   int kar, i, ind, exists;
   char *outname, cview[10];
   SUMA_Boolean brk = NOPE;
   SUMA_Boolean LocalHead = NOPE;

   SUMA_ENTRY;
   
   Opt = SUMA_Alloc_Generic_Prog_Options_Struct();
   
   kar = 1;
   Opt->SpatNormDxyz = 0.0;
   Opt->spec_file = NULL;
   Opt->out_vol_prefix = NULL;
   Opt->out_prefix = NULL;
   Opt->sv_name = NULL;
   Opt->N_surf = -1;
   Opt->in_name = NULL;
   Opt->cmask = NULL;
   Opt->MaskMode = 0;
   for (i=0; i<SUMA_GENERIC_PROG_MAX_SURF; ++i) { Opt->surf_names[i] = NULL; }
   outname = NULL;
   Opt->in_vol = NULL;
   Opt->nvox = -1;
   Opt->ninmask = -1;
   Opt->mcdatav = NULL;
   Opt->debug = 0;
   Opt->v0 = 0.0;
   Opt->v1 = -1.0;
   Opt->fvec = NULL;
   Opt->SurfFileType = SUMA_PLY;
   Opt->SurfFileFormat = SUMA_ASCII;
   Opt->xform = SUMA_ISO_XFORM_MASK;
   Opt->obj_type = -1;
   Opt->obj_type_res = -1;
   Opt->XYZ = NULL;
   Opt->in_1D = NULL;
   Opt->N_XYZ = 0;
   Opt->Zt = 0.6;
   Opt->ExpFrac = 0.1;
   Opt->N_it = 250;
   Opt->Icold = -1;
   Opt->NodeDbg = -1;
   Opt->t2 = Opt->t98 = Opt->t = Opt->tm = -1;
   Opt->r = -1.0;
   Opt->d1 = -1;
   Opt->su1 = 1;
   Opt->UseNew = -1.0;
   Opt->d4 = -1;
   Opt->ztv = NULL;
   Opt->Kill98 = 0;
   Opt->NoEyes = 1;
   Opt->NNsmooth = 72;
   Opt->smootheach = 50;
   Opt->avoid_vent = 1;
   Opt->smooth_end = 20;
   Opt->k98mask = NULL;
   Opt->k98maskcnt = 0;
   Opt->dbg_eyenodes = NULL;
   Opt->travstp = 1.0;
   Opt->Stop = NULL;
   Opt->MaxIntIter = 4;
   Opt->UseExpansion = 1;
   Opt->PercInt = 0;
   Opt->UseSkull = 0;
   Opt->send_hull = 1;
   Opt->bot_lztclip = -1; /* 0.5 is OK but causes too much leakage below cerebellum in most dsets, 0.65 seems better. 0 if you do not want to use it*/
	Opt->var_lzt = 1.0; /* a flag at the moment, set it to 1 to cause shirnk fac to vary during iterations. Helps escape certain large 
                           chunks of CSF just below the brain */
   Opt->DemoPause = SUMA_3dSS_NO_PAUSE;
   Opt->DoSpatNorm = 1;
   Opt->WriteSpatNorm = 0;
   Opt->fillhole = -1;
   Opt->iset = NULL;
   Opt->SpatShift[0] = Opt->SpatShift[1] = Opt->SpatShift[2] = 0.0;
   Opt->OrigSpatNormedSet = NULL;
   Opt->in_edvol = NULL;
   Opt->blur_fwhm = 0.0;
   Opt->shrink_bias_name = NULL;
   Opt->shrink_bias = NULL;
   Opt->specie = HUMAN;
   Opt->Use_emask = 1;
   Opt->emask  = NULL;
   Opt->PushToEdge = -1;
   Opt->DoSkulls = 0;
   Opt->UseThisBrain = NULL;
   Opt->UseThisBrainHull = NULL;
   Opt->UseThisSkullOuter = NULL;
      
   brk = NOPE;
	while (kar < argc) { /* loop accross command ine options */
		/*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
		if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
			 usage_SUMA_BrainWrap(ps);
          exit (0);
		}
		
		SUMA_SKIP_COMMON_OPTIONS(brk, kar);
      
      if (!brk && (strcmp(argv[kar], "-pushout") == 0)) {
         Opt->UseExpansion = 1;
         brk = YUP;
      }
      
      if (!brk && ( (strcmp(argv[kar], "-4Tom") == 0) || (strcmp(argv[kar], "-skulls") == 0) ) ) {
         Opt->DoSkulls = 1;
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-monkey") == 0)) {
         Opt->specie = MONKEY;
         brk = YUP;
      }
      if (!brk && (strcmp(argv[kar], "-rat") == 0)) {
         Opt->specie = RAT;
         brk = YUP;
      }
      if (!brk && (strcmp(argv[kar], "-visual") == 0)) {
         ps->cs->talk_suma = 1;
         ps->cs->kth = 5;
         ps->cs->Feed2Afni = 1;
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-no_pushout") == 0)) {
         Opt->UseExpansion = 0;
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-spatnorm") == 0)) {
         Opt->DoSpatNorm = 1;
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-no_spatnorm") == 0)) {
         Opt->DoSpatNorm = 0;
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-write_spatnorm") == 0)) {
         Opt->WriteSpatNorm = 1;
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-use_skull") == 0)) {
         Opt->UseSkull = 1;
         brk = YUP;
      }

      if (!brk && (strcmp(argv[kar], "-no_use_skull") == 0)) {
         Opt->UseSkull = 0;
         brk = YUP;
      }

      if (!brk && (strcmp(argv[kar], "-send_no_skull") == 0)) {
         Opt->send_hull = 0;
         brk = YUP;
      }
      
      
      if (!brk && (strcmp(argv[kar], "-var_shrink_fac") == 0)) {
         Opt->var_lzt = 1;
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-no_var_shrink_fac") == 0)) {
         Opt->var_lzt = 0;
         brk = YUP;
      }
      
      
      if (!brk && (strcmp(argv[kar], "-fill_hole") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -fill_hole \n");
				exit (1);
			}
         Opt->fillhole = atoi(argv[kar]);
         if ( (Opt->fillhole < 0 || Opt->fillhole > 50) ) {
            fprintf (SUMA_STDERR, "parameter after -fill_hole (%d) should be >= 0 and <= 50 \n", Opt->fillhole);
				exit (1);
         }
         brk = YUP;
      }
            
      if (!brk && (strcmp(argv[kar], "-perc_int") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -perc_int \n");
				exit (1);
			}
			Opt->PercInt = atof(argv[kar]);
         if ( (Opt->PercInt < 0 && Opt->PercInt != -1) || Opt->PercInt > 10) {
            fprintf (SUMA_STDERR, "parameter after -perc_int should be -1 or between 0 and 10 (have %f) \n", Opt->PercInt);
				exit (1);
         }
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-spatnorm_dxyz") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -spatnorm_dxyz \n");
				exit (1);
			}
			Opt->SpatNormDxyz = atof(argv[kar]);
         if ( Opt->SpatNormDxyz < 0  || Opt->SpatNormDxyz > 10) {
            fprintf (SUMA_STDERR, "parameter after -spatnorm_dxyz should be between 0 and 10 (have %f) \n", 
                     Opt->SpatNormDxyz);
				exit (1);
         }
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-blur_fwhm") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -blur_fwhm \n");
				exit (1);
			}
			Opt->blur_fwhm = atof(argv[kar]);
         if ( Opt->blur_fwhm < 0 || Opt->blur_fwhm > 50) {
            fprintf (SUMA_STDERR, "parameter after -blur_fwhm should be between 0 and 50 (have %f) \n", Opt->blur_fwhm);
				exit (1);
         }
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-init_radius") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -init_radius \n");
				exit (1);
			}
			Opt->r = atof(argv[kar]);
         if ( Opt->r <= 0 || Opt->r > 100) {
            fprintf (SUMA_STDERR, "parameter after -init_radius should be between 0 and 100 (have %f) \n", Opt->r);
				exit (1);
         }
         brk = YUP;
		}
      if (!brk && (strcmp(argv[kar], "-input_1D") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -input_1D \n");
				exit (1);
			}
			Opt->in_1D = argv[kar];
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-brain_contour_xyz_file") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -brain_contour_xyz_file \n");
				exit (1);
			}
			Opt->UseThisBrain = argv[kar];
         brk = YUP;
		}      
      
      if (!brk && (strcmp(argv[kar], "-brain_hull_xyz_file") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -brain_hull_xyz_file \n");
				exit (1);
			}
			Opt->UseThisBrainHull = argv[kar];
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-skull_outer_xyz_file") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -skull_outer_xyz_file \n");
				exit (1);
			}
			Opt->UseThisSkullOuter = argv[kar];
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-avoid_vent") == 0)) {
			Opt->avoid_vent = 1;
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-no_avoid_vent") == 0)) {
			Opt->avoid_vent = 0;
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-demo_pause") == 0)) {
			Opt->DemoPause = SUMA_3dSS_DEMO_PAUSE;
         brk = YUP;
		} 
      
      if (!brk && (strcmp(argv[kar], "-interactive") == 0)) {
			Opt->DemoPause = SUMA_3dSS_INTERACTIVE;
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-d1") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -d1 \n");
				exit (1);
			}
			Opt->d1 = atof(argv[kar]);
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-max_inter_iter") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -max_inter_iter \n");
				exit (1);
			}
			Opt->MaxIntIter = atoi(argv[kar]);
         if (Opt->MaxIntIter < 0 || Opt->MaxIntIter > 10) {
            fprintf (SUMA_STDERR, "-max_inter_iter parameter should be between 0 and 10 \n");
				exit (1);
         }  
         brk = YUP;
		}
      if (!brk && (strcmp(argv[kar], "-smooth_final") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -smooth_final \n");
				exit (1);
			}
			Opt->smooth_end = atoi(argv[kar]);
         if (Opt->smooth_end < 0 || Opt->smooth_end > 100 || Opt->smooth_end % 2) {
            fprintf (SUMA_STDERR, "irrational or exhuberant values for smooth_final\n Must use even number between 0 to 100 (%d entered)\n", Opt->smooth_end);
				exit (1);
         }
         brk = YUP;
		}
      if (!brk && (strcmp(argv[kar], "-NNsmooth") == 0 || strcmp(argv[kar], "-NN_smooth") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -NN_smooth \n");
				exit (1);
			}
			Opt->NNsmooth = atoi(argv[kar]);
         if (Opt->NNsmooth % 2) {
            fprintf (SUMA_STDERR, "Number of smoothing steps must be an even positive number (not %d) \n", Opt->NNsmooth);
				exit (1);
         }
         brk = YUP;
		}
      
      if (!brk && ((strcmp(argv[kar], "-shrink_fac") == 0) || (strcmp(argv[kar], "-bf") == 0))) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -shrink_fac || -bf \n");
				exit (1);
			}
			Opt->Zt = atof(argv[kar]);
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-shrink_fac_bot_lim") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -shrink_fac_bot_lim \n");
				exit (1);
			}
			Opt->bot_lztclip = atof(argv[kar]);
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-t2") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -t2 \n");
				exit (1);
			}
			Opt->t2 = atof(argv[kar]);
         brk = YUP;
		}
      if (!brk && (strcmp(argv[kar], "-t98") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -t98 \n");
				exit (1);
			}
			Opt->t98 = atof(argv[kar]);
         brk = YUP;
		}
      if (!brk && (strcmp(argv[kar], "-t") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -t \n");
				exit (1);
			}
			Opt->t = atof(argv[kar]);
         brk = YUP;
		}
      if (!brk && (strcmp(argv[kar], "-tm") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -tm \n");
				exit (1);
			}
			Opt->tm = atof(argv[kar]);
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-niter") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -niter \n");
				exit (1);
			}
			Opt->N_it = atoi(argv[kar]);
         if (Opt->N_it < 0 || Opt->N_it > 100000) {
            fprintf (SUMA_STDERR, "%d is a bad iteration number.\n", Opt->N_it);
				exit (1);
         }
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-exp_frac") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -exp_frac \n");
				exit (1);
			}
			Opt->ExpFrac = atof(argv[kar]);
         if (Opt->ExpFrac < -1 || Opt->ExpFrac > 1) { /* accroding to algo, should be between 0 and 1 */
            fprintf (SUMA_STDERR, "%f is a bad expantion fraction.\n", Opt->ExpFrac);
				exit (1);
         }
         brk = YUP;
		}
      if (!brk && ( (strcmp(argv[kar], "-node_dbg") == 0) || (strcmp(argv[kar], "-node_debug") == 0)) ) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -node_debug \n");
				exit (1);
			}
			Opt->NodeDbg = atoi(argv[kar]);
         if (Opt->NodeDbg < 0) {
            fprintf (SUMA_STDERR, "%d is a bad node number.\n", Opt->NodeDbg);
				exit (1);
         }
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-sm_fac") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -sm_fac \n");
				exit (1);
			}
			Opt->su1 = atof(argv[kar]);
         if (Opt->su1 < 0 || Opt->su1 > 1.5) {
            fprintf (SUMA_STDERR, "%f is a bad smoothness factor (acceptable range is 0 to 1\nbut values up to 1.5 are allowed for amusement).\n", Opt->su1);
				exit (1);
         }
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-ld") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -ld \n");
				exit (1);
			}
			Opt->Icold = atoi(argv[kar]);
         if (Opt->Icold < 0 || Opt->Icold > 300) {
            fprintf (SUMA_STDERR, "%d is a bad iteration number.\n", Opt->Icold);
				exit (1);
         }
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-debug") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -debug \n");
				exit (1);
			}
			Opt->debug = atoi(argv[kar]);
         if (Opt->debug > 2) { LocalHead = YUP; }
         brk = YUP;
		}      
      
     
      if (!brk && (strcmp(argv[kar], "-input") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -input \n");
				exit (1);
			}
			Opt->in_name = SUMA_copy_string(argv[kar]);
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-use_edge") == 0)) {
			Opt->Use_emask = 1;
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-no_use_edge") == 0)) {
			Opt->Use_emask = 0;
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-push_to_edge") == 0)) {
			Opt->PushToEdge = 1;
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-no_push_to_edge") == 0)) {
			Opt->PushToEdge = 0;
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-shrink_fac_bias") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -shrink_fac_bias \n");
				exit (1);
			}
			Opt->shrink_bias_name = SUMA_copy_string(argv[kar]);
         brk = YUP;
		}
      
      if (!brk && (strcmp(argv[kar], "-prefix") == 0)) {
         kar ++;
			if (kar >= argc)  {
		  		fprintf (SUMA_STDERR, "need argument after -prefix \n");
				exit (1);
			}
			Opt->out_vol_prefix = SUMA_copy_string(argv[kar]);
         brk = YUP;
		}
      
      if (!brk && ( (strcmp(argv[kar], "-mask_vol") == 0) ) ) {
         Opt->MaskMode = 1;
         brk = YUP;
      }
      if (!brk && ( (strcmp(argv[kar], "-orig_vol") == 0) ) ) {
         Opt->MaskMode = 2;
         brk = YUP;
      }
      if (!brk && ( (strcmp(argv[kar], "-norm_vol") == 0) ) ) {
         Opt->MaskMode = 0;
         brk = YUP;
      }
      if (!brk && ( (strcmp(argv[kar], "-touchup") == 0) ) ) {
         if (Opt->UseNew < 0) Opt->UseNew = 1.0;
         else ++ Opt->UseNew;
         brk = YUP;
      }
      
      if (!brk && ( (strcmp(argv[kar], "-no_touchup") == 0) ) ) {
         Opt->UseNew = 0.0;
         brk = YUP;
      }
      
      if (!brk && ( (strcmp(argv[kar], "-surface_coil") == 0) ) ) {
         Opt->SurfaceCoil = 1;
         brk = YUP;
      }
      
      if (!brk && (strcmp(argv[kar], "-k98") == 0)) {
         SUMA_SL_Warn("Bad option, causes trouble (big clipping) in other parts of brain.");
         Opt->Kill98 = 1;
         brk = YUP;
      }
      
      if (!brk && ( (strcmp(argv[kar], "-noeyes") == 0) || (strcmp(argv[kar], "-no_eyes") == 0) || (strcmp(argv[kar], "-avoid_eyes") == 0)) ) {
         Opt->NoEyes = 1;
         brk = YUP;
      }
      
      if (!brk && ( (strcmp(argv[kar], "-no_noeyes") == 0) || (strcmp(argv[kar], "-no_no_eyes") == 0) || (strcmp(argv[kar], "-no_avoid_eyes") == 0)) ) {
         Opt->NoEyes = 0;
         brk = YUP;
      }
      
      if (!brk && !ps->arg_checked[kar]) {
			fprintf (SUMA_STDERR,"Error %s:\nOption %s not understood. Try -help for usage\n", FuncName, argv[kar]);
			exit (1);
		} else {	
			brk = NOPE;
			kar ++;
		}
   }
   
   if (Opt->UseNew < 0) {
      if (Opt->specie != RAT) {
         Opt->UseNew = Opt->UseNew * -1.0;
      } else {
         Opt->UseNew = 0; /* not for ze ghat monsieur */
      }
   }
   
   if (Opt->PushToEdge < 0) Opt->PushToEdge = 0;
   
   if (Opt->PushToEdge > 0 && Opt->Use_emask <= 0) {
      fprintf(SUMA_STDERR,"Error %s:\nCannot use -push_to_edge without -use_edge\n", FuncName);
      exit (1);      
   }
   
   if (Opt->bot_lztclip < 0) {
      if (!Opt->Use_emask) Opt->bot_lztclip = 0.65;
      else Opt->bot_lztclip = 0.4;
   }
   
   if (Opt->Icold < 0) {
      if (!Opt->Use_emask) Opt->Icold = 20;
      else Opt->Icold = 30;
   }
   
   if (Opt->fillhole < 0) {
      if (Opt->UseExpansion) {
         if (Opt->debug) {
            SUMA_SL_Note("Setting fill_hole to 10");
         }
         Opt->fillhole = 10;
      } else  Opt->fillhole = 0;
   }
   
   /* transfer some options to Opt from ps. Clunky because this is retrofitting */
   if (ps->o_N_surfnames) {
      Opt->out_prefix = SUMA_copy_string(ps->o_surfnames[0]);
      Opt->SurfFileType = ps->o_FT[0];
      Opt->SurfFileFormat = ps->o_FF[0];
   }
   
   if (Opt->DoSkulls && !ps->o_N_surfnames) {
      fprintf (SUMA_STDERR,"Error %s:\n-skulls must be used in conjunction with -o_TYPE option\n", FuncName);
      exit(1);
   }
   
   if (!Opt->in_name) {
      fprintf (SUMA_STDERR,"Error %s:\n-input  must be used.\n", FuncName);
      exit(1);
   }
   /* what is the view of the input ?*/
   if (!SUMA_AfniView (Opt->in_name, cview)) {
      fprintf (SUMA_STDERR,"Error %s:\nCould not guess view from input dset %s\n", FuncName, Opt->in_name);
      exit(1);
   }

   if (!Opt->out_prefix) Opt->out_prefix = SUMA_copy_string("skull_strip_out");
   if (!Opt->out_vol_prefix) {
      if (!Opt->out_prefix) Opt->out_vol_prefix = SUMA_AfniPrefix("skull_strip_out", NULL, NULL, &exists);
      else Opt->out_vol_prefix = SUMA_AfniPrefix(Opt->out_prefix, NULL, NULL, &exists);
   } else {
      char *stmp = Opt->out_vol_prefix;
      Opt->out_vol_prefix = SUMA_AfniPrefix(stmp, NULL, NULL, &exists); 
      SUMA_free(stmp); stmp = NULL;
   }
   if (SUMA_AfniExistsView(exists, cview)) {
      fprintf (SUMA_STDERR,"Error %s:\nOutput dset %s%s exists, will not overwrite\n", FuncName, Opt->out_vol_prefix, cview);
      exit(1);
   }

   
   if (Opt->t2 >= 0 || Opt->t98 >= 0 || Opt->tm >= 0  || Opt->t >= 0 ) {
      if (!(Opt->t2 >= 0 && Opt->t98 > 0 && Opt->tm > 0 && Opt->t > 0)){
         fprintf (SUMA_STDERR,"Error %s: \nAll or none of the t parameters are to be specified on command line:\nt2 %f t %f tm %f t98 %f\n", 
            FuncName, Opt->t2, Opt->t, Opt->tm, Opt->t98);
         exit(1);
      }
   }
   
    
   SUMA_RETURN(Opt);
}




int main (int argc,char *argv[])
{/* Main */    
   static char FuncName[]={"3dSkullStrip"}; 
	int i, N_in = 0, i3, kth_buf, hull_ld;
   int ii,jj,kk,ll,ijk , nx,ny,nz , nn, nint = 0 , nseg;
   void *SO_name=NULL, *SO_name_hull=NULL, *SO_name_bhull = NULL, *SO_name_iskull = NULL, *SO_name_oskull = NULL;
   float vol, *isin_float=NULL, pint, *dsmooth = NULL, XYZrai_shift[3];
   SUMA_SurfaceObject *SO = NULL, *SOhull=NULL;
   SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt;  
   char  stmp[200], stmphull[200], *hullprefix=NULL, *prefix=NULL, *spatprefix=NULL, cbuf,
         *bhullprefix=NULL, *oskullprefix=NULL, *iskullprefix=NULL;
   SUMA_Boolean exists = NOPE;
   SUMA_GENERIC_ARGV_PARSE *ps=NULL;
   short *isin = NULL;
   SUMA_FORM_AFNI_DSET_STRUCT *OptDs = NULL;
   THD_3dim_dataset *dset = NULL;
   THD_ivec3 orixyz , nxyz ;
   THD_fvec3 dxyz , orgxyz , fv2, originRAIfv;
   THD_3dim_dataset *oset = NULL;
   MRI_IMAGE *imin=NULL, *imout=NULL, *imout_orig=NULL  ;
   
   SUMA_Boolean LocalHead = NOPE;

   SUMA_STANDALONE_INIT;
	SUMA_mainENTRY;
   

   /* Allocate space for DO structure */
	SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS);
   ps = SUMA_Parse_IO_Args(argc, argv, "-o;-talk;");
   
   if (argc < 2) {
      usage_SUMA_BrainWrap(ps);
      exit (1);
   }
   
   Opt = SUMA_BrainWrap_ParseInput (argv, argc, ps);

   if (Opt->debug > 2) LocalHead = YUP;

   SO_name = SUMA_Prefix2SurfaceName(Opt->out_prefix, NULL, NULL, Opt->SurfFileType, &exists);
   if (exists && strcmp(Opt->out_prefix,"skull_strip_out")) { /* do not worry about the default name for the surface */
      fprintf(SUMA_STDERR,"Error %s:\nOutput file(s) %s* on disk.\nWill not overwrite.\n", FuncName, Opt->out_prefix);
      exit(1);
   }
   bhullprefix = SUMA_append_string(Opt->out_prefix,"_brainhull");
   oskullprefix = SUMA_append_string(Opt->out_prefix,"_outerskull");
   iskullprefix = SUMA_append_string(Opt->out_prefix,"_innerskull");
   SO_name_bhull = SUMA_Prefix2SurfaceName(bhullprefix, NULL, NULL, Opt->SurfFileType, &exists);
   if (exists && strcmp(Opt->out_prefix,"skull_strip_out")) {
      fprintf(SUMA_STDERR,"Error %s:\nOutput file(s) %s* on disk.\nWill not overwrite.\n", FuncName, Opt->out_prefix);
      exit(1);
   }   
   SO_name_iskull = SUMA_Prefix2SurfaceName(iskullprefix, NULL, NULL, Opt->SurfFileType, &exists);
   if (exists && strcmp(Opt->out_prefix,"skull_strip_out")) {
      fprintf(SUMA_STDERR,"Error %s:\nOutput file(s) %s* on disk.\nWill not overwrite.\n", FuncName, Opt->out_prefix);
      exit(1);
   }  
   SO_name_oskull = SUMA_Prefix2SurfaceName(oskullprefix, NULL, NULL, Opt->SurfFileType, &exists);
   if (exists && strcmp(Opt->out_prefix,"skull_strip_out")) {
      fprintf(SUMA_STDERR,"Error %s:\nOutput file(s) %s* on disk.\nWill not overwrite.\n", FuncName, Opt->out_prefix);
      exit(1);
   }   
   
   hullprefix = SUMA_append_string(Opt->out_prefix,"_hull");
   SO_name_hull = SUMA_Prefix2SurfaceName(hullprefix, NULL, NULL, Opt->SurfFileType, &exists);
   if (exists) {
      fprintf(SUMA_STDERR,"Error %s:\nOutput file(s) %s* on disk.\nWill not overwrite.\n", FuncName, hullprefix);
      exit(1);
   }   
   kth_buf = ps->cs->kth; /* keep track of required value */
   
   /* turn on debugging for inodes */
   #if 0
   SUMA_SL_Note("Debugging for eye nodes");
   Opt->dbg_eyenodes = fopen("eyenodes.1D.dset", "w");
   #endif
   
   /* Load the AFNI volume and prep it*/
   if (Opt->DoSpatNorm) { /* chunk taken from 3dSpatNorm.c */
      if (Opt->debug) SUMA_SL_Note("Loading dset, performing Spatial Normalization");
      /* load the dset */
      Opt->iset = THD_open_dataset( Opt->in_name );
      if( !ISVALID_DSET(Opt->iset) ){
        fprintf(stderr,"**ERROR: can't open dataset %s\n",Opt->in_name) ;
        exit(1);
      }
      Opt->iset_hand = SUMA_THD_handedness( Opt->iset );
      if (LocalHead) fprintf(SUMA_STDERR,"%s: Handedness of orig dset %d\n", FuncName, Opt->iset_hand);
      
      /*--- get median brick --*/
      imin = THD_median_brick( Opt->iset ) ;
      if( imin == NULL ){
        fprintf(stderr,"**ERROR: can't load dataset %s\n",Opt->in_name) ;
        exit(1);
      }
      
      mri_speciebusiness(Opt->specie);
      if (Opt->SpatNormDxyz) {
         if (Opt->debug) SUMA_S_Note("Overriding default resampling");
         mri_brainormalize_initialize(Opt->SpatNormDxyz, Opt->SpatNormDxyz, Opt->SpatNormDxyz);
      } else {
         float xxdel, yydel, zzdel, minres;
         if (Opt->specie == MONKEY) minres = 0.5;
         else if (Opt->specie == RAT) minres = 0.1;
         else minres = 0.5;
         /* don't allow for too low a resolution, please */
         if (SUMA_ABS(Opt->iset->daxes->xxdel) < minres) xxdel = minres;
         else xxdel = SUMA_ABS(Opt->iset->daxes->xxdel);
         if (SUMA_ABS(Opt->iset->daxes->yydel) < minres) yydel = minres;
         else yydel = SUMA_ABS(Opt->iset->daxes->yydel);
         if (SUMA_ABS(Opt->iset->daxes->zzdel) < minres) zzdel = minres;
         else zzdel = SUMA_ABS(Opt->iset->daxes->zzdel);
         if (Opt->debug) {
            fprintf(SUMA_STDERR,"%s:\n Original resolution %f, %f, %f\n SpatNorm resolution %f, %f, %f\n",
                        FuncName, Opt->iset->daxes->xxdel, Opt->iset->daxes->yydel, Opt->iset->daxes->zzdel, 
                        xxdel, yydel, zzdel);
         }   
         mri_brainormalize_initialize(xxdel, yydel, zzdel);
      }
      
      if (Opt->d1 < 0) {
         Opt->d1 = 20.0/THD_BN_rat(); /* account for size difference */
      }
      if (Opt->d4 < 0) {
         Opt->d4 = 15.0/THD_BN_rat(); /* account for size difference */
      }
      
      if (Opt->debug > 1) fprintf(SUMA_STDERR,"%s: Size Ratio = %f\n", FuncName, THD_BN_rat());
      
      imin->dx = fabs(Opt->iset->daxes->xxdel) ;
      imin->dy = fabs(Opt->iset->daxes->yydel) ;
      imin->dz = fabs(Opt->iset->daxes->zzdel) ;

      DSET_unload( Opt->iset ) ;  /* don't need this data no more */

      /*-- convert image to shorts, if appropriate --*/
      if( DSET_BRICK_TYPE(Opt->iset,0) == MRI_short ||
          DSET_BRICK_TYPE(Opt->iset,0) == MRI_byte    ){

        imout = mri_to_short(1.0,imin) ;
        mri_free(imin) ; imin = imout ;
      }

      /*--- normalize image spatially ---*/
      mri_brainormalize_verbose( Opt->debug ) ;
      if (Opt->fillhole) {
         imout = mri_brainormalize( imin , Opt->iset->daxes->xxorient,
                                        Opt->iset->daxes->yyorient,
                                        Opt->iset->daxes->zzorient, &imout_orig, NULL) ;
      } else {
         imout = mri_brainormalize( imin , Opt->iset->daxes->xxorient,
                                        Opt->iset->daxes->yyorient,
                                        Opt->iset->daxes->zzorient, &imout_orig, NULL) ;
      }
      mri_free( imin ) ;

      if( imout == NULL ){
        fprintf(stderr,"**ERROR: normalization fails!?\n"); exit(1);
      }
      
      if (imout_orig) {
         if (Opt->debug > 1) SUMA_S_Note("Creating an output dataset in original grid...");
         /* me needs the origin of this dset in RAI world */
         LOAD_FVEC3(originRAIfv , Opt->iset->daxes->xxorg , Opt->iset->daxes->yyorg , Opt->iset->daxes->zzorg) ;
         originRAIfv = THD_3dmm_to_dicomm( Opt->iset , originRAIfv ) ;

         LOAD_FVEC3(fv2 , Opt->iset->daxes->xxorg + (Opt->iset->daxes->nxx-1)*Opt->iset->daxes->xxdel ,
                    Opt->iset->daxes->yyorg + (Opt->iset->daxes->nyy-1)*Opt->iset->daxes->yydel ,
                    Opt->iset->daxes->zzorg + (Opt->iset->daxes->nzz-1)*Opt->iset->daxes->zzdel  ) ;
         fv2 = THD_3dmm_to_dicomm( Opt->iset , fv2 ) ;

         if( originRAIfv.xyz[0] > fv2.xyz[0] ) { float tf; tf = originRAIfv.xyz[0]; originRAIfv.xyz[0] = fv2.xyz[0]; fv2.xyz[0] = tf; } 
         if( originRAIfv.xyz[1] > fv2.xyz[1] ) { float tf; tf = originRAIfv.xyz[1]; originRAIfv.xyz[1] = fv2.xyz[1]; fv2.xyz[1] = tf; }
         if( originRAIfv.xyz[2] > fv2.xyz[2] ) { float tf; tf = originRAIfv.xyz[2]; originRAIfv.xyz[2] = fv2.xyz[2]; fv2.xyz[2] = tf; }

         if (LocalHead) {
            fprintf(stderr,"++3dSpatNorm (ZSS): RAI origin info: %f %f %f\n", originRAIfv.xyz[0], originRAIfv.xyz[1], originRAIfv.xyz[2]);
         }

         Opt->OrigSpatNormedSet = EDIT_empty_copy( NULL ) ;
         tross_Copy_History( Opt->iset , Opt->OrigSpatNormedSet ) ;
         tross_Make_History( "3dSkullStrip" , argc,argv , Opt->OrigSpatNormedSet ) ;

         LOAD_IVEC3( nxyz   , imout_orig->nx    , imout_orig->ny    , imout_orig->nz    ) ;
         LOAD_FVEC3( dxyz   , imout_orig->dx    , imout_orig->dy    , imout_orig->dz    ) ;
         LOAD_FVEC3( orgxyz , originRAIfv.xyz[0]    , originRAIfv.xyz[1]    , originRAIfv.xyz[2]    ) ;
         LOAD_IVEC3( orixyz , ORI_R2L_TYPE , ORI_A2P_TYPE , ORI_I2S_TYPE ) ;

         prefix = SUMA_AfniPrefix(Opt->in_name, NULL, NULL, NULL); 
         if (!prefix) { SUMA_SL_Err("Bad prefix!!!"); exit(1); }
         spatprefix = SUMA_append_string(prefix, "_SpatNorm_OrigSpace");
         EDIT_dset_items( Opt->OrigSpatNormedSet ,
                            ADN_prefix      , spatprefix ,
                            ADN_datum_all   , imout_orig->kind ,
                            ADN_nxyz        , nxyz ,
                            ADN_xyzdel      , dxyz ,
                            ADN_xyzorg      , orgxyz ,
                            ADN_xyzorient   , orixyz ,
                            ADN_malloc_type , DATABLOCK_MEM_MALLOC ,
                            ADN_view_type   , VIEW_ORIGINAL_TYPE ,
                            ADN_type        , HEAD_ANAT_TYPE ,
                            ADN_func_type   , ANAT_BUCK_TYPE ,
                          ADN_none ) ;

         EDIT_substitute_brick( Opt->OrigSpatNormedSet , 0 , imout_orig->kind , mri_data_pointer(imout_orig) ) ;      
         oset = r_new_resam_dset ( Opt->OrigSpatNormedSet, Opt->iset,	0,	0,	0,	NULL, MRI_LINEAR, NULL);
         if (!oset) {
            fprintf(stderr,"**ERROR: Failed to reslice!?\n"); exit(1);
         }
         EDIT_dset_items(  oset ,
                            ADN_prefix      , spatprefix,
                            ADN_none ) ;
         tross_Copy_History( Opt->OrigSpatNormedSet , oset ) ;
         DSET_delete(Opt->OrigSpatNormedSet); Opt->OrigSpatNormedSet = oset; oset = NULL;

         if (Opt->WriteSpatNorm) {
            if (Opt->debug) SUMA_S_Note("Writing SpatNormed dset in original space");
            DSET_write(Opt->OrigSpatNormedSet) ;
         }
         if (prefix) SUMA_free(prefix); prefix = NULL;
         if (spatprefix) SUMA_free(spatprefix); spatprefix = NULL; 
      }
            
      oset = EDIT_empty_copy( NULL ) ;
      /* reset the idcode using a hash of a string formed by idcode or orig dset and _Spatnorm */
      {  char idstr[500], *nid=NULL; sprintf(idstr,"%s_Spatnorm", Opt->iset->idcode.str); 
         SUMA_NEW_ID(nid, idstr); strncpy(oset->idcode.str, nid, IDCODE_LEN); SUMA_free(nid); nid = NULL;}
      tross_Copy_History( Opt->iset , oset ) ;
      tross_Make_History( "3dSkullStrip" , argc,argv , oset ) ;
      
      LOAD_IVEC3( nxyz   , imout->nx    , imout->ny    , imout->nz    ) ;
      LOAD_FVEC3( dxyz   , imout->dx    , imout->dy    , imout->dz    ) ;
      LOAD_FVEC3( orgxyz , imout->xo    , imout->yo    , imout->zo    ) ;
      LOAD_IVEC3( orixyz , ORI_R2L_TYPE , ORI_A2P_TYPE , ORI_I2S_TYPE ) ;
      
      prefix = SUMA_AfniPrefix(Opt->in_name, NULL, NULL, NULL); 
      if (!prefix) { SUMA_SL_Err("Bad prefix!!!"); exit(1); }
      spatprefix = SUMA_append_string(prefix, "_SpatNorm");
      EDIT_dset_items( oset ,
                         ADN_prefix      , spatprefix ,
                         ADN_datum_all   , imout->kind ,
                         ADN_nxyz        , nxyz ,
                         ADN_xyzdel      , dxyz ,
                         ADN_xyzorg      , orgxyz ,
                         ADN_xyzorient   , orixyz ,
                         ADN_malloc_type , DATABLOCK_MEM_MALLOC ,
                         ADN_view_type   , VIEW_ORIGINAL_TYPE ,
                         ADN_type        , HEAD_ANAT_TYPE ,
                         ADN_func_type   , ANAT_BUCK_TYPE ,
                       ADN_none ) ; 

      EDIT_substitute_brick( oset , 0 , imout->kind , mri_data_pointer(imout) ) ;      
      if (Opt->WriteSpatNorm) {
         SUMA_LH("Writing SpatNormed dset");
         DSET_write(oset) ;
      }
      Opt->in_vol = oset; oset = NULL;
      
      if (prefix) SUMA_free(prefix); prefix = NULL;
      if (spatprefix) SUMA_free(spatprefix); spatprefix = NULL;
      if( Opt->debug ) fprintf(SUMA_STDERR,"%s: -spatnorm: Expecting %d voxels in in_vol dset (%d %d %d)\n", 
         FuncName, DSET_NVOX( Opt->in_vol ), DSET_NX( Opt->in_vol ), DSET_NY( Opt->in_vol ), DSET_NZ( Opt->in_vol )); 
      
   } else {
      /* volume already SpatNormed, or user does not want SpatNorm */
      SUMA_SL_Note("Loading dset, performing no Spatial Normalization");
      Opt->in_vol = THD_open_dataset( Opt->in_name );
      if( !ISVALID_DSET(Opt->in_vol) ){
        fprintf(stderr,"**ERROR: can't open dataset %s\n",Opt->in_name) ;
        exit(1);
      }
      if( Opt->debug ) fprintf(SUMA_STDERR,"%s: -no_spatnorm: Expecting %d voxels in in_vol dset (%d %d %d)\n", 
         FuncName, DSET_NVOX( Opt->in_vol ), DSET_NX( Opt->in_vol ), DSET_NY( Opt->in_vol ), DSET_NZ( Opt->in_vol )); 
      /* load the dset */
      DSET_load(Opt->in_vol);
      if (Opt->fillhole) Opt->OrigSpatNormedSet = Opt->in_vol; /* original is same as in_vol */
      /* initialize, just to make sure numbers are ok for if statement below */
      mri_speciebusiness(Opt->specie);
      mri_brainormalize_initialize(Opt->in_vol->daxes->xxdel, Opt->in_vol->daxes->yydel, Opt->in_vol->daxes->zzdel);
      if (DSET_NX( Opt->in_vol) !=  THD_BN_nx() || DSET_NY( Opt->in_vol) !=  THD_BN_ny()  || DSET_NZ( Opt->in_vol) !=  THD_BN_nz() ) {
         fprintf(SUMA_STDERR,"Error %s:\n SpatNormed Dset must be %d x %d x %d\n", FuncName, THD_BN_nx(), THD_BN_ny(), THD_BN_nz() );
         exit(1);
      }
      if (Opt->d1 < 0) {
         Opt->d1 = 20.0/THD_BN_rat(); /* half as big */
      }
      if (Opt->d4 < 0) {
         Opt->d4 = 15.0/THD_BN_rat(); /* half as big */
      }
      if (LocalHead) fprintf(SUMA_STDERR,"%s: Size factor = %f\n", FuncName, THD_BN_rat());

      Opt->iset_hand = SUMA_THD_handedness( Opt->in_vol );
      if (LocalHead) fprintf(SUMA_STDERR,"%s: Handedness of orig dset %d\n", FuncName, Opt->iset_hand);

   }
   
   /* set the travel step based on the resolution of the voxels */
   Opt->travstp = SUMA_MIN_PAIR(SUMA_ABS(Opt->in_vol->daxes->xxdel), SUMA_ABS(Opt->in_vol->daxes->yydel));
   Opt->travstp = SUMA_MIN_PAIR(Opt->travstp, SUMA_ABS(Opt->in_vol->daxes->zzdel));
    
   if (!ISVALID_DSET(Opt->in_vol)) {
      if (!Opt->in_name) {
         SUMA_SL_Err("NULL input volume.");
         exit(1);
      } else {
         SUMA_SL_Err("invalid volume.");
         exit(1);
      }
   } else if ( DSET_BRICK_TYPE(Opt->in_vol, 0) == MRI_complex) {
      SUMA_SL_Err("Can't do complex data.");
      exit(1);
   }

   /* calculate an edge mask ? */
   if (Opt->Use_emask) {
      float *emask_sort = NULL, PercRange[2]= { 10, 90 }, PercRangeVal[2] = { 0.0, 0.0 };
      
      Opt->emask = (float *) SUMA_malloc( sizeof(float)*DSET_NVOX(Opt->in_vol));
      if (!Opt->emask) {
         fprintf(SUMA_STDERR,"Error %s:\n Failed to allocate for edge mask\n", FuncName);
         exit(1);
      }
      {   
         if (0) { /* to get a fattened mask too */
            THD_3dim_dataset *outset=NULL;
            THD_3dim_dataset *fatoutset=NULL;
            if (!SUMA_3dedge3(Opt->in_vol, Opt->emask, &outset)) {
               fprintf(SUMA_STDERR , "ERROR: gradient extraction failed.\n" );
               exit( 1 );
            }
            /* create a fat mask please */
            {  /* need a block for compiling     18 Apr 2006 [rickr] */
               int code[3], ncode;
               MCW_cluster *nbhd=NULL ;

               if (Opt->debug) {
                  SUMA_S_Note("Fattening the edge mask");
               }
               code[0] = NSTAT_MEAN; 
               ncode = 1;
               nbhd = MCW_rectmask ( 1.0f, 1.0f, 1.0f , 1.0f, 1.0f, 1.0f  ) ;
               fatoutset = THD_localstat( outset , NULL , nbhd , 1 , code ) ;
               Opt->fatemask = (float *) SUMA_malloc( sizeof(float)*DSET_NVOX(fatoutset));
               if (!Opt->fatemask) {
                  fprintf(SUMA_STDERR,"Error %s:\n Failed to allocate for fat edge mask\n", FuncName);
                  exit(1);
               }
               EDIT_coerce_scale_type( DSET_NVOX(fatoutset) , DSET_BRICK_FACTOR(fatoutset,0) ,
                              DSET_BRICK_TYPE(fatoutset,0), DSET_ARRAY(fatoutset, 0) ,      /* input  */
                              MRI_float               , Opt->fatemask  ) ;   /* output */

               if (DSET_NVOX(fatoutset) != DSET_NVOX(outset) || DSET_NVOX(fatoutset) != DSET_NVOX(Opt->in_vol)) {
                  SUMA_S_Err("Bad news in tennis shoes!");
                  exit(1);
               }
               if (Opt->debug > 2) {
                  THD_write_3dim_dataset( NULL,NULL , fatoutset , True ) ;
                  fprintf(stderr,"  ++ Wrote output: %s\n",DSET_BRIKNAME(fatoutset)) ;   
               }
            }

            if (outset) DSET_delete(outset) ; outset = NULL;
            if (fatoutset) DSET_delete(fatoutset) ; fatoutset = NULL;
         } else {
            /* no fat junk */
            if (!SUMA_3dedge3(Opt->in_vol, Opt->emask, NULL)) {
               fprintf(SUMA_STDERR , "ERROR: gradient extraction failed.\n" );
               exit( 1 );
            }
         }
      }
      /* get the mask threshold */
      PercRange[0] = 92; PercRange[1] = 99.999;
      emask_sort = SUMA_PercRange (Opt->emask, NULL, DSET_NVOX(Opt->in_vol), PercRange, PercRangeVal, NULL);
      if (!emask_sort) {
         fprintf( stderr, "ERROR: mask sorting failed.\n" );
         exit( 1 );
      } else {
         SUMA_free(emask_sort); emask_sort = NULL;
      }
      /* The minimum acceptable edge is at least one tenth of the 99.999 percentile edge */
      if (PercRangeVal[0] < PercRangeVal[1]/10.0) PercRangeVal[0] = PercRangeVal[1]/10.0;
      
      if (Opt->debug) fprintf (SUMA_STDERR,  "%s: Edge threshold set to %f (perhaps from %f percentile, minimum acceptable was %f)\n"
                                             "      (%f percentile = %f)\n", 
                        FuncName, PercRangeVal[0], PercRange[0], PercRange[1]/10.0, PercRange[1], PercRangeVal[1]);
      /* Now that we have an edge vector, select appropriate values */
      for (ii=0; ii<DSET_NVOX(Opt->in_vol); ++ii) {
         if (Opt->emask[ii] < PercRangeVal[0]) Opt->emask[ii] = 0.0;
      }
      if (Opt->fatemask) {
         /* same for the fat mask */
         PercRange[0] = 90; PercRange[1] = 95;
         emask_sort = SUMA_PercRange (Opt->fatemask, NULL, DSET_NVOX(Opt->in_vol), PercRange, PercRangeVal, NULL);
         if (!emask_sort) {
            fprintf( stderr, "ERROR: mask sorting failed.\n" );
            exit( 1 );
         } else {
            SUMA_free(emask_sort); emask_sort = NULL;
         }

         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Fat Edge threshold set to %f (from %f percentile) , (%f percentile = %f)\n", 
                           FuncName, PercRangeVal[0], PercRange[0],  PercRange[1], PercRangeVal[1]);
         /* Now that we have an edge vector, select appropriate values */
         for (ii=0; ii<DSET_NVOX(Opt->in_vol); ++ii) {
            if (Opt->fatemask[ii] < PercRangeVal[0]) Opt->fatemask[ii] = 0.0;
         }
      }
   } 
  
   if (Opt->blur_fwhm) {
     if (Opt->debug) fprintf (SUMA_STDERR,"%s: Blurring...\n", FuncName);
     EDIT_blur_volume(  DSET_NX(Opt->in_vol), DSET_NY(Opt->in_vol), DSET_NZ(Opt->in_vol),
                        SUMA_ABS((DSET_DX(Opt->in_vol))), SUMA_ABS((DSET_DY(Opt->in_vol))),  SUMA_ABS((DSET_DZ(Opt->in_vol))),  
                        DSET_BRICK_TYPE(Opt->in_vol,0), DSET_ARRAY(Opt->in_vol,0), 0.42466090*Opt->blur_fwhm) ;
   }
   
   if (Opt->UseSkull) { SOhull = SUMA_Alloc_SurfObject_Struct(1); }
   else SOhull = NULL;
   sprintf(stmphull,"OuterHull");  

   if (Opt->debug) fprintf (SUMA_STDERR,"%s: Prepping volume...\n", FuncName);
   vol = SUMA_LoadPrepInVol (Opt, &SOhull);
   if ( vol <= 0 ) {
      SUMA_S_Err("Failed to load/prep volume");
      exit(1);
   } else {
      if (LocalHead) fprintf (SUMA_STDERR,"%s: Got me a volume of %f mm3\n", FuncName, vol);
   }
   
   /* create the ico, might need coords for bias correction below*/
   SO = SUMA_CreateIcosahedron (Opt->r/2.0, Opt->Icold, Opt->cog, "n", 1);
   if (!SO) {
      SUMA_S_Err("Failed to create Icosahedron");
      exit(1);
   }         
   /* Need Brain_Contour holder at the very least*/
   if (!Opt->Brain_Contour) Opt->Brain_Contour = (float *)SUMA_calloc(SO->N_Node * 3, sizeof(float));


   /* allocate and initialize shrink bias vector */
   {
      int nico = (2 + 10 * Opt->Icold * Opt->Icold );
      Opt->shrink_bias = (float *)SUMA_calloc(nico, sizeof(float));
      if (!Opt->shrink_bias) { SUMA_SL_Crit("Failed to allocate"); exit(1); }
      for (i=0; i<nico; ++i) Opt->shrink_bias[i] = 1.0;

      if (Opt->shrink_bias_name) {
         MRI_IMAGE *im = NULL;
         float *far = NULL;

         /* load the shrink_bias_file */
         im = mri_read_1D(Opt->shrink_bias_name);
         if (!im) { SUMA_SL_Err("Failed to read 1D file of shrink factor bias file."); exit(1);}
         far = MRI_FLOAT_PTR(im);
         if (im->ny != 2) { SUMA_SL_Err("Need 2 columns in shrink factor bias file."); exit(1); }
         if (im->nx > nico) {
            fprintf(SUMA_STDERR, "Error %s: File too big. Maximum number of lines (%d) should not exceed %d,\n"
                                 "which is the number of nodes forming the surface.\n", FuncName, im->nx, nico);
            exit(1);
         }

         /* change to row major major and make it match nodeind */
         for (i=0; i<im->nx; ++i) {
            if (far[i] < nico) {
               Opt->shrink_bias[(int)far[i]] = far[i+  im->nx];
            } else {
               fprintf(SUMA_STDERR, "Error %s: Node index of (%d) in shrink factor bias file\n"
                                    "exceeds maximum allowed node index (%d) for surface.\n", FuncName, (int)far[i], nico-1);
               exit(1);
            }
         }
         mri_free(im); im = NULL;   /* done with that baby */

      } else if (Opt->specie == RAT) {
      #if 0
         float p1[3], Y[3], Z[3], U[3], Un, dotz, doty;
         Y[0] = 0.0; Y[1] = 1.0; Y[2] = 0.0; /* The Y direction */
         Z[0] = 0.0; Z[1] = 0.0; Z[2] = 1.0; /* The Z direction */
         /* less on top, and sides, more in front */
         for (i=0; i<SO->N_Node; ++i) {
            /* vector from center to node */
            p1[0] = SO->NodeList[3*i  ]; p1[1] = SO->NodeList[3*i+1]; p1[2] = SO->NodeList[3*i+2];
            SUMA_UNIT_VEC(Opt->cog, p1, U, Un);  
            SUMA_DOTP_VEC(U,Y, doty , 3,float,float);
            SUMA_DOTP_VEC(U,Z, dotz , 3,float,float);
            Opt->shrink_bias[i] = ((1.5 - (SUMA_ABS(doty)*(1-SUMA_ABS(dotz))))) ;
         }
         if (Opt->debug) {
            snprintf(stmp, 198, "%s_shrink_bias.1D.dset", Opt->out_vol_prefix);
            SUMA_WRITE_ARRAY_1D(Opt->shrink_bias,SO->N_Node,1, stmp);        
         }
      #endif
      } else if (Opt->specie == MONKEY) {
      #if 0
         float p1[3], Y[3], Z[3], U[3], Un, dotz, doty;
         Y[0] = 0.0; Y[1] = 1.0; Y[2] = 0.0; /* The Y direction */
         Z[0] = 0.0; Z[1] = 0.0; Z[2] = 1.0; /* The Z direction */
         /* less on top, and sides, more in front */
         for (i=0; i<SO->N_Node; ++i) {
            /* vector from center to node */
            p1[0] = SO->NodeList[3*i  ]; p1[1] = SO->NodeList[3*i+1]; p1[2] = SO->NodeList[3*i+2];
            SUMA_UNIT_VEC(Opt->cog, p1, U, Un);  
            SUMA_DOTP_VEC(U,Y, doty , 3,float,float);
            SUMA_DOTP_VEC(U,Z, dotz , 3,float,float);
            if (doty < 0 && dotz > 0) { /* loosen front upper of brain */
               Opt->shrink_bias[i] = ((1.1 - (SUMA_ABS(doty)*(1-(dotz))))) ;
            } 
         }
         if (Opt->debug) {
            snprintf(stmp, 198, "%s_shrink_bias.1D.dset", Opt->out_vol_prefix);
            SUMA_WRITE_ARRAY_1D(Opt->shrink_bias,SO->N_Node,1, stmp);        
         }
      #endif
      }

   } 
   if (Opt->debug) fprintf (SUMA_STDERR,"%s: Beginning brain extraction...\n", FuncName);
   do {   
      /* Now create that little sphere that is about to expand */
      sprintf(stmp,"icobaby_ld%d", Opt->Icold);  
      if (SO) {
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Have surface, OK for 1st entry.\n", FuncName);
      }  else {   
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Creating Ico.\n", FuncName);
         SO = SUMA_CreateIcosahedron (Opt->r/2.0, Opt->Icold, Opt->cog, "n", 1);
         if (!SO) {
            SUMA_S_Err("Failed to create Icosahedron");
            exit(1);
         }
      }

      if (Opt->Stop) SUMA_free(Opt->Stop); Opt->Stop = NULL;
      if (!Opt->Stop) {
         Opt->Stop = (float *)SUMA_calloc(SO->N_Node, sizeof(float));
         if (!Opt->Stop) {
            SUMA_SL_Crit("Failed to allocate");
            exit(1);
         }
      }

      if (Opt->avoid_vent && Opt->specie != RAT) { /* No need for this avoidance in rodents*/
         float U[3], Un, *a, P2[2][3];
         for (i=0; i<SO->N_Node; ++i) {
            /* stretch the top coordinates by d1 and the back too*/
            a = &(SO->NodeList[3*i]); 
            if (a[2] - SO->Center[2] > Opt->r/3 || a[1] - SO->Center[1] > Opt->r/2) {
               SUMA_UNIT_VEC(SO->Center, a, U, Un);
               SUMA_POINT_AT_DISTANCE_NORM(U, SO->Center, (Un+1.1*Opt->d1), P2);
               SO->NodeList[3*i] = P2[0][0]; SO->NodeList[3*i+1] = P2[0][1]; SO->NodeList[3*i+2] = P2[0][2];
            }
         }   
      }
      /* allocate and fix zt */
      Opt->ztv = (float *)SUMA_malloc(sizeof(float)*SO->N_Node);
      if (!Opt->ztv) {
         SUMA_SL_Crit("Failed to allocate");
         exit(1);
      } 
      for (i=0; i<SO->N_Node; ++i) Opt->ztv[i] = SUMA_MIN_PAIR(1.0, (Opt->Zt*Opt->shrink_bias[i]));

      /* need sv for communication to AFNI */
      SO->VolPar = SUMA_VolParFromDset (Opt->in_vol);
      SO->SUMA_VolPar_Aligned = YUP; /* Surface is in alignment with volume, should not call SUMA_Align_to_VolPar ... */
      if (!SO->State) {SO->State = SUMA_copy_string("3dSkullStrip"); }
      if (!SO->Group) {SO->Group = SUMA_copy_string("3dSkullStrip"); }
      if (!SO->Label) {SO->Label = SUMA_copy_string(stmp); }
      /* make the idcode_str depend on the Label, it is convenient to
      send the same surface all the time to SUMA */
      if (SO->Label) { if (SO->idcode_str) SUMA_free(SO->idcode_str); SO->idcode_str = NULL; SUMA_NEW_ID(SO->idcode_str, SO->Label); }
      
      if (!nint && SOhull) {
         SOhull->VolPar = SUMA_VolParFromDset (Opt->in_vol);
         SOhull->SUMA_VolPar_Aligned = YUP; /* Surface is in alignment with volume, should not call SUMA_Align_to_VolPar ... */
   
         if (!SOhull->State) {SOhull->State = SUMA_copy_string("3dSkullStrip"); }
         if (!SOhull->Group) {SOhull->Group = SUMA_copy_string("3dSkullStrip"); }
         if (!SOhull->Label) {SOhull->Label = SUMA_copy_string(stmphull); }
         if (SOhull->Label) { if (SOhull->idcode_str) SUMA_free(SOhull->idcode_str); SOhull->idcode_str = NULL; SUMA_NEW_ID(SOhull->idcode_str,SOhull->Label); }
      }

      /* see if SUMA talk is turned on */
      if (ps->cs->talk_suma) {
         ps->cs->istream = SUMA_BRAINWRAP_LINE;
         ps->cs->afni_istream = SUMA_AFNI_STREAM_INDEX2;
         ps->cs->kth = 1; /* make sure all surfaces get sent */
         if (!SUMA_SendToSuma (NULL, ps->cs, NULL, SUMA_NO_DSET_TYPE, 0)) {
            SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
            ps->cs->Send = NOPE;
            ps->cs->afni_Send = NOPE;
            ps->cs->talk_suma = NOPE;
         } else if (!SUMA_SendToAfni (ps->cs, NULL,  0)) {
            SUMA_SL_Err("Failed to initialize SUMA_SendToAfni");
            ps->cs->afni_Send = NOPE;
            ps->cs->Send = NOPE;
         } else {
            if (!nint && SOhull) {
               if (Opt->send_hull) {
                  SUMA_LH("Sending Hull");
                  if (Opt->DemoPause == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("Sending HULL next"); }
                  SUMA_SendSumaNewSurface(SOhull, ps->cs);
               }
            }
            SUMA_LH("Sending Ico");
            if (Opt->DemoPause  == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("Sending Ico next"); }
            SUMA_SendSumaNewSurface(SO, ps->cs);

         }
         ps->cs->kth = kth_buf;
      }

      if (!nint && Opt->UseSkull) {
         /* get a crude mask of outer skull */
         if (Opt->DemoPause == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("Shrinking skull hull next"); }
         SUMA_SkullMask (SOhull, Opt, ps->cs);
         /* Now take mask and turn it into a volume */
         fprintf (SUMA_STDERR,"%s: Locating voxels on skull boundary  ...\n", FuncName);
         isin = SUMA_FindVoxelsInSurface (SOhull, SO->VolPar, &N_in, 0, NULL);
         for (i=0; i<SO->VolPar->nx*SO->VolPar->ny*SO->VolPar->nz; ++i) { if (isin[i] <= SUMA_ON_NODE) Opt->fvec[i] = 0; }
         #if 0
            SUMA_SL_Note("Writing hull mask");
            {
               FILE *fout=fopen("hullmask.1D","w");
               int ii, jj, kk; 
               for (i=0; i<SO->VolPar->nx*SO->VolPar->ny*SO->VolPar->nz; ++i) { 
                  SUMA_1D_2_3D_index(i, ii, jj, kk, SO->VolPar->nx, SO->VolPar->nx*SO->VolPar->ny); 
                  fprintf(fout,"%d %d %d %d\n",ii, jj, kk, isin[i]); 
               }
               fclose(fout);
            }
         #endif
         if (isin) SUMA_free(isin); isin = NULL;
      }
      
      /* send in_vol to afni */
      if (Opt->DoSpatNorm && ps->cs->afni_Send) {
         SUMA_SL_Note("Sending spatnormed volume to AFNI");
         if (!SUMA_SendToAfni(ps->cs, Opt->in_vol, 1)) {
            SUMA_SL_Err("Failed to send volume to AFNI");
            ps->cs->afni_Send = NOPE;
         }
      }
      
            
      /* This is it baby, start walking */
      if (Opt->DemoPause == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("Brain expansion next"); }
      if ( !Opt->UseThisBrain ) {
         SUMA_StretchToFitLeCerveau (SO, Opt, ps->cs);
      } else {
         /* DEVELOPMENT ONLY! */
         int ncol, nrow;
         float *far=SUMA_Load1D_s(Opt->UseThisBrain, &ncol, &nrow, 1, 0);
         if (!far || nrow != SO->N_Node || ncol != 3) {
            fprintf(SUMA_STDERR,"Error %s: SO has %d nodes, your coord file has %d cols, %d rows.\n", FuncName, SO->N_Node, ncol, nrow);
            exit(1);
         } else {
            fprintf(SUMA_STDERR,"Warning %s: adopting coordinates from %s\n", FuncName, Opt->UseThisBrain);
         }
         memcpy((void*)SO->NodeList,(void*)far, sizeof(float)*ncol*nrow);
         free(far); far = NULL;
         Opt->PercInt = -1; /* cancel intersection checking */ 
      }
      /* Make a copy to brain contours, in case user jumps ahead */
      memcpy((void*)Opt->Brain_Contour, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));
      
      /* check for intersections */
      if (Opt->PercInt >= 0) {
         if (Opt->debug) fprintf(SUMA_STDERR,"%s: Checking for self intersection...\n", FuncName);
         nseg = 30 * Opt->Icold * Opt->Icold; /* number of segments in Ico */
         nint = SUMA_isSelfIntersect(SO, (int)(Opt->PercInt * nseg / 100.0), NULL);
         if (nint < 0) {
            SUMA_SL_Err("Error in SUMA_isSelfIntersect. Ignoring self intersection test.");
            nint = 0;
         }
         /* percentage of guilty segments */
         pint = (float)nint / (float)nseg * 100;
         if (LocalHead) fprintf (SUMA_STDERR,"%s: at least %d (%f%%) of segments intersect the surface.\nStopping criterion is %f%%\n", FuncName, nint, pint, Opt->PercInt);
         if (pint > Opt->PercInt) {
            static int SelfIntRep = 0;
            int smstep;
            if (SelfIntRep < Opt->MaxIntIter) {
               /* SUMA_PAUSE_PROMPT("SelfIntersection Baby"); */
               if (!Opt->avoid_vent && !SelfIntRep) {
                  Opt->avoid_vent = 1;
               } else {
                  smstep = 12 * ( Opt->Icold / 25 ) * ( Opt->Icold / 25 ); /* 12 is OK for ld = 25 */ 
                  if ( smstep < 12) smstep = 12;
                  else if ( smstep % 2 ) ++smstep;
                  #if 0
                  if (!(SelfIntRep % 2)) { 
                     Opt->avoid_vent = 0;
                     Opt->NNsmooth += smstep; 
                  } else {
                     Opt->avoid_vent = 1;
                  }
                  #else
                     /* don't mess with avoid_vent option, it works well all the time */
                     Opt->NNsmooth += smstep; 
                  #endif
                  ++SelfIntRep;
               }
               fprintf(SUMA_STDERR,"Warning %s:****************\n Surface self intersecting! trying again:\n smoothing of %d, avoid_vent %d\n", FuncName, Opt->NNsmooth, (int)Opt->avoid_vent);
               SUMA_Free_Surface_Object(SO); SO = NULL;
            } else {
               fprintf(SUMA_STDERR,"Warning %s: Stubborn intersection remaining at smoothing of %d. Ignoring it.", FuncName, Opt->NNsmooth);
               nint = 0;
            }
         } else  {
            if (Opt->debug) {
               if (nint) fprintf(SUMA_STDERR,"%s: Number of intersection below criterion.\n", FuncName);
               else fprintf(SUMA_STDERR,"%s: No intersections found.\n", FuncName);
            }
            nint = 0;
         }
      } else {
         fprintf(SUMA_STDERR,"%s: Self intersection check turned off.\n", FuncName);
         nint = 0;   
      }
   } while (nint != 0);
   
   if ( !Opt->UseThisBrain ) {
      if (Opt->debug) fprintf(SUMA_STDERR,"%s: Final smoothing of %d\n", FuncName, Opt->NNsmooth);
      if (SUMA_DidUserQuit()) {
         if (Opt->debug) fprintf(SUMA_STDERR,"%s: straight to end per user demand (%d)...\n", FuncName, SUMA_DidUserQuit());
         goto FINISH_UP;
      }
      /* touch up, these might cause some surface intersection, but their effects should be small */
      /* TOUCHUP_1: */
      if (Opt->UseNew) {
            double mval = 255;
            if (Opt->debug) fprintf (SUMA_STDERR,"%s: Touchup correction, pass 1 ...\n", FuncName);
            if (Opt->DemoPause  == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("touchup correction next"); }
            if (Opt->DemoPause == SUMA_3dSS_INTERACTIVE) {
               /* Make a copy to brain contours, in case user jumps ahead */
               memcpy((void*)Opt->Brain_Contour, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));
               fprintf (SUMA_STDERR,"3dSkullStrip Interactive: \n"
                                    "Touchup, pass 1.\n"
                                    "Do you want to (C)ontinue, (P)ass or (S)ave this? ");
               cbuf = SUMA_ReadCharStdin ('c', 0,"csp");
               switch (cbuf) {
                  case 's':
                     fprintf (SUMA_STDERR,"Saving mask as is.\n");
                     goto FINISH_UP;
                     break;
                  case 'p':
                     fprintf (SUMA_STDERR,"Passing this stage \n");
                     goto PUSH_TO_EDGE;
                     break;
                  case 'c':
                     fprintf (SUMA_STDERR,"Continuing with stage.\n");
                     break;
               }                 
            }
            /* recover the eye balls please */
            if (mval < Opt->t98) {
               SUMA_SL_Warn("Looks like some values in dset might be larger than 255 !");
               mval = Opt->t98+10;
            }
            if (Opt->k98maskcnt && Opt->k98mask) { for (ii=0; ii<Opt->k98maskcnt; ++ii) Opt->fvec[Opt->k98mask[ii]] = mval; }
            /* SUMA_REPOSITION_TOUCHUP(6);*/
            SUMA_Reposition_Touchup(SO, Opt, 6, ps->cs);
            if (LocalHead) fprintf (SUMA_STDERR,"%s: Touchup correction  Done.\n", FuncName);
      }

      PUSH_TO_EDGE:
      if (Opt->PushToEdge) {
         fprintf (SUMA_STDERR,"%s: Pushing to Edge ...\n", FuncName);
         ps->cs->kth = 1; /*make sure all gets sent at this stage */
         if (Opt->DemoPause  == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("Push To Edge Correction"); }
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Push to edge correction ...\n", FuncName);
         if (Opt->DemoPause == SUMA_3dSS_INTERACTIVE) {
               /* Make a copy to brain contours, in case user jumps ahead */
               memcpy((void*)Opt->Brain_Contour, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));
               fprintf (SUMA_STDERR,"3dSkullStrip Interactive: \n"
                                    "Push To Edge.\n"
                                    "Do you want to (C)ontinue, (P)ass or (S)ave this?  ");
               cbuf = SUMA_ReadCharStdin ('c', 0,"csp");
               fprintf (SUMA_STDERR,"%c\n", cbuf);
               switch (cbuf) {
                  case 's':
                     fprintf (SUMA_STDERR,"Saving mask as is.\n");
                     goto FINISH_UP;
                     break;
                  case 'p':
                     fprintf (SUMA_STDERR,"Passing this stage \n");
                     goto BEAUTY;
                     break;
                  case 'c':
                     fprintf (SUMA_STDERR,"Continuing with stage.\n");
                     break;
               }                 
         }
         {  
            int il = 0;
            float dtroub = 1.0;
            int N_troub = 1, past_N_troub = 0;
            while (il < 5 && dtroub > 0.1 && N_troub) {
               N_troub = SUMA_PushToEdge(SO, Opt, 4, ps->cs, 0); SUMA_RECOMPUTE_NORMALS(SO);
               if (ps->cs->Send) {
                  if (!SUMA_SendToSuma (SO, ps->cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
                     SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
                  }
               }
               if (!past_N_troub) { 
                  past_N_troub = N_troub; 
                  if (LocalHead) fprintf (SUMA_STDERR,"%s: \n PushToEdge, pass %d %d troubled nodes, going for more...\n", FuncName, il, N_troub);
               } else {
                  dtroub = (float)(past_N_troub - N_troub)/(float)past_N_troub;
                  if (LocalHead) fprintf (SUMA_STDERR,"%s: \n PushToEdge, pass %d : %f change in troubled nodes.\n", FuncName, il, dtroub);
                  past_N_troub = N_troub;
               }
             ++il;
           }
         }
         if (LocalHead) fprintf (SUMA_STDERR,"%s: Edge push correction  Done.\n", FuncName);
         ps->cs->kth = kth_buf; 
      }


      BEAUTY:
      /* smooth the surface a bit */
      if (Opt->smooth_end) {
         ps->cs->kth = 1;  /*make sure all gets sent at this stage */
         if (Opt->DemoPause  == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("beauty treatment smoothing next"); }
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: The beauty treatment smoothing.\n", FuncName);
         if (Opt->DemoPause == SUMA_3dSS_INTERACTIVE) {
               /* Make a copy to brain contours, in case user jumps ahead */
               memcpy((void*)Opt->Brain_Contour, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));
               fprintf (SUMA_STDERR,"3dSkullStrip Interactive: \n"
                                    "Beauty treatment smoothing.\n"
                                    "Do you want to (C)ontinue, (P)ass or (S)ave this?  ");
               cbuf = SUMA_ReadCharStdin ('c', 0,"csp");
               switch (cbuf) {
                  case 's':
                     fprintf (SUMA_STDERR,"Saving mask as is.\n");
                     goto FINISH_UP;
                     break;
                  case 'p':
                     fprintf (SUMA_STDERR,"Passing this stage \n");
                     goto TOUCHUP_2;
                     break;
                  case 'c':
                     fprintf (SUMA_STDERR,"Continuing with stage.\n");
                     break;
               }                 
            }
         dsmooth = SUMA_Taubin_Smooth( SO, NULL,
                                       0.6307, -.6732, SO->NodeList,
                                       Opt->smooth_end, 3, SUMA_ROW_MAJOR, dsmooth, ps->cs, NULL, 0);    
         memcpy((void*)SO->NodeList, (void *)dsmooth, SO->N_Node * 3 * sizeof(float));
         SUMA_RECOMPUTE_NORMALS(SO);
         if (ps->cs->Send) {
            if (!SUMA_SendToSuma (SO, ps->cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
               SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
            }
         }
         ps->cs->kth = kth_buf; 
      }

      TOUCHUP_2:
      /* one more correction pass */
      if (Opt->UseNew > 1.0) {
         ps->cs->kth = 1; /*make sure all gets sent at this stage */
         if (Opt->DemoPause  == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("touchup correction 2 next"); }
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Final touchup correction ...\n", FuncName);
         if (Opt->DemoPause == SUMA_3dSS_INTERACTIVE) {
               /* Make a copy to brain contours, in case user jumps ahead */
               memcpy((void*)Opt->Brain_Contour, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));
               fprintf (SUMA_STDERR,"3dSkullStrip Interactive: \n"
                                    "Touchup, pass 2.\n"
                                    "Do you want to (C)ontinue, (P)ass or (S)ave this?  ");
               cbuf = SUMA_ReadCharStdin ('c', 0,"csp");
               fprintf (SUMA_STDERR,"%c\n", cbuf);
               switch (cbuf) {
                  case 's':
                     fprintf (SUMA_STDERR,"Saving mask as is.\n");
                     goto FINISH_UP;
                     break;
                  case 'p':
                     fprintf (SUMA_STDERR,"Passing this stage \n");
                     goto PUSH_TO_OUTER_SKULL;
                     break;
                  case 'c':
                     fprintf (SUMA_STDERR,"Continuing with stage.\n");
                     break;
               }                 
         }
         /* SUMA_REPOSITION_TOUCHUP(2); */
         SUMA_Reposition_Touchup(SO, Opt, 2, ps->cs);

         if (LocalHead) fprintf (SUMA_STDERR,"%s: Final touchup correction  Done.\n", FuncName);
         ps->cs->kth = kth_buf; 
      }
   } else {
      SUMA_S_Note("Using brain read from file");
   }
   

   /* Put brain contours in Brain_Contour*/
   memcpy((void*)Opt->Brain_Contour, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));
   
   PUSH_TO_OUTER_SKULL:
   if (Opt->DoSkulls) {
      if (ps->cs->Send) ps->cs->kth = 1; /* make sure all surfaces get sent */
      if (Opt->DemoPause  == SUMA_3dSS_DEMO_PAUSE) { SUMA_PAUSE_PROMPT("Skull detection next"); }
      if (Opt->debug) fprintf (SUMA_STDERR,"%s: Skull detection next ...\n", FuncName);
      if (Opt->DemoPause == SUMA_3dSS_INTERACTIVE) {
            fprintf (SUMA_STDERR,"3dSkullStrip Interactive: \n"
                                 "Skull detection.\n"
                                 "Do you want to (C)ontinue, (P)ass or (S)ave this?  ");
            cbuf = SUMA_ReadCharStdin ('c', 0,"csp");
            fprintf (SUMA_STDERR,"%c\n", cbuf);
            switch (cbuf) {
               case 's':
                  fprintf (SUMA_STDERR,"Saving mask as is.\n");
                  goto FINISH_UP;
                  break;
               case 'p':
                  fprintf (SUMA_STDERR,"Passing this stage \n");
                  goto FINISH_UP;
                  break;
               case 'c':
                  fprintf (SUMA_STDERR,"Continuing with stage.\n");
                  break;
            }                 
      }
      if (!Opt->UseThisBrainHull) {
         /* first get a convex hull volume of the brain surface */
         SUMA_Push_Nodes_To_Hull(SO, Opt, ps->cs, 15);
      } else {
         /* DEVELOPMENT ONLY! */
         int ncol, nrow;
         float *far=SUMA_Load1D_s(Opt->UseThisBrainHull, &ncol, &nrow, 1, 0);
         if (!far || nrow != SO->N_Node || ncol != 3) {
            fprintf(SUMA_STDERR,"Error %s: SO has %d nodes, your coord file has %d cols, %d rows.\n", FuncName, SO->N_Node, ncol, nrow);
            exit(1);
         } else {
            fprintf(SUMA_STDERR,"Warning %s: adopting brain hull coordinates from %s\n", FuncName, Opt->UseThisBrainHull);
         }
         memcpy((void*)SO->NodeList,(void*)far, sizeof(float)*ncol*nrow);
         free(far); far = NULL;
      }
      
      Opt->Brain_Hull = (float *)SUMA_calloc(SO->N_Node * 3, sizeof(float));
      memcpy((void*)Opt->Brain_Hull, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));      
      
      if (ps->cs->Send) {
         if (!SUMA_SendToSuma (SO, ps->cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
            SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
         }
      }
      
      if (!Opt->UseThisSkullOuter) {
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Push to Outer Skull ...                                               \n", FuncName);
         if (     LocalHead || Opt->debug > 1 
               || Opt->DemoPause  == SUMA_3dSS_DEMO_PAUSE
               || Opt->DemoPause  == SUMA_3dSS_INTERACTIVE
               ) { 
               SUMA_PAUSE_PROMPT("Brain hull done, Pausing before proceeding to outer skull "); 
         }
         {  
            int il = 0;
            float dtroub = 1.0;
            int N_exp, N_troub = 1, past_N_troub = 0;

            /* reset stop flags */
            Opt->nmask = (byte*)SUMA_malloc(sizeof(byte)*SO->N_Node);
            for (il=0; il<SO->N_Node; ++il) Opt->nmask[il] = 1;

            N_exp = 20;
            il = 0;
            while (il < N_exp || (N_troub < 0.01 * SO->N_Node && dtroub < 0.010)) {
               N_troub = SUMA_PushToOuterSkull(SO, Opt, 10+(25.0*(N_exp-il)/(float)N_exp), ps->cs, N_exp); SUMA_RECOMPUTE_NORMALS(SO);
               if (ps->cs->Send) {
                  if (!SUMA_SendToSuma (SO, ps->cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
                     SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
                  }
               }
               if (LocalHead) fprintf (SUMA_STDERR,"%s: %d trouble nodes reported by SUMA_PushToOuterSkull\n", FuncName, N_troub);
               if (!past_N_troub) { 
                  past_N_troub = N_troub; 
                  if (LocalHead) fprintf (SUMA_STDERR,"%s: \nSUMA_PushToOuterSkull , pass %d %d troubled nodes, going for more...\n", FuncName, il, N_troub);
               } else {
                  dtroub = (float)(past_N_troub - N_troub)/(float)past_N_troub;
                  if (LocalHead) fprintf (SUMA_STDERR,"%s: \nSUMA_PushToOuterSkull, pass %d : %f change in troubled nodes.\n", FuncName, il, dtroub);
                  past_N_troub = N_troub;
               }
             ++il;
           }
         }
         if (LocalHead) fprintf (SUMA_STDERR,"%s: Outer Skull push correction  Done.\n", FuncName);
         ps->cs->kth = kth_buf; 
         dsmooth = SUMA_Taubin_Smooth( SO, NULL,
                                       0.6307, -.6732, SO->NodeList,
                                       Opt->smooth_end, 3, SUMA_ROW_MAJOR, dsmooth, ps->cs, NULL, 0);    
         memcpy((void*)SO->NodeList, (void *)dsmooth, SO->N_Node * 3 * sizeof(float));
         SUMA_RECOMPUTE_NORMALS(SO);
         if (ps->cs->Send) {
            if (!SUMA_SendToSuma (SO, ps->cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
               SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
            }
         }
      } else {
         /* DEVELOPMENT ONLY! */
         int ncol, nrow;
         float *far=SUMA_Load1D_s(Opt->UseThisSkullOuter, &ncol, &nrow, 1, 0);
         if (!far || nrow != SO->N_Node || ncol != 3) {
            fprintf(SUMA_STDERR,"Error %s: SO has %d nodes, your coord file has %d cols, %d rows.\n", FuncName, SO->N_Node, ncol, nrow);
            exit(1);
         } else {
            fprintf(SUMA_STDERR,"Warning %s: adopting outer skull coordinates from %s\n", FuncName, Opt->UseThisSkullOuter);
         }
         memcpy((void*)SO->NodeList,(void*)far, sizeof(float)*ncol*nrow);
         free(far); far = NULL;
      }
      
      Opt->Skull_Outer = (float *)SUMA_calloc(SO->N_Node * 3, sizeof(float));
      memcpy((void*)Opt->Skull_Outer, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));      

      if (     LocalHead || Opt->debug > 1 
               || Opt->DemoPause  == SUMA_3dSS_DEMO_PAUSE
               || Opt->DemoPause  == SUMA_3dSS_INTERACTIVE
               ) { 
         SUMA_PAUSE_PROMPT("Outer Skull done, Pausing before proceeding to inner skull "); 
      }
      /* now for the inner skull */
      {  
         int il = 0;
         /* reset stop flags */
         Opt->nmask = (byte*)SUMA_malloc(sizeof(byte)*SO->N_Node);
         for (il=0; il<SO->N_Node; ++il) Opt->nmask[il] = 1;
         
         ps->cs->kth = 1;
         SUMA_PushToInnerSkull(SO, Opt, 35.0, ps->cs); 
         SUMA_RECOMPUTE_NORMALS(SO);
      }
      if (ps->cs->Send) {
         if (!SUMA_SendToSuma (SO, ps->cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
            SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
         }
      }
      
      Opt->Skull_Inner = (float *)SUMA_calloc(SO->N_Node * 3, sizeof(float));
      memcpy((void*)Opt->Skull_Inner, (void *)SO->NodeList, SO->N_Node * 3 * sizeof(float));      

      ps->cs->kth = kth_buf; 
   }
   

   

   FINISH_UP:
   /* reset coords to brain contours */
   memcpy((void *)SO->NodeList, (void*)Opt->Brain_Contour, SO->N_Node * 3 * sizeof(float));    
   
   /* send the last surface (kind a stupid since you have som many surfaces) ...*/
   ps->cs->kth = 1;
   if (ps->cs->Send) {
      SUMA_LH("SendSuma");
      if (!SUMA_SendToSuma (SO, ps->cs, (void *)SO->NodeList, SUMA_NODE_XYZ, 1)) {
         SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCommunication halted.");
      }
   }
   ps->cs->kth = kth_buf; 
   
   if (Opt->DoSpatNorm) {
      float ispat, jspat, kspat, iorig, jorig, korig , xrai_orig, yrai_orig, zrai_orig;
      
      SUMA_LH("Changing coords of output surface");
 
      /* what does the origin point (THD_BN_XORG THD_BN_YORG THD_BN_ZORG, ijk 0 0 0 )in the spat normed brain correspond to ? */
      ispat = 0; jspat = 0; kspat = 0;
      brainnormalize_coord( ispat , jspat, kspat,
                           &iorig, &jorig, &korig , Opt->iset,
                           &xrai_orig, &yrai_orig, &zrai_orig);
      Opt->SpatShift[0] = xrai_orig - THD_BN_xorg(); Opt->SpatShift[1] = yrai_orig - THD_BN_yorg(); Opt->SpatShift[2] = zrai_orig - THD_BN_zorg();

      /* shift the surface */
      for (i=0; i<SO->N_Node; ++i) {
         i3 = 3*i;
         SO->NodeList[i3 + 0] += Opt->SpatShift[0];
         SO->NodeList[i3 + 1] += Opt->SpatShift[1];
         SO->NodeList[i3 + 2] += Opt->SpatShift[2];
      }
      /* do the deed for the hull thing */
      if (SOhull) {
         for (i=0; i<SOhull->N_Node; ++i) {
            i3 = 3*i;
            SOhull->NodeList[i3 + 0] += Opt->SpatShift[0];
            SOhull->NodeList[i3 + 1] += Opt->SpatShift[1];
            SOhull->NodeList[i3 + 2] += Opt->SpatShift[2];
         }
      }
      /* ditto for other layers */
      if (Opt->Brain_Contour) {
         for (i=0; i<SO->N_Node; ++i) {
            i3 = 3*i;
            Opt->Brain_Contour[i3 + 0] += Opt->SpatShift[0];
            Opt->Brain_Contour[i3 + 1] += Opt->SpatShift[1];
            Opt->Brain_Contour[i3 + 2] += Opt->SpatShift[2];
         }
      }
      if (Opt->Brain_Hull) {
         for (i=0; i<SO->N_Node; ++i) {
            i3 = 3*i;
            Opt->Brain_Hull[i3 + 0] += Opt->SpatShift[0];
            Opt->Brain_Hull[i3 + 1] += Opt->SpatShift[1];
            Opt->Brain_Hull[i3 + 2] += Opt->SpatShift[2];
         }
      }
      if (Opt->Skull_Outer) {
         for (i=0; i<SO->N_Node; ++i) {
            i3 = 3*i;
            Opt->Skull_Outer[i3 + 0] += Opt->SpatShift[0];
            Opt->Skull_Outer[i3 + 1] += Opt->SpatShift[1];
            Opt->Skull_Outer[i3 + 2] += Opt->SpatShift[2];
         }
      }
      if (Opt->Skull_Inner) {
         for (i=0; i<SO->N_Node; ++i) {
            i3 = 3*i;
            Opt->Skull_Inner[i3 + 0] += Opt->SpatShift[0];
            Opt->Skull_Inner[i3 + 1] += Opt->SpatShift[1];
            Opt->Skull_Inner[i3 + 2] += Opt->SpatShift[2];
         }
      }
      
      /* Change the number of voxels in VolPar to reflect the number of voxels in the non-spatnormed dset */
      /* SUMA_VolDims(Opt->iset, &SO->VolPar->nx, &SO->VolPar->ny, &SO->VolPar->nz);  *//* remember, the dset that SO->VolPar represents is in RAI still */
      if (LocalHead) fprintf(SUMA_STDERR,"%s: \nPre: %d %d %d\n", FuncName, SO->VolPar->nx, SO->VolPar->ny, SO->VolPar->nz); 
      SUMA_Free_VolPar(SO->VolPar); SO->VolPar = NULL;
      SO->VolPar = SUMA_VolParFromDset(Opt->iset);
      if (LocalHead) fprintf(SUMA_STDERR,"%s: \nPost: %d %d %d\n", FuncName, SO->VolPar->nx, SO->VolPar->ny, SO->VolPar->nz); 
      if (SOhull) {
         SUMA_Free_VolPar(SOhull->VolPar); SOhull->VolPar = NULL;
         SOhull->VolPar = SUMA_VolParFromDset (Opt->iset);
      }
   }
   
   /* write the surfaces to disk */
   if (strcmp(Opt->out_prefix,"skull_strip_out")) {
      SUMA_LH("Output surfaces");
      if (Opt->Brain_Hull) {
         memcpy((void *)SO->NodeList, (void*)Opt->Brain_Hull, SO->N_Node * 3 * sizeof(float));  
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Writing Brain Hull surface  ...\n", FuncName);
         if (!SUMA_Save_Surface_Object (SO_name_bhull, SO, Opt->SurfFileType, Opt->SurfFileFormat, NULL)) {
            fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
            exit (1);
         }
      }
      if (Opt->Skull_Outer) {
         memcpy((void *)SO->NodeList, (void*)Opt->Skull_Outer, SO->N_Node * 3 * sizeof(float));  
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Writing Skull Outer surface  ...\n", FuncName);
         if (!SUMA_Save_Surface_Object (SO_name_oskull, SO, Opt->SurfFileType, Opt->SurfFileFormat, NULL)) {
            fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
            exit (1);
         }
      }
      if (Opt->Skull_Inner) {
         memcpy((void *)SO->NodeList, (void*)Opt->Skull_Inner, SO->N_Node * 3 * sizeof(float));  
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Writing Skull Inner surface  ...\n", FuncName);
         if (!SUMA_Save_Surface_Object (SO_name_iskull, SO, Opt->SurfFileType, Opt->SurfFileFormat, NULL)) {
            fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
            exit (1);
         }
      }
      
      /* leave this one at the end since the work afterwards will assume we are working with Brain_Contour in SO->NodeList */ 
      if (Opt->Brain_Contour) {
         memcpy((void *)SO->NodeList, (void*)Opt->Brain_Contour, SO->N_Node * 3 * sizeof(float));  
         if (Opt->debug) fprintf (SUMA_STDERR,"%s: Writing Brain Contour surface  ...\n", FuncName);
         if (!SUMA_Save_Surface_Object (SO_name, SO, Opt->SurfFileType, Opt->SurfFileFormat, NULL)) {
            fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
            exit (1);
         }
      }
   }
   
   if (Opt->debug) {
      float rad, vol, *p;
      int kkk;
      SUMA_LH("Rad Ratting");

      vol = SUMA_Mesh_Volume(SO, NULL, -1);
      rad = pow(3.0/4.0/SUMA_PI*vol, 1.0/3.0);
      SUMA_MIN_MAX_SUM_VECMAT_COL(SO->NodeList, SO->N_Node, SO->NodeDim, SO->MinDims, SO->MaxDims, SO->Center);
      SO->Center[0] /= (float)SO->N_Node; 
      SO->Center[1] /= (float)SO->N_Node; 
      SO->Center[2] /= (float)SO->N_Node; 
      /* what is the deviation from a sphere? */
      for (kkk=0; kkk<SO->N_Node; ++kkk) {
         p=&(SO->NodeList[3*kkk]);
         SUMA_SEG_LENGTH(SO->Center, p , Opt->shrink_bias[kkk]);  
         Opt->shrink_bias[kkk] /= rad; 
      }
      snprintf(stmp, 198, "%s_radrat.1D.dset", Opt->out_vol_prefix);
      SUMA_WRITE_ARRAY_1D(Opt->shrink_bias, SO->N_Node, 1, stmp);
   }
   
   if (Opt->UseSkull && SOhull) {
      fprintf (SUMA_STDERR,"%s: Writing skull surface  ...\n", FuncName);
      if (!SUMA_Save_Surface_Object (SO_name_hull, SOhull, Opt->SurfFileType, Opt->SurfFileFormat, NULL)) {
         fprintf (SUMA_STDERR,"Error %s: Failed to write surface object.\n", FuncName);
         exit (1);
      }
   }
   
   /* prepare to write masked volume */
   OptDs = SUMA_New_FormAfniDset_Opt();
   if (Opt->out_vol_prefix) {
      SUMA_FileName NewName = SUMA_StripPath(Opt->out_vol_prefix);
      OptDs->prefix = NewName.FileName; NewName.FileName = NULL;
      OptDs->prefix_path = NewName.Path; NewName.Path = NULL;
   }  else {
      OptDs->prefix = SUMA_copy_string("3dSkullStrip");
      OptDs->prefix_path = SUMA_copy_string("./");
   }
   if (Opt->DoSpatNorm) {
      OptDs->mset = Opt->iset; 
   } else {
      OptDs->mset = Opt->in_vol;
   }
   
   /* what voxels are inside the surface ? */
   if (Opt->debug) fprintf (SUMA_STDERR,"%s: Locating voxels inside surface  ...\n", FuncName);
   isin = SUMA_FindVoxelsInSurface (SO, SO->VolPar, &N_in, Opt->fillhole, Opt->OrigSpatNormedSet);
   isin_float = (float *)SUMA_malloc(sizeof(float) * SO->VolPar->nx*SO->VolPar->ny*SO->VolPar->nz);
   if (!isin_float) {
      SUMA_SL_Crit("Failed to allocate");
      exit(1);
   }
   
   /* change Opt->fvec to reflect original data (not spat normed baby)*/
   {
      THD_3dim_dataset *dout=NULL;
      
      if (Opt->MaskMode == 0 || Opt->MaskMode == 1) { /* use spatnormed baby, OK for mask too*/
         dout = Opt->OrigSpatNormedSet;
      } else if (Opt->MaskMode == 2) { /* use original dset */
         DSET_load(Opt->iset);
         dout = Opt->iset;
      } else {
         SUMA_S_Errv("Bad MaskMode value of %d!\n", Opt->MaskMode);
         SUMA_RETURN(NOPE);
      }
      
      if (Opt->fvec) { SUMA_free(Opt->fvec); Opt->fvec = NULL; }
      Opt->nvox = DSET_NVOX( dout );
      Opt->fvec = (float *)SUMA_malloc(sizeof(float) * Opt->nvox);
      if (!Opt->fvec) {
         SUMA_SL_Crit("Failed to allocate for fvec.\nOh misery.");
         SUMA_RETURN(NOPE);
      }

      EDIT_coerce_scale_type( Opt->nvox , DSET_BRICK_FACTOR(dout,0) ,
                              DSET_BRICK_TYPE(dout,0), DSET_ARRAY(dout, 0) ,      /* input  */
                              MRI_float               , Opt->fvec  ) ;   /* output */
   }
   if (Opt->MaskMode == 0 || Opt->MaskMode == 2) {
      SUMA_LH("Creating skull-stripped volume");
      for (i=0; i<SO->VolPar->nx*SO->VolPar->ny*SO->VolPar->nz; ++i) {
         /* apply the mask automatically */
         if (isin[i] >= SUMA_ON_NODE) isin_float[i] = (float)Opt->fvec[i];
         else isin_float[i] = 0.0;
      }
   } else if (Opt->MaskMode == 1) {
      SUMA_LH("Creating mask volume");
      for (i=0; i<SO->VolPar->nx*SO->VolPar->ny*SO->VolPar->nz; ++i) {
         isin_float[i] = (float)isin[i];
      }
   } else {
      SUMA_S_Errv("Bad MaskMode of %d!\n", Opt->MaskMode);
      SUMA_RETURN(NOPE);
   }
   if (isin) SUMA_free(isin); isin = NULL;
      
   if (Opt->debug) fprintf (SUMA_STDERR,"%s: Writing masked volume  ...\n", FuncName);
   OptDs->full_list = 1;
   OptDs->dval = 1;
   dset = SUMA_FormAfnidset (NULL, isin_float, SO->VolPar->nx*SO->VolPar->ny*SO->VolPar->nz, OptDs);
   
   /* erode and dilate, a bit of a cleanup? */
   if (1){
      EDIT_options *edopt = SUMA_BlankAfniEditOptions();
      if (Opt->debug) fprintf (SUMA_STDERR,"%s: Applying a bit of erosion and dilatation \n", FuncName);
      edopt->edit_clust = ECFLAG_SAME;
      edopt->clust_rmm = SUMA_MAX_PAIR(SUMA_ABS((DSET_DX(OptDs->mset))), SUMA_ABS((DSET_DY(OptDs->mset))));
      edopt->clust_rmm = SUMA_MAX_PAIR(SUMA_ABS((DSET_DZ(OptDs->mset))), edopt->clust_rmm)*1.01;
	   edopt->clust_vmul = 1000*SUMA_ABS((DSET_DX(OptDs->mset)))*SUMA_ABS((DSET_DY(OptDs->mset)))*SUMA_ABS((DSET_DZ(OptDs->mset)));
      edopt->erode_pv  = 75.0 / 100.0;
      edopt->dilate = 1;
      EDIT_one_dataset( dset , edopt);
      SUMA_free(edopt);
   }
   
   
   if (!dset) {
      SUMA_SL_Err("Failed to create output dataset!");
   } else {
      tross_Make_History( FuncName , argc,argv , dset ) ;
      DSET_write(dset) ;
      if (Opt->MaskMode != 2) {
         if (Opt->MaskMode == 0) {
            fprintf(SUMA_STDERR,
                  "The intensity in the output dataset is a modified version\n"
                  "of the intensity in the input volume.\n" );
         } else {
            fprintf(SUMA_STDERR,
                  "The output dataset is a mask reflecting where voxels in the\n"
                  "input dataset lie in the brain.\n");
         }
         fprintf(SUMA_STDERR,
               "To obtain a masked version of the input with identical values inside\n"
               "the brain, you can either use 3dSkullStrip's -orig_vol option\n"
               "or run the following command:\n"
               "  3dcalc -a %s -b %s+orig -expr 'a*step(b)' \\\n"
               "         -prefix %s_orig_vol\n"
               "to generate a new masked version of the input.\n",
               Opt->in_name, Opt->out_vol_prefix, Opt->out_vol_prefix);
               
      }
   }
   
   /* you don't want to exit rapidly because the SUMA might not be done processing the last elements*/
   if (ps->cs->Send && !ps->cs->GoneBad) {
      /* cleanup and close connections */
      if (!SUMA_SendToSuma (SO, ps->cs, NULL, SUMA_NODE_XYZ, 2)) {
         SUMA_SL_Warn("Failed in SUMA_SendToSuma\nCleanup failed");
      }
   }   
   
   if (dsmooth) SUMA_free(dsmooth); dsmooth = NULL;
   if (OptDs) { OptDs->mset = NULL; OptDs = SUMA_Free_FormAfniDset_Opt(OptDs);  }
   if (dset) { DSET_delete(dset); dset = NULL; }
   if (isin) { SUMA_free(isin); isin = NULL; }
   if (isin_float) { SUMA_free(isin_float); isin_float = NULL; }
   if (ps) SUMA_FreeGenericArgParse(ps); ps = NULL;
   if (Opt) Opt = SUMA_Free_Generic_Prog_Options_Struct(Opt);
   if (hullprefix) SUMA_free(hullprefix); hullprefix = NULL;
   if (bhullprefix) SUMA_free(bhullprefix); bhullprefix = NULL;
   if (oskullprefix) SUMA_free(oskullprefix); oskullprefix = NULL;
   if (iskullprefix) SUMA_free(iskullprefix); iskullprefix = NULL;
   
   if (SO_name_hull) SUMA_free(SO_name_hull); SO_name_hull = NULL;
   if (SO_name_bhull) SUMA_free(SO_name_bhull); SO_name_bhull = NULL;
   if (SO_name_iskull) SUMA_free(SO_name_iskull); SO_name_iskull = NULL;
   if (SO_name_oskull) SUMA_free(SO_name_oskull); SO_name_oskull = NULL;
   if (SO_name) SUMA_free(SO_name); SO_name = NULL;
   if (SO) SUMA_Free_Surface_Object(SO); SO = NULL;
   if (SOhull) SUMA_Free_Surface_Object(SOhull); SOhull = NULL;
   if (!SUMA_Free_Displayable_Object_Vect (SUMAg_DOv, SUMAg_N_DOv)) {
      SUMA_SL_Err("DO Cleanup Failed!");
   }
   if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1);
   exit(0);
}   
#endif


syntax highlighted by Code2HTML, v. 0.9.1