// Created 12/17/07 19:38:16 by /usr/site/scripts/loadfiles
//================================================================
// INSERTED batch.hoc
// =Id=  batch.hoc,v 1.30 2006/11/08 01:18:54 billl Exp 

mapped_nrnmainmenu_ = 1
batch_flag = 1
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/setup.hoc
// =Id=  setup.hoc,v 1.24 2006/11/08 00:51:51 billl Exp 
// variables normally controlled by SIMCTRL

// load_file("setup.hoc")
load_file("stdgui.hoc")
show_panel=0
strdef simname, filename, output_file, datestr, uname, comment, section, osname
objref tmpfile,nil,graphItem,sfunc
sfunc = hoc_sf_  // from stdlib.hoc
proc chop () { sfunc.left($s1,sfunc.len($s1)-1) }

tmpfile = new File()
simname = "sim"      // helpful if running multiple simulations simultaneously
runnum = 1           // updated at end of run
system("uname -m",uname)  // keep track of type of machine for byte compatibility
chop(uname)
system("date +%y%b%d",datestr)
chop(datestr) // may prefer to downcase later
sprint(output_file,"data/%s.%02d",datestr,runnum)  // assumes a subdir called data
if (unix_mac_pc()==1) osname = "Linux" else if (unix_mac_pc()==2) { 
    osname = "Mac" } else if (unix_mac_pc()==3) osname = "PC"
printStep = 0.25 // time interval for saving to vector
graph_flag=0
batch_flag=1
xwindows = 0     // can still save but not look without xwindows

// load_file("nrnoc.hoc")
// END /usr/site/nrniv/local/hoc/setup.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/nrnoc.hoc
// =Id=  nrnoc.hoc,v 1.74 2007/11/20 07:51:52 billl Exp 

proc nrnoc () {}

// Users should not edit nrnoc.hoc or default.hoc.  Any local 
// changes to these files should be made in local.hoc.

// key '*&*' is picked up by to indicate command for emacs
proc elisp () { printf("*&* %s\n",$s1) }
// if (not exists(simname)) { strdef simname, output_file, datestr, comment }

// Simctrl.hoc will automatically load stdgraph.hoc which automatically
// loads stdrun.hoc
strdef temp_string_, user_string_  // needed for simctrl
/* Global variable default values.  NOTE that stdrun.hoc, stdgraph.hoc
and simctrl.hoc all contain variable definitions and thus default.hoc
should be loaded after these files */
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/default.hoc
// =Id=  default.hoc,v 1.5 2003/07/08 16:16:52 billl Exp 
/* This file contains various global defaults for hoc

** Users should not edit nrnoc.hoc or default.hoc.  Any local 
changes to these files should be made in local.hoc.
----------------------------------------------------------------*/

/*------------------------------------------------------------
Object defaults
------------------------------------------------------------*/

/*** Define a "nil" object ***/
objectvar nil

/*------------------------------------------------------------
String defaults
------------------------------------------------------------*/

/*** "Section" is used if errors are found in the initializiations ***/
strdef section

/*** Misc defines used by graphic routines ***/
temp_string_ = "t"
tempvar = 0

/*------------------------------------------------------------
Simulation defaults
------------------------------------------------------------*/

                        /* To be consistent w/the nmodl values */
FARADAY = 96520.        /* Hoc default = 96484.56 */
PI      = 3.14159       /* Hoc default = 3.1415927 */

                        /* 0=off, 1=on */
print_flag  = 0         /* Write to output file */
graph_flag  = 1         /* Plot output */
iv_flag     = 1         /* Using Interviews plotting */
batch_flag  = 0         /* Using batch_run() */
compress_flag = 0       /* Compress output file when saved */
stoprun     = 0         /* 0=running, 1=stopped */
iv_loaded   = 0         /* Load initial iv stuff on once */

init_seed   = 830529
run_seed    = 680612

t           = 0         /* msec */
dt          = .01       /* msec */
tstop       = 100       /* msec */
printStep   = 0.1       /* msec */
plotStep    = 0.1       /* msec */
flushStep   = 0.1       /* msec */
eventStep   = 50        /* Number of nstep's before a doEvent */

secondorder = 0

celsius     = 6.3       /* degC */

v_init      = -70       /* (mV) */
global_ra   = 200       /* (ohm-cm) specific axial resisitivity */

/*** Ion parameters ***/
ca_init     = 50e-6     /* mM */
na_init     = 10        /* mM */
k_init      = 54.4      /* mM */

// END /usr/site/nrniv/simctrl/hoc/default.hoc
//================================================================

/* Allows arrays of strings */
objref hoc_obj_[2]
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/simctrl.hoc
// =Id=  simctrl.hoc,v 1.14 2000/11/27 21:59:33 billl Exp 
// Graphic routines for neuremacs simulation control

proc sim_panel () {
    xpanel(simname)
          xvarlabel(output_file)
  	xbutton("Init", "stdinit()")
  	xbutton("Init & Run", "run()")
  	xbutton("Stop", "stoprun=1")
  	xbutton("Continue till Tstop", "continueRun(tstop)")
  	xvalue("Continue till", "runStopAt", 1, "{continueRun(runStopAt) stoprun=1}", 1, 1)
  	xvalue("Continue for", "runStopIn", 1, "{continueRun(t + runStopIn) stoprun=1}", 1,1)
  	xbutton("Single Step", "steprun()")
  	xvalue("Tstop", "tstop", 1, "tstop_changed()", 0, 1)
  	graphmenu()
  	sim_menu_bar()
  	misc_menu_bar()
    xpanel()
  }

proc misc_menu_bar() {
    xmenu("Miscellaneous")
      xbutton("Label Graphs", "labelgrs()")
      xbutton("Label With String", "labelwith()")
      xbutton("Label Panel", "labelpanel()")
  	xbutton("Parameterized Function", "load_template(\"FunctionFitter\") makefitter()")
    xmenu()
  }

proc sim_menu_bar() {
    xmenu("Simulation Control")
      xbutton("File Vers", "elisp(\"sim-current-files\")")
      xbutton("File Status...", "elisp(\"sim-rcs-status\")")
      xbutton("Sim Status", "elisp(\"sim-portrait\")")
      xbutton("Load Current Files", "elisp(\"sim-load-sim\")")
      xbutton("Load Templates", "elisp(\"sim-load-templates\")") 
      xbutton("Load File...", "elisp(\"sim-load-file\")") 
      xbutton("Save Sim...", "elisp(\"sim-save-sim\")")
      xbutton("Set File Vers...", "elisp(\"sim-set-file-ver\")")
      xbutton("Read Current Vers From Index", "elisp(\"sim-read-index-file\")")
      xbutton("Read Last Saved Vers", "elisp(\"sim-read-recent-versions\")")
      xbutton("Output to sim buffer", "elisp(\"sim-direct-output\")")
    xmenu()
  }

proc labelpanel() {
    xpanel(simname,1)
  	xvarlabel(output_file)
    xpanel()
  }

proc labels () {
    labelwith($s1)
    labelgrs()
  }

proc labelgrs () { local i, j, cnt
    for j=0,n_graph_lists-1 {
        cnt = graphList[j].count() - 1
        for i=0,cnt labelgr(graphList[j].object(i))
      }
  }

proc labelwith () { local i, j, cnt
    temp_string_ = user_string_  // save the old one
    if (numarg() == 1) { /* interactive mode */  
        user_string_ = $s1
      } else {
        string_dialog("write what?", user_string_)
      }
    for j=0,n_graph_lists-1 {
        cnt = graphList[j].count() - 1
        for i=0,cnt {
            graphList[j].object(i).color(0)
            graphList[j].object(i).label(0.5,0.9,temp_string_)
            graphList[j].object(i).color(1)
            graphList[j].object(i).label(0.5,0.9,user_string_)
          }
      }
  }

proc labelgr () { local i
    $o1.color(0)  // white overwrite
    for (i=0;i<10;i=i+1) { // erase every possible runnum for this date
        sprint(temp_string_,"%s %d%d",datestr,i,i)
        $o1.label(0.1,0.7,temp_string_) }
    $o1.color(1) // back to basic black
    sprint(temp_string_,"%s %02d",datestr,runnum)
    $o1.label(0.1,0.7,temp_string_)
  }

// END /usr/site/nrniv/simctrl/hoc/simctrl.hoc
//================================================================

proc run () {
    running_ = 1
    stdinit()
    continueRun(tstop)
    finish()
  }

proc continueRun () { local rt, rtstart, ts
    if (numarg()==1) ts=$1 else ts=t+1e3
    realtime = 0  rt = screen_update_invl  rtstart = startsw()
    eventcount=0
    eventslow=1
    stoprun = 0
    if (using_cvode_) {
        if (cvode.use_local_dt || (cvode.current_method()%10) == 0) {
            cvode.solve(ts)
            flushPlot()
            realtime = startsw() - rtstart
            return
          }
      } else {
        ts -= dt/2
      }
    while (t<ts && stoprun==0) {
        step()
        realtime = startsw() - rtstart
        if (realtime >= rt) {
            //                        if (!stdrun_quiet) fastflushPlot()
            screen_update()
            //really compute for at least screen_update_invl
            realtime = startsw() - rtstart
            rt = realtime + screen_update_invl
          }
      }
    if (using_cvode_ && stoprun == 0) { // handle the "tstop" event
        step() // so all recordings take place at tstop
      }
    flushPlot()
    realtime = startsw() - rtstart
  }

proc stdinit() {
          cvode_simgraph()
          realtime = 0
          setdt()
          init()
          initPlot()
  }

proc init () {
    cvode_simgraph()
    initMech()
    initMisc1()
  
    // Initialize state vars then calculate currents
    // If user hand-set v in initMisc1() then v_init should be > 1000,
    // else all compartments will be set to v_init
    if (v_init < 1000) {
        finitialize(v_init)
      } else {
        finitialize()
      }
  
    // Set ca pump and leak channel for steady state
    setMemb()
  
    initMisc2()
    if (cvode_active()) cvode.re_init() else fcurrent()
    frecord_init()
  }

// Initialization of mechanism variables
// NOTE: if any changes are made to the NEURON block of any local mod
// file, the user must add the necessary inits to initMisc1()
proc initMech () { 
    forall {
        if ((!ismembrane("pas")) && (!ismembrane("Passive"))) { 
            // Allow for either pas or Passive mod file usage
            // errorMsg("passive not inserted") 
          }
    
        if (ismembrane("na_ion")) { 
            nai = na_init
            nai0_na_ion = na_init
          }
        
        if (ismembrane("k_ion")) {
            ki = k_init
            ki0_k_ion = k_init
          }
        
        if (ismembrane("ca_ion")) { 
            cai = ca_init
            cai0_ca_ion = ca_init
          }
      }
  }

//* setMemb complex -- multiple names for passive mech
//** declarations
iterator scase() { local i
    for i = 1, numarg() { temp_string_ = $si iterator_statement }}
objref paslist,pasvars[3],XO
double pasvals[2],x[1]
paslist = new List()
for ii=0,2 pasvars[ii]= new String()
for scase("fastpas","pas","Pass","Passive") paslist.append(new String(temp_string_))

//** getval(),setval() -- return/set the hoc value of a string
func retval () { return getval($s1) }
func getval () { 
    sprint(temp_string2_,"x=%s",$s1)
    execute(temp_string2_)
    return x
  }
proc setval () { 
    sprint(temp_string2_,"%s=%g",$s1,$2)
    execute(temp_string2_)
  }

//** findpas()
// assumes that we are starting in a live section since looks for pass mech there
qx_=0
proc findpas () {
    for ii=0,paslist.count-1 {
        XO=paslist.object(ii)
        if (ismembrane(XO.s)) {
            // print XO.s,"found"
            pasvars[2].s=XO.s
            sprint(pasvars[0].s,"g_%s(qx_)",XO.s)
            for scase("e","erev","XXXX") {  // look for the proper prefix
                sprint(temp_string_,"%s_%s",temp_string_,XO.s)
                if (name_declared(temp_string_)==1) break
              }
            if (name_declared(temp_string_)==0) { // not found
                printf("SetMemb() in nrnoc.hoc: Can't find proper 'erev' prefix for %s\n",XO.s)
              } else {
                sprint(pasvars[1].s,"%s(qx_)",temp_string_)
              }
          }
      }
  }

proc setMemb () {
    if (!secp()) return
    findpas() // assume that passive name is the same in all sections
    forall for (qx_,0) {  // will eventually want 'for (x)' to handle all the segments
        if (ismembrane(pasvars[2].s)) {
              for ii=0,1 pasvals[ii]=getval(pasvars[ii].s)
              setmemb2()
              for ii=0,1 setval(pasvars[ii].s,pasvals[ii])
          }
      }
  }

// secp() determine whether any sections exist
func secp () { local n
    n=0
    forall n+=1
    if (n>0) return 1 else return 0
  }

func setother () {return 0} // callback stub
proc setmemb2 () { local iSum, ii, epas, gpas
    if (!secp()) return
    gpas=pasvals[0] epas=pasvals[1]
    // Setup steady state voltage using leak channel
    iSum = 0.0
    if (ismembrane("na_ion")) { iSum += ina(qx_) }
    if (ismembrane("k_ion"))  { iSum += ik(qx_)  }
    if (ismembrane("ca_ion")) { iSum += ica(qx_) }
    iSum += setother()
  
    if (iSum == 0) {        // Passive cmp so set e_pas = v
        epas = v
      } else {
        if (gpas > 0) {    // Assume g set by user, calc e
            epas = v + iSum/gpas
      
          } else {            // Assume e set by user, calc g
            if (epas != v) {
                gpas = iSum/(epas - v)
              } else { gpas=0 }
          }
        if (gpas < 0) errorMsg("bad g", gpas)
        if (epas < -100 || epas > 0) {
            printf(".")
            // printf("%s erev: %g %g %g\n",secname(),e_pas,ina,ik)
          }
      }
    pasvals[0]=gpas pasvals[1]=epas
  }

proc finish () {
    /* Called following completion of continueRun() */
  
  finishMisc()
  
  if (graph_flag == 1) {
      if (iv_flag == 1) {
          flushPlot()
          doEvents()
        } else {
          graphmode(-1)
          plt(-1)
        }
    }
  
  if (print_flag == 1) {
      wopen("")
    }
  }

/*------------------------------------------------------------
User definable GRAPHICS and PRINTING routines
------------------------------------------------------------*/

proc outputData() {
    // Default procedure - if outputData() doesn't exist in the run file
  
    if (graph_flag == 1) {
        if (iv_flag == 1) {
            Plot()
            rt = stopsw()
            if (rt > realtime) {
                realtime = rt
                fastflushPlot()
                doNotify()
                if (realtime == 2 && eventcount > 50) {
                    eventslow = int(eventcount/50) + 1
                  }
                eventcount = 0
              }else{
                eventcount = eventcount + 1
                if ((eventcount%eventslow) == 0) {
                    doEvents()
                  }
              }
      
          } else {
            graph(t)
          }
      }
  
    if (print_flag == 1) { 
        if (t%printStep <= printStep) { printOut() }
      }
  }

proc printOut() {
    /* Default procedure - if printOut() doesn't exist in the run file */
  }

proc initGraph() {
    /* Default procedure - if initGraph() doesn't exist in the run file */
  
  graph()
  }

proc initPrint() {
    /* Default procedure - if initPrint() doesn't exist in the run file */
  
  wopen(output_file)
  }

/*------------------------------------------------------------
User definable BATCH RUN routines
------------------------------------------------------------*/

proc nextrun() {
    // Called from finishmisc() following completion of batch in an autorun
    wopen("")   
    runnum = runnum + 1
    sprint(output_file,"data/b%s.%02d", datestr, runnum)
  }                       

// commands for emacs
proc update_runnum() { 
    runnum = $1
    sprint(output_file,"data/%s.%02d", datestr, runnum)
    print "^&^ (progn (sim-index-revert)(setq sim-runnum ",runnum,"))" }
proc nrn_write_index() { printf("&INDEX& %s\n",$s1) }
proc nrn_update () { elisp("nrn-update") }
proc nrn_message () { printf("!&! %s\n",$s1) } 

/*------------------------------------------------------------
User definable INITIALIZATION and FINISH routines
------------------------------------------------------------*/

// Default procedure - if initMisc1() doesn't exist in the run file 
// Initializations performed prior to finitialize() 
// This should contain point process inits and inits for any changes 
//        made to the NEURON block of any local mod file 
proc initMisc1() { }

// Default procedure - if initMisc2() doesn't exist in the run file 
// Initializations performed after finitialize() 
proc initMisc2() { }

// Default procedure - if finishMisc() doesn't exist in the run file 
proc finishMisc() { }

/*------------------------------------------------------------
Miscellaneous routines
------------------------------------------------------------*/

proc errorMsg() {
    /* Print warning, assumes arg1 is string and arg2 if present is a
    variable value */
  
  sectionname(section)
  
  if (numarg() == 0) {
      printf("ERROR in errorMsg(): Needs at least 1 argument.\n")
    } else if (numarg() == 1) {
      printf("ERROR: %s in section %s.\n", $s1, section)
    } else {
      printf("ERROR: %s in section %s (var=%g).\n", $s1, section, $2)
    }
  }

proc clear() {
    /* Clear non-interviews plot window */
  plt(-3)
  }

func mod() { local x, y
    /* Mod function for non-integers */
  
  x=$1
  y=$2
  
  return (x/y - int(x/y))
  }

proc whatSection() { print secname() }

proc print_pp_location() { local x //arg1 must be a point process
     x = $o1.get_loc()
     sectionname(temp_string_)
     printf("%s located at %s(%g)\n", $o1, temp_string_, x)
     pop_section()
  }

//* set method with method()
proc method () { local prc
    if (numarg()==0) {
        if (cvode_active() && cvode_local()) { printf("\tlocal atol=%g\n",cvode.atol)
          } else if (cvode_active()) { printf("\tglobal atol=%g\n",cvode.atol)
          } else if (secondorder==2) { printf("\tCrank-Nicholson dt=%g\n",dt)
          } else if (secondorder==0) { printf("\timplicit dt=%g\n",dt)
          } else { printf("\tMethod unrecognized\n") }
        return
      }
    if (numarg()==2) prc = $2 else prc=0
    finitialize()
    if (strcmp($s1,"global")==0) {
        cvode_active(1)
        cvode.condition_order(2)
        if (prc) cvode.atol(prc)
      } else if (strcmp($s1,"local")==0) {
        cvode_local(1)
        cvode.condition_order(2)
        if (prc) cvode.atol(prc)
      } else if (strcmp($s1,"implicit")==0) {
        secondorder=0
        cvode_active(1)
        cvode_active(0)
        if (prc) dt=prc
      } else if (strcmp($s1,"CN")==0) {
        secondorder=2
        cvode_active(1) // this turns off local
        cvode_active(0)
        if (prc) dt=prc
      } else {
        printf("Integration method %s not recognized\n",$s1)
      }
  }

//* Load local modifications to nrnoc.hoc and default.hoc
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/local.hoc
//  $Header: /usr/site/nrniv/simctrl/hoc/RCS/local.hoc,v 1.15 2003/02/13 15:32:06 billl Exp $
//
//  This file contains local modifications to nrnoc.hoc and default.hoc
//
//  Users should not edit nrnoc.hoc or default.hoc.  Any local 
//  changes to these files should be made in this file.

// ------------------------------------------------------------
//* MODIFICATIONS TO NRNOC.HOC
// The procedures declared here will overwrite any duplicate
// procedures in nrnoc.hoc.
// ------------------------------------------------------------

//*MODIFICATIONS TO DEFAULT.HOC
//
// Vars added here may not be handled properly within nrnoc.hoc
//------------------------------------------------------------

//** String defaults

//** Simulation defaults

long_dt     = .001      // msec 

objref sfunc,tmpfile
sfunc = hoc_sf_   // needed to use is_name()
tmpfile = new File()  // check for existence before opening a user's local.hoc file

proc write_comment () {
    tmpfile.aopen("index")
    tmpfile.printf("%s\n",$s1)
    tmpfile.close()  
  }

func asin () { return atan($1/sqrt(1-$1*$1)) }
func acos () { return atan(sqrt(1-$1*$1)/$1) }

objref mt[2]
mt = new MechanismType(0)
proc uninsert_all () { local ii
    forall for ii=0,mt.count()-1 {
        mt.select(ii)
        mt.selected(temp_string_)
        if (strcmp(temp_string_,"morphology")==0) continue
        if (strcmp(temp_string_,"capacitance")==0) continue
        if (strcmp(temp_string_,"extracellular")==0) continue
        if (sfunc.substr(temp_string_,"_ion")!=-1) continue
        mt.remove()
        // print ii,temp_string_
      }
  }

condor_run = 0  // define for compatability
// END /usr/site/nrniv/simctrl/hoc/local.hoc
//================================================================

if (xwindows && graph_flag) { nrnmainmenu() } // pwman_place(50,50)

print "Init complete.\n"
// END /usr/site/nrniv/simctrl/hoc/nrnoc.hoc
//================================================================
//================================================================
// INSERTED init.hoc
// =Id=  init.hoc,v 1.13 2006/11/06 22:56:37 billl Exp 

show_panel=0
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/grvec.hoc
//* =Id=  grvec.hoc,v 1.634 2007/11/26 17:27:51 billl Exp 

// argtype: 0:double; 1:obj; 2:str; 3:double pointer
objref g[10],printlist,grv_,panobj,panobjl
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/decvec.hoc
// =Id=  decvec.hoc,v 1.366 2007/11/28 17:02:15 billl Exp 

proc decvec() {}

//* Declarations
objref ind, tvec, vec, vec0, vec1, tmpvec, vrtmp, veclist, veccollect, pwm
objref tmpobj, XO, YO, rdm, dir
strdef filename,dblform,tabform
dblform="%3.4g"

dir = new List()
tmpfile = new File()
if (! name_declared("datestr")) load_file("setup.hoc")
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/declist.hoc
// =Id=  declist.hoc,v 1.129 2007/12/18 00:13:46 billl Exp 

//* Declarations
strdef mchnms
objref tmplist,tmplist2,tmpobj,aa,XO,YO
if (! name_declared("datestr")) load_file("setup.hoc")
tmplist = new List()
proc declist() {}

//* Templates
//** template String2
begintemplate String2
public s,t,x,append,prepend,exec,tinit
strdef s,t
proc init() {
    if (numarg() == 1) { s=$s1 }
    if (numarg() == 2) { s=$s1 t=$s2 }
    if (numarg() == 3) { s=$s1 t=$s2 x=$3 }
  }
proc append () { local i
    if (argtype(1)==2) sprint(t,"%s%s",s,$s1)
    for i=2,numarg() sprint(t,"%s%s",t,$si)
  }
proc prepend () { local i
    if (argtype(1)==2) sprint(t,"%s%s",$s1,s)
    for i=2,numarg() sprint(t,"%s%s",$si,t)
  }
proc exec () {
    if (numarg()==1) sprint(t,"%s%s",$s1,s)
    execute(t)
  }
proc tinit() { t=$s1 }

endtemplate String2

//** template DBL
begintemplate DBL
  public x
  proc init () { if (numarg()==1) x=$1 else x=0 }
endtemplate DBL

//** template Union
// USAGE: XO=new Union(val) where val can be a number string or object
//        XO=new Union(list,index) will pick up a string or object from list
//        XO=new Union(vec,index)  will pick up a number from vector
//        XO=new Union(&dbl,index) will pick up a number from double array
// Union allows storage of a double, string or object
// It is useful as a localobj in an obfunc since it will permit returning anything
// It also makes it easy to pick up any kind of value out of a list, vector or array
begintemplate Union
public ty,x,s,t,u,v,o
strdef s,t,u,v
objref o[10]
double x[10]
external sfunc,tstr
// 1arg -- store a num, string or obj
// 2arg -- pick up type out of list
proc init() { local ii
    x=x[1]=0 ty=-1
    if (numarg() == 1) {
        ty = argtype(1)
        if (ty==0) { x=$1
          } else if (ty==2) { s=$s1 
          } else if (ty==1) { o=$o1 
          } else printf("Union ERR: argtype not recognized %d\n",ty)
      } else if (numarg()==2) {
        ii=$2
        if (argtype(1)==1) {
            if (isobj($o1,"Vector")) { 
                if (ii<0 || ii>=$o1.size) {
                    printf("Union ERR: vec index (%d) out of bounds for %s\n",ii,$o1)
                    return }
                ty=0 x=$o1.x[ii] o=$o1
              } else if (isobj($o1,"List")) {
                if (ii<0 || ii>=$o1.count) {
                    printf("Union ERR: list index (%d) out of bounds for %s\n",ii,$o1)
                    return }
                if (isobj($o1.object(ii),"String")) { // will handle String2
                    ty=2 s=$o1.object(ii).s o=$o1.object(ii) x=ii
                  } else { ty=1 o=$o1.object(ii) x=ii }
              }
          } else if (argtype(1)==3) {
            ty=0 x=$&1[ii] // could check - but no + bound checking possible
          }
      }
  }

func isobj () {
    sprint(tstr,"%s",$o1)
    if (sfunc.substr(tstr,$s2)==0) return 1 else return 0
  }
endtemplate Union

//* Iterators
//** list iterator ltr
// usage 'for ltr(tmplist) { print XO }' :: 1 arg, assumes XO as dummy
// usage 'for ltr(YO, tmplist) { print YO }' 2 arg, specify dummy
// usage 'for ltr(XO, tmplist, &x) { print XO,x }' :: x is counter (else use global i1)
// usage 'for ltr(XO, tmplist, 5) { print XO,x }' :: max; only print out 0-5
// usage 'for ltr(XO, tmplist, 5, 7) { print XO,x }' :: print 5-7
// usage 'for ltr(XO, tmplist, &x, 5) { print XO,x }' :: counter with max
// usage 'for ltr(XO, tmplist, &x, 5, 7) { print XO,x }' :: counter,min,max
iterator ltr () { local i,min,max,ifl
    min=0 max=1e9 ifl=0 // iterator flag
    if (numarg()==3) {
        if (argtype(3)==3) {ifl=1 $&3=0}
        if (argtype(3)==0) max=$3
      } else if (numarg()==4) { 
        if (argtype(3)==0) i1=min=$3 else {ifl=1 $&3=0}
        max=$4 
      } else if (numarg()==5) { 
        $&3=min=$4 max=$5 ifl=1 
      }
    if (! ifl) i1=0
    if (numarg()==1) {
        for i = 0, $o1.count-1 {
            XO = $o1.object(i)
            iterator_statement
            i1+=1
          }
        tmpobj=$o1
        XO=nil
      } else {
        if (max==1e9) max=$o2.count()-1 else if (max<0) { min=$o2.count+max max=$o2.count-1 
          } else if (max>$o2.count-1) max=$o2.count-1
        for i = min, max {
            $o1 = $o2.object(i)
            iterator_statement
            if (ifl) { $&3+=1 } else { i1+=1 }
          }
        tmpobj=$o2
        $o1 = nil
      }
  }

//** list iterator ltrb -- backwards list iterator
// usage 'for ltrb(tmplist) { print XO }' :: 1 arg, assumes XO as dummy
// usage 'for ltrb(YO, tmplist) { print YO }' 2 arg, specify dummy
// usage 'for ltrb(XO, tmplist, &x) { print XO,x }' :: 3 args, define counter (else i1 default)
//                                                 :: note that x, i1 must be defined
iterator ltrb () { local i
    if (numarg()==1) {
        i1=$o1.count-1
        for (i=$o1.count()-1;i>=0;i-=1) {
            XO = $o1.object(i)
            iterator_statement
            i1-=1
          }
        tmpobj=$o1 XO=nil
      } else {
        if (numarg()==3) $&3=$o2.count-1 else i1=$o2.count-1
        for (i=$o2.count()-1;i>=0;i-=1) {
            $o1 = $o2.object(i)
            iterator_statement
            if (numarg()==3) { $&3-=1 } else { i1-=1 }
          }
        tmpobj=$o2
        $o1 = nil
      }
  }

//** list iterator ltr2
// usage 'for ltr2(XO, YO, list1, list2) { print XO,YO }'
iterator ltr2() { local i,cnt
    if (numarg()==5) $&5=0 else i1=0
    cnt=$o4.count
    if ($o3.count != $o4.count) { print "ltr2 WARNING: lists have different lengths" 
        if ($o3.count<$o4.count) cnt=$o3.count }
    for i = 0, cnt-1 {
        $o1 = $o3.object(i)
        $o2 = $o4.object(i)
        iterator_statement
        if (numarg()==5) { $&5+=1 } else { i1+=1 }
      }
    $o1=nil $o2=nil
  }

//** list pairwise iterator ltrp
// usage 'for ltrp(XO, YO, list) { print XO,YO }' takes them pairwise
iterator ltrp() { local i
    if (numarg()==4) {$&4=0} else {i1 = 0}
    for (i=0;i<$o3.count()-1;i+=2) {
        $o1 = $o3.object(i) $o2 = $o3.object(i+1)
        iterator_statement
        if (numarg()==4) { $&4+=1 } else { i1+=1 }
      }
    $o1=nil $o2=nil
  }

//** list iterator sltr
// usage 'for sltr(XO, string) { print XO }'
iterator sltr() { local i
    tmplist = new List($s2)
    if (numarg()==3) {$&3=0} else {i1=0}
    for i = 0, tmplist.count() - 1 {
        $o1 = tmplist.object(i)
        iterator_statement
        if (numarg()==3) { $&3+=1 } else { i1+=1 }
      }
    $o1 = nil
  }

//* Procedures
//** append(LIST,o1,o2,...) -- like revec() makes a list of objects
proc append () { local i,max
    if (!isassigned($o1)) $o1=new List()
    max=numarg()
    if (argtype(max)==0) {max-=1 $o1.remove_all}
    for i=2,max $o1.append($oi)
  }

//** rcshead([flag])
// with flag does head from archive
func rcshead () { local x,flag localobj st
    x=-1 flag=0
    st=new String2()
    if (numarg()==2) {
        st=dirname($s1)
        sprint(st.t,"%sRCS/%s,v",st.s,st.t)
        flag=1
      } else st.t=$s1
    sprint(st.s,"head -1 %s",st.t)
    system(st.s,st.s)
    if (flag) sscanf(st.s,"head\t1.%d",&x) else sscanf(st.s,"%*[^,],v 1.%d",&x)
    return x
  }

//** getenv()
obfunc getenv () { localobj st
    st=new String()
    sprint(st.s,"echo $%s",$s1)
    system(st.s,st.s)
    sfunc.left(st.s,sfunc.len(st.s)-1)
    if (numarg()==2) $s2=st.s
    return st
  }

//** rcsopen(file,vers[,flag])  -- version open, flag to do load_file
// rcsopen(file,vers,proc_name)  -- just load the single proc or func from that vers
//  rcsopen("nqsnet.hoc,43,network.hoc,17,params.hoc,842,run.hoc,241") will open several files
func rcsopen () { local a,vers,ii,x,ret localobj st,fn,v1,o,xo
    st=new String2()
    st.s=$s1 ret=1
    // open network.hoc,params.hoc,run.hoc files for "#.#.#" 
    if (strm(st.s,"^[^,]+,[^,]+,[^,]+,[^,]+")) {
        a=allocvecs(v1)  o=new List()
        split(st.s,o)
        for (ii=1;ii<o.count;ii+=2) v1.append(str2num(o.o(ii).s))
        if (o.count!=v1.size*2) { printf("rcsopen() discrepency: ") vlk(v1) llist(o) dealloc(a) 
            return 0 }
        for ltr(xo,o,&x) if (x%2==0) { // every other
            printf("Opening %s%d\n",xo.s,v1.x[x/2])
            if (!rcsopen(xo.s,v1.x[x/2])) { dealloc(a) ret=0 }
          }
        dealloc(a)
        return ret
      }
    if (numarg()>1) vers=$2 else vers=0
    if (! vers) vers=rcshead(st.s,1) // vers=0 means get latest version
    // do checkout
    fn=filname(st.s)
    sprint(st.t,"RCS/%s,v",st.s)
    if (sfunc.len(fn.t)>0) {
        sprint(st.t,"%sRCS/%s,v",fn.t,fn.s)
        print st.s,"::",st.t,"::",fn.s,"::",fn.t
      } else if (fexists(st.t)) {
        if (rcshead(st.s)!=vers) {
            sprint(st.t,"cp -f %s %s.OLD",st.s,st.s)   system(st.t)
            sprint(st.t,"co -f -r1.%d %s",vers,st.s)   system(st.t)
          }
      } else { // look for file in remote location
        getenv("SITE",st.t)
        sprint(st.t,"%s/nrniv/local/hoc/%s",st.t,st.s)
        if (! fexists(st.t)) {printf("Can't find %s\n",st.t) return 0}
        sprint(st.s,"%s%d",st.s,vers)
        printf("Found %s at %s -> %s\n",$s1,st.t,st.s)
        sprint(st.t,"co -f -p1.%d %s > %s",vers,st.t,st.s) system(st.t)
      }
    if (numarg()>2) {
        if (argtype(3)==0) {  // 3rd arg 1 means do load_file statt xopen
            if ($3) { 
                load_file(st.s)
                return 1
              } else return 1 // 3rd arg 0 does co but no open
          } else { // 3rd arg string means locate a single proc, iter etc.
            sprint(st.s,"hocproc %s %s %s",st.s,$s3,".tmp")
            system(st.s,st.t)
            if (strm(st.t,"ERROR")) return 0 else {
                printf("Loading '%s()' from %s%d (via .tmp)\n",$s3,$s1,vers)
                xopen(".tmp")
                return 1
              } 
          }
      }
    xopen(st.s)
    return 1
  }

//** pxopen(FILE) prints out the version before opening a file
proc pxopen () { local flag localobj o
    flag=1
    o=new List("ParallelContext")
    if (o.count>0) if (o.o(0).id!=0) flag=0
    if (flag) printf("%s version %d\n",$s1,rcshead($s1))
    xopen($s1)
  }

//** lrm(LIST,STR) will remove item with string from LIST
proc lrm () { local cnt
    cnt=0
    if (argtype(2)==2) {
        for ltrb(XO,$o1) if (strm(XO.s,$s2)) { $o1.remove(i1) cnt+=1 }
        printf("%s found %d time\n",$s2,cnt)
      } else {
        $o1.remove($o1.index($o2))
      }
  }

//** lcnt(LIST,STR) will count item with string in LIST
func lcnt () { local cnt localobj xo
    cnt=0
    for ltr(xo,$o1) if (strm(xo.s,$s2)) cnt+=1
    return cnt
  }

//** lrepl(LIST,#,OBJ) will replace item at location # with OBJ
proc lrepl () { $o1.remove($2) $o1.insrt($2,$o3) }

//** lswap(list,#1,#2) swap items on a list
proc lswap () { local a,b
    if ($2<$3) {a=$2 b=$3} else {a=$3 b=$2}
    $o1.insrt(a,$o1.object(b))
    $o1.remove(b+1)
    $o1.insrt(b+1,$o1.object(a+1))
    $o1.remove(a+1)
  }

//** proc shl() show a list
proc shl () { 
    if (numarg()==1) tmpobj=$o1 else tmpobj=tmplist 
    if (tmpobj.count==0) return
    if (isstring(tmpobj.object(0),tstr)) {
        for ltr(XO,tmpobj) print XO.s
      } else for ltr(XO,tmpobj) print XO
  }

//** lfu() = ltr follow-up, pick out a single item from the last ltr request
// lfu(list,num[,obj])
proc lfu () { 
    if (numarg()==1) { 
        if (argtype(1)==0) XO=tmpobj.object($1)
        if (argtype(1)==1) tmpobj=$o1
      }
    if (numarg()==2) {
        if (argtype(1)==1 && argtype(2)==0) {tmpobj=$o1 XO=$o1.object($2)}
        if (argtype(1)==0 && argtype(2)==1) {$o2=tmpobj.object($1)}
      }
    if (numarg()==3) {
        if (argtype(1)==1 && argtype(2)==0 && argtype(3)==1) { tmpobj=$o1 $o3=$o1.object($2) }
      }
    if (numarg()==4) {
        $o2=tmpobj.object($1)  $o4=tmpobj.object($3) 
      }
  }

//** listedit() allows you to remove things by clicking
proc listedit () {
    if (numarg()==0) { print "listedit(list,str) gives browser(list,str) for removing items" return}
    if (numarg()==1) {
      if (! isstring($o1.object(0),temp_string_)) {print "Give name for string of object?" return }
        sprint(temp_string_,"proc ledt1 () {sprint(temp_string_,%s,hoc_ac_,%s.object(hoc_ac_).%s)}","\"%d:%s\"",$o1,"s")
      } else {
        sprint(temp_string_,"proc ledt1 () {sprint(temp_string_,%s,hoc_ac_,%s.object(hoc_ac_).%s)}","\"%d:%s\"",$o1,$s2)
      }
    execute1(temp_string_)
    $o1.browser("Double click to remove",temp_string_,"ledt1()")
    sprint(temp_string_,"%s.remove(hoc_ac_)",$o1)
    $o1.accept_action(temp_string_)
  }

//** crac() create and access
proc crac () {
    execute("create acell_home_")
    execute("access acell_home_")
  }

//** listXO() connects stuff to XO from a list
proc listXO () {
    if (numarg()==1) {
        $o1.browser("Double click")
        sprint(temp_string_,"print hoc_ac_,\":XO -> \",%s.object(hoc_ac_) XO = %s.object(hoc_ac_)",$o1,$o1)
        $o1.accept_action(temp_string_)
      } else if (numarg()==2) {
        $o1.browser($s2)
        sprint(temp_string_,"XO = %s.object(hoc_ac_) print %s.object(hoc_ac_).%s",$o1,$o1,$s2)
        $o1.accept_action(temp_string_)
      } else if (numarg()==3) {
        $o1.browser($s2)
        sprint(temp_string_,"XO = %s.object(hoc_ac_) print %s.object(hoc_ac_).%s,%s.object(hoc_ac_).%s",$o1,$o1,$s2,$o1,$s3)
        $o1.accept_action(temp_string_)
      }
  }

//** lcatstr(list,s1,s2,...) make new List("s1") new List("s2") ... in one list
proc lcatstr() { local i
    if (numarg()<3) { print "lcatstr(l1,s1,s2,...) puts new Lists into l1" return }
    $o1 = new List($s2)
    for i=3,numarg() {
        tmplist2 = new List($si)
        for ltr(XO,tmplist2) { $o1.append(XO) }  
      }
  }

//** sublist() places a sublist in LIST0 from LIST1 index BEGIN to END inclusive
proc sublist () { local ii
    $o1.remove_all
    for ii=$3,$4 {
        $o1.append($o2.object(ii))
      }
  }

//* catlist() concats LIST2...LISTN on end of LIST1
proc catlist () { local i
    for i = 2, numarg() {
        for ltr(YO,$oi) {
            $o1.append(YO)
          }
      }
  }  

//* mechlist() creates a LIST of all this CELL type's TEMPLATE type
// list, cell, template
// make a list of mechanisms belonging to a certain template
proc mechlist () { local num,ii
  //  mchnms = ""  // not a good storage since runs out of room
    if (numarg()==0) { print "mechlist(list, cell, template)" return}
    $o1 = new List($s2)
    num = $o1.count
    for ii=0,num-1 {
        sprint(temp_string_,"%s.append(%s.%s)",$o1,$o1.object(ii),$s3)
        execute(temp_string_)
        sprint(mchnms,"%s/%d/%s.%s",mchnms,ii,$o1.object(ii),$s3)
      }
    for (ii=num-1;ii>=0;ii=ii-1) { $o1.remove(ii) }
  }

//* lp() loop through a list running command in object's context
// assumes list in tmplist
// with 1 args run $o1.object().obj_elem
// with 2 args run comm($o1.object().obj_elem)
proc lp () {
    for ii=0,tmplist.count-1 {
        printf("%s ",tmplist.object(ii))
        if (numarg()==2) {
            sprint(temp_string_,"%s(%s.%s)",$s2,tmplist.object(ii),$s1)
          } else {
            sprint(temp_string_,"%s.%s",tmplist.object(ii),$s1)
          }
        execute(temp_string_)
      }
  }

//* prlp() loop through a list printing object name and result of command
proc prlp () {
    tmpobj=tmplist
    if (numarg()>0) if (argtype(1)==1) tmpobj=$o1
    for ltr(XO,tmpobj) {
        printf("%d %s ",i1,XO)
        if (numarg()>1) {
            sprint(temp_string_,"print %s.%s",XO,$s2)
            execute(temp_string_)
          } else { print "" }
      }
  }

//* String functions
//** repl_str(str,stra,strb): replace stra with strb in string
// will only replace first string match
proc repl_str() { localobj scr
    scr=new String()
    if (sfunc.head($s1,$s2,scr.s) == -1) { print $s2," not in ",$s1  return }
    sfunc.tail($s1,$s2,scr.s)
    sprint(scr.s,"%s%s",$s3,scr.s)
    sfunc.head($s1,$s2,$s1)
    sprint($s1,"%s%s",$s1,scr.s)
  }

//** find_str(str,left,right,dest): pull out dest flanked by left and right
proc find_str() {
    if (sfunc.tail($s1,$s2,$s4) == -1) { print $s2," not in ",$s1  return }
    sfunc.head($s4,$s3,$s4)
  }

//** find_num(str,left,right): pull out number flanked by left and right
func find_num() { local x localobj st
    st=new String()
    if (sfunc.tail($s1,$s2,st.s) == -1) { print $s2," not in ",$s1  return }
    sfunc.head(st.s,$s3,st.s)
    sscanf(st.s,"%g",&x)
    return x
  }

//** repl_mstr(str,stra,strb): replace stra with strb in string
// multiple replace
proc repl_mstr () { localobj scr
    scr=new String()
    while (sfunc.head($s1,$s2,scr.s) != -1) {
        sfunc.tail($s1,$s2,scr.s)
        sprint(scr.s,"%s%s",$s3,scr.s)
        sfunc.head($s1,$s2,$s1)
        sprint($s1,"%s%s",$s1,scr.s)
      }
  }

//** extract(str,stra,strb[,dest]): pull out piece of string surrounded by stra,strb
obfunc str_extract() { local b,e,err localobj scr
    scr=new String2() err=0
    b=sfunc.tail($s1,$s2,scr.s) // scr.s contains after s2
    if (b==-1){printf("%s not found in %s\n",$s2,$s1) err=1}
    e=sfunc.head(scr.s,$s3,scr.t) // beg of s3
    if (e==-1){printf("%s not found in %s\n",$s3,scr.s) err=1}
    if (err) scr.s="" else sfunc.left(scr.s,e)
    if (numarg()==4) $s4=scr.s
    return scr
  }

//** clean_str(str,scratch,s1,s2,s3,...)
// remove serial $si from string
proc clean_str () { local i
    for i=3,numarg() {
        while (sfunc.head($s1,$si,$s2) != -1) { 
            sfunc.tail($s1,$si,$s2)
            sfunc.head($s1,$si,$s1)
            sprint($s1,"%s%s",$s1,$s2)      
          }
      }
  }

//** aaaa() (or $o2) becomes a list of strings from file $s1
proc aaaa () { local flag
    if (numarg()==2) { tmpfile.ropen($s1) aa=$o2 flag=0
      } else if (numarg()==1) { tmpfile.ropen($s1) flag=1
      } else { tmpfile.ropen("aa") flag=1 }
    if (flag==1) if (isobj(aa,"List")) { aa.remove_all() } else { aa=new List() }
    while (tmpfile.gets(temp_string_)>0) {
        chop(temp_string_)
        tmpobj=new String(temp_string_)
        aa.append(tmpobj)
      }
    tmpobj=nil
  }

//* Object identification
//** objid() find information about object -- replaces var2obj, canobj, objnum
obfunc objid () { local flag localobj xo
    xo=new Union()
    if (argtype(1)==1) sprint(xo.s,"tmpobj=%s",$o1) else sprint(xo.s,"tmpobj=%s",$s1)
    execute(xo.s) // change variable name to object name
    xo.o=tmpobj
    sprint(xo.s,"%s",xo.o)
    sscanf(xo.s,"%*[^[][%d]",&xo.x)
    return xo
  }

//** var2obj() and canobj() -- find true object names
// var2obj("tstr"[,"objvar"]) replaces variable name with actual name of the object
// default into XO; optional second arg allows to place somewhere else
// eg tstr="TC[0].ampa" var2obj(tstr) -> AMPA[0]
proc var2obj () { local flag
    if (numarg()==1) flag=1 else flag=0
    if (flag) sprint($s1,"XO=%s",$s1) else sprint($s1,"%s=%s",$s2,$s1)
    execute($s1) // change variable name to object name
    if (flag) sprint($s1,"%s",XO) else sprint($s1,"%s",$s2)
    printf("var2obj() PLEASE REPLACE WITH objid()\n") 
  }

//** objnum(OBJ) -- find object number
func objnum () { local x localobj st
    st=new String()
    if (argtype(1)==1) sprint(st.s,"%s",$o1) else st.s=$s1
    if (sscanf(st.s,"%*[^[][%d]",&x) != 1) x=-1
    return x
  }

proc allobjs () {
    hoc_stdout($s1)
    allobjects()
    hoc_stdout()
  }

//** strnum(str,"PRE") -- pull number out of a string
func strnum () { local x localobj st
    st=new String2($s1)
    sfunc.tail(st.s,$s2,st.t)
    if (sscanf(st.t,"%d",&x) != 1) x=-99e99
    return x
  }

//** canobj(obj[,"OBJVAR"]) -- default will assign to XO
// canonical object -- return canonical identity for an object
// eg canobj(tc,"YO") -- figure out what tc is and assign it to YO
proc canobj () { local flag
    if (numarg()==1) flag=1 else flag=0
    if (flag) sprint(tstr,"XO=%s",$o1) else sprint(tstr,"%s=%s",$s2,$o1)
    execute(tstr) // change variable name to object name
    sprint(tstr,"%s",$o1)
    printf("canobj() PLEASE REPLACE WITH objid()\n") 
  }

//* push() and pop() for objects -- returns
proc push () { local i
    for i=2,numarg() $o1.append($oi)
  }

//** pop()
obfunc pop () { local i,cnt localobj o
    cnt=$o1.count-1
    if (cnt==-1) { print "ERR: unable to pop" return } 
    o=$o1.object(cnt)
    $o1.remove(cnt)
    return o
  }

//* time()
strdef tmstr
tmstr="run()"
func time () { local tti,uintmax,cps
    uintmax=4294967295 // UINT_MAX/CLOCKS_PER_SEC
    cps=1e6 // CLOCKS_PER_SEC
    tti=prtime()
    system("date")
    if (numarg()==1) execute1($s1) else execute1(tmstr)
    tti=prtime()-tti
    if (tti<0) tti+=uintmax
    if (tti<cps) {           print tti/1e3,       "kilocycles" 
      } else if (tti<60*cps) { print tti/cps,   "s" 
      } else                   print tti/cps/60,"m"
    system("date")
    return tti/1e3
  }

func ftime () { local tti
    prtime()
    if (numarg()==1) execute($s1) else execute(tmstr)
    tti=prtime()
    return tti
  }

proc setdate () {
    system("date +%y%b%d",datestr)
    chop(datestr)
    downcase(datestr)
  }

proc sortlist () { local a,err,ii,x,rev,na localobj v1,v2,xo,nl,il
    il=$o1
    err=rev=0
    na=numarg()
    for ii=2,3 if (na>=ii) if (argtype(ii)==0) rev=1
    a=allocvecs(v1,v2,il.count)
    nl=new List()
    if (!name_declared("oform")) err=1
    if (!err) if (oform(v1)==NOP) err=1
    if (err) {printf("sortlist uses oform()\n") err()}
    for ltr(xo,il) v1.append(oform(xo))
    v1.sortindex(v2)
    if (rev) v2.reverse
    for ii=0,v2.size-1 nl.append(il.o(v2.x[ii]))
    if ((na==2 && !rev) || na==3) $o2=nl else {
        il.remove_all
        for ltr(xo,nl) il.append(xo)
      }
    dealloc(a)
  }

// LAR: list_array is list used as an array
begintemplate LAR
public l,set,x,size,nil,resize,get
objref l,nil
double size[1]

proc init () { local ii
    size=$1
    l=new List()
    for ii=0,size-1 l.append(l) // place holder
  }

func set () { local ix
    ix=$1
    if (ix>=size) {printf("LAR set OOR %d>=%d\n",ix,size) return -1}
    l.remove(ix) l.insrt(ix,$o2) 
    return ix
  }

obfunc x ()   { if (eqojt(l,l.o($1))) return nil else return l.o($1) }
obfunc get () { if (eqojt(l,l.o($1))) return nil else return l.o($1) }

proc resize () { local newsz,ii
    newsz=$1
    if (newsz<size) {
        for (ii=size-1;ii>=newsz;ii-=1) l.remove(ii)
      } else if (newsz>size) {
        for ii=size,newsz-1 l.append(l)
      }
    size=newsz
  }
endtemplate LAR
// END /usr/site/nrniv/local/hoc/declist.hoc
//================================================================
print "Loading decvec"

fnum=verbose=0
{symnum = 7 colnum = 10}
func cg () { return $1%(colnum-1)+1 } // skip white color
objref clrsym[colnum+1]
for ii=0,colnum { clrsym[ii]=new Union() clrsym[ii].x=ii%colnum }
// black->red->blue->green->orange->brown->violet->yellow->grey
{clrsym[0].s="white" clrsym[1].s="black" clrsym[2].s="red" clrsym[3].s="blue"
  clrsym[4].s="green" clrsym[5].s="orange" clrsym[6].s="brown" clrsym[7].s="violet" 
  clrsym[8].s="yellow" clrsym[9].s="grey"} 
clrsym[0].o=new List()
{symmax=20 symmin=2}
obfunc sg () { local ii localobj o
    ii=$1
    o=clrsym[ii%(colnum-1)+1]
    o.t=clrsym[0].o.o(ii%symnum).s
    o.x[1]=(3-ii)%4+1 // descending line types
    o.x[2]=(symmax-symmin-2*ii)%(symmax-symmin+1)+symmin
    o.x[3]=(4-ii)%(symmax-symmin+1)+symmin
    o.x[4]=(int((ii+1)/5)%2+1)*4-(ii+1)%4+1 // another line type sequence
    return o
  }

{ MSONUM=100 MSOSIZ=100 msomax=0 msoptr=0 objref mso[MSONUM] }
double x[4],y[4]
xx=0 // declare a scalar 
ind = new Vector(100)
tvec = new Vector(100)
vec = new Vector(100)
vec0 = new Vector(10)
vec1 = new Vector(10)
vrtmp = new Vector(10)
veclist = new List()
veccollect = new List()
rdm = new Random()
rdm.MCellRan4()

if (!(xwindows && name_declared("xwindows"))) {
    xwindows=0
    objref graphItem
    strdef temp_string_, temp_string2_
  }
strdef xtmp
if (wopen("xtmp")) xtmp = "xtmp" else xtmp="/tmp/xtmp"  // scratch file to save system output to

//* stuff that doesn't belong here
//** dired([list,]file) - put together list of files matching 'file', calls 'ls -1 file'
//   dired([list,]file,1) file name to read for list of files
//   dired([list,]file,2) clear dir first; if list isn't present assume 'dir'
func dired () { local f,i,f1 localobj st,o
    f1=f=0
    st=new String2()
    if (numarg()==0) { print "dired([list,]filename[,flag])\t\
        adds the filename to list (use wildcards) (flag:1 read file;flag:2 clear list)"
        return }
    if (argtype(1)==2) {o=dir st.s=$s1 i=2} else {o=$o1 st.s=$s2 i=3}
    while (i<=numarg()) { 
        if (argtype(i)==2) st.t=$si else f=$i
        i+=1
      }
    if (f==2) o.remove_all
    if (f==1) {
        tmpfile.ropen(st.s) 
      } else { // f!=1
        if (strm(st.s,"[*?]")) f1=0 else f1=1 // is this a wildcard or a directory
        if (f1) {  
            if (sfunc.len(st.t)>0) {
                sprint(st.t,"find %s -name %s > %s",st.s,st.t,xtmp)
              } else  sprint(st.t,"find %s > %s",st.s,xtmp)
          } else     sprint(st.t,"ls -1R %s > %s",st.s,xtmp)
        system(st.t)
        tmpfile.ropen(xtmp)
      }
    while (tmpfile.scanstr(st.t) != -1) {
        if (f1) { // a directory
            if ((x=ftype(st.t))!=2) {print "Ignoring ",st.t,x  continue}
          }
        o.append(new String(st.t))
        tmpfile.gets(st.t)  // get rid of the rest of the line
      }
    printf("%d files in dir\n",o.count)
    return o.count
  }

// lsdir([dir])
proc lsdir () { 
    if (numarg()==1) {
        for ltr($o1) {sprint(tstr,"ls -l %s",XO.s) system(tstr)}
      } else for ltr(dir) {sprint(tstr,"ls -l %s",XO.s) system(tstr)}
  }

//** lbrw(list,action) is used to put up a browser
// note action given without '()'
proc lbrw () {
    $o1.browser($s2,"s")
    sprint($s2,"%s()",$s2)
    $o1.accept_action($s2)
  }

//** l2v(S1,S2) makes a list(S1) and puts all the XO.S2 into vec
// eg l2v("IClamp","amp")
proc l2v () {
    tmpobj=new List($s1)
    if (numarg()==3) YO=$o3 else YO=vec
    YO.resize(tmpobj.count) YO.resize(0)
    for ltr(tmpobj) {
        sprint(tstr,"YO.append(%s.%s)",XO,$s2)
        execute(tstr)
      }
  }

//* vector iterator vtr
// for vtr(vec) { print x }
// for vtr(&x, vec) { print x }
// for vtr(&x, vec, &y) { print x,y }
// for vtr(&x, vec, max_ind) { print x }
// for vtr(&x, vec, min_ind, max_ind) { print x }
// for vtr(&x, vec, &y, min_ind, max_ind) { print x,y }
iterator vtr () { local i,j,pf,cf,b,e localobj o
    cf=pf=0
    if (argtype(1)==1) { // 1st arg a vector or the pointer
        o=$o1 i=2
      } else if (argtype(1)==3) {
        pf=1 o=$o2 i=3 // pointer alway in position 1
      } 
    print o
    b=0 e=o.size-1 // default: do whole vec
    // now can take counter or limits
    if (argtype(i)==3) {cf=i i+=1} // cf gives counter location
    if (argtype(i)==0) {
        if (argtype(i+1)==0) {b=$i i+=1 e=$i} else e=$i
      }
    if (!cf) i1=0 else {i=cf $&i=0} // default counter
    for j=b,e {
        if (pf) $&1=o.x[j] else x=o.x[j]  
        iterator_statement 
        if (cf) $&i+=1 else i1+=1
      }
  }

//* vector iterator vtr2, treat two vectors as pairs
// usage 'for vtr2(&x, &y, vec1, vec2) { print x,y }'
iterator vtr2 () { local i,pairwise,noi1
    noi1=pairwise=0
    if (numarg()==3) { pairwise=1 i1=0 }
    if (numarg()==4) if (argtype(4)==3) { pairwise=1 $&4=0 noi1=1}
    if (pairwise) if ($o3.size%2!=0) { print "vtr2 ERROR: vec not even sized." return }
    if (! pairwise) {
        if ($o3.size != $o4.size) { print "vtr2 ERROR: sizes differ." return }
        if (numarg()==5) {$&5=0 noi1=1} else {i1 = 0}
      }
    for i = 0,$o3.size()-1 {
        $&1 = $o3.x[i]
        if (pairwise) $&2=$o3.x[i+=1] else $&2=$o4.x[i]
        iterator_statement
        if (noi1) { if (pairwise) $&4+=1 else $&5+=1 } else i1+=1
      }
  }

//** viconv(TARG,OLD_INDS,NEW_INDS)
proc viconv () { local a,b
    if (numarg()==0) { printf("viconv(TARG,OLD_INDS,NEW_INDS)\n") return }
    a=b=allocvecs(2) b+=1
    if ($o2.size!=$o3.size) {printf("OLD_INDS %d != NEW_INDS %d\n",$o2.size,$o3.size) return}
    mso[b].resize($o1.size)
    for vtr2(&x,&y,$o2,$o3) { // x -> y
        mso[a].indvwhere($o1,"==",x)
        mso[b].indset(mso[a],y)
      }
    $o1.copy(mso[b])
    dealloc(a)
  }

//* iterator lvtr, step through a list and a vector together
// usage 'for lvtr(XO, &x, list, vec) { print XO,x }'
iterator lvtr () { local i
    if ($o3.count <  $o4.size) { printf("lvtr ERROR: vecsize > listsize: list %d,vec %d.\n",$o3.count,$o4.size) return }
    if ($o3.count != $o4.size) { printf("lvtr WARNING: sizes differ: list %d,vec %d.\n",$o3.count,$o4.size) }
    if (numarg()==5) {$&5=0} else {i1 = 0}
    for i = 0, $o4.size()-1 {
        $o1 = $o3.object(i)
        $&2 = $o4.x[i]
        iterator_statement
        if (numarg()==5) { $&5+=1 } else { i1+=1 }
      }
  }

//* other iterators: case, scase, ocase
iterator case () { local i,j,max,flag
    if (argtype(numarg())==3) {flag=1 max=numarg()-1} else {flag=0 max=numarg()}
    if (flag) {i=max+1 $&i=0} else i1 = 0
    for i = 2, max {
        $&1 = $i
        iterator_statement
        if (flag) {j=i i=max+1 $&i+=1 i=j} else i1+=1
      }
  }

iterator scase () { local i,j,min,max,flag
    if (argtype(numarg())==3) {flag=1 max=numarg()-1} else {flag=0 max=numarg()}
    if (flag) {i=max+1 $&i=0} else i1=0
    if (argtype(1)==1) {
        if (! isobj($o1,"String")) $o1=new String() // will accept String or String2
        min=2 
      } else min=1
    for i = min,max {
        if (min==1) temp_string_=$si else $o1.s=$si
        iterator_statement
        if (flag) {j=i i=max+1 $&i+=1 i=j} else i1+=1
      }
  }

// eg for scase2("a","b","c","d","e","f") print tmpobj.s,tmpobj.t
iterator scase2 () { local i,min,flag,na,newstr localobj o
    flag=i1=0 newstr=min=1 
    na=numarg()
    if (argtype(na)==0) {i=na newstr=$i na-=1}
    if (argtype(1)==1) {flag=1 min=2}
    for i=min,na {
        if (i==min || newstr) o=new String2()
        o.s=$si i+=1  o.t=$si
        if (flag) $o1=o else tmpobj=o
        iterator_statement
        i1+=1
      }
  }

iterator ocase () { local i
    i1 = 0
    if (isassigned($o1)) {
        for i = 1, numarg() {
            XO = $oi
            iterator_statement
            i1+=1
          }
     } else {
        for i = 2, numarg() {
            $o1 = $oi
            iterator_statement
            i1+=1
          }
      }
  }

//* strm(STR,REGEXP) == regexp string match 
func strm () { return sfunc.head($s1,$s2,"")!=-1 }
func strc () { return strcmp($s1,$s2)==0 }

//** count_substr(str,sub): count occurences of substring in str
func count_substr () { local cnt
    cnt = 0
    while (sfunc.tail($s1,$s2,$s1) != -1) { cnt += 1}
    return cnt
  }

//* nind(targ,data,ind) fill the target vector with data NOT index by ind (opposite of v.index)
proc nind () { 
    if (! eqobj($o1,$o2)) $o1.copy($o2)
    $o1.indset($o3,-1e20)
    $o1.where($o1,">",-1e20)
  }

//* vlk(vec)
// vlk(vec,max)
// vlk(vec,min,max)
// vlk(vec,min,max,"INDEX") -- give index of each entry
// prints out a segment of a vector
vlk_width=80
proc vlkomitoff () { execute1("func vlkomit () {return NOP}") }
proc vlkomit0(){execute1("func vlkomit(){if(vcnt($o1,0)==$o1.size) return 1 else return 0}")}
vlkomitoff()
proc vlk () { local ii,i,j,ami,min,max,wdh,nl,na,width,tablen,omfl,ixfl localobj st,v1,vi
    st=new String2()  v1=new Vector(numarg()) vi=new Vector()
    nl=1 wdh=vlk_width j=0 omfl=ixfl=0 ami=2
    na=numarg() min=0 max=$o1.size-1
    if (vlkomit(v1)!=NOP) omfl=1 // omfl to omit printing some
    if (argtype(na)==2) {i=na 
        if (strm($si,"I")) {ixfl=1 vrsz($o1,vi) vi.indgen ami=1}
        na-=1
      }
    if (argtype(na)==0) {i=na 
        if ($i<0) min=$i else max=$i 
        na-=1
      }
    if (argtype(na)==0) {i=na min=$i na-=1}
    if (max<0) max+=$o1.size
    if (min<0) min+=$o1.size
    if (max>$o1.size-1) { max=$o1.size-1 printf("vlk: max beyond $o1 size\n") }
    sprint(st.t,"%%s:%s",dblform)
    width=0
    if (strm(tabform,"\t")) tablen=6 else if (strm(tabform,"\n")) tablen=-1e5 else {
        tablen=sfunc.len(tabform) }
    for ii=min,max { 
        if (omfl) { v1.resize(0)
            for i=1,na v1.append($oi.x[ii])
            if (vlkomit(v1)) continue
          }
        if (ixfl) sprint(st.s,dblform,vi.x[ii]) else sprint(st.s,dblform,$o1.x[ii])
        for i=ami,na sprint(st.s,st.t,st.s,$oi.x[ii]) 
        width+=(sfunc.len(st.s)+tablen)
        if (width>vlk_width && nl) {printf("\n") width=0}
        printf("%s%s",st.s,tabform)
      }
    if (nl) print ""
  }

//** vlkp(SRC,PVEC) uses indices in PVEC to print out values in SRC
proc vlkp () { local i,j,wdh
    j=0 nl=1 wdh=vlk_width
    if (numarg()==2) {
        for vtr(&x,$o1) {
            printf("%g%s",$o2.x[x],tabform)
            if ((j=j+1)%vlk_width==0 && nl && strcmp(tabform," ")==0) { print "" }
          }
      } else {
        for vtr(&x,$o1) { for i=2,numarg() printf("%g%s",$oi.x[x],tabform) 
            print "" }
      }
    if (nl) print ""
  }

//* vprf() prints 1,2 or 3 vectors in parallel to output file
proc vprf () { local x2
    if (! tmpfile.isopen()) {
        print "Writing to temp file 'temp'"
        tmpfile.wopen("temp")
      }
    if (numarg()==1) { 
        for vtr(&x,$o1) { tmpfile.printf("%g\n",x) }
      } else if (numarg()==2) { 
        for vtr2(&x,&y,$o1,$o2) { tmpfile.printf("%g %g\n",x,y) }
      } else if (numarg()==3) { 
        for vtr2(&x,&y,$o1,$o2,&ii) { x2=$o3.x[ii] tmpfile.printf("%g %g %g\n",x,y,x2) }
      }
    tmpfile.close
  }

//* vpr() prints 1,2 or 3 vectors in parallel to STDOUT
proc vpr () { local x2
    if (numarg()==1) { 
        for vtr(&x,$o1) { printf("%g",x) }
      } else if (numarg()==2) { 
        for vtr2(&x,&y,$o1,$o2) { printf("%g:%g ",x,y) }
      } else if (numarg()==3) { 
        for vtr2(&x,&y,$o1,$o2,&ii) { x2=$o3.x[ii] printf("%g:%g:%g ",x,y,x2) }
      }
    print ""
  }

//* readvec(vec) read from line
proc readvec () { 
    $o1.resize(0)
    while (read(xx)) $o1.append(xx)
    vlk($o1)
  }
  
//* popvec(), savenums, readnums, vecsprint, savevec, savestr
//  vrsz(), vcp(), zvec(), resize, copy, empty
proc pushvec () { local i // same as .append, retained for compatability
    for i=2, numarg() $o1.append($i)
  }

//** insvec(VEC,IND,VAL1[,VAL2,...]) insert values into the vector
proc insvec () { local ix,i,a // insert values into a vector
    a=allocvecs(1)  ix=$2
    for i=3, numarg() mso[a].append($i)
    $o1.insrt(ix,mso[a])
    dealloc(a)
  }

//** revec() clear vector then append
proc revec () { local i // clear vector then append
    if (! isobj($o1,"Vector")) $o1 = new Vector()
    $o1.resize(0)
    if (numarg()>1) if (argtype(2)==1) { 
        for i=2,numarg() $oi.resize(0) 
      } else {
        for i=2,numarg() if (argtype(i)==0) $o1.append($i) else $o1.append($&i)
      }
  }

//** unvec(VEC,&a,&b,...) put values from vector back into doubles (via pointers)
proc unvec () { local i
    if ($o1.size!=numarg()-1) { printf("unvec WARNING resizing %s to %d\n",$o1,numarg()-1) 
        $o1.resize(numarg()-1) }
    for i=2,numarg() $&i=$o1.x[i-2] 
  }

//** wevec(VEC,wt0,wt1,...) returned weighted sum
func wevec () { local i,sum
    if ($o1.size!=numarg()-1) { printf("wevec SIZE ERR %d %d\n",$o1.size,numarg()-1) return }
    sum=0
    for i=2,numarg() sum+=$o1.x[i-2]*$i
    return sum
  }

//** vrsz(VEC or NUM,VEC1,VEC2...,VECn or NUM)  -- vector resize -- to size of first arg
// optional final number is fill
proc vrsz () { local i,sz,max,fill,flag,rsz0
    max=numarg()
    flag=rsz0=0
    if (argtype(1)==1) { 
        if (isobj($o1,"Vector")) sz=$o1.size else if (isobj($o1,"List")) sz=$o1.count
      } else sz=$1
    if (argtype(max)==0) {i=max max-=1 fill=$i flag=1}
    if (argtype(max)==2) {max-=1 rsz0=1} // string means resize(0)
    for i=2, max { 
        $oi.resize(sz)  
        if (rsz0) $oi.resize(0) else if (flag) $oi.fill(fill) 
      }
  }

//** vcp() -- copy vector segment with resizing
proc vcp () { local i,sz
    $o1.resize($4-$3+1) $o1.copy($o2,$3,$4)
  }

//** veccut(VEC,min,max) just keep a piece of the vector
// veccut(VEC,min,max,tstep) generate indices from times using tstep
proc veccut () { local a localobj v1
    a=allocvecs(v1)
    if (numarg()==4) { min=round($2/$4) max=round($3/$4)
      } else { min=$2 max=$3 }
    v1.copy($o1,min,max) 
    $o1.copy(v1) 
    dealloc(a)
  }

//** zvec()
proc zvec () { local i // make vectors zero size
    for i=1, numarg() $oi.resize(0)
  }

//* save and read series
//** savenums(x[,y,...]) save numbers to tmpfile via a vector
proc savenums () { local i,vv
    vv=allocvecs(1)
    for i=1, numarg() mso[vv].append($i)
    mso[vv].vwrite(tmpfile)
    dealloc(vv)
  }

//** savedbls(&x,sz) save a double array of size sz
proc savedbls () { local vv,i
    vv=allocvecs(1)
    mso[vv].from_double($2,&$&1)
    mso[vv].vwrite(tmpfile)
    dealloc(vv)
  }

//** readnums(&x[,&y...]) recover nums from tmpfile via a vector
func readnums () { local vv,i,cnt
    vv=allocvecs(1) cnt=0
    if (mso[vv].vread(tmpfile)) {
        if (numarg()!=mso[vv].size) {
            printf("readnums WARNING: args=%d;vec.size=%d\n",numarg(),mso[vv].size)
            if (numarg()>mso[vv].size) { 
                for i=1,mso[vv].size $&i = mso[vv].x[i-1]        
                cnt=mso[vv].size
              }
          }
        if (cnt==0) {
            for i=1,numarg() $&i = mso[vv].x[i-1]
            cnt=numarg()
          }
      } else cnt=-1
    dealloc(vv)
    return cnt
  }

//** readdbls(&x,sz) read a double array of size sz
func readdbls () { local vv,i,flag
    vv=allocvecs(1) flag=1
    if (mso[vv].vread(tmpfile)) {
        mso[vv].v2d(&$&1)   // seg error risk
      } else flag=0
    dealloc(vv)
    return flag
  }

//** wrvstr(str) save string to a file by converting to ascii
proc wrvstr () { local vv,i
    vv=allocvecs(1)
    str2v($s1,mso[vv])
    mso[vv].vwrite(tmpfile,1)
    dealloc(vv)
  }

//** rdvstr(str) read string from a file via vread and conversion
func rdvstr () { local vv,i,flag
    flag=1
    vv=allocvecs(1)
    if (mso[vv].vread(tmpfile)) {
        if (numarg()==1) v2str(mso[vv],$s1) else v2str(mso[vv],tstr)
      } else flag=0
    dealloc(vv)
    return flag
  }

//** str2v()
proc str2v () { localobj lo
    lo=new String()
    $o2.resize(0)
    lo.s=$s1
    while (sfunc.len(lo.s)>0) {
        sscanf(lo.s,"%c%*s",&x)
        sfunc.right(lo.s,1)
        $o2.append(x)
      }
  }
    
//** v2str() translates from vector to string
proc v2str () { local ii,x
    $s2=""
    round($o1)
    for ii=0,$o1.size-1 { x=$o1.x[ii] sprint($s2,"%s%c",$s2,x) }
  }

//* popvec() remove last entry
func popvec () { local sz, ret
    sz = $o1.size-1
    if (sz<0) return 1e9
    ret = $o1.x[sz]
    $o1.resize[sz]
    return ret
  }

//* chkvec (look at last entry)
func chkvec () { if ($o1.size>0) return $o1.x[$o1.size-1] else return -1e10 }

// vecsprint(strdef,vec)
proc vecsprint () { local ii
    if ($o2.size>100) { return }
    for ii=0,$o2.size-1 { sprint($s1,"%s %g ",$s1,$o2.x[ii]) }
  }

// savevec([list,]vec1[,vec2,...]) add vector onto veclist or other list if given as 1st arg
// don't throw out vectors
func savevec () { local i,flag,beg localobj v1
    if (numarg()==0) { savevec(hoc_obj_[0],hoc_obj_[1]) return }
    if (isobj($o1,"List")) beg=2 else beg=1
    for i=beg, numarg() { 
        if (veccollect.count>0) { // grab a vector from garbage collection
            v1=veccollect.object(veccollect.count-1)
            veccollect.remove(veccollect.count-1)
          } else v1 = new Vector($oi.size)
        v1.copy($oi)
        if (beg==2) $o1.append(v1) else veclist.append(v1)
      }
    if (beg==2) return $o1.count-1 else return veclist.count-1
  }

// prveclist(filename[,list])
proc prveclist () {
    if (!batch_flag && tmpfile.ropen($s1)) {
        printf("%s exists; save anyway? (y/n) ",$s1)
        getstr(temp_string_) chop(temp_string_)
        if (strcmp(temp_string_,"y")!=0) return
      }
    if (! tmpfile.wopen($s1)) { print "Can't open ",$s1  return }
    if (numarg()==2) {
        for ltr(XO,$o2) XO.vwrite(tmpfile)
      } else {
        for ltr(XO,veclist) XO.vwrite(tmpfile)
      }
    tmpfile.close()
  }

// rdveclist("FILENAME"[,list])
// rdveclist("FILENAME"[,NOERASE])
proc rdveclist () { local flag,a
    flag=0
    a=allocvecs(1)
    if (numarg()==1) { flag=1 clrveclist() } else if (argtype(2)==1) $o2.remove_all else flag=1
    if (! tmpfile.ropen($s1)) { print "Can't open ",$s1  return }
    while (mso[a].vread(tmpfile)) {
        if (flag) savevec(mso[a]) else savevec($o2,mso[a])
      }
    tmpfile.close()
    tmpobj=veclist
    dealloc(a)
  }
  
// rdvecs("FILENAME",vec1,vec2,...)
proc rdvecs () { local i
    if (! tmpfile.ropen($s1)) { print "Can't open ",$s1  return }
    for i=2,numarg() if ($oi.vread(tmpfile)==0) printf("WARNING nothing to read into %s\n",$oi)
    tmpfile.close()
  }
  
// svvecs("FILENAME",vec1,vec2,...)
proc svvecs () { local i
    clrveclist()
    for i=2,numarg() savevec($oi)
    prveclist($s1)
  }
  
// vpad(vec,howmany,val[,right])
proc vpad () { local a
    a=allocvecs(1)
    mso[a].resize($2) mso[a].fill($3)
    if (numarg()==4) $o1.append(mso[a]) else {
        mso[a].append($o1) $o1.copy(mso[a])     }
    dealloc(a)
  }

// vtrunc(vec,howmany[,right])
proc vtrunc () { local a
    if (numarg()==3) $o1.resize($o1.size-$2) else {
        $o1.reverse $o1.resize($o1.size-$2) $o1.reverse
      }
  }

proc rdxy () { local a
    a = allocvecs(1)
    revec(ind,vec)
    tmpfile.ropen("aa")
    mso[a].scanf(tmpfile)
    if (mso[a].size%2!=0) {print "rdxy ERR1 ",mso[a].size return}
    for vtr2(&x,&y,mso[a]) {ind.append(x) vec.append(y)}
    print ind.size," points read from aa into ind and vec"
    dealloc(a)
  }

// closest(vec,num) -- return ind for vec member closest to num
func closest () { local a,ret
    a=allocvecs(1)
    mso[a].copy($o1) mso[a].sub($2) mso[a].abs
    ret=mso[a].min_ind
    dealloc(a)
    return ret
  }

// memb(TEST#,#1,#2,...) -- true if the TEST# is in the list
func memb () { local na,i
    for i=2,numarg() if ($1==$i) return 1
    return 0
  }

proc clrveclist () { localobj o
    if (numarg()==1) o=$o1 else o=veclist
    for ltr(XO,o) { XO.resize(0) veccollect.append(XO) }
    o.remove_all()
  }

// savestr(str1...) add string obj onto tmplist
proc savestr () { local i
    if (argtype(1)==1) for i=2, numarg() $o1.append(new String($si)) else {
        for i=1, numarg() tmplist.append(new String($si))
      }
  }

// redund with v.count in vecst.mod
func vcount () { local val,sum
    val=$2 sum=0
    for vtr(&x,$o1) if (x==val) sum+=1
    return sum
  }

// tvecl(inlist[,outlist]) -- transpose veclist
obfunc tvecl () { local x,cnt,sz,err,ii,p localobj xo,il,ol
    il=$o1 
    if (numarg()>1) ol=$o2
    if (!isassigned(ol)) {ol=veclist clrveclist()} else ol.remove_all
    err=0   cnt=il.count sz=il.o(0).size
    for ltr(xo,il,&x) if (xo.size!=sz) err=x
    if (err) { print "Wrong size vector is #",x return ol }
    p = allocvecs(1,cnt)  mso[p].resize(cnt)
    for ii=0,sz-1 {
        for jj=0,cnt-1 mso[p].x[jj] = il.o(jj).x[ii]
        savevec(ol,mso[p])
      }
    dealloc(p)
    return ol
  }  

//* vinsect(v1,v2,v3) -- v1 gets intersection (common members) of v2,v3
//  replaced by v.insct() in vecst.mod
proc vinsect () {
    $o1.resize(0)
    for vtr(&x,$o2) for vtr(&y,$o3) if (x==y) $o1.append(x)
  }

//* vecsplit(vec,vec1,vec2[,vec3,...])
// splits vec into other vecs given
proc vecsplit () { local num,ii,i
    num = numarg()-1 // how many
    for i=2,numarg() $oi.resize(0)
    for (ii=0;ii<$o1.size;ii+=num) {
        for i=2,numarg() if (ii+i-2<$o1.size) $oi.append($o1.x[ii+i-2])
      }
  }

//* vecsort(vec,vec1,vec2[,vec3,...])
// sorts n vecs including first vec by first one
proc vecsort () { local i,inv,scr,narg
    narg=numarg()
    if (narg<2 || narg>10) {print "Wrong #args in decvec.hoc:vecsort" return}
    scr=inv=allocvecs(2) scr+=1
    $o1.sortindex(mso[inv])
    mso[scr].resize(mso[inv].size)
    sprint(temp_string_,"%s.fewind(%s,%s,%s",mso[scr],mso[inv],$o1,$o2)
    for i=3,narg sprint(temp_string_,"%s,%s",temp_string_,$oi)
    sprint(temp_string_,"%s)",temp_string_)
    execute(temp_string_)
    dealloc(inv)
  }

//** order(&x,&y,...) put values in order
proc order () { local a,i,na
    na=numarg()
    a=allocvecs(1)
    for i=1,na mso[a].append($&i)
    mso[a].sort
    for i=1,na $&i=mso[a].x[i-1]
    dealloc(a)  
  }

//** vdelind()  -- delete a single index
proc vdelind () { local i,iin
    iin = $2
    if (iin<0) iin=$o1.size+iin
    if (iin>$o1.size-1 || iin<0) {
        printf("vdelind Error: index %d doesn't exist.\n",iin) return }
    if (iin<$o1.size-1) $o1.copy($o1,iin,iin+1,$o1.size-1)
    $o1.resize($o1.size-1)
  }

//* mkveclist(num[,sz]) recreate veclist to have NUM vecs each of size SZ (or MSOSIZ)
proc mkveclist () { local ii,num,sz,diff
    num=$1 
    diff = num-veclist.count
    if (numarg()==2) { sz=$2 } else { sz = MSOSIZ }
    if (diff>0) {
        for ii=0,diff-1 {
          tmpvec = new Vector(sz)
          veclist.append(tmpvec)
          }
      } else if (diff<0) {
        for (ii=veclist.count-1;ii>=num;ii=ii-1) { veclist.remove(ii) }
      }
    for ltr(XO,veclist) { XO.resize(sz) }
  }

//* allocvecs
// create temp set of vectors on mso
// returns starting point on mso 
// eg p = allocvecs(3)
// p = allocvecs(v1,v2,v3) // where v1..v3 are localobj or objref
// p = allocvecs(v1,v2,v3,...,size) // set all to size
// p = allocvecs(num,list) // append num vecs to list
// p = allocvecs(num,size) // num vecs of size size
// p = allocvecs(num,size,list) // append num vecs of size to list
// p = allocvecs(num,list,size) // allow args to be given in reverse order
// access these vectors by mso[p+0] ... [p+2]
func allocvecs () { local i,ii,llen,sz,newv,aflg,lflg localobj o
    if (numarg()==0) { 
        print "p=allocvecs(#) or p=allocvecs(v1,v2,...), access with mso[p], mso[p+1]..." return 0 }
    sz=MSOSIZ  
    lflg=0
    if (argtype(1)==0) {
        aflg=0 newv=$1
        if (numarg()>=2) if (argtype(2)==0) sz=$2 else {lflg=1 o=$o2} // append to list in arg2
        if (numarg()>=3) if (argtype(3)==0) sz=$3 else {lflg=1 o=$o3} 
        if (lflg) o.remove_all
      } else {
        aflg=1
        if (argtype(numarg())==0) {
            i=numarg() sz=$i newv=i-1
          } else newv=numarg() 
      }
    llen = msoptr
    for ii=msomax,msoptr+newv-1 { // may need new vectors
        if (ii>=MSONUM) { print "alloc ERROR: MSONUM exceeded." return 0 }
        mso[ii] = new Vector(sz)
      }
    for ii=0,newv-1 {
        mso[msoptr].resize(sz) 
        mso[msoptr].resize(0)
        msoptr = msoptr+1
      }
    if (msomax<msoptr) msomax = msoptr
    if (aflg) for i=1,newv $oi=mso[i-1+llen]
    if (lflg) for i=0,newv-1 o.append(mso[i+llen])
    return llen
  }

//** dealloc(start)
// remove temp set of vectors from mso
proc dealloc () { local ii,min
    if (numarg()==0) { min = 0 } else { min = $1 }
    msoptr = min
  }

//* indvwhere family
//** vwh(VEC,VAL) returns index where VEC.x[i]==VAL
func vwh () { 
    if (argtype(2)==0) return $o1.indwhere("==",$2) 
    if (numarg()==3) return $o1.indwhere($s2,$3)
    return $o1.indwhere($s2,$3,$4)
  }

//** vval(VEC,STR,NUM) uses indwhere to return first value that qualifies
func vval () {
    if (argtype(2)==0) return $o1.x[$o1.indwhere("==",$2)]
    if (numarg()==3) return $o1.x[$o1.indwhere($s2,$3)] 
    return $o1.x[$o1.indwhere($s2,$3,$4)] 
  }

//** vcnt(VEC,STR,x[,y]) uses indvwhere and returns # of values that qualify
func vcnt () { local a,ret
    a=allocvecs(1) 
    if (numarg()==2) mso[a].indvwhere($o1,"==",$2)
    if (numarg()==3) mso[a].indvwhere($o1,$s2,$3)
    if (numarg()==4) mso[a].indvwhere($o1,$s2,$3,$4)
    ret = mso[a].size
    // if ($o1.size>0) printf("%d/%d (%g)\n",ret,$o1.size,ret/$o1.size*100)
    dealloc(a)
    return ret
  }
//** civw(DEST,SRC1,STR1,x1[,y1]...) does compound indvwhere
// overwrites tstr; DEST should be size 0 unless to be compounded
// civw(DEST,0,...) will resize DEST to 0
func civw () { local i,a,b,c,f2,x,y,sz,min
    a=b=c=allocvecs(3) b+=1 c+=2
    min=2
    // if ($o1.size>0) print "Starting with previously set index vector"
    if (argtype(2)==0) {
        if ($2==0) { $o1.resize(0) min=3
            if (argtype(3)==1) sz=$o3.size else {
                printf("ERR0: arg 3 should be obj when $2==0\n",i) return -1 }
          } else {
            printf("ERR0a: arg 2 should be 0 if a number -- zero sizes ind vector\n") 
            return -1
          }
      } else if (argtype(2)==1) sz=$o2.size else {
        printf("ERR0b: arg 2 should be obj\n",i) return -1 }
    for (i=min;i<=numarg();) {
        mso[c].copy($o1) 
        if (argtype(i)!=1) { printf("ERR1: arg %d should be obj\n",i) return -1}
        if ($oi.size!=sz)  { printf("ERR1a: all vecs should be size %d\n",sz) return -1}
        mso[a].copy($oi)  i+=1   // look in a
        if (argtype(i)!=2) { printf("ERR2: arg %d should be str\n",i) return -1}
        tstr=$si          i+=1
        if (strm(tstr,"[[(]")) f2=1 else f2=0 // opstring2 needs 2 args
        if (argtype(i)!=0) { printf("ERR3: arg %d should be dbl\n",i) return -1}
        x=$i              i+=1 
        if (f2) {
            if (argtype(i)!=0) { printf("ERR4: arg %d should be dbl\n",i) return -1}
            y=$i            i+=1
          }
        if (f2) mso[b].indvwhere(mso[a],tstr,x,y) else { // the engine
                  mso[b].indvwhere(mso[a],tstr,x)   }
        $o1.resize(sz) // make sure it's big enough for insct -- shouldn't need
        if (mso[c].size>0) $o1.insct(mso[b],mso[c]) else $o1.copy(mso[b])
        if ($o1.size==0) break
      }
    dealloc(a)
    return $o1.size
  }

//* vecconcat(vec1,vec2,...)
// destructive: concatenates all vecs onto vec1
proc vecconcat () { local i,max
    max=numarg()
    if (numarg()<2) { print "vecconcat(v1,v2,...) puts all into v1" return }
    if (argtype(max)==0) {max-=1 $o1.resize(0)}
    for i=2,max $o1.append($oi)
  }
  
//** vecelim(v1,v2)  eliminates items in v1 given by index vec v2
proc vecelim () {
    for vtr(&x,$o2) { $o1.x[x]= -1e20 }
    $o1.where($o1,"!=",-1e20)
  }

//** redundout(vec) eliminates sequential redundent entries
// destructive
func redundout () { local x,ii,p1
    p1=allocvecs(1)
    $o1.sort
    mso[p1].resize($o1.size)
    mso[p1].redundout($o1)
    $o1.copy(mso[p1])
    dealloc(p1)
    return $o1.size
  }

//** uniq(src,dest[,cnt]) uses redundout to return random values of a vector
// like redundout except nondestructive
obfunc uniq () { local a localobj v1,vret
    a=allocvecs(v1)
    v1.copy($o1) v1.sort 
    if (numarg()==3) {          $o2.redundout(v1,0,$o3) 
      } else if (numarg()==2) {   $o2.redundout(v1) 
      } else {
        vret=new Vector(v1.size) vret.redundout(v1)
      }
    dealloc(a)
    if (numarg()==1) return vret else return $o2
  }

//** complement(ind,max) for indices -- return values from 0..max that are not in ind
proc complement () { local a,b,max
    a=b=allocvecs(2) b+=1
    max=$2
    mso[a].indgen(0,max,1)
    mso[b].resize(mso[a].size)
    mso[b].cull(mso[a],$o1)
    $o1.copy(mso[b])
    dealloc(a)
  }

//** albetname() generate sequential 3 char alphabetical file names (make filenames)
obfunc albetname () { local na,sret localobj st
    na=numarg() sret=0
    st=new String2()
    if (na==0) { fnum+=1 st.t=".id"
      } else if (na>=1) {
        if (argtype(1)==2) {st.t=$s1 fnum+=1} else fnum=$1
      }
    if (na==2) st.t=$s2  // partially back compatible, doesn't handle albetname(tstr,".id")
    if (na==3) {st.t=$s3 sret=1}
    if (fnum>17575) printf("albetname WARN: out of names: %d > %d\n",fnum,26^3-1)
    sprint(st.s,"%c%c%c",  fnum/26/26%26+97,fnum/26%26+97,fnum%26+97)
    if (sfunc.len(st.t)>0) sprint(st.s,"%s%s",st.s,st.t)
    if (sret) $s2=st.s 
    return st
  }

// save_idraw([filename,save_all,PS]) -- save idraw to file
// default is to generate albetname, save selected to idraw
proc save_idraw () { local sv,ps localobj st,li
    st=new String()
    find_pwm()
    ps=sv=1
    if (argtype(1)==2) {
        st.s=$s1 
        if (argtype(2)==0) sv=$2
        if (argtype(3)==0) ps=$3
      } else if (argtype(1)==0) {
        sv=$1
        if (argtype(2)==0) ps=$2  
      }
    if (sfunc.len(st.s)==0) st.s=albetname().s
    if (verbose) printf("Saving to %s\n",st.s)
    pwm.printfile(st.s, ps, sv)
  }

proc find_pwm () { localobj li
    if (isassigned(pwm)) return
    li=new List("PWManager")
    if (li.count==0) pwm=new PWManager() else pwm=li.o(0)
  }

// vecconv() convert $o1 by replacing instances in $o2 by corresponding instances in $o3
proc vecconv () { local a,b
    a=b=allocvecs(2) b+=1
    vrsz($o1,mso[b])
    for vtr2(&x,&y,$o2,$o3) { // x -> y
        mso[a].indvwhere($o1,"==",x)
        mso[b].indset(mso[a],y)
      }
    $o1.copy(mso[b])
  }

//** veceq()  like vec.eq but don't have to be same size and shows discrepency
func veceq () { local sz1,sz2,eq,beg,ii,jj,kk
    sz1=$o1.size sz2=$o2.size
    if (numarg()==3) beg=$3 else beg=0
    if (sz1!=sz2) printf("%s %d; %s %d\n",$o1,sz1,$o2,sz2)
    ii=0 jj=beg
    while (ii<sz1 && jj<sz2) {
        if ($o1.x[ii]!=$o2.x[jj]) { 
            eq=0
            printf("Differ at %d %d\n",ii,jj) 
            for kk=-10,10 if ((ii+kk)>=0 && (ii+kk)<sz1 && (jj+kk)>=0 && (jj+kk)<sz2) {
                printf("(%d)%g:(%d)%g ",(ii+kk),$o1.x[ii+kk],(jj+kk),$o2.x[jj+kk])  }
            print ""
            break 
          } else eq=1
        ii+=1 jj=ii+beg
      }
    return eq
  }

//* isstring() determine if object $o1 is of type string, if so return the string in [$s2]
func isstring () {
    sprint(tstr,"%s",$o1)
    if (sfunc.substr(tstr,"String")==0) {
        if (numarg()==2) sprint($s2,"%s",$o1.s)
        return 1
      } else {
        if (numarg()==2) sprint($s2,"%s",$o1)
        return 0
      }
  }

//** isassigned() checks whether an object is Null
if (name_declared("VECST_INSTALLED")) {
    sprint(tstr,"func isassigned () { return !isojt($o1,nil) }")
  } else {
    sprint(tstr,"func isassigned () { return !isobt($o1,nil) }")
  }
execute1(tstr)

//** declared goes through a list of function names and makes sure they exist
// useful to check a bunch of names before entering a template that calls them as external
proc declared () { local i,nd
    for i=1,numarg() {
        nd=name_declared($si)
        if (nd==0) { // declare it
            // sprint(tstr,"func %s () {printf(\"\\tEMPTY FUNCTION %s()\\n\") return 0}",$si,$si)
            sprint(tstr,"func %s () {return 0}",$si)
            execute1(tstr)
          } else if (nd!=1) { // 2=obj,3=sec,4=str,5=dbl
            printf("NAME CONFLICT: %s can't be a func since was declared as a %d\n",$si,nd)
          }
      }
  }

//** isit() like isassigned() but can take a string instead
obfunc isit () { local ret localobj sv,o,st
    o=new Union()  st=new String()
    if (argtype(1)==2) {
        sv=XO
        sprint(st.s,"XO=%s",$s1)
        execute(st.s) // XO points to the thing
        ret=isassigned(XO)
        o.x=ret
        o.s=$s1
        o.o=XO
        XO=sv
        return o
      } else return isassigned($o1)
  }

//** isob(s1,s2) like isobj but takes string statt obj
func isob () { localobj st
    st=new String()
    sprint(st.s,"XO=%s",$s1)
    execute(st.s) // XO points to the thing
    sprint(st.s,"%s",XO)
    if (sfunc.substr(st.s,$s2)==0) {
        return 1
      } else {
        return 0
      }
  }

//** eqobj(o1,o2) checks whether 2 objects are the same
func eqobj () {	return object_id($o1) == object_id($o2) }
//** ocnt(STR) counts number of objects named string
func ocnt () { local ret
    tmpobj=new List($s1) ret=tmpobj.count
    tmpobj=nil
    return ret
  }

//** isobj(o1,s2) checks whether object $o1 is of type $s2
func isobj () { localobj st
    st=new String()
    sprint(st.s,"%s",$o1)
    if (sfunc.substr(st.s,$s2)==0) {
        return 1
      } else {
        return 0
      }
  }

//** isobt(o1,o2) checks whether object $o1 is of type $o2
func isobt () { localobj s
    s=new String2()
    sprint(s.s,"%s",$o1)  sprint(s.t,"%s",$o2)
    sfunc.head(s.s,"\\[",s.s) sfunc.head(s.t,"\\[",s.t)
    if (strc(s.s,s.t)) return 1 else return 0
  }

// destructive of $s1
func str2num () { local x localobj o,st
    x=1e9
    if (sscanf($s1,"%d",&x)!=1) {
        o=new Union() st=new String()
        sprint(st.s,"%s.x=%s",o,$s1)  // o has temp existance in global namespace
        if (!execute1(st.s,0)) printf("Can't find '%s'\n",$s1)
        x=o.x
      }
    return x
  }

func isnum () { return strm($s1,"^[-+0-9.][-+0-9.eE]*$") }

// like perl chop -- removes the last character
// chop(STR[,TERM]); TERM chop only TERM
// note that no + means must repeat char eg "))*" statt ")+"
func chop () { local ln1,match localobj st
    ln1=sfunc.len($s1)  st=new String()
    if (numarg()==2) { 
        sprint($s2,"%s$",$s2) // just look for terminal character
        if ((match=sfunc.head($s1,$s2,st.s))==-1) {
            return 0 
          } else {
            sfunc.left($s1,match) 
            return match
          }
      } else if (sfunc.len($s1)>=1) {
        sfunc.left($s1,ln1-1) 
        return 1
      } else {
        print "ERR: chop called on empty string" }
      return 0
  }

// lchop(STR[,BEGIN]) -- chop from the left
func lchop () { local ln1,match localobj st
    ln1=sfunc.len($s1)  st=new String()
    if (numarg()==2) { 
        sprint($s2,"^%s",$s2) // just look for initial chars
        if ((match=sfunc.tail($s1,$s2,st.s))==-1) {
            return 0 
          } else {
            sfunc.right($s1,match) 
            return match
          }
      } else if (sfunc.len($s1)>=1) {
        sfunc.right($s1,1) 
        return 1
      } else {
        print "ERR: chop called on empty string" }
      return 0
  }

// strcat(tstr,"stra","strb",...) tstr=stra+strb+...
// 1st arg can be a strdef or String obj
// other args can be strdef, String obj, literal string, or number handled as %g
// returns String obj
obfunc strcat () { local i,na localobj out
    na=numarg() 
    if (argtype(1)==0) { out=new String() 
      } else if (argtype(1)==1) { 
        if (isassigned($o1)) out=$o1 else { out=new String() $o1=out }
      } else { out=new String() out.s=$s1 }
    if (argtype(na)==0) { out.s="" na-=1 } // clear string
    for i=2,na {
        if (argtype(i)==1) {        sprint(out.s,"%s%s",out.s,$oi.s) 
          } else if (argtype(i)==2) { sprint(out.s,"%s%s",out.s,$si) 
          } else                      sprint(out.s,"%s%g",out.s,$i) 
      }
    if (argtype(1)==2) $s1=out.s
    return out
  }

// split(string,vec) // split comma sep string into numbers
// split(string,list) // split comma sep string into list of strings
// split(string,list,regexp) // split regexp sep string into list of strings
// split(string,vec,regexp,1) // split but don't interpret: eg "5*3"->15 or "x"->val
// split(string,list,num) // split every num chars
// eg split("534,  43 , 2, 1.4, 34",vec[,"/"])
// split("13, 3*PI/2*tau/2, 32+7, 6, 9.2, 42/3",vec) 
//    optional 3rd str is what to split on; default is comma
func split () { local vf,x,nointerp,done,num localobj s,st,o
    if (numarg()==0) {
        printf("eg split(\"534 43 2 1.4 34\",vec,\" \") split(\"a,b,c,d,e\",tmplist)")
        return -1 }
    s=new String2() st=new String2()
    s.t=$s1 o=$o2
    if (numarg()>3) nointerp=1 else nointerp=0 // 4th flag nointerp: don't interpret strings
    if (isobj(o,"Vector")) vf=1 else {
        vf=0
        if (!isassigned(o)) { o=new List() $o2=o }
      }
    if (vf) revec(o) else o.remove_all
    if (argtype(3)==2) st.s=$s3 else st.s="[, ]+"
    if (argtype(3)==0) {
        if (vf) {printf("Split err: attempting to do length split into vector: %s",o) return 0}
        num=$3 
        sprint(st.s,"%%*%ds%%s",num) // eg "%2*s%s" to get all but first 2 chars
        sprint(st.t,"%%%ds",num)     // eg "%2s"    to get first 2 chars
        if (num>sfunc.len(s.t)){
            printf("split() ERRA %s of length %d in pieces of %d?\n",s.t,sfunc.len(s.t),num) return 0}
      } else num=0
    while (sfunc.len(s.t)>0) {
        done=0
        if (vf) {
            if (!nointerp) if (strm(s.t,"^[^,]+[+*/-]")) {
                sfunc.head(s.t,",",s.s)
                if (sfunc.len(s.s)==0) s.s=s.t
                sprint(s.s,"%s.append(%s)",o,s.s) execute(s.s)
                done=1
              } 
            if (!done) if (sscanf(s.t,"%lf",&x)) { 
                o.append(x)
                done=1
              } 
            if (!done && !nointerp) { // try to interpret as a variable
                y=2.775434e-23 // global 'y'
                sfunc.head(s.t,st.s,s.s)
                if (sfunc.len(s.s)==0) s.s=s.t // the end
                sprint(st.t,"y=%s",s.s)
                execute1(st.t,0) // no error
                if (y==2.775434e-23) {
                    printf("split WARNING skipping non-number: %s\n",s.s) 
                  } else {
                    o.append(y) 
                  }
                done=1
              }
          } else { // split into a list
            if (num) {
                sscanf(s.t,st.t,s.s)
                o.append(new String2(s.s,s.s))
              } else {
                sfunc.head(s.t,st.s,s.s)
                if (sfunc.len(s.s)==0) s.s=s.t // the end
                o.append(new String2(s.s,s.s))
              }
            done=1
          }
        if (num) { // splitting equal length strings
            if (sfunc.len(s.t)<=num) s.t="" else sscanf(s.t,st.s,s.t)
          } else {
            sfunc.tail(s.t,st.s,s.t)
          }
      }
    if (vf) return o.size else return o.count
  }

// parsenums(STR,VEC)
func parsenums () { local x localobj st
    st = new String2()
    revec($o2)
    st.t=$s1
    while (sfunc.len(st.t)>0) {
        if (sscanf(st.t,"%g",&x) != 1) {
            sfunc.tail(st.t,"[^-0-9]+",st.s)  st.t=st.s
          } else {
            sfunc.tail(st.t,"[-e0-9.]+",st.s)  st.t=st.s
            $o2.append(x)
          }
      }
    return $o2.size
  }

// intervals(TRAIN,OUTPUT)
func intervals () { local a
    if ($o1.size<=1) { printf("%s size <2 in intervals()\n",$o1) return 0}
    $o2.deriv($o1,1,1)
    return $o2.size
  }

// invl(train,stats[,thresh])
func invl () { local a,x,sz localobj v1,v2
    a=allocvecs(v1,v2)
    if ($o1.size<=1) { printf("%s size <2 in invl()\n",$o1) 
        $o2.resize(5) $o2.fill(-1)
        dealloc(a)
        return 0
      }
    if (!$o1.ismono(2)) printf("decvec::invl() WARN: %s not sorted\n",$o1)
    v1.deriv($o1,1,1)
    if (numarg()==3) {
        if ((x=v1.w("<",$3,-1))>0) { // tag and remove all below threshold
            v1.sort v1.reverse
            v1.resize(v1.size-x)
          }
      }
    stat(v1,$o2)
    sz=v1.size
    dealloc(a)
    return sz
  }

// freql(train,stats)
// doesn't make much sense to take the mean of inverses 
func freql () { local a localobj v1
    a=allocvecs(v1)
    if ($o1.size<=1) { printf("%s size <2 in intervals()\n",$o1) return 0}
    v1.deriv($o1,1,1)
    v1.inv(1e3)
    stat(v1,$o2)
    return v1.size
  }

// downcase(tstr[,UPCASE]) 
proc downcase () { local len,ii,let,diff,min,max
    diff=32 min=65 max=90
    if (numarg()==2) { diff=-diff min=97 max=122 } // if flag -> upcase
    len = sfunc.len($s1)
    for ii=1,len {
        sscanf($s1,"%c%*s",&x)
        sfunc.right($s1,1)
        if (x>=min&&x<=max) {
            sprint($s1,"%s%c",$s1,x+diff)
          } else sprint($s1,"%s%c",$s1,x) // just rotate the letter
      }
  }

// newlst() puts a newline in the middle of a string
proc newlst () { local l
    if (numarg()>1) l=$2 else l=int(sfunc.len($s1)/2)
    temp_string_=$s1
    temp_string2_=$s1
    sfunc.left(temp_string_,l)
    sfunc.right(temp_string2_,l)
    sprint($s1,"%s\n%s",temp_string_,temp_string2_)
  }

//* rdcol(file,vec,col#,cols): read multicolumn file
func rdcol () { local col,cols,length
    if (numarg()==0) { print "\trdcol(\"file\",vec,col#,cols) // col#=1..." return 0}
    col=$3 cols=$4 length=0
    if (! tmpfile.ropen($s1)) { printf("\tERROR: can't open file \"%s\"\n",$s1) return 0}
    while (tmpfile.gets(temp_string_) != -1) length+=1 // count lines
    print length
    tmpfile.seek()
    $o2.scanf(tmpfile,length,col,cols)
    if ($o2.size!=length) printf("rdcol ERR: only read %d statt %d\n",$o2.size,length)
    return length
  }

//* rdmuniq(vec,n,rdm) -- augment vec by n unique vals from rdm
//  rdmuniq(vec,n,max) -- augment vec by n unique vals 0-max
//  rdmuniq(vec,n,min,max) -- augment vec by n unique vals min-max
// draw n numbers without replacement, only makes sense with discrete distribution
// could do something like 
// mso[a].setrand($o3) mso[d].copy(mso[a]) 
//     mso[b].indsort(mso[a]) mso[a].sort() mso[c].redundout(mso[a],1)
// to get indices of unique values but then have to back index to original
proc rdmuniq () { local n,num,flag,xx,loop,a localobj ro
    if (numarg()==0) {
        printf("rdmuniq(vec,n,rdm) - augment vec by n unique vals from rdm\
      rdmuniq(vec,n,max) - augment vec by n unique vals 0-max\
      rdmuniq(vec,n,min,max) - augment vec by n unique vals min-max\n") 
      return }
    a=allocvecs(1)
    n=$2  num=0  flag=1 loop=0
    mso[a].resize(n*4) // hopefully will get what we want
    revec($o1)
    if (argtype(3)==1) ro=$o3 else {
        ro=rdm // or could create a new Random
        if (numarg()>3) ro.discunif($3,$4) else ro.discunif(0,$3)
      }
    while (flag) {
        mso[a].setrand(ro)
        for ii=0,mso[a].size-1 {
            xx=mso[a].x[ii]
            if (! $o1.contains(xx)) { $o1.append(xx) num+=1 }
            if (num==n) { flag=0 break }
          }
        loop+=1
        if (loop==10) { print "rdmunq ERR; inf loop" flag=0 break }
      }
    dealloc(a)
  }

// rdmord (vec,n) randomly ordered numbers 0->n-1 in vec
// eg rdmord(ind,ind.size); check: for ii=0,ind.size-1 if (ind.count(ii)!=1) print ii
proc rdmord () { local n,a localobj v1
    a=allocvecs(v1)  n=$2
    rdm.uniform(0,100)
    v1.resize(n)
    v1.setrand(rdm)
    v1.sortindex($o1)
    dealloc(a)
  }

// shuffle(VSRC[,VDEST]) randomly rearrange elements of vec
obfunc shuffle () { local a  localobj v1,v2,oi,oo
    oi=$o1
    if (numarg()==2) oo=$o2 else oo=$o1
    a=allocvecs(v1,v2)
    rdmord(v1,oi.size)
    v2.index(oi,v1)
    oo.copy(v2)
    dealloc(a)
    return oo
  }

// sample(vec,beg,end,vals) pick out n integer values from given range
// sample(vec,end,vals) -- assumes 0
proc sample () { local min,max,vals
    min=0
    if (numarg()==4) {min=$2 max=$3 vals=$4} else {max=$2 vals=$3}
    $o1.indgen(min,max,1)
    shuffle($o1)
    $o1.resize(vals)
  }

// round() round off to nearest integer
func round () { local ii
    if (argtype(1)==1) {
        if ($o1.size==0) return 1e9
        for ii=0,$o1.size-1 {
            if ($o1.x[ii]>0) $o1.x[ii]=int($o1.x[ii]+0.5) else $o1.x[ii]=int($o1.x[ii]-0.5) 
          }
        return($o1.x[0])
      } else {
        if ($1>0) return int($1+0.5) else return int($1-0.5) 
      }
  } 

// filevers() pulls out version of file from first line
func filevers () { localobj f1,s1,lx1
    f1=new File() s1=new String() lx1=new Union()
    if (! f1.ropen($s1)) { printf("filevers ERR, can't open %s\n",$s1) 
        return 0 }
    f1.gets(s1.s)
    if (sscanf(s1.s,"%*s $Id: %*s %*d.%d",&lx1.x)!=1) {
        printf("filevers ERR, sscanf failed %s: %s",$s1,s1.s) }
    f1.close
    return lx1.x
  }

//* hocfind(FILENAME) searches through HOC_LIBRARY_PATH and locates file
obfunc hocfind () { local done localobj f1,s1,s2
    f1=new File() s1=new String() s2=new String()
    done=0
    system("echo -n $HOC_LIBRARY_PATH",s1.s)
    sprint(s1.s,"%s ",s1.s) // to look at last item
    while (sfunc.len(s1.s)>2) {
        sfunc.head(s1.s,"[ :]",s2.s)
        sprint(s2.s,"%s/%s",s2.s,$s1)
        if (f1.ropen(s2.s)) {done=1 break}
        sfunc.tail(s1.s,"[ :]",s1.s)
      }
    if (!done) if (f1.ropen($s1)) {sprint(s2.s,"./%s",$s1) done=1}
    if (!done) s2.s="NOT FOUND"
    return s2
  }

//* usefiles(F1[,F2,...]) list of files returns string with list of files and versions
obfunc usefiles () { local i localobj s1,s2
    s2=new String()
    s2.s="Using "
    for i=1,numarg() {
        s1=hocfind($si)
        sprint(s2.s,"%s %s%d",s2.s,$si,filevers(s1.s))
      }
    return s2
  }

//* ttest(v1,v2)  student t-test
// nrniv/sync/notebook.dol:16230
// checked against http://www.physics.csbsju.edu/stats/t-test_bulk_form.html
func ttest () {  local prob,df
    df=$o1.size+$o2.size-2
    t_val=($o1.mean-$o2.mean)/sqrt($o1.var/$o1.size + $o2.var/$o2.size)
    prob=betai_stats(0.5*df,0.5,df/(df+t_val*t_val))
    return prob
  }

// pttest() paired t-test
func pttest () {  local prob,sd,df,cov,j,ave1,ave2,var1,var2
    n=$o1.size ave1=$o1.mean ave2=$o2.mean var1=$o1.var var2=$o2.var cov=0
    if (n!=$o2.size) {printf("pttest ERR: != sizes\n",n,$o2.size) return -1}
    for (j=0;j<n;j+=1) cov+=($o1.x[j]-ave1)*($o2.x[j]-ave2)
    cov /= (df=n-1)
    sd=sqrt((var1+var2-2.0*cov)/n)
    t_val=(ave1-ave2)/sd
    prob=betai_stats(0.5*df,0.5,df/(df+t_val*t_val))
    // printf("%g ",t_val)
    return prob
  }

func howfull () { local a,min,max,bins,ret localobj v1
    min=0 bins=1e3
    if (numarg()==4){min=$2 max=$3 bins=$4} else if (numarg()==3){max=$2 bins=$3} else max=$2
    a=allocvecs(v1,bins)
    $o1.bin(v1,(max-min)/bins,min,max)
    ret=1-v1.count(0)/bins
    dealloc(a)
    return ret
  }

for scase(XO,"o","t","s","O","T","S","+") clrsym.o.append(new String(XO.s))
// END /usr/site/nrniv/local/hoc/decvec.hoc
//================================================================
gnum=-1
if (! name_declared("show_panel")) show_panel=1
obfunc file_with_dot(){} // stubs to declare later, otherwise external barfs
obfunc filname(){} 
obfunc dirname(){}
func file_len(){}
proc tog (){if (numarg()==1) print $&1=1-$&1 else print gvmarkflag=1-gvmarkflag}
proc pvout2 () { }  // stub for manipulating printlist
proc rv2 () { }  // stub for manipulating the vectors before graphing
proc rv3 () { }  // stub for manipulating the label
func setfilt2 () { return 0 }  // stub for setting filter
func dir2mf2() {return 1} // stub for checking whether to include a trace

//* template vfile_line (vector file line) template gives information about a line
//  in a file that gives a vector: name, size and location
begintemplate vfile_line
  public name, size, loc, segs, num, ix, f
  strdef name,f
  double loc[1]
  proc init () { 
      segs=1
      if (numarg()>4) if (argtype(5)==0) segs=$5 else f=$s5
      name=$s1 size=$2 num=$4
      double loc[segs]
      loc[0] = $3
      ix=-1 // can be used as index if needed
    }
endtemplate vfile_line

//* template vitem (vector item) is an internal vector used to store output from 
// new vitem(var_name,vec_size,friendly_name)
// new vitem(var_name,vec_size,1) -- force tvec creation even if not cvode_local
// a simulation holds the name and the vector itself
tvflag_on=1
begintemplate vitem
  external cvode,tvflag_on,isassigned
  public tvec,vec,name,tvflag,pstep,o,code,resize
  objref tvec,vec,o,this // o not set here but used for Acells
  strdef tstr,name // variable name
  proc init () {
      name=$s1  tvflag=0 pstep=0 code=0
      if (cvode.active()) { if (cvode.use_local_dt()) tvflag=1 else tvflag=-1 }
      if (tvflag_on) tvflag=1
      if (argtype(2)==0) vec=new Vector($2) else if (argtype(2)==1) vec=$o2
      if (argtype(3)==0) { // sloppy -- what if pstep=1??
          if ($3==1) tvflag=1 else {tvflag=0 pstep=$3} 
        } else if (argtype(3)==1) {
          tvec=$o3
          tvflag=1 // don't create another one
        }
      if (argtype(4)==0) if ($4==1) tvflag=1 else {tvflag=0 pstep=$4}
      if (tvflag==1 && !isassigned(tvec)) tvec=new Vector($2) 
      if (tvflag==-1) {
          sprint(tstr,"if (!isassigned(tvec)) tvec=new Vector(%d)",$2) execute(tstr) 
          sprint(tstr,"%s.tvec=tvec",this) execute(tstr)
        }
    }
  proc resize () {
      vec.resize($1) 
      if (isassigned(tvec)) tvec.resize($1)
    }
endtemplate vitem

//* main template: GRV
// the attributes of a particular set of graphs including line colors,
// world coordinates, ...
// glist is a list of all graphs created from this panel
// llist is a list of available names and associated vectors or locations
begintemplate GRV
  public color,line,super,curcol,comment,vecpanel,mesg,tmplist,gxpan
  public glist,oglist,llist,tvec,size,shift,vsz,vjmp,tloc,vloc,remote
  public entries,segments,clear,keepgr
  public read_vfile,rvaltdisp,read_file,grvec,remgrs,clear,record,read_pclamp
  public cpplitem,chgplname,npl,new_pri,prlexp,numovecs,fchooser
  public read_vdotfile,rpanel,panobjl,ddir,filter
  public rlist,rvlist,attrpanl,wvpanl,remgrs,collapsegrs,viewplot,nvwall
  public geall,lblall,relbl,grall,grsel,tposvec,fliptb,setrange,setgrransel,grransel
  public chrange,rv,rv_readvec,rvec,rvl,read_rfile,gv
  public grrtsize,ge,pvall,pvother,pvplist,pvclose,vf2fwf
  public pvnext,pvout,prvec,pv,lpvec,nvplt,apbrowse,apkill
  public newpl,find_secname,mkmenu,dir2pr,dir2mf,read_mf
  public mkpanel,pbrgr,remprl,filename,onum,po,stub,go
  public rvtr,vrdr,prdr,tmpobj,printlist,output_file,attr0,attrnum,s,vite
  public glist,llist,tvec,ind,vec,vrtmp,tmpvec,tf1,tmpobj,apvb,printStep
  public gvmarkflag,gveraseflag,fchooser_flag,byte_store,bst,szstr,regexp,tmpfile
  public magga,mvga,ll

  double size[4],vsz[2],wvloc[4],x[4]
  objref glist, oglist, llist, tvec, ind, vec, vrtmp, tmpvec, tf1, tmpobj, apvb, ovb, printlist
  objref vite,scob,printlist,szstr[4],g,this,tmplist,panobj,panobjl,Xo,Yo,tmpfile, gcomms
  strdef comment,recstr,grvecstr,readtag,rvvec_name,grep,tstr,tstr2,ddir,filter
  strdef temp_string_,temp_string2_,output_file,s,filename,mesg,regexp
  external sfunc,osname,vfile_line,vitem,uname,nil,simname,gnum,XO,YO,graphList,isassigned
  external isobj,isit,mso,msoptr,allocvecs,dealloc,tstop,method,cvode,show_panel,rv2,rv3,setfilt2
  external cvode_active,cvode_local,datestr,runnum,i1,graphItem,GRV,strm,objnum,DBL,dir2mf2
  external file_with_dot,count_substr,file_len,filname,dirname,dir,grv_,repl_mstr,pvout2

// list iterator ltr
// usage 'for ltr(YO, tmplist) { print YO }'
iterator ltr () { local i
    ii1=0
    for i = 0,$o2.count-1 {
        $o1 = $o2.object(i)
        iterator_statement
        ii1+=1
      }
    $o1=nil
  }

proc init () { local flag,nopan
    flag=1e9
    if (numarg()==1) if (argtype(1)==0) flag=$1 
    if (numarg()==2) if (argtype(2)==0) flag=$2 else printf("2nd arg for GRV should be flag\n")
    nopan=0 color=1 line=1 curcol=1 keepgr=tloc=-1 nvec=bvec=super=0 vjmp=50 entries=1 segments=1
    fchooser_flag=0
    vsz[0] = 300  vsz[1] = 200
    glist = new List()
    tmpfile = new File()
    oglist = glist // save old glist for after superimpose
    llist=new List() gcomms=new List() printlist=llist
    tvec=new Vector(0) ind=tvec.c vec=tvec.c vrtmp=tvec.c tmpvec=tvec.c
    rvvec_name = "vec"
    ddir = "data/"
    printStep=gvmarkflag=gveraseflag=mff=0
    remote=0
    entries=segments=shift=0
    tloc=vloc=vjmp=x=y=luprd=0
    wvloc[0]=50 wvloc[1]=50 wvloc[2]=800 wvloc[3]=150
    onum=objnum(this)
  
    for ii=0,3 { szstr[ii] = new String() }
    if (sfunc.substr(osname,"inux")==1) grep="grep -a" else grep="grep"
    readtag = "^//[:pbCM ]"  // regexp used to identify header in mixed binary files
    { szstr[0].s="Set xmin" szstr[1].s="Set xmax" szstr[2].s="Set ymin" szstr[3].s="Set ymax" }
    multi_files = 1 // set 0 to show individual segments of multi-seg files
    dec_runnum = 0  // whether to decrement runnum when saving a new file
    byte_store = 4  // store as ascii (0), byte (1), int (2), float (3), double (4)
    tvec_bytesize = 4  // always store tvecs with more precision
    outvecint = 0     // dump vectors every outvecint time if not 0
    outvect = 0     // time for next vec dump
    labelm = 1       // set to 0 to turn off labeling
    attr0=0 // default is a panel for reading files
    if (flag==0) { // make a sim-recording panel
        if (numarg()>1) printf("GRV WARNING: creating simpan, ignoring filename\n")
        attr0=1 attrnum=0
        if (! isobj(panobjl,"List")) panobjl = new List() 
        attrnum=panobjl.append(this)-1
        if (attrnum!=0) printf("GRV WARNING: attr0 with attrnum=%d!\n",attrnum)
        if (show_panel) vecpanel()
        sprint(tstr,"printlist=%s.printlist",this)
        execute(tstr)
        sprint(s,"GRV[%d]:%s (sim vecs)",objnum(this),simname)
        return
      }
    panobjl=grv_.panobjl
    attrnum=panobjl.append(this)-1
    if (flag==-2) nopan=1 
    if (flag==-1) { fchooser() // ask user for filename
      } else if (numarg()>=1) {
        if (argtype(1)==2) read_vfile($s1)
      }
    if (!nopan) attrpanl()
  }

//** newfile() calls fchooser
proc newfile () { localobj o
    o = apvb
    fchooser() 
    attrpanl()
  }

//** bst() selects byte_store
func bst () { 
    if (numarg()>=1) byte_store=$1 
    if (numarg()>=2) tvec_bytesize=$2
    return byte_store 
  }

//* attrpanl() gives attributes for a set of graphs
proc attrpanl () { local ii,jj
    sfunc.tail(filename,"data.*/",grvecstr)
    apvb=new VBox() 
    apvb.intercept(1) 
    xpanel(temp_string_)
    xvarlabel(filename)
    if (sfunc.len(mesg)>40) sfunc.left(mesg,40)
    xvarlabel(mesg)
    xvalue("Color(-1=multi)","color",1,"if (color==0) curcol=0",0,1)
    xvalue("Line","line",1,"",0,1)
    xpanel()
    xpanel("",1)
    xbutton("Superimpose: ","tog(&super) if (super==0) gnum=-1 sprint(mesg,\"super=%d\",super)")
    xbutton("Where?","sprimp()")
    xbutton("Restore","glist=oglist sprint(mesg,\"Restore graph list\")")
    xpanel()
    xpanel("",1)
    xbutton("Limits","wvpanl()")
    xbutton("Erase","geall()")
    xbutton("Mark","togmark()")
    if (attr0) xbutton("Panel","pbrgr(\"Graph\",\"gv\")") else {
        xbutton("New file","newfile()") }
    xpanel()
    xpanel("",1)
    xmenu("Graphs")
    xbutton("Erase/redraw","gveraseflag=-(gveraseflag-1) if (gveraseflag==1) super=1 else super=0 sprint(mesg,\"Erase=%d\",gveraseflag)")
    xbutton("Erase graphs","geall()")
    xbutton("Remove graphs","remgrs()")
    xbutton("Clean graph list","collapsegrs()")
    xbutton("Erase axes","setrange(3)")
    xbutton("Draw axes","setrange(0)")
    xbutton("Label graphs","lblall()")
    sprint(tstr,"execute(\"disptray(%d)\")",onum)
    xbutton("Make tray",tstr)
    xbutton("View = plot","for ltr(Xo,glist) Xo.exec_menu(\"View = plot\")")
    xbutton("Crosshair","for ltr(Xo,glist) Xo.exec_menu(\"Crosshair\")")
    xbutton("New view","for ltr(Xo,glist) Xo.exec_menu(\"NewView\")")
    xbutton("Zoom","for ltr(Xo,glist) Xo.exec_menu(\"Zoom in/out\")")
    xbutton("Delete Text","for ltr(Xo,glist) Xo.exec_menu(\"Delete\")")
    xbutton("Move Text","for ltr(Xo,glist) Xo.exec_menu(\"Move Text\")")
    xbutton("Change Text","for ltr(Xo,glist) Xo.exec_menu(\"Change Text\")")
    xmenu()
    // sprint(temp_string_,"remote",attrnum)
    // sprint(temp_string2_,"grall(%d)",attrnum)
    // xvalue("Graph all",temp_string_,0,temp_string2_)
    if (attr0) redo_printlist() else xbutton("Show full panel","rpanel()")
    xpanel()
    apvb.intercept(0) 
    if (attr0) {   sprint(s,"GRV[%d] %s SIM CONTROL",objnum(this),simname)
      } else       { 
        if (sfunc.len(filename)>0) filname(filename,grvecstr)
        sprint(s,"GRV[%d] %s:%s",objnum(this),simname,grvecstr) 
      }
    apvb.map(s)
  }

//** sprimp() superimpose on another sim
proc sprimp () {
    super=1
    sprint(tstr,"SUPERIMPOSE %s ON?",s)
    ovb=new VBox() 
    ovb.intercept(1) 
    xpanel(tstr)
    xvalue("Superimpose on Graph[#]","gnum",1)
    for ltr(Xo,panobjl) {
        sprint(temp_string2_,"glist=%s.glist sprint(mesg,\"Using graph list from %s\") ovb.unmap() ovb=nil",Xo,Xo)
        xbutton(Xo.s,temp_string2_)
      }
    xpanel()
    ovb.intercept(0) 
    ovb.map(tstr)
    ovb.dismiss_action("ovb.unmap ovb=nil")
  }

//** fchooser() finds file and then create panel from it using rpanel
proc fchooser () { 
    if (fchooser_flag == 0) {  // create panel first time only
        if (setfilt2(filter)) { // do nothing
          } else if (strm(filter,"\\*")) { // do nothing
          } else sprint(filter,"*%s*",datestr)
        tmpfile.chooser("","Read from a file",filter,"Open","Cancel",ddir)
      }
    fchooser_flag = 1
    if (tmpfile.chooser()) {
        // find out whether this is a vector file or not
        tmpfile.getname(filename)
        if (strm(filename,"\.mf")) read_mf() else read_vfile() 
      }
  }

//** newpan() create a new panel and call fchooser from there
proc newpan () { tmpobj=new GRV(-1) }

//** read_vfile() creates a panattr object from information in a file
// (uses grep to avoid loading big file)
// assumes file in tmpfile
func read_vfile () { local flag, ii, sz, loc, mult, sze, cloc, segs
    if (numarg()>=2) if (strcmp(filename,$s1)==0) return 2 // check if file is already active 
    if (attr0) {
        if (!boolean_dialog("Look at file data instead of sim?","YES","NO")) {
            printf("Read file cancelled\n")
            return 0
          }
      } else { attr0=0 }
    if (numarg()>=1) filename=$s1 else tmpfile.getname(filename)
    if (strm(filename,"\.mf$")) return read_mf(filename)
    sprint(s,"GRV[%d] %s: %s",objnum(this),simname,filename)
    clear()
    // grab hold of the different lines using grep
    file_with_dot(filename,temp_string_) // put .filename into temp_string_
    if (!tmpfile.ropen(temp_string_)) {
        print "E1: Can't open ",temp_string_ // avoid grep error
        return 0
      } else flag = 1 // signifies that .file exists to use as key
    while ((numr = tmpfile.gets(tstr)) != -1) {  // throw out the leading '//'
        // read the line
        if (sfunc.head(tstr,"//[^b]",temp_string2_)==0) {
            read_vinfo()  // a line giving info about the file (eg comment)
          } else {   // NB: code in v60:516 to pickup byte_store value
            if (flag && entries > 1) { // a .file with MULTI segs
                tmpfile.seek(-numr,1) // backup to beginning of line
                read_vdotfile()
              } else if (segments > 1) { // mult segs: different times for same var
                tmpfile.seek(-numr,1) // backup to beginning of line
                segments = read_vsegs() //**** NEEDS to be recovered from grvec.hoc442
              } else {  // read each line in for itself
                if (  sscanf(tstr,"//b%1ld %g %s %ld %ld",&bvec,&nvec,tstr2,&sze,&loc)!=5) {
                    if (sscanf(tstr,"//b%1ld %s %ld %ld",&bvec,tstr2,&sze,&loc)!=4) {
                        printf("**** GRV read_vfile() parse ERR on %s in %s",tstr,filename)
                      } else if (printStep==-2) nvec=-2 else nvec=-1 // guess
                  }
                if (nvec==2) {
                    printf("read_vfile forward compat. **** WARNING ****\n\t****consider edit of %s dot file to change 2 to -2\n",filename)
                    nvec=-2
                  }
                if (strcmp(tstr2,"CVODE1.0 tvec")==0) {
                    tvec.resize(0)
                    printStep=-1
                    tloc = loc // where to find tvec later
                  } else {
                    tmpobj = new vfile_line(tstr2,sze,loc,nvec) // name size loc num
                    llist.append(tmpobj)
                    tmpobj = nil
                  }
              }
          }
      }
    if (llist.count==0) {
        printf("grvec.hoc::read_vfile ERR no vecs read from %s\n",filename)}
    if (entries==1) entries = llist.count
    if (! flag && segments>1) write_vsegs()  // create key .file
    if (! tmpfile.ropen(filename)) { print "E3: Can't open ",filename
        return 0
      }
    if (printStep==-1) rtvec() // code for cvode_active()
    mff=0
    return 1
  }

//** rtvec() reads tvec if it exists, returns -1 if it doesn't
func rtvec () {
    if (tloc > -1) {
        tmpfile.seek(tloc)
        tvec.vread(tmpfile)
        return 1
      } else {
        return 0
      }
  }

proc write_vsegs () { print "NEEDS to be ported from grvec.hoc442" }

//** read_vinfo()
proc read_vinfo () {
    if (strm(tstr,"//printStep")) {
        sfunc.tail(tstr," ",tstr) // just take end of string following space
        sscanf(tstr,"%g",&printStep) // printstep==-1 means cvode
      } else if (strm(tstr,"^//:")) { // a comment
        sfunc.tail(tstr,"//: *",tstr)
        sfunc.head(tstr,"\n",comment) // chop final newline
        mesg=comment
      } else if (strm(tstr,"^//CPU")) { // the machine type for byte storage
        sfunc.tail(tstr," ",tstr)
        if (! strm(tstr,uname)) {
            printf("%s written from %s\n",filename,tstr)
          }
      } else if (strm(tstr,"^//MULTI")) { // multiple lines for each entry
        sfunc.tail(tstr," ",tstr)
        if (sscanf(tstr,"%d %d",&entries,&segments)==2) {
            if (! multi_files) printf("**************** GRV read_vinfo ERRa\n") 
          } else segments=1
      } else {
        printf("Line:\t%s\n\tnot recognized in %s\n",tstr,filename)
      }
  }

//** read_vdotfile() read .file in abbreviated format (see write_vsegs)
proc read_vdotfile() { local loc,entries,segments,ii
    entries=entries segments=segments
    for i=1,entries {  // read this abbreviated file version (much faster)
        tmpfile.scanstr(temp_string_)
        loc = tmpfile.scanvar()
        tmpobj = new vfile_line(temp_string_,-1,loc,segments) // don't set size
        llist.append(tmpobj)
        for ii=1,segments-1 { tmpobj.loc[ii] = tmpfile.scanvar() }
      }
  }

//** rpanel() creates a panel from information in llist
proc rpanel () { local ii
    if (llist.count > 8) { rlist() return }
    sprint(temp_string_,"%s ",simname)
    xpanel(temp_string_)
    xlabel(filename)
    for ii=0,llist.count-1 {
        sprint(temp_string2_,"rv(%d)",ii)
        xbutton(llist.object(ii).name,temp_string2_)
      }
    xbutton("Attributes","attrpanl()")
    sprint(temp_string_,"lpvec(filename,vrtmp,%g)",printStep)
    xbutton("Print last vec",temp_string_)
    xbutton("Erase","ge()")
    xpanel()
  }

//** rlist(): like rpanel() but puts up a browser list instead of a panel
proc rlist () {
    sprint(tstr,"%d items on list: Enter regexp for subset or \"All\"",llist.count)
    if (llist.count>50 || numarg()>=1) {
        if (numarg()>=1) regexp=$s1 else if (!string_dialog(tstr,regexp)) return
        if (! strm(regexp,"[Aa][Ll][Ll]")) {
            if (! isobj(tmplist,"List")) tmplist = new List()
            tmplist.remove_all
            for ltr(Xo,llist) {
                Xo.ix=ii1
                if (strm(Xo.name,regexp)) tmplist.append(Xo)
              }
            tmplist.browser(filename,"name")
            tmplist.accept_action("rv(tmplist.object(hoc_ac_).ix)")
            printf("%d selected\n",tmplist.count)
            return
          }
      }
    llist.browser(filename,"name")
    llist.accept_action("rv(hoc_ac_)")
  }

//** rvlist(): like rpanel() but puts up a browser list instead of a panel
proc rvlist () { local flag,rdstr
    rdstr = 1
    flag = $1
    if (numarg()==2) { recstr=$s2  rdstr=0 }
    if (flag==0) {
        llist.browser(filename,"name")
        llist.accept_action("rvec(hoc_ac_)")
      } else if (flag==1) { // proc(vec)
        if (rdstr) string_dialog("Procedure name: proc, called as proc(vec)",recstr)
        llist.browser(recstr,"name")
        sprint(temp_string_,"rv_readvec(hoc_ac_,%s) execute1(\"%s(%s)\")",rvvec_name,recstr,rvvec_name)
        llist.accept_action(temp_string_)
        print ":",recstr,":",temp_string_,":",rvvec_name
      } else if (flag==2) { // vec.command
        if (rdstr) string_dialog("comm: print vec.comm",recstr)
        llist.browser(recstr,"name")
        sprint(temp_string_,"{rvec(hoc_ac_) print %s.%s}",rvvec_name,recstr)
        llist.accept_action(temp_string_)
      }
  }

//* rv() reads line of vector file into IV graph via vector
// rv(llist_ind1[,llist_ind2])
// rvaltdisp(tvec,vec,name)
func rvaltdisp () { return 0 } // if returns 1 means there is an alternate display for rv
obfunc rv () { local inx,inx2 localobj o
    // open the file and go to correct position
    if (numarg() == 0) { print "rv(ind1,ind2) reads into vrtmp bzw vec" return this}
    inx = $1
    if (attr0) {return gv(inx)}
    o=llist.object(inx)
    if (numarg()>1) inx2 = $2 else inx2 = -1 // to graph one vec against another 
    rv_readvec(inx,vrtmp)
    rv2(vrtmp,tvec)
    // create a new plot if necessary and set color
    if (vrtmp.size==0) { // assume this is a spike train in tvec
        nvplt(ind,vrtmp)
        ind.resize(tvec.size) ind.fill(0)
        ind.mark(graphItem,tvec,"O",line,curcol)
      } else if (inx2>-1) { // only make sense if they share the same tvec
        rv_readvec(inx2,vec)
        nvplt(vec,vrtmp)
        if (numarg() >= 3) {
            vec.mark(graphItem,vrtmp,$s3,line,curcol)
          } else {
            vec.mark(graphItem,vrtmp,"O",line,curcol)
          }
      } else if (o.num==-2) {
        nvplt(vrtmp,tvec)
        if (gvmarkflag) {
            if (! rvaltdisp(tvec,vrtmp,llist.object(inx).name)) {
                vrtmp.mark(graphItem,tvec,"O",line,curcol,4) }
          } else vrtmp.line(graphItem,tvec,curcol,line)
      } else if (o.num==-1) {
        printf("rv() PROBLEM: CVODE global read not implemented\n")
      } else {
        if (o.num==0) {
            printf("rv WARNING: taking printstep %g for %s\n",printStep,o.name)
            o.num=printStep
          }
        nvplt(vrtmp,o.num)
        if (gvmarkflag) {
                 vrtmp.mark(graphItem,o.num,"O",line,curcol,4)
          } else vrtmp.line(graphItem,o.num,curcol,line)
      }
    // too much fussing with labels
    if (sfunc.substr(filename,"batch")!=-1 || \
        sfunc.substr(filename,"data")==-1) {
        grvecstr = filename
        } else sfunc.tail(filename,"data",grvecstr)
    if (sfunc.len(llist.object(inx).name)>40) {
        grvecstr=llist.object(inx).name } else {
        sprint(grvecstr,"%s:%s",grvecstr,llist.object(inx).name) }
    rv3(grvecstr)
    if (super == 0 && labelm) { graphItem.label(0,0.9,grvecstr)
      } else if (labelm) graphItem.label(0.0,0.95,grvecstr)
    return graphItem
  }

//* gv(vnum) graphs vector
obfunc gv () {  local a,inx,lin localobj o,v1,vtmp
    inx=-1
    lin=line
    a=allocvecs(vtmp)
    if (numarg()==0) { inx = hoc_ac_ } else { 
        if (argtype(1)==0) inx = $1
        if (argtype(1)==2) {
            for ltr(Xo,printlist) if (strm(Xo.name,$s1)) inx=ii1
            if (inx==-1) {print $s1," not found" return this}}
      }
    if (numarg()>=2) { color=curcol=$2 }
    if (numarg()>=3) { lin=$3 }
    o = printlist.object(inx)
    vtmp.copy(o.vec)
    rv2(o.vec) // alters vtmp
    if (o.vec.size==0) { // assume that this is spk trace
        if (o.tvec.size==0) { printf("\tNO SPIKES IN %s\n",printlist.object(inx).name)
          } else {
            nvplt(o.tvec)
            ind.resize(o.tvec.size) ind.fill(1)
            ind.mark(graphItem,o.tvec,"O",lin,curcol)
          }
      } else { 
        if (o.tvflag!=0) { // o.tvec should point to tvec if tvflag==-1
            nvplt(o.vec,o.tvec)
            if (gvmarkflag) { o.vec.mark(graphItem,o.tvec,"O",lin,curcol)
              } else {          o.vec.line(graphItem,o.tvec,curcol,lin) }
          } else {
            if (o.pstep==0) {
                printf("gv WARNING: vitem.pstep not set with tvflag==0 (%s)\n",o)
                o.pstep=printStep
              }
            nvplt(o.vec,o.pstep)
            if (gvmarkflag) { o.vec.mark(graphItem,o.pstep,"O",lin,curcol)
              } else {          o.vec.line(graphItem,o.pstep,curcol,lin) }
          }
        if (labelm) {
            grvecstr=printlist.object(inx).name
            rv3(grvecstr) graphItem.label(0.,0.9,grvecstr) 
          }
      }
    o.vec.copy(vtmp) // in case has been changed by rv2()
    dealloc(a)
    return graphItem
  }


// go(n) will goto location in the data file
obfunc go () { localobj o
    if (argtype(1)==0) { inx=$1 o=llist.object(inx) } else o=$o1
    tmpfile.seek(o.loc)
    return o
  }

// rv_readvec(index,vec)
// read vector #index from file into vector vec
func rv_readvec () { local inx,ii,n localobj o
    if (argtype(1)==0) { inx=$1 o=llist.object(inx) } else o=$o1
    n=o.num
    if (mff) {tstr=filename filename=o.f}
    tmpfile.getname(temp_string_) // may not be necessary?
    if (strcmp(temp_string_,filename)!=0 || tmpfile.isopen()==0) { // don't reopen file if there
        if (! tmpfile.ropen(filename)) {
            print "ERROR rv() can't read ",filename 
            return 0
          }
      }
    tmpfile.seek(o.loc)
    if (numarg()>=3) { 
        if (n!=-2) {
            printf("ERROR rv() called with 2 vecs but only find 1 in %s %s %d\n",filename,o.name,inx)
            return 0
          }
        $o2.vread(tmpfile) $o3.vread(tmpfile) 
      } else {
        if (n==-2) if (! tvec.vread(tmpfile)) {
            printf("rv_readvec tvec READ failure in %s %s %d\n",filename,o.name,inx)
            return 0
          }
        if (! $o2.vread(tmpfile)) {
            printf("rv_readvec vec READ failure in %s %s %d\n",filename,o.name,inx)
            return 0
          }
        if (n==-2 && (tvec.size != $o2.size)) {
            printf("rv_readvec size mismatch in %s %s %d\n",filename,o.name,inx)
            return 0
          }
      }
    if (segments>1) { // needs rewrite
        tmpvec = new Vector($o2.size)
        for ii=1,segments-1 {
            tmpfile.seek(llist.object(inx).loc[ii])
            tmpvec.vread(tmpfile)
            $o2.copy(tmpvec,$o2.size)
          }
        tmpvec = nil
      }
    if (mff) filename=tstr // restore
    return n
  }

//** vf2fwf() take a file in vformat and prints out as multiple fwrites
proc vf2fwf () { local ii localobj f
    f=new File()
    f.wopen($s1)
    for ii=0,entries-1 {
        rv_readvec(ii,vrtmp)
        vrtmp.fwrite(f)
        printf("%d ",vrtmp.size)
      }
    f.close
    printf("\n dt=%g\n",printStep)
  }

//** rvec(num[,vec]) writes to vec, or contents of rvvec_name or
//  to vector of same name if rvvec_name is empty
proc rvec () { local flag,on
    flag=0
    if (sfunc.len(rvvec_name)==0) flag=1
    if (numarg()<1) on=hoc_ac_ else on=$1
    if (numarg()>1) sprint(rvvec_name,"%s",$o2)
    if (sfunc.len(rvvec_name)==0) rvvec_name=llist.object(on).name 
    printf("Copying %s to %s\n",llist.object(on).name,rvvec_name) 
    sprint(temp_string_,"%s.rv_readvec(%d,%s)",this,on,rvvec_name)
    if (flag) rvvec_name="" // clear it again
    if (! execute1(temp_string_)) print "ERROR: Declare target as a vector"
    if (numarg()==4) $o4.copy(tvec)
  }

//** rvl() reads line of vector file into IV graph via vector
// rvl(name,pos[,pos2,pos3,...])
proc rvl () { local i
    // open the file and go to correct position
    tmpfile.getname(temp_string_)
    if (strcmp(temp_string_,filename)!=0 || tmpfile.isopen()==0) {
        tmpfile.ropen(filename) }  // only open if necessary
    if (tmpfile.isopen==0) { printf("ERROR: %s not found.\n",filename)
          return }
    if (numarg() == 3) { 
        tmpfile.seek($3)
        tmpfile.gets(temp_string_) // throw away line
        vrtmp.vread(tmpfile)
      } else {
        tmpvec = new Vector()
        for i=3,numarg() {
            tmpfile.seek($i)
            tmpvec.vread(tmpfile)
            vrtmp.copy(tmpvec,vrtmp.size)
          } 
      }
    tmpvec = nil
    nvplt(vrtmp)
    vrtmp.line(graphItem,printStep,curcol,line)
    // graph it and label the graph
    if (sfunc.substr(filename,"batch")!=-1) { grvecstr = filename
      } else { sfunc.tail(filename,"data",grvecstr) }
    sprint(grvecstr,"%s:%s",grvecstr,$s2)
    if (super==0 && labelm) { graphItem.label(0,0.9,grvecstr)
      } else if (labelm) graphItem.label(grvecstr)
  }

//* utility programs (not all used or even all usable)
//** nvplt() put up new voltage plot
obfunc nvplt () { local xs,ys,flag,prstep
    prstep=10
    if (super == 0) flag=1 else {
        if (gnum>-1) {
            sprint(tstr,"{Graph[%d]}",gnum)
            if (execute1(tstr,0)) { // Graph[gnum] exists
                if (Graph[gnum].view_count>0) { 
                    graphItem=Graph[gnum] flag=0
                  }               
              } 
          } else if (isobj(graphItem,"Graph")) if (graphItem.view_count() > 0) { 
            flag=0
          } else { flag=1 }                   // else need new graph
      }
    if (flag) {
        if (numarg()==2) if (argtype(2)==0) prstep=$2 else prstep=-1
        if (size[1] != 0) { // xmax is set
            newpl(size[0],size[1],size[2],size[3])
          } else if (prstep<0) {
            newpl(0,$o2.max,$o1.min,$o1.max)
          } else {
            newpl(0,$o1.size()*prstep,$o1.min,$o1.max)
          }
      } else if (gveraseflag) graphItem.erase_all
    if (color == -1) {
        curcol += 1
        if (curcol == 0 || curcol>7) curcol = 1 
      } else curcol = color
    graphItem.color(curcol)
    g=graphItem
    return g
  }

//** grrtsize() use view=plot and then pad a little
proc grrtsize () { local h,w,frac
    if (numarg()>=1) tmpobj=$o1 else tmpobj=graphItem
    if (numarg()>=2) frac = $2 else frac=.05
    tmpobj.exec_menu("View = plot")
    tmpobj.size(&x)
    w=frac*(x[1]-x[0])  h=frac*(x[3]-x[2])
    x[0]-=2*w x[1]+=w x[2]-=4*h x[3]+=h // need extra padding on bottom
    tmpobj.size(x[0],x[1],x[2],x[3])
  }

//** newpl()
proc newpl () { local w,h
    if (numarg()==5) newPlot($1,$2,$3,$4) // 5th arg is flag
    if (numarg()==8) {wvloc[0]=$5 wvloc[1]=$6 wvloc[2]=$7 wvloc[3]=$8}
    graphItem = new Graph(0) 
    g=graphItem
    graphItem.xaxis()	// view axis for x and y
    graphItem.view($1,$3,$2-$1,$4-$3,wvloc[0],wvloc[1],wvloc[2],wvloc[3])
    glist.append(graphItem)
  }

//** find_secname(variable,result): put secname into result
proc find_secname () { localobj o
    if ((sfunc.head($s1,"\.[_A-Za-z0-9]+$",$s2))==0) { // strip off stuff after terminal .
        printf("grvec.hoc:find_secname ERR: no section found: %s\n",$s1) err() }
    if (    strm($s1,"\.[_A-Za-z0-9]+[(][0-9.]+[)]$")) {  // form eg v(0.5)
        sfunc.head($s1,"\.[_A-Za-z0-9]+[(][0-9.]+[)]$",$s2)
      } else {
        o=isit($s2)
        if (o.x) {  // the stem is an obj
          o.o.get_loc() 
          sectionname($s2)
          pop_section()
          } else {
            printf("grvec.hoc:f_s ERR0: Can't find sec: %s\n",$s1) err() 
          }
      }
  }

//** vecpanel() main panel
proc vecpanel () {
    if (! attr0) {printf("vecpanel (main panel) can only be run from attr0\n") return }
    fchooser_flag = 0  // used to initialize the file chooser
    sprint(temp_string_,"%s Vectors",simname)
    xpanel(temp_string_)
    xbutton("Graph from file","newpan()")
    xbutton("Sim vectors","pbrgr(\"Graph\",\"gv\")")
    xbutton("Sim attributes","attrpanl(0)")
    xbutton("Save Sim","pvall()")
    xbutton("Panels","apbrowse()")
    redo_printlist()
    xpanel()
  }

//** lpvec(title,vector,printstep) dumps a single vector onto the printer using jgraph
proc lpvec () { local inx,ii
    tmpfile.wopen("lptmp")
    tmpfile.printf("newgraph\nnewcurve pts\n")
    for ii = 0,$o2.size-1 {
        tmpfile.printf("%g ",ii*$3)
        $o2.printf(tmpfile,"%g",ii,ii)
      }
    tmpfile.printf("marktype none\nlinetype solid\ntitle : %s\n",$s1)
    tmpfile.close()
    system("jgraph -P lptmp > lptmp2")
    system("lpt lptmp2")
  }

//** remgrs() -- clears glist
proc remgrs () { local ii
    for ltr(Xo,glist) Xo.unmap
    if (keepgr!=-1) {
        for (ii=glist.count-1;ii>0;ii-=1) glist.remove(ii) // leave #1
      } else glist.remove_all
  }

//** clear() -- clears llist
proc clear () {
    entries=1 segments=1
    comment = ""
    llist.remove_all()
  }

//** ll() same as external llist
proc ll () { 
    if (numarg()==1) {
        if (attr0==1) { for ltr(XO,printlist) if (strm(XO.name,$s1)) print ii1,XO.name,XO.vec.size
          } else          for ltr(XO,llist) if (strm(XO.name,$s1)) print ii1,XO.name,XO.size
      } else {
        if (attr0==1) { for ltr(XO,printlist) print ii1,XO.name,XO.vec.size
          } else          for ltr(XO,llist) print ii1,XO.name,XO.size
      }
  }

//* read_pclamp(file,vscale,tscale): read physiol data file, similar to read_file()
proc read_pclamp () { local ii,cols,pt,length,pstep,tscale,vscale
    if (! tmpfile.ropen($s1)) { printf("\tERROR: can't open file \"%s\"\n",$s1) }
    if (numarg()>=2) vscale=$2 else vscale=1
    if (numarg()>=3) tscale=$3 else tscale=1e3
    printlist.remove_all()
    method("implicit") printStep=0.1
    tmpfile.gets(temp_string_)  
    length=1
    while (! strm(temp_string_,"^\"Time")) {
        length += 1
        tmpfile.gets(temp_string_)  // first word in line was not a number so next line
      }
    temp_string2_ = temp_string_ // column def line
    cols = count_substr(temp_string_,"[(]") // destructive function
    pt = tmpfile.tell()
    length = file_len($s1) - length
    vrtmp.scanf(tmpfile,length,1,cols) // tvec
    pstep=vrtmp.x[1]-vrtmp.x[0]
    pstep*=tscale // typically gives it in s statt ms
    print "Reading ", cols, " columns; ", length, " lines; tstep=",pstep
    for ii=2,cols { // pick up all of the columns
        tmpfile.seek(pt)
        vrtmp.scanf(tmpfile,length,ii,cols)
        vrtmp.mul(vscale) // correct for a common scaling
        npl("col",ii,vrtmp,pstep)
      }
    if (1) {
        sprint(temp_string2_,"%s:%s",$s1,temp_string2_)
        file_with_dot($s1,filename,"v") // put vfilename into name
        print "Saving to ",filename
        pvplist(filename,temp_string2_)
      }
  }

//* read_file(file,cols[,length]): read multicolumn file
//  see also read_pclamp() above
func read_file () { local ii,cols,pt,length
    if (numarg()==0) { print "\tread_file(\"file\",cols)"
        print "\t(must set tstop and printStep.)"
        return 0
      }
    printStep=10
    if (cvode_status()!=0) print "WARNING: Turn off cvode."
    if (numarg()==3) { length = $3 } else { length=tstop/printStep }
    cols = $2
    if (! tmpfile.ropen($s1)) { printf("\tERROR: can't open file \"%s\"\n",$s1) return 0}
    //  printlist.remove_all()
    tmpfile.scanstr(temp_string_)  pt = 0
    // skip over a comment line; note that this will skip extra line if comment line is
    // just one word long
    while (sfunc.head(temp_string_,"[^-+0-9.e]",temp_string2_) != -1) {
        tmpfile.gets(temp_string_)  // first word in line was not a number so next line
        pt = tmpfile.tell()         // location at next line
        tmpfile.scanstr(temp_string_) // get first word here
        print temp_string2_
      }
    for ii=1,cols { // pick up all of the columns
        tmpfile.seek(pt)
        vrtmp.scanf(tmpfile,length,ii,cols)
        npl("col",ii,vrtmp)
      }
    return 1
  }

//* read_rfile(file): read multirow file
//  use col2row to transpose columnar file first
proc read_rfile() { local num
    if (numarg()==0) { print "\tread_rfile(\"file\")" return }
    if (! tmpfile.ropen($s1)) { printf("\tERROR: can't open file \"%s\"\n",$s1) return}
    printlist.remove_all()
    while (tmpfile.scanstr(temp_string_) != -1) {  // read lines
        num = tmpfile.scanvar() // pick up number of items in col
        vrtmp.scanf(tmpfile,num)
        npl(temp_string_,vrtmp)
      }
  }

//* redo_printlist() menu allows removal or addition of inidividual items
proc redo_printlist () {
    xmenu("Printlist")
    xbutton("Save Sim","pvall()")
    xbutton("Add var to printlist","redolist(0)")
    xbutton("Clear printlist","printlist.remove_all()")
    xbutton("Remove item from printlist","redolist(1)")
    xbutton("Vector.op","redolist(2)")
    xbutton("Proc(vector)","redolist(6)")
    xbutton("Link XO->vec,YO->tvec","redolist(7)")
    xbutton("Graph vector","redolist(4)")
    xbutton("Save printlist","redolist(5)")
    xbutton("Archive to file:","pbrgr(\"Archive\",\"pv\")")
    xbutton("Add all obj's of this type to printlist","redolist(3)")
    xmenu()
  }

//* redolist() set of functions for altering the printlist called by redo_printlist()
proc redolist () { local ii,flag
    if (! isobj(printlist,"List")) printlist = new List()
    flag = $1  rdstr = 1
    if (numarg()==2) { recstr=$s2  rdstr=0 }
    if (flag==0) {
        if (! isobj(scob,"SymChooser")) scob = new SymChooser()
        if (scob.run()) {
            scob.text(temp_string_)
            npl(temp_string_)
          }
      } else if (flag==1) { // remove item
        printlist.browser("Double click on item to remove","name")
        printlist.accept_action("printlist.remove(hoc_ac_)")
      } else if (flag==2) { // .op
        if (rdstr) string_dialog("Enter operation to be run on vec",recstr)
        temp_string_ = "\"%s.%s = %g\\n\""
        sprint(temp_string_,"printf(%s,printlist.object(hoc_ac_).name,\"%s\",x=printlist.object(hoc_ac_).vec.%s)",temp_string_,recstr,recstr)
        printlist.browser(recstr,"name")
        printlist.accept_action(temp_string_)
      } else if (flag==3) { // put another set of things on list
        if (! isobj(scob,"SymChooser")) scob = new SymChooser()
        if (rdstr) string_dialog("String to be used as suffix for all items on list",recstr)
        scob.run()
        scob.text(temp_string_)
        tmplist = new List(temp_string_)
        record(tmplist,recstr)
      } else if (flag==4) { // show it
        pbrgr("Graph","gv")
      } else if (flag==5) {
        fchooser_flag = 0
        tmpfile.chooser("a","Add printlist to file")
        if (tmpfile.chooser()==1) {
            tmpfile.printf("\nproc make_printlist() { \n")
              tmpfile.printf("  printlist.remove_all()\n")
              for ii=0,printlist.count-1 {
                  tmpfile.printf("  npl(\"%s\")\n",printlist.object(ii).name)
                }
              tmpfile.printf("}\nmake_printlist()\n")
            tmpfile.close()
          }
      } else if (flag==6) { // proc(vec)
        if (rdstr) string_dialog("Enter procedure name \"proc\",called as proc(vec,var,num)",recstr)
        printlist.browser(recstr,"name")
        sprint(temp_string_,"%s(printlist.object(hoc_ac_).vec,printlist.object(hoc_ac_).name,hoc_ac_)",recstr)
        printlist.accept_action(temp_string_)
      } else if (flag==7) { // XO is pointer to vec
        printlist.browser("XO","name")
        sprint(temp_string_,"{tmpobj=printlist.object(hoc_ac_) print hoc_ac_,tmpobj.name XO=tmpobj.vec YO=tmpobj.tvec}")
        printlist.accept_action(temp_string_)
      } 
  }

//** mkmenu(title,action,proc) makes a menu from printlist
proc mkmenu () { local ii
    xmenu($s1)
    for ii=0,printlist.count-1 {
        sprint(temp_string_,"%s %s",$s2,printlist.object(ii).name)
        sprint(temp_string2_,"%s(%d)",$s3,ii)
        xbutton(temp_string_,temp_string2_)
      }
    sprint(temp_string_,"mkpanel(\"%s\",\"%s\",\"%s\")",$s1,$s2,$s3)
    xbutton("Leave up",temp_string_)
    xmenu()
  }

//** pbrgr(browser name,action) is used to put up a browser
// note action given without '()'
proc pbrgr () {
    if (printlist.count == 1) {
        gv(0)
      } else if (printlist.count <= 8) {
        mkpanel("Vector",$s1,$s2)
      } else {
        sprint(temp_string_,"%s:%s",simname,$s1)
        printlist.browser(temp_string_,"name")
        sprint(temp_string2_,"%s()",$s2)
        printlist.accept_action(temp_string2_)
      }
  }

//** mkpanel(title,action,proc) makes a panel from printlist
proc mkpanel () { local ii
    sprint(temp_string_,"%s:%s",simname,$s1)
    xpanel(temp_string_)
    for ii=0,printlist.count-1 {
        sprint(temp_string_,"%s %s",$s2,printlist.object(ii).name)
        sprint(temp_string2_,"%s(%d)",$s3,ii)
        xbutton(temp_string_,temp_string2_)
      }
    xpanel()
  }

//** remprl() -- remove printlist item by name
proc remprl () { local flag
    flag=0
    if (numarg()==2) flag=1 else print "LISTING ONLY; rerun with 2 args to remove"
    for (ii=printlist.count-1;ii>=0;ii-=1) {
        Xo=printlist.object(ii)
        if (strm(Xo.name,$s1)) if (flag) printlist.remove(ii) else print Xo.name
      }
  }

// for ltr(XO,glist) { print XO,XO.view_count }

//** wvpanl() 
proc wvpanl () { local  ii
    sfunc.tail(filename,"data.*/",grvecstr)
    sprint(temp_string_,"%s:%s (WVPANL)",simname,grvecstr)
    xpanel(temp_string_)
    sprint(temp_string_,"%d Vectors",llist.count)
    xlabel(temp_string_)
    for ii=0,3 {
         sprint(temp_string_,"size[%d]",ii)
         sprint(temp_string2_,"chrange(%d)",ii)
         xvalue(szstr[ii].s,temp_string_,0,temp_string2_,0,1)
      }
    xvalue("Shift L/R","shift",0,"chrange(-2)",0,1)
    xmenu("Other")
    xbutton("Clear/Set to G0","chrange(-1)")
    xbutton("View=plot","viewplot()")
    xbutton("0,tstop,-90,50","setrange(0,tstop,-90,50)")
    // xbutton("Clean graph list","collapsegrs()")
    xbutton("Attributes","attrpanl()")
    xmenu()
    xpanel()
    if (glist.count>0) for ii=0,3 if (size[ii]==0) size[ii]=glist.object(0).size(ii+1)
  }

//** chrange() changes range for a set of graphs (called from attrpanl)
proc chrange () { local cnt, flag, ii, sz1, sz2, sz3, sz4
    if (numarg()==1) { flag = $1 } else { flag = -1 }
    cnt = glist.count()
    for (ii=cnt-1;ii>=0;ii=ii-1) if (glist.object(ii).view_count() == 0) glist.remove(ii)
    cnt = glist.count() // check again after removing any with no views
    if (cnt==0) { for ii=0,3 size[ii]=0 return }
    // flag -1 means set everything from the first graph
    if (flag==-1) for ii=0,3 size[ii] = glist.object(0).size(ii+1)
    if (flag==-2) for ii=0+luprd,1+luprd size[ii] += shift // shift right or left
    if (flag==5) { size[0]=0 size[1]=tstop } // just set x
    // for each of the graphs
    for ltr(Xo,glist) {
        sz1=Xo.size(1) sz2=Xo.size(2) sz3=Xo.size(3) sz4=Xo.size(4)
        if (flag==0) Xo.size(size[0],sz2,sz3,sz4)
        if (flag==1) Xo.size(sz1,size[1],sz3,sz4)
        if (flag==2) Xo.size(sz1,sz2,size[2],sz4)
        if (flag==3) Xo.size(sz1,sz2,sz3,size[3])
        if (flag==-1 || flag==4) Xo.size(size[0],size[1],size[2],size[3])
        if ((flag==-2 && !luprd) || flag==5) Xo.size(size[0],size[1],sz3,sz4)
        if (flag==-2 && luprd) Xo.size(sz1,sz2,size[2],size[3])
      }
    for ii=0,3 if (size[ii]==0) size[ii]=glist.object(0).size(ii+1)
  }

//** grall() graphs all of the lines from the file
// use vector $o2 as indices for vectors (see tposvec)
proc grall () { local cnt,ii,min,max,gr,skip,iskp,vind,sind,a
    if (numarg()==0) {printf("grall(min,max,gr_offset,skipgr,iskp]): graph vectors.\n") return }
    sind=vind=0
    cnt = llist.count()
    min=0 max=cnt-1
    // will reset max if is vector with numarg()==2
    // with 2 args, vector $o2 gives indices for vectors (see tposvec)
    if (numarg()>=1) {
        if (argtype(1)==0) { min=$1
          } else { // a vector of indices or a string for prdr/vrdr
            a=allocvecs(1)
            if (argtype(1)==1) { vind=1 mso[a].copy($o1) } else sind=1
          }
      }
    if (numarg()>1) { max=$2 if (max<0) max+=llist.count }
    if (numarg()>2) gr=$3 else gr=0
    if (numarg()>3) skip=$4 else skip=1
    if (numarg()>4) iskp=$5 else iskp=1
    if (iskp==0) iskp=1
    if (super==1 && glist.count==0) { 
        remgrs()
        print "Creating plot"
        skip=0
        newPlot(0,tstop,-100,100) glist.append(graphItem)}
    if (super==0 && glist.count==0) size[1]=0
    if (sind) { 
        // for vrdr(aa,$s2,1,1) aa.x(0).append(ii1)
        vind=1
      }
    if (vind) { min=0 max=mso[a].size-1 }
    for (ii=min;ii<=max;ii+=iskp) {
        if (super == 1) { 
            if (gr >= glist.count()) break
            graphItem = glist.object(gr) 
            gr=gr+skip
          }
        if (vind) rv(mso[a].x[ii]) else rv(ii)
      }
    if (vind) dealloc(a)
  }

// go through tmplist selected in rlist and graph onto glist
proc grsel () { localobj o
    for ii=0,tmplist.count-1 {
        rv_readvec((o=tmplist.o(ii)),vrtmp)
        if (ii<glist.count) graphItem=glist.o(ii) else {
            printf("GRV grsel() glist exhausted\n")
            return }
        if (o.num==-2) { // guess should do mark
            vrtmp.mark(graphItem,tvec,"O",line+2,curcol,4)
          } else vrtmp.line(graphItem,o.num,curcol,line)
      }
  }    

// tposvec(rows,cols): generate the indices for a transposed matrix of rows x cols
proc tposvec () { local rows,cols,i,j
    rows=$2 cols=$3
    $o1.resize($2*$3)
    for (i=0;i<rows;i+=1) for (j=0;j<cols;j+=1) $o1.x[j*rows+i]=i*cols+j
  }

// fliptb(rows,cols): generate the indices for a transposed matrix of rows x cols
proc fliptb () { local rows,cols,i,j,p
    rows=$2 cols=$3
    if ($o1.size != $2*$3) {print "Wrong size vector in fliptb()" return}
    p = allocvecs(1) mso[p].resize(rows)
    for (j=0;j<cols;j+=1) {
        mso[p].copy($o1,j*rows,(j+1)*rows-1)
        mso[p].reverse
        $o1.copy(mso[p],j*rows)
      }
  }

//** setrange() sets the range
// setrange(x0,x1,y0,y1)
proc setrange () { local i,ii
    if (numarg()==0){print "setrange(x0,x1,y0,y1)\n setrange(3) erases axes"}
    if (numarg()==0) { for ltr(Xo,glist) Xo.size(0,tstop,-100,50)
      } else if (numarg()==1) { for ltr(Xo,glist) Xo.xaxis($1)
      } else if (numarg()==2) { for ltr(Xo,glist) Xo.size(0,tstop,$1,$2)
      } else {
        size[0]=$1
        for ltr(Xo,glist) Xo.size($1,$2,$3,$4)
        for i=1,4 size[i-1]=$i
      }
    for ii=0,3 if (size[ii]==0) size[ii]=glist.object(0).size(ii+1)
  }

//* gxpan()
proc gxpan () { local x localobj xo,yo,g1
    gcomms.remove_all
    gcomms.append(new String2("Move","mvga"))
    gcomms.append(new String2("Mag","magga"))
    for ltr(xo,gcomms) for ltr(yo,glist) {
        yo.menu_remove(xo.s)
        yo.menu_tool(xo.s,xo.t)
      }
    gcomms.append(new String2("Crosshair",""))
    xpanel("Manipulate graphs",1)
    x=-1
    for ltr(xo,gcomms) {sprint(tstr,"mvgaset(%d)",x+=1) xradiobutton(xo.s,tstr)}
    xpanel()
  }  

proc mvgaset () { localobj yo
    print $1,gcomms.o($1).s
    for ltr(yo,glist) yo.exec_menu(gcomms.o($1).s) 
  }

proc mvga () { local type,x,y,keystate,sz1,sz2,sz3,sz4 localobj xo,yo
    type=$1 x=$2 y=$3 keystate=$4 // 2 for press, 1 for dragging, and 3 for release
    xo=glist.o(0)
    sz1=xo.size(1) sz2=xo.size(2) sz3=xo.size(3) sz4=xo.size(4)
    if (type == 2) {
        begx=x begy=y
      } else if (type==3) {
        x-=begx y-=begy
        size[0]=sz1-x size[1]=sz2-x size[2]=sz3-y size[3]=sz4-y
        for ltr(xo,glist) xo.size(sz1-x,sz2-x,sz3-y,sz4-y)
      }
  }

proc magga () { local tmp,type,x,y,begx,begy,keystate,sz1,sz2,sz3,sz4 localobj xo,yo
    type=$1 x=$2 y=$3 keystate=$4 // 2 for press, 1 for dragging, and 3 for release
    xo=glist.o(0)
    sz1=xo.size(1) sz2=xo.size(2) sz3=xo.size(3) sz4=xo.size(4)
    if (type == 2) {
        begx=x begy=y
      } else if (type==3) {
        if (x<begx) { tmp=x x=begx begx=tmp }
        if (y<begy) { tmp=y y=begy begy=tmp }
        size[0]=begx size[1]=x size[2]=begy size[3]=y
        for ltr(xo,glist) xo.size(size[0],size[1],size[2],size[3])
      }
  }

//* grransel() -- graph range select
proc setgrransel () {
    for ltr(Xo,glist) { 
        Xo.menu_remove("REVIEW")
        sprint(tstr,"proc p%d(){grransel($1,$2,$3,$4,%d,%s)}",ii1,ii1,Xo)
        execute1(tstr)
        sprint(tstr,"p%d",ii1)
        Xo.menu_tool("REVIEW", tstr)
        Xo.exec_menu("REVIEW")
      }
  }
  
//** grransel(): CTL-hit == Crosshair
//               SHT-hit == resize
//               hit-drag-release == show in square
//               SHT-hit-drag-release == show new thing there
// Type: press (2), drag (1), release (3)
// Keystate: META-SHT-CTL eg 101=5 is META-CTL
grrcnt=-1
// not debugged
proc grransel () { local type, x0, y0, keystate, ii, gr
    type=$1 x0=$2 y0=$3 keystate=$4 gr=$5
    graphItem=$o7 // = glist.object(gr)
    if (keystate==1 && type==2) { graphItem.exec_menu("Crosshair") // CTL-MOUSE-1
      } else if (keystate==3 && type==3) { 
        print grrcnt
        if (grrcnt>-1) { printf("Graphing %s\n",printlist.object(grrcnt).name)
            graphItem.erase_all()
            rv(grrcnt) 
            graphItem.exec_menu("View = plot")
          }
        graphItem.size(size[0],size[1],size[2],size[3])
      } else if (keystate==2 && type==2) { grrcnt=-1
      } else if (keystate==2 && type==1) { 
        x+=1 // slow it down five-fold
        if (x>5) { grrcnt=(grrcnt+1)%printlist.count
            printf("%d: %s\n",grrcnt,printlist.object(grrcnt).name)
            x=0
          }
      } else if (keystate==0 && type==2) { x=x0 y=y0 } else if (keystate==0 && type==3) {
        graphItem.size(x,x0,y,y0) // resize to chosen square
      } 
  }

//** remgrs() gets rid of all of the graphs (called from attrpanl)
proc remgrs () { local ii,cnt
    if (isobj(graphItem,"Graph")) { graphItem.unmap graphItem = nil }
    for ltr (Xo,glist) Xo.unmap()
    glist.remove_all
  }

//** collapsegrs () take off of glist graphs that have been closed on screen
proc collapsegrs () { local ii
    for (ii=glist.count-1;ii>=0;ii-=1) {
        if (glist.object(ii).view_count() == 0) { 
            glist.remove(ii)
          }
      }
  }

//** viewplot() set the world for each graph correctly
proc viewplot () { local cnt,ii,flag,sz1,sz2,sz3,sz4
    if (numarg()==1) flag=$1 else flag=-1
    if (flag==0) { sz1=sz3=1e10 sz2=sz4=-1e10 }
    for ltr(Xo,glist) {
        Xo.size(&x[0])
        if (flag==0) { 
            if (x[0]<sz1) sz1=x[0]
            if (x[1]>sz2) sz2=x[1]
            if (x[2]<sz3) sz3=x[2]
            if (x[3]>sz4) sz4=x[3]
          } else if (flag==9) {
            Xo.size(0,tstop,x[2],x[3])
          } else { Xo.size(x[0],x[1],x[2],x[3]) }
      }
    if (flag==9) { size[0]=0 size[1]=tstop }
    if (flag==0) for ltr(Xo,glist) Xo.size(sz1,sz2,sz3,sz4)
  }

//** nvwall() changes the size of the graphs
proc nvwall () { local cnt,ii,sz1,sz2,sz3,sz4,wd,ht
    if (numarg()==2) { wd=$1 ht=$2 } else { wd=vsz[0] ht=vsz[1] }
    cnt = glist.count()
    for (ii=cnt-1;ii>=0;ii=ii-1) { 
        if (glist.object(ii).view_count()==0) {glist.remove(ii)
          } else {
            sz1 = glist.object(ii).size(1)
            sz2 = glist.object(ii).size(2)
            sz3 = glist.object(ii).size(3)
            sz4 = glist.object(ii).size(4)
            glist.object(ii).unmap()
            vloc = vloc+vjmp
            if (vloc > 700) { vloc = 0 }
            glist.object(ii).view(sz1,sz3,sz2-sz1,sz4-sz3,0,vloc,wd,ht)
          }
      }
  }

//** geall() erases all of the graphs
proc geall () { local cnt,ii
    cnt = glist.count()
    for ii=0,cnt-1 { 
        glist.object(ii).erase_all()
      }
  }

//** lblall(label,#,xloc,yloc) put label on all of the graphs
// arg3 tells which single graph to put it on
proc lblall () { local cnt,ii,min,max,lx,ly
    if (numarg()==0) { printf("lblall([,loc])\n")  return }
    cnt = glist.count()
    if (numarg()>1) { min=max=$2 } else { min=0 max=cnt-1 }
    if (numarg()==5) { lx=$3 ly=$4 } else { lx=0.1 ly=0.8 }
    if (numarg()>1) { if (sfunc.len($s1)>0) { temp_string_ = $s1
        }}
    for ii=min,max { 
        glist.object(ii).color(color)
        glist.object(ii).label(lx,ly,temp_string_)
      }
  }

//** relbl() put appropriate label on all of the graphs
proc relbl () { local cnt,ii,min,max,lx,ly
    if (numarg()==0) { printf("relbl([str])\n")  return }
    cnt = glist.count()
    if (numarg()==4) { lx=$3 ly=$4 } else { lx=0.1 ly=0.8 }
    if (numarg()>1) glist.object(0).label($s2)
    for ii=0,glist.count-1 {
        Xo=glist.object(0) Yo=llist.object(0)
        Xo.color(0)
        Xo.label(0.,.9,Yo.name) 
        Xo.color(color)
        Xo.label(lx,ly,Yo.vec.label)
      }
  }

//** toggle functions
proc tog (){if (numarg()==0) print super=1-super else print $&1=1-$&1}
proc togmark () {
    if (gvmarkflag==0) { gvmarkflag=1 if (line<4) line+=1
      } else {             gvmarkflag=0 if (line>6) line-=1
      }
    sprint(tstr,"gvmarkflag=%d",gvmarkflag) // set external gvmarkflag as well
    execute(tstr)
    sprint(mesg,"mark=%d",gvmarkflag)
  }

//* panobjl stuff
proc apbrowse () {
    panobjl.browser("attrpanls","s")
    panobjl.accept_action("panobjl.object(hoc_ac_).attrpanl()")
  }

//** po(NUM) set global panobj to that number
proc po () { 
    sprint(tstr,"panobj=GRV[%d]",$1)
    execute(tstr)
  }

proc apkill () {
    panobjl.browser("attrpanls","s")
    panobjl.accept_action("panobjl.remove(hoc_ac_)")
  }

//* printlist stuff

//** record(list,what,vecptr) from items in $o1 object(ii).$s2 in vectors
// $o1 is the list arg $s2 is the thing to be recorded [eg soma.v(0.5)]
// optional $3 is the name of an object belonging to list items that will
// serve as a pointer to the recording vector
proc record () { local ii, dur, na3
    if (isobj($o1,"List")) for ltr(Xo,$o1) {
        sprint(recstr,"%s.%s",Xo,$s2)
        npl(recstr) 
        if (numarg()==3) { 
            sprint(temp_string_,"%s.%s=printlist.object(printlist.count-1).vec",Xo,$s3)
            execute(temp_string_) // only way to get call by ref for object
          }
      } else forsec $o1 { // assume sectionlist
        sprint(recstr,"%s.%s",secname(),$s2)
        npl(recstr) 
        if (numarg()==3) { 
            sprint(temp_string_,"%s.%s=printlist.object(printlist.count-1).vec",Xo,$s3)
            execute(temp_string_) // only way to get call by ref for object
          }
      } 
  }

//** npl(name) adds this item to the printlist
//  npl(name,vec) adds this vec to the printlist
//  npl(name,vec,tvec) adds this vec to the printlist
//  npl(var,name) use name instead of variable name
//  npl(var,ptr) provide an objref to point to the vec
//  npl(name,num,vec)??adds this vec to the printlist under name_num0,name_num1,...
proc npl () { local dur,nflag,tvflag,prstep  // METHOD DEPENDENT
    if (! isobj(printlist,"List")) printlist = new List()
    tvflag=nflag=0  prstep=0.05
    if (cvode_status()==0.0) {
        sprint(tstr,"%s.printStep=printStep",this)
        execute(tstr)
        prstep=printStep
      } else if (cvode_status()==1.1) {
        tvflag=1
      } else if (cvode_status()==1.0) { // ??
      }
    if (outvecint == 0) dur = tstop else dur = outvecint
    grvecstr = $s1
    repl_mstr(grvecstr," ","",temp_string2_) // no longer splits on '/'
    // eg npl(name,ii,vec)
    if (numarg()>=4) if ($4<=0) tvflag=1 else { tvflag=0 prstep=$4 }
    if (numarg()>=3) { // allows formation of tags on the fly
        if (argtype(3)==0) { 
            if ($3<=0) tvflag=1 else { tvflag=0 prstep=$3 }
          } else if (argtype(2)==0) {
            sprint(temp_string_,"%s%s",grvecstr,":%d")
            sprint(temp_string_,temp_string_,$2)
            vite = new vitem(temp_string_,$o3.size)
            vite.vec.copy($o3)
            if (numarg()==4) if (argtype(4)==1) {
                vite.tvec.copy($o4) vite.tvflag=1 vite.pstep=0
              } else if (argtype(4)==0) { vite.pstep=$4
              } else printf("Arg 4 unrecognized in npl?\n")
            printlist.append(vite)
            return
          } else if (argtype(2)==1) { 
            vite = new vitem(grvecstr,$o2.size,1)
            vite.vec.copy($o2) vite.tvec.copy($o3)
            printlist.append(vite)
            return
          }
      } 
    if (numarg()>=2) { // second arg is a vector to store
        if (argtype(2)==1) {
            vite = new vitem(grvecstr,$o2.size)
            vite.tvflag=tvflag vite.pstep=prstep
            vite.vec.copy($o2)
            printlist.append(vite)
            return
          } else if (argtype(2)==2) {  // give explicit name for the thing to store
            nflag=1
          }
      }
    if (cvode_status()==1.0) { 
        if (tvec.buffer_size==0){tvec.resize(dur/prstep+10) tvec.resize(0)}
        tvec.record(&t) 
      } else if (isobj(tvec,"Vector")) if (tvec.size!=0) { 
        tvec.resize(0) tvec.play_remove()          
      }
    if (nflag) { 
        if (tvflag) { vite = new vitem($s2,dur/prstep+10,1) } else {
                        vite = new vitem($s2,dur/prstep+10,prstep)   }
      } else {
        if (tvflag) { vite = new vitem(grvecstr,dur/prstep+10,1) } else {
                        vite = new vitem(grvecstr,dur/prstep+10,prstep) }
      }
    if (numarg()==2) if (argtype(2)==1) $o2=vite.vec // allow user to assign a pointer
    printlist.append(vite)
    if (tvflag) {
        vite.vec.resize(dur/prstep+10) vite.tvec.resize(dur/prstep+10)
        find_secname(grvecstr,temp_string_) // with lvardt, need to assign in proper context
        sprint(temp_string_,"%s {cvode.record(&%s,%s.vite.vec,%s.vite.tvec)}",temp_string_,grvecstr,this,this)
      } else if (cvode_status()==1.0) { // don't give an explicit prstep
        vite.vec.resize(dur/prstep+10)
        sprint(temp_string_,"%s.vite.vec.record(&%s)",this,grvecstr)
      } else {
        sprint(temp_string_,"%s.vite.vec.record(&%s,%g)",this,grvecstr,prstep)
      }
    if (! execute1(temp_string_)) print "Unable to excute ",temp_string_
    vite=nil
  }

//** store cvode state in a double in form active.local
func cvode_status () { return cvode.active() + cvode.use_local_dt()/10 }

proc ulv () {  }

//** pvall() dumps all vectors to output_file
// Save logic:
// 1) Interactive mode: you're watching simulations while printing out
// data.  You see something you like and save it - the runnum in the
// index file then corrsponds to the number on the data file, it is
// subsequently augmented
// 2) Batch mode: you're running very long sims and saving directly to
// vector files.  You put together a simulation you want and save it
// immediately rather than waiting for the sim to return (in 1 or 2
// days).  To correspond, the data file (v*) must then be numbered
// 'runnum-dec_runnum'
proc pvall () { 
    if (numarg()>=1) { 
        comment = $s1 // a comment
      } else if (sfunc.len(comment)==0) {
        sprint(tstr,"%s.comment=comment",this) execute(tstr)
        sprint(tstr,"Use: %s ?",comment)
        if (!boolean_dialog(tstr)) return
      }
    if (numarg()>=2) output_file=$s2 else {
        sprint(output_file,"%sv%s.%02d",ddir,datestr,runnum-dec_runnum)
        while (tmpfile.ropen(output_file)) { runnum = runnum+1
            printf("%s found, trying %sv%s.%02d\n",output_file,ddir,datestr,runnum-dec_runnum)
            sprint(output_file,"%sv%s.%02d",ddir,datestr,runnum-dec_runnum) 
          }
      }
    printf("Saving to %s\n",output_file)
    pvplist(output_file,comment)
    sprint(output_file,"%sv%s.%02d",ddir,datestr,runnum)
    comment=""
  }

//** pvplist(file,comment) print out the printlist with comment at head
proc pvother () {}  // user can dump other vectors at top with prvec()
proc pvplist () { local inx
    output_file=$s1
    if (! pvplist0()) return // open file(s)
    pvplist1($s2) // print string header
    pvout() 
    if (numarg()<3) { // else leave for appending
        tmpfile.close()
        tf1.close()
      }
  }

//** pvclose() -- close files used for writing
proc pvclose () {
    tmpfile.close()
    tf1.close()
  }

//** pvplist0() -- open output_file and ancillary dot file if needed
func pvplist0 () { localobj st
    st=new String2()
    file_with_dot(output_file,st.s) // put .filename into st.s
    if (numarg()==0) {
        if (tmpfile.ropen(st.s)) { printf("WARNING: removing %s\n",st.s)
            sprint(st.t,"rm %s",st.s) system(st.t) }
        if (tmpfile.wopen(st.s)==0) { print "Can't open ",st.s  return 0}
        if (! isojt(tf1,tmpfile)) tf1=new File()
        tf1.wopen(output_file)
      } else {
        if (tmpfile.aopen(st.s)==0) { print "Can't open ",st.s," to append" return 0}
        if (! isojt(tf1,tmpfile)) tf1=new File()
        tf1.aopen(output_file)
      }
    return 1
  }

//** prplist1()
proc pvplist1 () {
    tmpfile.printf("//: %s\n",$s1) // comment
    if (cvode_status()==1.1) {
        tmpfile.printf("//printStep -2\n")
      } else if (cvode_status()==1.0) {
        tmpfile.printf("//printStep -1\n")
      } else {
        sprint(tstr,"%s.printStep=printStep",this)
        execute(tstr)
        tmpfile.printf("//printStep %g\n",printStep)
      }
    if (byte_store) tmpfile.printf("//CPU %s\n",uname)
  }

//** pvnext() append another printlist set to same file
proc pvnext () { local ii
    if ($1==0) { 
        pvplist(output_file,comment,1)
        return
      }
    pvplist0(0) // open for appending
    pvout()
    printf("Append to %s\n",output_file)
    tmpfile.close()
    tf1.close
  }

//** pvout() called by pvplist() and pvnext(), actually puts out the vecs
proc pvout () {  // METHOD DEPENDENT
    pvout2()
    if (cvode_status()==1.0 && tvec.max>0) { 
        tmpfile.printf("//b%d 1 %s %d %d\n",tvec_bytesize,"CVODE1.0 tvec",tvec.size,tf1.tell)
        tvec.vwrite(tf1,tvec_bytesize) 
      }
    for ltr(Xo,printlist) { // no whitespace allowed
        if (Xo.code==2) continue
        if (sfunc.len(Xo.vec.label)>0) sprint(temp_string_,"%s__(%s)",Xo.vec.label,Xo.name) else {
            temp_string_=Xo.name } 
        pvpone(Xo)
      }
  }

//** dir2pr(item#[,OUTFILE,OUTCOMMENT]) read the files in dir and add one item to printlist
// see also collect.hoc for batch use
proc dir2pr () { local ix,ps
    secname() // a section must exist
    printlist.remove_all 
    ix=$1
    for ltr(Xo,dir) {
        read_vfile(Xo.s)
        rv_readvec(ix,vrtmp)
        ps=llist.o(ix).num // pstep: need if want to save a fixed step entry
        grv_.npl(comment,vrtmp,tvec)
      }
    if (numarg()==3) { grv_.pvplist($s2,$s3) read_vfile($s2) }
  }

//** dir2mf(FILENAME,COMMENT) read the files in dir and create a master file
proc dir2mf () { local ix,ps,n localobj f
    secname() // a section must exist
    f=new File()
    f.wopen($s1)
    f.printf("//: %s\n",$s2)
    for ltr(Xo,dir) {
        read_vfile(Xo.s)
        n=-1
        for ltr(Yo,llist) if (dir2mf2(n+=1)) {
            // repl_mstr(comment," ",";",temp_string2_) // no spaces allowed
            // sprint(temp_string_,"%s_%s",Yo.name,comment)
            f.printf("//b%d %g %s %d %d %s\n",bvec,Yo.num,Yo.name,Yo.size,Yo.loc,filename)
          }
      }
    f.close()
  }

//** read_mf() reads a master file
// assumes file in tmpfile
func read_mf () { local ii,sz,loc,mult,sze,cloc,segs localobj o
    if (attr0) {
        if (!boolean_dialog("Look at file data instead of sim?","YES","NO")) {
            printf("Read file cancelled\n")
            return 0
          }
      } else { attr0=0 }
    if (numarg()==1) filename=$s1 else tmpfile.getname(filename)
    sprint(s,"GRV[%d] %s: %s",objnum(this),simname,filename)
    clear()
    if (!tmpfile.ropen(filename)) { print "E1: Can't open ",filename return 0 }
    while ((numr = tmpfile.gets(tstr)) != -1 && (sfunc.head(tstr,"//[^b]",temp_string2_)==0)) {
        read_vinfo()  // a line giving info about the file (eg comment)
      }
    tmpfile.seek(-numr,1) // back up
    ii=0
    while ((numr = tmpfile.gets(tstr)) != -1) {
        if (((ii+=1)%10000)==0) printf("%d ",ii)
        if (sscanf(tstr,"//b%1ld %g %s %ld %ld %s",&bvec,&nvec,tstr2,&sze,&loc,tstr)!=6) {
            printf("**** GRV read_mf() parse ERR on %s in %s",tstr,filename)
            return 0
          }
        llist.append(new vfile_line(tstr2,sze,loc,nvec,tstr))  // name size loc num
      }
    if (llist.count==0) {
        printf("grvec.hoc::read_mf ERR nothing read from %s\n",filename)
        return 0
      }
    entries=llist.count
    mff=1
    return 1
  }

//** prvec(name,vec,byte_flag[,file])
proc prvec () { local bflag
    if (numarg()>3) { tmpfile.aopen($s4) }
    bflag = $3
    tmpfile.printf("//b%d 1 %s %d %d\n",bflag,$s1,$o2.size,tf1.tell())
    $o2.vwrite(tf1,bflag) 
    if (numarg()>3) { tmpfile.close() }
  }

//** pv() dumps a single vector into output_file
proc pv () { local inx  
    sprint(output_file,"%sv%s.%02d",ddir,datestr,runnum-dec_runnum)
    if (numarg()==0) { inx = hoc_ac_ } else { inx = $1 }
    printf("Printing %s to %s\n",printlist.object(inx).name,output_file)
    // string_dialog("Name for saved vector",printlist.object(inx).name)
    if (tmpfile.ropen(output_file)) { // file exists already
        file_with_dot(output_file,temp_string_) // put .filename into temp_string_
        tmpfile.aopen(temp_string_) tf1.aopen(output_file)
        printf("Appending to %s\n",output_file)
      } else { 
        pvplist0()
        pvplist1(comment)
      }
    pvpone()
    tmpfile.close()
    tf1.close
  }

//** pvpone() -- write out a vector or vector pair to the file
proc pvpone () {  // METHOD DEPENDENT
    if (byte_store) {
        if (isassigned($o1.tvec)) {
            tmpfile.printf("//b%d -2 %s %d %d\n",byte_store,temp_string_,$o1.vec.size,tf1.tell)
            $o1.tvec.vwrite(tf1,tvec_bytesize) 
          } else if ($o1.pstep>0) {
            tmpfile.printf("//b%d %g %s %d %d\n",byte_store,$o1.pstep,temp_string_,$o1.vec.size,tf1.tell)
          } else {
            tmpfile.printf("//b%d -1 %s %d %d\n",byte_store,temp_string_,$o1.vec.size,tf1.tell)
          }
        $o1.vec.vwrite(tf1,byte_store)
      }
  }

//** cpplitem([num]) copy X0 to new item in printlist, optional arg can be pos or neg
proc cpplitem () { local num,cnt
    cnt = printlist.count
    if (numarg()>0) {if ($1>=0) num=$1 else num=cnt+$1} else num=cnt-1
    if (num>cnt-1 || num<0) {
        printf("%d!: Only %d items (0-%d) in list.\n",num,cnt,cnt-1) return 
      }
    if (numarg()>1) grvecstr=$s2 else sprint(grvecstr,"Copy_of_%s",printlist.object(num).name)
    npl(grvecstr,printlist.object(num).vec)
    print printlist.count-1,":XO -> ",grvecstr
    XO = printlist.object(printlist.count-1).vec
  }

//** chgplname([num],STR) change name of item in printlist
proc chgplname () { local num,cnt
    cnt = printlist.count
    if (numarg()>0) {if ($1>=0) num=$1 else num=cnt+$1} else num=cnt-1
    if (num>cnt-1 || num<0) {
        printf("%d!: Only %d items (0-%d) in list.\n",num,cnt,cnt-1) return 
      }
    printlist.object(num).name=$s2
  }

// new_pri(NAME,TVEC,VEC) quick and dirty new_printlist_item
proc new_pri () {
    vite = new vitem($s1,$o2.size)
    if (numarg()==3) { vite.tvec.copy($o2) vite.vec.copy($o3) } else vite.vec.copy($o2)
    printlist.append(vite)
    vite=nil
  }

//* prlexp(sz) expands all the vectors in printlist to size sz
proc prlexp () { 
    sz = $1
    tvec.resize(sz)
    for ltr(Xo,printlist) { Xo.vec.resize(sz) }
  }

//* iterators for printlist and files
//** rvtr() read vector iterator
// usage 'for rvtr(vec) XO.vec.printf' where # is attrpanl#
// not debugged for presence of tvec in cvode
iterator rvtr () { local i,flag,s4flag
    if (numarg()>=2) {$&2=0} else {i1 = 0}
    if (numarg()==3) s4flag=1 else s4flag=0
    for i = 0, entries-1 {
        tstr = llist.object(i).name
        if (s4flag) {if (strm(tstr,$s3)) flag=1 else flag=0}
        if (flag) {
            rv_readvec(i,$o1)    
            iterator_statement
            if (numarg()>=2) { $&2+=1 } else { i1+=1 }
          }
      }
  }

//** vrdr(vlist[,REGEXP or INDV,flag,&y]) -- used for llist
// similar to rvtr() but does interpolation
// use regexp eg for prdr("PYR2.8") { ... }
// optional flag to NOT interpolate
// indv gives set of llist nums to search through (can use with "" as regexp)
// sets 4 vectors in vlist: voltage,times,interp v, interp t
iterator vrdr () { local flag,a,ii localobj rxp,v1,tv1,v2,tv2,ipt
    if (numarg()==0) printf("\t**** HELP::  vrdr(vlist[,REGEXP or INDV,flag,&y]) ****\n")
    curcol=0
    rxp=new String()
    a=allocvecs(ipt)
    if (!isojt($o1,llist)) $o1=new List()
    if ($o1.count==4) { // use the list we're given
        for ii=0,3 if (!isojt($o1.o(ii),vrtmp)) {
            printf("vrdr: Nonvector in vlist:%s\n",$o1.o(ii))
            return
          }
      } else {
        $o1.remove_all 
        for ii=0,3 $o1.append(new Vector())
      }
    v1=$o1.o(0) tv1=$o1.o(1) v2=$o1.o(2) tv2=$o1.o(3) 
    ipt.indgen(0,llist.count-1,1)
    if (numarg()>=2) if (argtype(2)==1) { ipt.copy($o2) 
                } else if (argtype(2)==2) { rxp.s=$s2
                } else { printf("vrdr() ERR arg 2 should be vector or string\n") }
    if (numarg()>=3) flag=$3 else flag=0
    if (numarg()>=4) {$&4=0} else {ii1 = 0}
    if (!flag) {
        if (tvec.max != tstop) printf("WARNING: tvec set?: %g %g\n",tstop,tvec.max)
        tv2.copy(tvec)  // tvec must be preassigned for interpolation
      }
    tmpfile.ropen(filename)
    for (ii1=0;ii1<llist.count;ii1+=1) {
        if (ipt.contains(ii1) && strm(llist.object(ii1).name,rxp.s)) {
            XO=llist.object(ii1)
            if (mff) if (strcmp(filename,XO.f)!=0) { filename=XO.f tmpfile.ropen(filename) }
            tmpfile.seek(XO.loc)
            if (XO.num==-2) tv1.vread(tmpfile) else {
                if (XO.num<=0) {printf("vrdr INTERR; ?printStep for interpolation\n") err()}
                tv1.indgen(0,tstop+0.01,XO.num) }
            v1.vread(tmpfile)
            v2.resize(0)
            if (XO.num==-2 && !flag) v2.interpolate(tv2,tv1,v1)
            i1=ii1
            iterator_statement
            if (numarg()>=4) { $&4+=1 }
          }
      }
    tmpfile.close
    dealloc(a)
  }

//** prdr() -- used for printlist
// use regexp eg for prdr("PYR2.8") { ... }
// optional flag to NOT interpolate
// ind=tvec, vec1=original trace, vec interpolated on tvec
// note that i1 here gives list number, not sequential
// eg for panobj.prdr("V$",1) gv(i1)
iterator prdr () { local flag
    if (numarg()>1) flag=$2 else flag=0
    if (numarg()==3) {$&3=0} else {i1 = 0}
    v1=tv1=v2=tv2=allocvecs(4) tv1+=1 v2+=2 tv2+=3
    if (!flag) {
        if (tvec.max != tstop) printf("WARNING: tvec set?: %g %g\n",tstop,tvec.max)
        mso[tv2].copy(tvec)  // tvec must be preassigned for interpolation
      }
    curcol=0
    if (attr0) for (ii1=0;ii1<printlist.count;ii1+=1) {
        XO=printlist.object(ii1)
        if (strm(XO.name,$s1)) {
            sprint(tstr,"tstr=\"%s\"",XO.name) execute(tstr) // set global tstr
            mso[v1].copy(XO.vec) 
            if (isit(XO.tvec)) mso[tv1].copy(XO.tvec) 
            if (!flag && isit(XO.tvec)) mso[v2].interpolate(mso[tv2],XO.tvec,XO.vec)
            i1=ii1
            iterator_statement
            if (numarg()==3) { $&3+=1 }
          }    
      } else for (ii1=0;ii1<llist.count;ii1+=1) {
        if (strm(llist.object(ii1).name,$s1)) {
            XO=llist.object(ii1)
            i1=ii1
            iterator_statement
            if (numarg()>=3) { $&3+=1 }
          }
      }
    dealloc(v1)
  }

//* outvec() routines for printing out in sections - NOT DEBUGGED

//** outvec_init([output_file,comment])
proc outvec_init() { local segs
    if (numarg()>0) { output_file = $s1 } else {
        sprint(output_file,"%sv%s.%02d",ddir,datestr,runnum-dec_runnum)
        while (tmpfile.ropen(output_file)) { runnum = runnum+1 // don't allow an overwrite
            sprint(output_file,"%sv%s.%02d",ddir,datestr,runnum-dec_runnum) }
      }
    if (numarg()>1) { comment = $s2 }
    print "\nOutput to ",output_file
    if (print_flag) { print "WARNING: print_flag=1 --> 0\n"
        print_flag = 0 }
    if (outvecint==0 || outvecint>tstop) {
        printf("WARNING: outvecint being set to tstop\n")
        outvecint = tstop }
    outvect = outvecint
    segs = int(tstop/outvecint)
    if (tstop/outvecint > segs) { segs=segs+1 }
    tmpfile.wopen(output_file)
    if (strcmp(comment,"")!=0) { tmpfile.printf("//: %s\n",comment) }
    tmpfile.printf("//printStep %g\n",printStep)
    tmpfile.printf("//MULTI %d %d\n",printlist.count,segs)
    tmpfile.close()
  }

//** outvecs()  : print out the vectors and reset them for recording
proc outvecs () { local ii
    if (t<outvect || outvecint == 0) { return }
    tmpfile.aopen(output_file)
    for ii=0,printlist.count-1 {
        tmpfile.printf("//b%d 1 %s %d %d\n",byte_store,printlist.object(ii).name,t-outvecint,tmpfile.tell())
        printlist.object(ii).vec.vwrite(tmpfile,byte_store)
        tmpfile.printf("\n")
        printlist.object(ii).vec.play_remove()
        sprint(temp_string_,"printlist.object(%d).vec.record(&%s,%g)",\
               ii,printlist.object(ii).name,printStep)
        execute(temp_string_)
      }
    tmpfile.close
    outvect = outvect+outvecint
  }

//** outvec_finish () : put out the last section if needed, update the output_file name
proc outvec_finish() {
    if (t > outvect-outvecint+2*dt) {
        tmpfile.aopen(output_file)
        for ii=0,printlist.count-1 {
            tmpfile.printf("//b%d 1 %s %d %d\n",byte_store,printlist.object(ii).name,t-outvecint,tmpfile.tell())
            printlist.object(ii).vec.vwrite(tmpfile,byte_store)
            tmpfile.printf("\n")
          }
        tmpfile.close()
      }
  }

//* endtemplate; assignments:
endtemplate GRV

printStep=0.1
grv_ = new GRV(0)
{panobj=grv_ printlist=grv_.printlist panobjl=grv_.panobjl}

//* external routines
//** new_printlist_item(name) adds this item to the printlist
//  new_printlist_item(name,vec) adds this vec to the printlist
//  new_printlist_item(name,vec,tvec) adds this vec to the printlist
//  new_printlist_item(var,name) use name instead of variable name
//  new_printlist_item(var,ptr) provide an objref to point to the vec
//  new_printlist_item(name,num,vec)??adds this vec to the printlist under name_num0,name_num1,...
proc new_printlist_item () { local dur,nflag,tvflag
    if (! isassigned(grv_)) { grv_ = new GRV(0) printlist=grv_.printlist }
    if (numarg()==1) { grv_.npl($s1)
      } else if (numarg()==2) {
        if (argtype(2)==1) {
            grv_.npl($s1,$o2)
          } else if (argtype(2)==2) {
            grv_.npl($s1,$s2)
          } else grv_.npl($s1,$2)
      } else if (numarg()==3) {
        if (argtype(2)==1) {
            grv_.npl($s1,$o2,$o3)
          } else if (argtype(2)==0) {
            grv_.npl($s1,$2,$o3)
          }
      }
  }

//** llist() print out contents of a list
proc llist () { local done localobj o,st,xo
    st=new String()  o=panobj
    if (numarg()==2) st.s=$s2
    if (numarg()>=1) { 
        if (argtype(1)==1) {
            if (isobj($o1,"List")) { 
                if ($o1.count==0) {print "empty list" return}
                if (isobj($o1.object(0),"String2")) {
                    for ltr(xo,$o1) if (strm(xo.s,st.s)) print xo.s,xo.t
                  } else if (isobj($o1.object(0),"String")) { 
                    for ltr(xo,$o1) if (strm(xo.s,st.s))  print xo.s
                  } else if (isobj($o1.object(0),"Vector")) {
                    done=0
                    if (name_declared("oform")) if (oform(vec)!=NOP) {
                        for ltr(xo,$o1) print xo,oform(xo) 
                        done=1 
                      }
                    if (!done) for ltr(xo,$o1) print xo,xo.size
                  } else if (isobj($o1.object(0),"Union")) {
                    for ltr(xo,$o1) if (strm(xo.s,st.s)) print xo,xo.s,xo.t,xo.u,xo.v
                  } else for ltr(xo,$o1) print xo
                return
              } else o=$o1
          } else if (argtype(1)==2) st.s=$s1
      }
    if (o.attr0) { for ltr(xo,printlist) if (strm(xo.name,st.s)) print i1,xo.name,xo.vec.size
      } else         for ltr(xo,o.llist) if (strm(xo.name,st.s)) print i1,xo.name,xo.size      
  }

//** cpprl(PRINTLIST,TMPLIST) copies printlist vitem's to tmplist
proc cpprl () { localobj xo,yo
    $o2.remove_all
    for ltr(xo,$o1) {
        $o2.append((yo=new vitem(xo.name,xo.vec.size)))
        yo.tvflag=xo.tvflag yo.pstep=xo.pstep yo.o=xo.o yo.vec.copy(xo.vec)
        if (yo.tvflag) {yo.tvec=new Vector() yo.tvec.copy(xo.tvec)}
      }
  }

//** abbreviated proc calls
proc gvpwpl () { pwman_place(500,500) }
proc vp () { grv_.vecpanel }
obfunc gvnew () { 
    if (numarg()==1) {
        if (argtype(1)==0) {
            panobj=new GRV($1)
          } else if (argtype(1)==2) {
            panobj=new GRV($s1)
          } else if (argtype(1)==1) {
            $o1=new GRV(-2)
            panobj=$o1
          }
      } else if (numarg()==2) {
        if ($2>0) {
            panobj=panobjl.object($2)
            panobj.read_vfile($s1)
          } else panobj=new GRV($s1,$2) // file,flag
      } else panobj=new GRV(1) // default
    return panobj
  }

proc ap () { local ii,attr0,nopan localobj o
    nopan=ii=0
    if (numarg()==0) { o=panobj 
      } else if (numarg()>=1) {
        if (argtype(1)==0) { ii=$1 
            o=grv_.panobjl.object(ii)
            if (ii<0 || ii>=grv_.panobjl.count) { 
                printf("**** ap(%d) ERR panobj #%d not found -- run gvnew() \n",ii,ii) return }
          } else o=$o1
      }
    if (numarg()>=2) if (argtype(2)==0) if ($2==-2) nopan=1
    attr0=o.attr0
    o.attrpanl()
    if (!nopan) if (attr0) o.pbrgr("Graph","gv") else o.rpanel()
    panobj=o
  }
proc disptray () { print "Must load boxes.hoc to get trays" }

//** gg() graph vectors and functions directly
//** gs(#) select graph (by setting g and graphItem to this Graph#
proc gs () { 
    if (argtype(1)==1) {      g=$o1 graphItem=g 
      } else if (numarg()==2) { g[$1]=Graph[$2] 
      } else {                  g=Graph[$1] graphItem=g }
  }
// gg(g[i],vec) gg(vec,step) gg(vec,ind) gg(g,"FUNC","min,max") [color,line,symbol]
strdef symb
symb = "O"
gvmarkflag=0
obfunc gg () { local gp,na,newgr,clr,a,stp,i,tmp localobj ty,ts,abs,ord,o,go
    a=allocvecs(ty,abs,ord)
    ts=new String2()
    na=numarg() newgr=1
    ty.resize(10) ty.fill(-1)
    for i=1,na ty.x[i]=argtype(i)
    i=1
    clr=panobj.color lne=panobj.line
    if (ty.x[i]==0) { 
        gp=$i                                         i+=1
      } else gp=0
    if (gp<10) {
        if (isassigned(g[gp])) if (g[gp].view_count>0) newgr=0
        if (newgr) g[gp]=new Graph()
        go=graphItem=g[gp]
        graphList[0].append(g[gp])  panobj.glist.append(g[gp])
      } else {
        graphItem=go=new Graph()
        graphList[0].append(go)  panobj.glist.append(go)
      }
    if (gvmarkflag) ts.t="mark" else ts.t="line"
  
    if (na==1 && ty.x[0]==0) { return  // gg(#) just put up the graph
      } else if (na==i && ty.x[i]==1) { 
        sprint(ts.t,"%s.%s(%s,1",$oi,ts.t,go)   // gg(vec)
      } else if (ty.x[i]==2) { // gg("FUNC","min,max,step")
        min=0 max=10 stp=0
        ts.s=$si                                      i+=1
        if (ty.x[i]==2) {
            split($si,abs) min=abs.x[0] max=abs.x[1] 
            if (abs.size==3) stp=abs.x[2]               i+=1
          }
        if (stp==0) stp=(max-min)/200
        abs.indgen(min,max,stp) ord.copy(abs) 
        print ts.s
        ord.apply(ts.s)
        sprint(ts.t,"%s.%s(%s,%s",ord,ts.t,go,abs)
      } else if (ty.x[i]==1 && ty.x[i+1]==0) {     // gg(vec,step)
        o=$oi                                         i+=1
        if (isobj(o,"List")) {
            tmp=$i   i+=1
            if (int($i)!=$i) { // a timestep
                sprint(ts.t,"%s.%s(%s,%g",o.o(tmp),ts.t,go,$i)      i+=1  
              } else {
                sprint(ts.t,"%s.%s(%s,%s",o.o(tmp),ts.t,go,o.o($i)) i+=1  
              }
          } else { // vector
            sprint(ts.t,"%s.%s(%s,%g",o,ts.t,go,$i)     i+=1  
          }                                          
      } else if (ty.x[i]==1 && ty.x[i+1]==1) {     // gg(vec,ind)
        o=$oi                                         i+=1
        sprint(ts.t,"%s.%s(%s,%s",o,ts.t,go,$oi)   i+=1
      }
    if (ty.x[i]==0) { clr=$i                        i+=1 }
    if (ty.x[i]==0) { lne=$i                        i+=1 }
    if (ty.x[i]==2) { symb=$si                      i+=1 }
    if (sfunc.len(ts.t)>4) {
        if (gvmarkflag) { sprint(ts.s,"%s,\"%s\",%d,%d,1)",ts.t,symb,lne,clr)
          } else { sprint(ts.s,"%s,%d,%d)",ts.t,clr,lne) }
        execute(ts.s)
      }
    dealloc(a)
    return graphItem
  }

//*** ge() erases IV graph
proc ge () { if (numarg()==0) graphItem.erase_all() else g[$1].erase_all }

//** gv() calls internal gv
proc gv () {  local inx,na // EXTERNAL VERSION -- same name in template
    na=numarg()
    if        (argtype(1)==0) { inx = $1
      } else if (argtype(1)==2) {
          for ltr(XO,printlist) if (strm(XO.name,$s1)) inx=i1
          if (inx==-1) {print $s1," not found" return }
      }
    if (na==1) grv_.gv(inx) else if (na==2) grv_.gv(inx,$2) else if (na==3) grv_.gv(inx,$2,$3)
  }

//** restore_printlist() restores the plist from a file in an attrnum
objref vite
proc restore_printlist () { local cnt,ii,attrnum,savlvar localobj aa,st
    printf("NOT WORKING\n")
    st=new String()
    attrnum=$1
    printlist.remove_all
    panobj=grv_.panobjl.object(attrnum)
    for panobj.vrdr(aa,"",1) {
        vite= new vitem(st.s,aa.o(0).size)
        vite.vec.copy(aa.o(0))
        printlist.append(vite)
      }
  }

//** dirname(full,path) filname(full,file) splits up path/file
// eg filname("/home/billl/nrniv/thal/params.hoc",temp_string_)
//    temp_string_ => params.hoc
obfunc dirname () { localobj st
    st=new String2()
    sfunc.head($s1,"[^/]+$",st.s)
    sfunc.tail($s1,st.s,st.t)
    if (numarg()==2) $s2=st.s
    return st
  }

//** filname()
obfunc filname () { localobj st
    st=new String2()
    sfunc.head($s1,"[^/]+$",st.t)
    sfunc.tail($s1,st.t,st.s)
    if (numarg()==2) $s2=st.s
    return st
  }

//** file_with_dot(filename,[result,prefix]): put .filename into result
obfunc file_with_dot () { localobj st
    st=dirname($s1)
    if (numarg()==3) { sprint(st.s,"%s%s%s",st.s,$s3,st.t)
      } else             sprint(st.s,"%s.%s", st.s,    st.t)
    if (numarg()>=2) $s2=st.s
    return st
  }

//* fexists()
func fexists () { localobj o
    o=new File()
    return o.ropen($s1)
  }

//** ftype()
func ftype () { local ty localobj st
    ty=0
    st=new String2()
    sprint(st.t,"stat -c %%F %s 2>&1",$s1)
    system(st.t,st.s)
    chop(st.s)
    if (strm(st.s,"\n")) {               return 10 //  more than 1 file -- ie * used
      } else if (strm(st.s,"No such"))   { return -1
      } else if (strm(st.s,"directory")) { return 0
      } else if (strm(st.s,"symbolic")) {  return 8
      } else if (strm(st.s,"regular"))  {  return 2
      } else { // not identified
        printf("File %s is a %s\n",$s1,st.s)
        return -2
      }
  }

//** file_len() uses wc
func file_len () { local x localobj st
    st=new String()
    sprint(st.s,"wc -l \"%s\"",$s1)
    system(st.s,st.s)
    sscanf(st.s,"%d",&x)
    return x
  }

func cvode_status () { return cvode.active() + cvode.use_local_dt()/10 }

proc pvall () { localobj o
    o=panobjl.o(0)
    if (! o.attr0) { printf("pvall() ERR %s not attr0==0\n",o)
      } else o.pvall()
  }

//** procbutt() put up a single proc in a button
proc procbutt () {
    xpanel($s1)
    xbutton($s1,$s1)
    xpanel(500,500)
  }

// mdl2view(g,X,Y) converts model coordinates to view coordinates
// eg {XO=mdl2view(g,12,533.7) g.label(XO.x,XO.x[1],"AA",2,2,0.5,0.5,1)}
obfunc mdl2view () { local a,ii,x0,y0 localobj o,v1
    x0=$2 y0=$3
    o=new Union()
    a=allocvecs(v1)
    for ii=1,4 v1.append($o1.size(ii))
    o.x=   (x0-v1.x[0])/(v1.x[1]-v1.x[0])
    o.x[1]=(y0-v1.x[2])/(v1.x[3]-v1.x[2])  
    return o
  }

proc stopper () {
    xpanel("STOP")
    xbutton("STOP","stoprun=1")
    xbutton("FINI","finish()")
    xbutton("CONT","time(\"cvode.solve(tstop)\")")
    xbutton("RUN","time()")
    xpanel()
  }

// END /usr/site/nrniv/local/hoc/grvec.hoc
//================================================================
//================================================================
// INSERTED nqs.hoc
// =Id=  nqs.hoc,v 1.439 2006/07/06 19:49:58 billl Exp 

// primarily edited in nrniv/place
if (!name_declared("VECST_INSTALLED")) {
    printf("NQS ERROR: Need vecst.mod nmodl package compiled in special.\n")
  }
if (!VECST_INSTALLED) install_vecst()
if (! name_declared("datestr")) load_file("setup.hoc")

objref g[10]
gvmarkflag=0
declared("file_len")
strdef execstr,strform,dblform
{strform="%s " dblform="%3.4g "}

//* stubs for ancillary programs
double sops[19]  // AUGMENT TO ADD NEW OPSYM
declared("whvarg","whkey","varstr","nqsdel","chsel2","grsel2")

//* NQS template
// potential to overwrite XO,tmpfile,i1
begintemplate NQS
public cob,out,up // operate on this or out 
public s,comment,file,v,m,x,ind,scr,fcd,fcds,fcdo,fcdl,this,sstr // strings and vecs
public objl,verbose,tmplist,vlist,nval,sval,oval,selcp,rxpstr,slorflag,stub,chunk,rdpiece
public sv,rd,append,pr,prn,zvec,resize,size,fi,sets,set,setcol,setcols,gets,get,fetch,tog
public cp,copy,mo,aind,it,qt,ot,appi,eq,fcdseq,fcdoeq,sort,select,stat,rdcols,map,apply,applf
public calc,pad,delect,fill,uniq,gr,clear,strdec,coddec,odec,join,fillin,fillv,otl,selall
public unuselist,useslist,renamecol,delrow,elimrepeats,grow,shuffle,fewind,listvecs,loose
public percl,psel,svsetting,getrow,getcol,resize2,find,family,delcol,delcols,keepcols,selone
public sethdrs,gethdrs,version,svvers,i2
objref v[1],s[1],is[4],x,nil,ind,scr[3],fcd,fcds,fcdo,fcdl,this,objl
objref cob,out,up,Xo,Yo,oval,tmplist,otl,vlist

strdef comment,file,sstr,sstr2,sstr3,sstr4,tstr,sval,nqsvers
double m[1]
external readnums,savenums,readdbls,savedbls,rdvstr,wrvstr,sfunc,repl_mstr,isobj,rdmord
external vlk,Union,String,tmpfile,strm,XO,execstr,i1,allocvecs,dealloc,mso,strform,dblform
external eqobj,isnum,chop,isassigned,whvarg,whkey,sops,batch_flag,g,varstr,gvmarkflag
external file_len,nqsdel,chsel2,grsel2

//** init()
proc init () { local i,ii,flag,scnt,na,fl,rdflag
    nval=fl=scnt=flag=rdflag=0 // flag set if creating the internal NQS
    ni=0
    selcp=verbose=1
    svsetting=3 loose=1e-4
    for ii=2,3 is[ii]=new String()
    is[2].s="INDEX"  is[3].s="SCRATCH"
    na=numarg()
    for i=1,na scnt+=(argtype(i)==2) // string count
    if (na==0) scnt=-1
    if (na==1) if (argtype(1)==2) rdflag=1
    if (na>=1) if (argtype(1)==0) {
        fl=1 // 1 arg taken care of
        if ($1==1e-9) {
            flag=1 up=$o2 fl=2
            m=up.m 
            if (m>0) {
                objref v[m],s[m]
                for ii=0,m-1 {v[ii]=new Vector() s[ii]=up.s[ii]}
              }
            fcd=up.fcd
            fcds=up.fcds fcdl=up.fcdl fcdo=up.fcdo // finish creation of .out here
          } else {
            m=$1
            objref v[m],s[m]
            for ii=0,m-1 { v[ii]=new Vector() s[ii]=new String2() }
          }
      }
    if (fl!=1 && na==scnt) { // all strings
        fl=2 // all args taken care of
        m=na
        objref v[m],s[m]
        for ii=0,m-1 {i=ii+1 v[ii]=new Vector() s[ii]=new String($si) }
      }
    if (fl!=2 && na>=2) if (argtype(2)==0) { 
        fl==2  // all args taken care of
        for ii=0,m-1 v[ii].resize($2) 
      }
    if (fl!=2) { // if first arg is not a string these other can be
        if (na>=2) file=$s2
        if (na>=3) comment=$s3
        if (na>=4) x.x[0]=$4
      }
    if (!flag) { 
        // fcd gives field codes according to values used for argtype()
        fcds=new List() fcd=new Vector(m) tmplist=new List() vlist=new List()
        fcd.resize(m) fcd.fill(0) // field codes to have a field that's string based
      }
    x=new Vector(m) ind=x.c for ii=0,2 scr[ii]=x.c
    scr.resize(0) ind.resize(0)
    objl=new List() cob=this
    v0sz=slorflag=0
    chunk=100
  nqsvers="=Id=  nqs.hoc,v 1.439 2006/07/06 19:49:58 billl Exp " svvers=-1
    if (!flag) { 
        out=new NQS(1e-9,this)
        if (rdflag) rd($s1)
      } 
  }

//** tog() toggle flag that determines whether actions are on out or this
proc tog () { 
    if (numarg()==0) {
        if (eqobj(cob,out)) { cob=this if (verbose) print "Operate on full db"
          } else {              cob=out  if (verbose) print "Operate on output of select" }
      } else if (numarg()==1) {
        if (argtype(1)==0) {  // just give information
            if (eqobj(cob,out)) { print "Using output db"
              } else {              print "Using full db" }
          } else if (argtype(1)==2) { // out,output,selected to choose these
            if (strm($s1,"[Oo][Uu][Tt]") || strm($s1,"[Ss][Ee][Ll]")) {
                cob=out } else cob=this
         }
      }
  }

//** sethdrs() set the column names to given args
// sethdrs(#,"NAME") sethdrs("NAME1","NAME2",...)  sethdrs(nq) -- copy from nq
proc sets () { printf("sets() changed to sethdrs()\n") }
proc sethdrs () { local i,nm
    nm=numarg()
    // out.s should always be a pointer to s but early on was keeping different copies:
    if (! eqobj(s,out.s)) printf("sets INTERRA\n")
    if (nm==2 && argtype(1)==0) { 
        s[$1].s=$s2 
      } else if (nm==1) {
        if ($o1.m!=m) resize($o1.m)
        for i=0,m-1 s[i].s=$o1.s[i].s
      } else {
        if (nm>m) { 
            if (batch_flag) {
                printf("NQS sets WARNING resized table from %d to %d\n",m,nm)
              } else if (! boolean_dialog("Resize TABLE?","YES","NO")) return
            printf("resizing TABLE: %d -> %d\n",m,nm) resize(nm) 
          }
        for i=1,nm { s[i-1].s=$si }
      }
  }

// gethdrs() print the strings
proc gets () { printf("gets() changed to gethdrs()\n") } 
proc gethdrs () { local ii,jj,kk,mm localobj o
    if (numarg()==1) { // set the strings
        o=new String("%s%c")
        for ii=0,m-1 {
            jj=ii%26 kk=int(ii/26)+1
            for mm=1,kk sprint(s[ii].s,o.s,s[ii].s,65+jj)
          }
      }
    for ii=0,m-1 printf("%s(%d) ",s[ii].s,ii) 
  }

//* selone(COL,VAL[,FLAG]) -- uses vec.selone when just working with one col and one value
func selone () { local val,niflag
    if (numarg()==3) niflag=$3 else niflag=0 // use if searching repeatedly through same vec
    tog("DB") // start at full db
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    if (fl==-1) return
    val=$2
    // if (!v[fl].ismono) {printf("NQS selone: must sort on %s before using\n",s[fl].s) return -1}
    if (niflag) ni=ind.slone(v[fl],val,ni) else ni=ind.slone(v[fl],val)
    if (selcp) {
        if (ind.size==0) { 
            if (verbose) printf("None selected\n") 
          } else {
            out.ind.copy(ind) 
            aind()
            cob=out
          }
      } else cob=this
    return ind.size
  }
  
//* select() -- based loosely on SQL select
func select () { local ii,i,tmp,tmp1,ret,isv,key,arg,vc,selcpsav,savind,union,not,rxpflg localobj o
    if (numarg()==0) { out.cp(this,2) cob=out return v.size }
    tog("DB") // start at full db
    if (size(1)==-1) { printf("NQS:select ERR0: cols not all same size\n") return -1 }
    // key holds OPs; arg holds ARGs; vc holds COL NAMEs
    key=arg=vc=allocvecs(3) arg+=1 vc+=2 // key is an operator, arg is args, vc is col#
    selcpsav=selcp i=1 not=rxpflg=union=savind=0
    tmplist.remove_all vlist.remove_all
    if (argtype(i)==0) if ($1==-1) {selcp=0  i+=1} // else is a number identifying a vector
    if (argtype(i)==2) { // check first string for &&, ||, !
        if (strcmp($si,"&&")==0) {        savind=1 union=0 i+=1 
          } else if (strcmp($si,"||")==0) { savind=1 union=1 i+=1 
          } else if (strcmp($si,"!")==0)  { savind=0  not=1 i+=1
          } else if (strcmp($si,"&&!")==0)  {savind=1 not=1 i+=1
          } else if (strcmp($si,"||!")==0)  {savind=1 union=1 not=1 i+=1 }
      } else if (argtype(i)==1) { i+=1
        if (isobj($o1,"Vector")) { ind.copy($o1) savind=1 union=0 // assume &&
          } else { 
            printf("NQS:select ERR0a: first vec obj should be ind vector\n") dealloc(key) return -1 }
      }
    if (savind) scr.copy(ind) else scr.resize(0)
  
    while (i<=numarg()) {
        if (argtype(i)==2) { 
            if (strcmp($si,"IND_")==0) {
                if ((vn=fi($si,"NOERR"))!=-3) { 
                    printf("NQS:select() WARNING: IND_ is a reserved word: ?%s\n",s[vn].s) }
                vn=-1e9  scr[1].indgen(0,v.size-1,1) tmplist.prepend(scr[1])
              } else if ((vn=fi($si))<0) { dealloc(key) return -1 }
            sstr=$si  // save for join: use with "NAME",EQW,OTHER_NQS
          } else if (argtype(i)==0) { vn=$i // can avoid repeated string search
            if (vn<0 || vn>=m) {
                printf("NQS:select ERR0b: can't ident arg %d: %d\n",i,vn) dealloc(key) return -1}
            sstr=s[vn].s
          } else {printf("NQS:select ERR1: arg %d should be col name or num\n",i) dealloc(key) return -1}
        mso[vc].append(vn)                        i+=1 
        if (argtype(i)==0) {
            if ((isv=isvarg($i))==-1) { 
                mso[key].append(EQU) // if arg2 is a regular number presume that op is EQU arg2
                mso[arg].append($i,0)
                i+=1
                continue
              } else { lk=$i }
          } else if (argtype(i)==2) { isv=isvarg(lk=whvarg($si))
            if (isv==-1) { 
                if (strcmp($si,"~")==0) {
                    mso[key].append(EBE) // approximately equal -- generate a range
                    i+=1
                    tmp=$i*(1-loose) tmp1=$i*(1+loose)
                    if (tmp<tmp1) mso[arg].append(tmp,tmp1) else mso[arg].append(tmp1,tmp)
                    i+=1
                    continue
                  } else {
                    printf("NQS:select ERR1a: operator %s not recognized\n",$si) dealloc(key) return -1 
                  }
              }
          } else {
            printf("NQS:select ERR2: arg should be symbolic (eg GTE, EQU ...) or string (eg '[)','<=') op \n",i)
            dealloc(key) return -1 
          }
        mso[key].append(lk)                       i+=1
        // pick up ARGS
        for ii=0,isv-1   {  
            if (argtype(i)==0) { 
                mso[arg].append($i)                   i+=1 
              } else if (argtype(i)==2) {
                if (lk==EQV) { // look for a column id
                    vn=fi($si) // OPSYM exception
                    if (vn==-1) { printf("NQS:select ERR2a EQV but what col?\n") dealloc(key) return -1 }
                    mso[arg].append(0)
                    mso[vc].append(vn)                    i+=1
                  } else if (lk==SEQ) {
                    mso[key].x[mso[key].size-1]=EQU
                    if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
                    mso[arg].append(ret=finval(vn,argtype(i),lk))  i+=1
                  } else if (lk==RXP) {
                    mso[key].x[mso[key].size-1]=EQW
                    mso[arg].append(0)
                    if (argtype(i)!=2) {printf("NQS:select ERR2a1\n") dealloc(key) return -1}
                    if (rxpflg==1) {printf("NQS:select ERR2a2: RXP twice\n") dealloc(key) return -1}
                    ret=tmplist.prepend(scr[2]) rxpflag=1
                    if (rxpstr(vn,$si,scr[2])==0) {
                        printf("NQS:select WARNING: No RXP matches for %s\n",$si) }
                    mso[vc].append(-1e9)                  i+=1
                  } else {printf("NQS:select ERR2b string arg needs EQV,SEQ or RXP?\n")
                    dealloc(key) return -1}
              } else if (argtype(i)==1) { 
                if (lk==EQW) { // pick up a vector
                    if (isobj($oi,"Vector")) {
                        mso[arg].append(0)
                        mso[vc].append(-i)                    i+=1
                      } else if (isobj($oi,"NQS")) {
                        mso[arg].append(0)
                        if ((tmp=$oi.fi(sstr,"NOERR"))!=-1) { // JOIN with output from other nqs
                            tmplist.prepend($oi.out.v[tmp])
                          } else {
                            o=$oi                               i+=1
                            if ((tmp=o.fi($si))==-1) { printf("NQS:select ERR2c: cant' find %s in %s?\n",$si,o)
                                dealloc(key) return -1 }
                            tmplist.prepend(o.out.v[tmp])
                          }
                        mso[vc].append(-1e9)                  i+=1
                      } else { printf("NQS:select ERR2c1: EQW needs Vec or NQS not %s?\n",$oi)
                        dealloc(key) return -1
                      }
                  } else { printf("NQS:select ERR2d only EQW takes obj arg: %d:%d?\n",i,argtype(i))
                    dealloc(key) return -1}
              } else {
                whkey(lk,sstr) printf("NQS:select ERR3 arg %d should be arg for %s",i,sstr) 
                dealloc(key) return -1
              }
          }
        // args in wrong order - swap
        if (isv==2) if (mso[arg].x[mso[arg].size-2]>mso[arg].x[mso[arg].size-1]) {
            tmp=mso[arg].x[mso[arg].size-2]
            mso[arg].x[mso[arg].size-2]=mso[arg].x[mso[arg].size-1]
            mso[arg].x[mso[arg].size-1]=tmp
          }
        // pad so every OP sees 2 ARGS
        for ii=0,2-isv-1 { mso[arg].append(0) } 
      }
    ind.resize(v.size)
  
    for ii=0,mso[vc].size-1 { vn=mso[vc].x[ii] 
        if (vn==-1e9) { // code for EQW case with NQS arg
            vlist.append(tmplist.object(tmplist.count-1)) 
            tmplist.remove(tmplist.count-1) // pop
          } else if (vn<0) { i=-vn // code for EQV case where vector is in the arg list
            vlist.append($oi) 
          } else vlist.append(v[vn]) 
      }
    if (tmplist.count!=0) { printf("NQS:select ERR5 %s.tmplist not empty\n",this) return -1 }
  
    if (slorflag) { ind.slor(mso[key],mso[arg],vlist)
      } else        { ind.slct(mso[key],mso[arg],vlist) }
  
    if (not==1) complement() // ind->!ind
    if (savind) { 
        if (union==1) {
            scr.append(ind) scr.sort ind.resize(scr.size+ind.size)
            ind.redundout(scr)
          } else {
            mso[key].resize(scr.size+ind.size)
            mso[key].insct(scr,ind) ind.copy(mso[key]) }
      }
    ret=ind.size
    if (selcp) {
        if (ind.size==0) { 
            if (verbose) printf("None selected\n") 
          } else {
            out.ind.copy(ind) 
            aind()
            cob=out
          }
      } else cob=this
    dealloc(key)
    selcp=selcpsav
    slorflag=0
    return ret
  }

//** selall()
proc selall () { local ii
    if (numarg()==2) {
        for ii=0,m-1 out.v[ii].where(v[ii],$s1,$2)
      } else {
        for ii=0,m-1 out.v[ii].where(v[ii],$s1,$2,$3)
      }
    tog("SEL")
  }

//** complement() ind -> !ind
proc complement () { local a,b
    a=b=allocvecs(2) b+=1
    mso[a].indgen(0,size(1)-1,1)
    mso[b].resize(mso[a].size)
    mso[b].cull(mso[a],ind)
    ind.copy(mso[b])
    dealloc(a)
  }

//** delect([NQS])
// move the selected rows from the out db [or other] back to the main db
// the assumption is that you have operated on some of the fields and now want to
//      put the rows back
// ind must not have been altered since it will be used to replace the items
func delect () { local beg,ii,flag
    scr.resize(v.size)
    if (numarg()==1) flag=1 else flag=0
    if (flag) { 
        if (m!=$o1.m){ 
            printf("NQS:delect ERRa m mismatch: %s:%d vs %s:%d\n",this,m,$o1,$o1.m) return -1 }
        ind.copy($o1.ind)
      } else if (!out.ind.eq(ind) || ind.size!=out.v.size) {
        printf("NQS:delect ERR ind size mismatch\n") 
        return -1 
      }
    for (beg=0;beg<m;beg+=11) { // sindx() can only handle 11 vecs at a time
        tmplist.remove_all vlist.remove_all
        for ii=beg,beg+10 if (ii<m) tmplist.append(v[ii])
        for ii=beg,beg+10 if (ii<m) if (flag) { 
            vlist.append($o1.v[ii]) 
          } else {
            vlist.append(out.v[ii]) 
          }
        ind.sindx(tmplist,vlist)
      }      
    cob=this
    return ind.size
  }  
  
//** isvarg() returns number of args an op takes or -1 if not symbolic OP
func isvarg () { local m,op // ADD NEW OPSYM CHECK
    op=$1
    for m=0,5 if (op<=EBE*(m+1) && op>=ALL*(m+1)) { op/=(m+1) break } // m is is field key 1-5
    if (op<ALL) return -1 else if (op<GTH) return 0 else if (op<IBE) { return 1 
      } else if (op<=EBE) return 2 else return -1 
  }

//** fi(STR[,XO]) find the index for a particular string, can set a objref
//  fi(STR,INDEX) return INDEXed value from that vector
//  fi(STR,-1) suppress error message
func fi () { local num,flag,ii,ret,err
    noerr=err=num=flag=0
    if (numarg()==2) if (argtype(2)==2) noerr=1 // use "NOERR" string
    for ii=0,m-1 if (strcmp(s[ii].s,$s1)==0) {flag=1 ret=ii break} // exact match
    if (strcmp($s1,"scr")==0 || strcmp($s1,"SCR_")==0) {flag=1 ret=-2}
    if (strcmp($s1,"IND_")==0) {flag=1 ret=-3}
    if (!flag) for ii=0,m-1 if (strm(s[ii].s,$s1)) { 
        if (num>=1) {
            err=1 printf("NQS fi ERR: regexp matches more than once: %d %s\n",ii,s[ii].s)
          } else {
            num+=1 ret=ii flag=1
          }
      }
    if (err) printf("NQS WARNING; ambiguous regexp; fi() returning pointer for: %d %s\n",ret,s[ret].s)
    if (flag) {
        if (numarg()==2 && noerr==0) { 
            if        (argtype(2)==1) { 
                if (ret==-2) $o2=scr else if (ret==-3) {printf("NQS:fi ERRa copy what?\n") return ret
                  } else $o2=v[ret] 
              } else if (argtype(2)==0) { 
                if ($2<0 || $2>=v[ret].size) { 
                    printf("NQS:fi ERR index out of bounds: %d %d\n",$2,v[ret].size) 
                    return -1
                  }
                if (ret==-2) ret=scr.x[$2] else if (ret==-3) {printf("NQS:fi ERRb what?\n") return ret
                  } else ret=v[ret].x[$2]
              } else                    { printf("NQS:fi WARNING 2nd arg ignored\n") }
          }
        return ret
      } else {
        if (!noerr) printf("NQS.fi() ERR '%s' not found\n",$s1)
        return -1
      }
  }

//** find(STR) find the vector associated with a COL label
obfunc find () { local fl
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    fl=fi($s1)
    if (fl==-2) { return scr 
      } else if (fl==-3) { return ind
      } else return cob.v[fl]
  }

//** set("name",IND,VAL)
proc set () { local fl,ix,i
    if (eqojt(cob,out)) { 
        printf("NQS set() ERR: attempting to set a value in Selected db\n")
        return  }
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    ix=$2 
    if (fl==-1) return
    if (ix<0) ix=v[fl].size+ix
    // 2 LINE 'SET' MACRO
    i=3 // arg 3 will be the value
    if (argtype(i)==0) nval=$i else if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
    v[fl].x[ix]=newval(argtype(i),fl)
  }

//** setcol("name",VEC)
proc setcol () { local fl
    if (eqobj(cob,out) && verbose) { 
        printf("NQS setcol() ERR: attempting to set column in Selected db\n")
        return  }
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    if (fl==-1) return
    if (v[fl].size!=0) {
        printf("NQS setcol() ERR: clear() column before setting\n")
        return  }
    if (numarg()==3) v[fl]=$o2 else v[fl].copy($o2)
  }

//** setcols(VEC1,VEC2,...) -- does either pointer or copy depending on scpflag
// see also resize("NAME",vec, ...) for similar functionality
scpflag=0
proc setcols () { local i,na
    na=numarg()
    if (na==0) { scpflag=1-scpflag
        if (scpflag) printf("setcols() will copy vecs\n") else {
            printf("setcols() will use vec pointers\n") }
        return
      }
    if (m==0) resize(na)
    if (eqobj(cob,out) && verbose) { 
        printf("NQS setcols() ERR: attempting to set column in Selected db\n")
        return  }
    if (na!=m) {
        printf("NQS setcols() ERR: need %d not %d args\n",m,na)
        return  }
    if (scpflag) for i=1,m v[i-1].copy($oi) else for i=1,m v[i-1]=$oi
  }

//** newval(typ,col#) -- check if a value is already on the list and if not put it there
// usuall preceded by eg:
// if (argtype(i)==0) nval=$i else if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
func newval () { local ret,typ,fl,ii
    typ=$1 fl=$2
    if (fcd.x[fl]!=typ && fcd.x[fl]!=-1) { 
        printf("nqs::newval() ERRa %d statt %d\n",typ,fcd.x[fl]) return ERR }
    if (typ==0 || typ==-1) { 
        return nval
      } else if (typ==1) { // object handling
        for (ii=0;ii<fcdo.count;ii+=1) { 
            if (eqojt(fcdo.object(ii),oval)) return ii // obj already on list
          }
        return fcdo.append(oval)-1
      } else if (typ==2) { // string handling
        for (ii=0;ii<fcds.count;ii+=1) { 
            Xo=fcds.object(ii)
            if (strcmp(Xo.s,sval)==0) return ii
          }
        return fcds.append(new String(sval))-1
      }
  }

//*** finval(col#,type,OP) find the location on list for an object or string
func finval () { local fl,typ,op,ii,ret
    fl=$1 typ=$2 op=$3 ret=-1
    if (fcd.x[fl]!=typ) { // doesn't handle fcd.x[]==-1
        printf("nqs::finval ERRa type mismatch; %d %d\n",fcd.x[fl],typ) return ERR }
    for ii=0,fcds.count-1 { Xo=fcds.object(ii)
        if (typ==2) { 
            if (strcmp(Xo.s,sval)==0) return ii
          } else {}
      }
    // if (ret==-1) printf("nqs::finval WARNING %s not found in string or object list\n",sval)
    return ret
  }

//*** rxpstr(col#,vec) find the location on list for an object
func rxpstr () { local fl
    fl=$1 $o3.resize(0)
    if (fcd.x[fl]!=2) {
        printf("nqs::rxpstr ERRa type mismatch; %d %d\n",fcd.x[fl],2) return -1 }
    for ii=0,fcds.count-1 if (strm(fcds.object(ii).s,$s2)) $o3.append(ii)
    return $o3.size
  }

//*** getval(col#,index) return type and value in nval,oval,sval as appropriate
// usually followed by eg
// if (typ==0) ... nval else if (typ==1) ... oval else if (typ==2) ... sval
func getval () { local typ,n,flag,fl,ix,ii
    fl=$1 ix=$2 flag=0
    typ=fcd.x[fl] // argtype
    if (typ==0) { 
        nval=ix
      } else if (typ==10) { 
        if (numarg()==3) nval=uncodf($3,ix) else {scr.resize(5) scr.uncode(ix)}
      } else if (typ==1) { // object handling
        if (ix>fcdo.count-1) {
            printf("nqs::getval() ERR fcdo index OOB %d, %d\n",ix,fcdo.count) return ERR 
          } else if (ix<0) {
            printf("nqs::getval() WARNING empty obj ptr\n\t")
          } else oval = fcdo.object(ix)
      } else if (typ==2) { // string handling
        if (ix==-1) {
            sval="NULL"
          } else if (ix<0 || ix>fcds.count-1) {
            printf("nqs::getval() ERR index OOB %d, %d\n",ix,fcds.count) return ERR 
          } else sval=fcds.object(ix).s
      } else if (typ==-1) { // string from external list
        if (fcdl.count<=fl) {printf("NQS getval ERRa\n") return -1}
        if (! isobj(fcdl.object(fl),"List")) {printf("NQS getval ERRb\n") return -1}
        if (fcdl.object(fl).count<=ix) {printf("NQS getval ERRc\n") return -1}
        if (ix==-1) sval="XX" else {
            if (! isobj (fcdl.object(fl).object(ix),"String")) {printf("NQS getval ERRd\n") return -1}
            sval=fcdl.object(fl).object(ix).s
          }
      }
    return typ
  }

//*** useslist() connects a list of strings to fcdl to use when printing
// fcdl: list of lists to make it easy to attach lists from outside
proc useslist () { local fl,ii
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    if (fl==-1) return
    if (! isobj(fcdl,"List")) {fcdl=new List() out.fcdl=fcdl}
    if (fcdl.count!=m) for ii=fcdl.count,m-1 fcdl.append(fcdl) // use fcdl as placeholder
    fcdl.remove(fl) fcdl.insrt(fl,$o2)  // replace:fcdl.object(fl)=$o2
    fcd.x[fl]=-1
  }

//*** unuselist() connects a list of strings to fcdl to use when printing
// fcdl: list of lists to make it easy to attach lists from outside
proc unuselist () { local fl,ii
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    if (fl==-1) return
    fcd.x[fl]=0
  }

//*** listvecs(LIST) put the vecs in the list for use with eg uncode()
proc listvecs () { local ii
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    if (!isassigned($o1)) $o1=new List()
    $o1.remove_all
    for ii=0,m-1 $o1.append(cob.v[ii])
  }

//*** prtval() use %g or %s to print values
proc prtval () { local i,typ,flag localobj f1
    if (argtype(1)==0) {typ=$1 flag=0 i=2} else {f1=$o1 flag=1 typ=$2 i=3}
    if (typ==0) sstr=dblform else sstr=strform
    if (numarg()==i) { 
        sprint(sstr,"%s%s",sstr,$si)
      } else if (numarg()==i+1) {
        sprint(sstr,"%s%s",$si,sstr) i+=1 sprint(sstr,"%s%s",sstr,$si)
      }
    if (flag) {
             if (typ==0) { f1.printf(sstr,nval)
        } else if (typ==1) { f1.printf(sstr,oval) 
        } else if (typ==2) { f1.printf(sstr,sval) 
        } else if (typ==10) { for ii=0,4 f1.printf("%d ",scr.x[ii])
        } else if (typ==-1) { f1.printf(sstr,sval) } // special code for externally provided list
      } else {
             if (typ==0) { printf(sstr,nval)
        } else if (typ==1) { printf(sstr,oval) 
        } else if (typ==2) { printf(sstr,sval) 
        } else if (typ==10) { for ii=0,4 printf("%d ",scr.x[ii])
        } else if (typ==-1) { printf(sstr,sval) } // special code for externally provided list
      }
  }

//** get("name",[IND]]) if omit IND take ind from first ind.x[0]
obfunc get () { local ty,fl,ix,outf localobj lo
    outf=0
    if (argtype(1)==0) { fl=$1 sstr2=s[fl].s
      } else if (argtype(1)==2) { fl=fi($s1) sstr2=$s1 }
    if (fl==-1) { return -1 }
    if (eqobj(cob,out)) { outf=1 
        if (verbose) printf(" *Selected* ") }
    if (numarg()==1) {
        if (outf) ix=0 else ix=ind.x[0]
      } else ix=$2
    if (ix<0 || ix>=cob.v[fl].size) {
        printf("NQS::get ERR ix %d out of range for %s (%s)\n",ix,sstr2,cob) return -1 }
    ty=fcd.x[fl]
    if (ty==0) lo=new Union(cob.v[fl].x[ix])
    if (ty==1) lo=new Union(fcdo,cob.v[fl].x[ix])
    if (ty==2) lo=new Union(fcds,cob.v[fl].x[ix])
    if (ty==-1) lo=new Union(fcdl.object(fl),cob.v[fl].x[ix])
    return lo
  }

//** fetch(COLA,VAL,COLB) does fast select where COLA is VAL and returns value in COLB
// only works with VAL as number
func fetch () { local fl1,fl2,max,i localobj st
    if (numarg()==3) {
        if (argtype(1)==2) fl1=fi($s1) else fl1=$1
        if (argtype(3)==2) fl2=fi($s3) else fl2=$3
        if ((i=v[fl1].indwhere("==",$2))<0) {
            printf("fetch ERR %d not found in %s\n",$2,s[fl1].s)
            return -1 }
        return v[fl2].x[i]
      } else {
        st=new String("select(")
        for i=1,numarg()-1 {
            if (argtype(i)==0) sprint(st.s,"%s%g,",st.s,$i) else sprint(st.s,"%s\"%s\",",st.s,$si)
          }
        chop(st.s) sprint(st.s,"%s)",st.s)
        execute(st.s,this)
        i=numarg()
        if (argtype(i)==0) fl2=$i else fl2=fi($si)
        if (out.v.size!=1) printf("NQS fetch WARNING -- %d lines found\n",out.v.size)
        if (out.v.size>0) return out.v[fl2].x[0] else return -1
      }
  }

//** stat("COL","operation")
//   stat("COL",VEC) // save into a vector: max,min,mean,sdev
proc stat () { local i,vn
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (numarg()==0) {
        for i=0,m-1 { printf("%s:\t",s[i].s) stat(i) } // recursive call
        return
      }
    if (argtype(1)==0) vn=$1 else vn=fi($s1)
    if (vn<0||vn>=m) return
    i=2
    if (cob.size(1)<2) { printf("NQS:stat small NQS: %d\n",cob.size(1)) return }
    if (vn==-2) {
        sprint(sstr2,"%s",scr) 
      } else if (fcd.x[vn]==10) { 
        scr.resize(cob.v.size)
        field=$i i+=1
        cob.v[vn].uncode(scr,field)
        sprint(sstr2,"%s",scr) 
      } else {
        sprint(sstr2,"%s",cob.v[vn])
      }
    if (numarg()<i) {
        sprint(sstr,   "printf(\"max=%%g; \",%s.max) ",sstr2)
        sprint(sstr,"%s printf(\"min=%%g; \",%s.min) ",sstr,sstr2)
        sprint(sstr,"%s printf(\"mean=%%g; \",%s.mean) ",sstr,sstr2)
        sprint(sstr,"%s printf(\"stdev=%%g; \",%s.stdev) ",sstr,sstr2)    
        execute(sstr)
        print ""
      } else if (argtype(i)==1) { // a vector
        $oi.resize(0)
        $oi.append(cob.v[vn].max,cob.v[vn].min,cob.v[vn].mean,cob.v[vn].stdev)
      } else for (;i<=numarg();i+=1) {
        if (strm($si,"[(][)]$")) {
            sfunc.left($si,sfunc.len($si)-2)
            sprint(sstr,"printf(\"%s()=%%g; \",%s(%s))",$si,$si,sstr2)
          } else sprint(sstr,"printf(\"%s=%%g; \",%s.%s)",$si,sstr2,$si)
        execute(sstr)
        print ""
      }
  }

//** iterator it() iterates over columns
// set's global tstr and XO to string bzw vec
iterator it () { local ii
    i2=0
    for ii=0,m-1 {
        XO=cob.v[ii] execstr=s[ii].s
        iterator_statement
        i2+=1
      }
  }

//** iterator ot() creates names for each col (same as col header) and goes through them all
iterator ot () { local i,na,val
    if (! isobj(otl,"List")) { // create list to execute
        otl=new List()
        for i=0,m-1 { 
            Xo=new String(s[i].s)
            if (fcd.x[i]==2) {
                varstr(Xo.s,1) 
                sprint(Xo.s,"%s=%s.fcds.object(%s.cob.v[%d].x[i2]).s",Xo.s,this,this,i)
              } else {
                varstr(Xo.s) 
                sprint(Xo.s,"%s=%s.cob.v[%d].x[i2]",Xo.s,this,i)
              }
            otl.append(Xo)
          }
        Xo=nil
      }
    for (i2=0;i2<cob.v[0].size;i2+=1) {
        for i=0,m-1 execute(otl.object(i).s)
        iterator_statement
      }
  }

//** iterator qt(&x1,NAME1,&x2,NAME2,...) 
// eg for sp.qt(&x,"PRID",&y,"POID",&z,"NC1",&ii,"WID1",&jj,"WT1") print x,y,z,ii,jj
iterator qt () { local i,ii,na,val
    na=numarg() scr.resize(0)
    if (na/2!=int(na/2)) {print "NQS::qt() needs even # of args\n" return }
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    for (i=2;i<=na;i+=2) { 
        if (argtype(i)!=2) val=$i else val=fi($si)
        scr.append(val) // scr has col #s
        if (val<0 || val>=m) { if (argtype(i)==2) printf("(%s)",$si)
            printf("NQS::qt() ERR %d not found\n",val) return }}
    scr[1].copy(fcd)          // scr[1] gives codes for col's
    for (i=1;i<=na;i+=2) {
        // can't do iteration over externally defined strings (eg -1) see useslist()
        if (scr.x[int(i/2)]<0) continue
        if (scr[1].x[scr.x[int(i/2)]]!=0) { 
            if (argtype(i)==3) {
                printf("NQS::qt() WARNING using list index statt str for col %s\n",s[scr.x[int(i/2)]].s) 
                scr[1].set(scr.x[int(i/2)],0)
              }
          }
        if (scr[1].x[scr.x[int(i/2)]]==2 && argtype(i)!=2) {
            printf("NQS::qt() ERR %s is strdec but arg %d not string\n",s[scr.x[int(i/2)]].s,i) return }
        if (scr[1].x[scr.x[int(i/2)]]==1 && argtype(i)!=1) {
            printf("NQS::qt() ERR %s is odec but arg %d not obj\n",s[scr.x[int(i/2)]].s,i) return }
      }
    for (i2=0;i2<cob.v[0].size;i2+=1) {
        for (i=1;i<=na;i+=2) {
            if (scr.x[int(i/2)]==-3) { // IND_, not doing SCR_ for now
                $&i= cob.ind.x[i2]
              } else if (scr[1].x[scr.x[int(i/2)]]==0) {
                $&i=            cob.v[scr.x[int(i/2)]].x[i2]
              } else if (scr[1].x[scr.x[int(i/2)]]==2) {
                $si=fcds.object(cob.v[scr.x[int(i/2)]].x[i2]).s
              } else if (scr[1].x[scr.x[int(i/2)]]==1) {
                $oi=fcdo.object(cob.v[scr.x[int(i/2)]].x[i2])
              } else {
                printf("NQS qt ERRA: %d %d\n",i,scr.x[int(i/2)])
                continue
              }
          }
        iterator_statement
        for (i=1;i<=na;i+=2) {
            if (scr.x[int(i/2)]==-3) {
                // do nothing -- can't overwrite indices
              } else if (scr[1].x[scr.x[int(i/2)]]==0) {
                cob.v[scr.x[int(i/2)]].x[i2]=$&i
              } else if (scr[1].x[scr.x[int(i/2)]]==2) {
                fcds.object(cob.v[scr.x[int(i/2)]].x[i2]).s=$si
              } else if (scr[1].x[scr.x[int(i/2)]]==1) {
                if (!eqojt(fcdo.object(cob.v[scr.x[int(i/2)]].x[i2]),$oi)) {
                    printf("NQS qt ERRB: can't reassigne obj: %d %s %s\n",\
                           i,fcdo.object(cob.v[scr.x[int(i/2)]].x[i2]),$oi)
                  }
              }
          }
      }
  }

//** calc() spread-sheet functionality using vector functions
// takes a compound expression utilizing column names in slant brackets <>
// anything quoted can use either ' or \"
// eg sp.calc("<DIST>.c.mul(DELD).add(DEL)")
proc calc () { local ii,vn
    if (numarg()==0) { 
        printf("eg calc(\"<SCR>.copy(<COL1>.c.mul(<COL2>).add(5))\") \ntakes a compound expression utilizing column names in slant brackets <>\nanything quoted can use either ' slash quote.\n")
        return 
      } else sstr=$s1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    while (sfunc.tail(sstr,"<",sstr2)!=-1) {
        sfunc.head(sstr2,">",sstr2)
        if (strcmp(sstr2,"SCR")==0) { 
            sprint(sstr3,"%s",cob.scr)
          } else if ((vn=fi(sstr2))==-1) return else {
            sprint(sstr3,"%s",cob.v[vn])      
          }
        sprint(sstr2,"<%s>",sstr2)
        repl_mstr(sstr,sstr2,sstr3,sstr4)
      }
    repl_mstr(sstr,"'","\"",sstr4)
    execute(sstr)
  }

//** sort () sort according to one index
func sort () { local beg,ii,vn
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (argtype(1)==0) vn=$1 else vn=fi($s1)
    if (vn<0||vn>=m) return -1
    cob.v[vn].sortindex(cob.ind)
    if (numarg()==2) if ($2==-1) cob.ind.reverse
    fewind()
    return vn
  }  

//** percl ("FIELD",n %ile) check whether the first n% of the vector are in the top n %ile
// usage -- reverse sort according to 1 field and then ask if other field is in top n %ile
func percl () { local beg,ii,vn,nile,sz
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (argtype(1)==0) vn=$1 else vn=fi($s1)
    if (vn<0||vn>=m) return -1
    sz=cob.v[vn].size
    nile=int($2*sz/100)
    scr[1].copy(cob.v[vn]) scr[1].sort() scr.resize(0) scr.copy(scr[1],sz-nile-1,sz-1)
    scr.reverse() // the top n-ile percentile
    scr[2].resize(0) scr[2].copy(cob.v[vn],0,nile) // the first set of values from NQS
    // scr[1].insct(scr,scr[2])    // find all common values
    for ii=0,scr[2].size-1 if (scr.contains(scr[2].x[ii])) return ii // which one is top of scr[2]
    return -1
  }  

// family("COLA",val,"COLB","COLC")
// pick out rows that have are same as row with "COLA" val except that COLB COLC
//  etc. can be anything
func family () { local a,i,ii,vn,va,nile,sz,om localobj key,arg
    tog("DB") // start at full db
    a=allocvecs(key,arg)
    sz=size(1)
    tmplist.remove_all arg.resize(0) key.resize(0)
    if (select(-1,$s1,$2)!=1) printf("WARNING: NQS family found more than 1 %s=%g\n",$s1,$2)
    va=fi($s1)
    scr.resize(0) scr.append(va)
    for i=3,numarg() scr.append(fi($si))
    for i=0,m-1 if (! scr.contains(i)) {
        tmplist.append(v[i])
        key.append(EQU) 
        arg.append(v[i].x[ind.x[0]],0)
      }
    ind.resize(v.size)
    ind.slct(key,arg,tmplist) // run select function
    if (ind.size>0) {
        out.ind.copy(ind) 
        aind()
        cob=out
      } else if (verbose) printf("None selected\n") 
    dealloc(a)
    return ind.size
  }  

// psel(%ile,"COLA","COLB","COLC")
// psel("COLA",%ileA,"COLB",%ileB,"COLC",%ileC)
// neg %ile means bottom -- eg 10 is largest 10% and -10 is smallest 10%
// return top percentile in these columns
func psel () { local a,i,ii,vn,nile,sz,om localobj key,arg
    tog("DB") // start at full db
    a=allocvecs(key,arg)
    om=numarg()-1
    sz=size(1)
    tmplist.remove_all arg.resize(0) key.resize(0)
    if (argtype(1)==0) {
        if (int($1*sz/100)==0) { printf("NQS psel(): ERROR: unable %d%% of %d\n",$1,sz)
            return -1 }
        key.resize(om)
        if ($1>0) { 
            nile=sz-int($1*sz/100) 
            key.fill(GTE) 
          } else { 
            nile=-int($1*sz/100)
            key.fill(LTE) 
          }
        for i=2,numarg() { 
            if (argtype(i)==0) vn=$i else vn=fi($si)
            if (vn<0||vn>=m) return -1
            tmplist.append(v[vn])
            scr[1].copy(v[vn])
            scr[1].sort()
            arg.append(scr[1].x[nile],0) // 2nd arg for GTE ignored
            printf("%s:%g ",$si,scr[1].x[nile])
          }
      } else for i=1,numarg() { 
        tstr=$si
        vn=fi($si)      i+=1
        if (int($i*sz/100)==0) { printf("NQS psel(): WARNING: ignoring %d%% of %d\n",$i,sz)
            continue }
        if (vn<0||vn>=m) return -1
        tmplist.append(v[vn])
        scr[1].copy(v[vn])
        scr[1].sort()
        if ($i>0) { 
            nile=sz-int($i*sz/100) 
            key.append(GTE) 
          } else { 
            nile=-int($i*sz/100)
            key.append(LTE) 
          }
        arg.append(scr[1].x[nile],0) // 2nd arg for GTE ignored
        printf("%s:%g ",tstr,scr[1].x[nile])
      }
    ind.resize(v.size)
    ind.slct(key,arg,tmplist) // run select function
    if (ind.size>0) {
        out.ind.copy(ind) 
        aind()
        cob=out
      } else if (verbose) printf("None selected\n") 
    print ""
    dealloc(a)
    return ind.size
  }  

//** uniq(COLNAME) will pick out unique row (1st) for the chosen column
func uniq () { local vn
    if (! eqobj(cob,out)) {printf("Only run NQS:uniq() on prior selected set.\n") return -1}
    vn=sort($s1)
    cob.ind.resize(cob.v.size)
    cob.ind.redundout(cob.v[vn],1)
    fewind()
    return vn
  }

//** elimrepeats(COLA[,COLB,...])
func elimrepeats () { local a,b,i,ii,indflag localobj sl,tl,v1
    if (eqobj(cob,out)) {printf("NQS ERR: run elimrepeats on full db\n")  return 0.}
    if (size(1)==0) { print "NQS:elimirepeats Empty NQS" return 0.}
    a=allocvecs(v1) b=1 indflag=0
    sl=new List() tl=new List()
    if (numarg()==0) {
        for ii=0,m-1 { sl.append(v[ii]) v1.append(ii) }
        b=numarg()+1
      } else if (argtype(1)==0) if ($1==-1) {b=2 indflag=1}
    for i=b,numarg() {
        if ((ii=fi($si))==-1) return 0 else {
            sl.append(v[ii])
            v1.append(ii)
          }
      }
    for ii=0,m-1 if (!v1.contains(ii)) tl.append(v[ii])
    for (ii=v1.size-1;ii>=0;ii-=1) sort(v1.x[ii]) // sort them in the reverse order of calling
    ii=ind.mredundout(sl,indflag,tl)
    dealloc(a)
    return ii
  }

//** shuffle()
proc shuffle () { local a,b,i,ii,indflag localobj sl,tl,v1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    if (size(1)==0) { print "NQS:shuffle Empty NQS" return}
    rdmord(ind,cob.v.size)
    fewind()
  }

//** fewind () -- index all of the vecs in place using fewing
proc fewind () {
    cob.scr.resize(cob.v.size)
    for (beg=0;beg<m;beg+=10) { // fewind() can only handle 10 vecs at a time
        tmplist.remove_all
        for ii=beg,beg+9 if (ii<m) tmplist.append(cob.v[ii])
        cob.scr.fewind(cob.ind,tmplist)
      }      
    cob.ind.resize(0) // prevents reusing it
  }

//** aind () -- index all of the vecs into out list
proc aind () { local beg,ii
    for (beg=0;beg<m;beg+=10) {
        tmplist.remove_all vlist.remove_all
        for ii=beg,beg+10 if (ii<m) {
            out.v[ii].resize(ind.size)
            tmplist.append(v[ii])
            vlist.append(out.v[ii])
          }
        ind.findx(tmplist,vlist)
      }      
  }  

//** append(VEC[,begin]) appends to ends of given vectors
// append(x1,x2,...); append(NQS)
proc append () { local ii,i,flag,begin
    cob=this
    if (argtype(1)==1) {
        if (isobj($o1,"Vector")) { // a vector
            if (numarg()>1) begin=$2 else begin=0
            if (begin+$o1.size>m) { 
                printf("NQS append ERR1: vec %s too large; doing nothing: %d>%d",$o1,begin+$o1.size,m)
              } else {
                for i=begin,begin+$o1.size-1 v[i].append($o1.x[i-begin])
              }
          } else if (isobj($o1,"NQS")) { // another NQS to add onto end
            if ($o1.m != m) { 
                printf("NQS append ERR1a, %s size (%d)!= %s size (%d)?\n",this,m,$o1,$o1.m)
                return }
            for ii=0,m-1 v[ii].append($o1.v[ii])
            ind.append($o1.ind)
          } else { printf("NQS append ERR1b, what is %s?\n",$o1) }
        return
      }
    if (argtype(1)==2) if ((ii=fi($s1,"NOERR"))!=-1) { // a field name
        for i=1,numarg() { 
            if ((ii=fi($si))==-1) return  
            i+=1 
            if (argtype(i)==0) nval=$i else if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
            v[ii].append(newval(argtype(i),ii))
          }
        return
      }
    if (numarg()>m) { print "NQS append ERR2: args>m; doing nothing" return }
    if (numarg()<=m) {
        if (numarg()<m) printf("NQS::append() WARNING only filling %d/%d cols for %s\n\tuse NQS.pad",numarg(),m,this)
        for ii=0,numarg()-1 {
            i=ii+1
            if (argtype(i)==0) nval=$i else if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
            v[ii].append(newval(argtype(i),ii))
          }
        return
      }
  }

//** appi(index,VEC) or append(index,x1,x2,...) appends to ends of vectors starting at index
proc appi () { local i,ix
    cob=this ix=$1
    if (numarg()==2 && argtype(2)==1) { // a vector
        if ($o2.size>m-ix) { print "NQS appi ERR1: vec too large; doing nothing\t"
          } else {
            for i=ix,$o2.size-1 v[i].append($o2.x[i])
          }
      } else {
        if (numarg()-1>m-ix) {
            print "NQS appi ERR2: args>m; doing nothing"
            return
          } 
        for i=2,numarg() {
            if (argtype(i)==0) nval=$i else if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
            v[ix+i-2].append(newval(argtype(i),ix+i-2))
          }
      }
  }

//** map(FUNC,arg1,...) map $s1 command to other args, replacing strings with vectors as found
// eg nqs.map("gg",0,"volt","cai",2)
proc map () { local i,agt,wf
    if (numarg()==0) { 
        printf("map(FUNC,arg1,...) apply function to args using names for columns.\n")
        return }
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    sprint(sstr,"%s(",$s1) // the command
    wf=0
    for i=2,numarg() { // the args
        agt=argtype(i)
        if (agt==0) {
            sprint(sstr,"%s%g,",sstr,$i)
          } else if (agt==1) {
            sprint(sstr,"%s%s,",sstr,$oi)
          } else if (agt==2) {
            if ((vn=fi($si))==-1) {
                sprint(sstr,"%s\"%s\",",sstr,$si) 
                printf("NQS.map WARNING: including raw string: %s\n",$si) wf=1
              } else if (vn==-2) { // code for scr vector
                sprint(sstr,"%s%s,",sstr,cob.scr) 
              } else {
                sprint(sstr,"%s%s,",sstr,cob.v[vn]) 
              }
          } else { printf("argtype %d for arg %d not implemented for NQS:map\n",agt,i) return }
      }
    chop(sstr) sprint(sstr,"%s)",sstr)
    if (wf && !batch_flag) if (boolean_dialog(sstr,"CANCEL","EXECUTE")) return
    execute(sstr)
  }

//*** gr() use map to graph
// need to assign .crosshair_action so can do visual select procedure
proc gr () { local i,nm,gn,col,lne,f3d,y,x,done localobj symb
    nm=numarg() gn=0 f3d=-1
    gvmarkflag=col=2 lne=4
    done=0
    symb=new String()
  
    if (nm==0) { print "gr(\"Y\"[,\"X\",Z,g#,col,line])" return
      } else if (nm==1) {  map("gg",0,$s1,1,col,lne)               done=1
      } else if (nm==2) {  map("gg",0,$s1,$s2,col,lne)             done=1 }
    i=3
    if (! done)  {
        if (argtype(i)==2) f3d=fi($si) else i-=1
        i+=1 if (i<=nm) gn=$i 
        i+=1 if (i<=nm) col=$i 
        i+=1 if (i<=nm) lne=$i 
        if (f3d!=-1) {
            if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
            if (!gvmarkflag) {printf("NQS gr ERR: 3D and gvmarkflag=0\n") return}
            y=fi($s1) x=fi($s2)
            if (lne==1) lne=2 else lne-=2 // will augment below
            if (x==-1 || y==-1) {printf("NQS gr ERR: %s,%s not fi()\n",$s1,$s2) return}
            for i=0,cob.v.size-1 {
                if (i%9==0) lne+=2
                g[gn].mark(cob.v[x].x[i],cob.v[y].x[i],"o",lne,cob.v[f3d].x[i]%9+1,4)
              }
          } else map("gg",gn,$s1,$s2,col,lne)
      }
    g[gn].color(col)
    g[gn].label(0.05,0.95,$s1)
    if (nm>=2) g[gn].label(0.85,0.05,$s2)
    g[gn].color(1)
    setgrsel(g[gn],fi($s1),fi($s2))
    setchsel(g[gn],fi($s1),fi($s2))
  }

//** grsel(): CTL-hit == Crosshair
//            SHT-hit == resize
//            hit-drag-release == show in square
//            SHT-hit-drag-release == show new thing there
// Type: press (2), drag (1), release (3)
// Keystate: META-SHT-CTL eg 101=5 is META-CTL
proc setgrsel () {
    $o1.menu_remove("Selector")
    sprint(tstr,"proc p(){grsel($1,$2,$3,$4,%d,%d)}",$2,$3)
    execute1(tstr,this)
    $o1.menu_tool("Selector", "p")
  }

proc setchsel () {
    sprint(tstr,"proc q(){chsel($1,$2,$3,%d,%d)}",$2,$3)
    execute1(tstr,this)
    $o1.crosshair_action("q")
  }

grsbegx=grsbegy=1e9
proc grsel () { local type, x0, y0, keystate, fl1,fl2,sel
    type=$1 x0=$2 y0=$3 keystate=$4 fl1=$5 fl2=$6
    if (type==3) {
        if (grsbegx==1e9) { // no drag was done
            if ((sel=select(fl2,"~",x0,fl1,"~",y0))!=0) {
                pr()
              } else print "Can't find ",s[fl2].s,"~ ",x0,s[fl1].s,"~ ",y0
          } else { // consider a rectangle
            order(&grsbegx,&x0) order(&grsbegy,&y0)
            if ((sel=select(fl2,"[]",grsbegx,x0,fl1,"[]",grsbegy,y0))!=0) {
                if (keystate==0) { grsel2() 
                  } else if (keystate==3) {  // CTL or SHIFT alone are being used by fvwm2
                    pr() // print grsbegx,x0,grsbegy,y0
                  }
              } else printf("Can't find %s %g-%g; %s %g-%g\n",s[fl2].s,grsbegx,x0,s[fl1].s,grsbegy,y0)
            grsbegx=grsbegy=1e9
          }
      } else if (type==1 && grsbegx==1e9) {grsbegx=x0 grsbegy=y0 }
  }

// order(&x,&y) returns the values in order
proc order () { local tmp
    if ($&2<$&1) { tmp=$&2 $&2=$&1 $&1=tmp }
  }

proc chsel () { local ascii, x0, y0,  fl1,fl2,sel
    x0=$1 y0=$2 ascii=$3 fl1=$4 fl2=$5
    if ((sel=select(fl2,"~",x0,fl1,"~",y0))!=0) {
        if (ascii==32) { chsel2()
          } else pr()
      } else print "Can't find ",s[fl2].s,"~ ",x0,s[fl1].s,"~ ",y0
  }

//** apply function or .op to every selected vector -- ignore return val, see applf
proc apply () { local i,fl
    if (numarg()==0) { 
        printf("apply(FUNC,COL1,...) apply function or .op to every selected vector.\n")
        printf("must be function, not proc, since will return value.\n")
        return }
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (numarg()==1) for i=0,m-1 { // apply to all vectors
        if (strm($s1,"^\\.")) sprint(sstr,"%s%s"  ,cob.v[i],$s1) else {
                                sprint(sstr,"%s(%s)",$s1,cob.v[i]) }
        execute(sstr)
      } else for i=2,numarg() {
        if ((fl=fi($si))==-1) return
        if (strm($s1,"^\\.")) sprint(sstr,"%s%s"  ,cob.v[fl],$s1) else {
                                sprint(sstr,"%s(%s)",$s1,cob.v[fl]) }
        execute(sstr)
      }
  }

//** applf(FUNC,COL) function or .op which returns a value
func applf () { local a,fl,ret localobj v1
    if (numarg()==0) { 
        printf("applf(FUNC,COLNAME) apply function or .op to selected vector.\n")
        printf("must be function, not proc, since will return value.\n")
        return -1 }
    a=allocvecs(v1)
    v1.resize(1)
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    if (argtype(2)==2) {
        if ((fl=fi($s2))==-1) return -1
      } else fl=$2
    if (strm($s1,"^\\.")) sprint(sstr,"%s.x[0]=%s%s"  ,v1,cob.v[fl],$s1) else {
                            sprint(sstr,"%s.x[0]=%s(%s)",v1,$s1,cob.v[fl]) }
    execute(sstr)
    ret=v1.x[0]
    dealloc(a)
    return ret
  }

//** fill(NAME,val[,NAME1,val1 ...])
// fill each selected vector with next arg
func fill () { local i,fl,fl2,x
    if (numarg()==0) { 
        printf("fill(NAME,val[,NAME1,val1 ...])\n\tfill each selected vector with val\nval can be num, vector, or other col name\n")
        return -1}
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    for i=1,numarg() { 
        fl=fi($si) i+=1
        if (fl==-1) return -1
        field=0
        if (fcd.x[fl]==10) { // code field
            field=$i i+=1
          }
        if (argtype(i)==0) {
            if (field>0) cob.v[fl].uncode(field,$i) else cob.v[fl].fill($i)
          } else if (argtype(i)==1) {
            if (!isobj($oi,"Vector")){
                printf("NQS:fill() ERRa: only fill with vector: %s\n",$oi) return -1}
            if ($oi.size!=cob.v.size){
                printf("NQS:fill() ERRb: wrong vec size: %d!=%s:%d\n",cob.v.size,$oi,$oi.size) return -1}
            if (field>0) cob.v[fl].uncode(field,$oi) else cob.v[fl].copy($oi)
          } else if (argtype(i)==2) {
            fl2=fi($si,"NOERR")
            if (fl2== -1) { // add this string to this field?
                if (fcd.x[fl]==2) {
                    sval=$si
                    x=newval(2,fl)
                    cob.v[fl].fill(x)
                  } else {
                    printf("NQS:fill() ERRc: trying to fill field %s with string %s\n",s[fl].s,$si)
                    return -1
                  }
              } else if (field>0) {
                     cob.v[fl].uncode(field,cob.v[fl2]) 
              } else cob.v[fl].copy(cob.v[fl2])
            i+=1
          }
      }
    return cob.v[fl].size
  }

//** fillin(NAME,val[,NAME1,val1 ...])
// fill in place according to indices in ind -- use with selcp=0
proc fillin () { local i,fl
    if (numarg()==0) { 
        printf("fillin(NAME,val[,NAME1,val1 ...])\n\tfill selected vectors in place\n")
        printf("\tuse after select(-1,...) eg selcp==0\n")
        return 
      }
    scr.resize(0)
    for (i=2;i<=numarg();i+=2) scr.append($i)
    tmplist.remove_all
    for (i=1;i<=numarg();i+=2) {
        if (argtype(i)==2) { 
            if ((fl=fi($si))==-1) return
          } else fl=$i
        tmplist.append(v[fl])
      }
    ind.sindv(tmplist,scr)
  }

//** fillv(NAME,v1[,NAME1,v2 ...])
// fill from vectors v1,v2,..., places in ind -- use with selcp=0
proc fillv () { local i,fl
    if (numarg()==0) { 
        printf("fillv(NAME,vec1[,NAME1,vec2 ...])\n\tfill selected vectors from vectors\n")
        printf("\tuse after select() with selcp==0\n")
        return 
      }
    tmplist.remove_all vlist.remove_all
    for (i=1;i<=numarg();i+=2) {
        if (argtype(i)==2) { 
            if ((fl=fi($si))==-1) return
          } else fl=$i
        tmplist.append(v[fl])
      }
    for (i=2;i<=numarg();i+=2) vlist.append($oi)
    ind.sindx(tmplist,vlist)
  }

//** pr() print out vectors
// eg pr("COLA","COLB",3,7)
func pr () { local ii,i,min,max,na,flag,jj,e,fout
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (m==0) {print "EMPTY" return 0}
    flag=min=0 max=cob.v.size-1 na=numarg()
    if (na>=2) { 
        if (argtype(na-1)==0) { 
            i=na na-=2
            max=$i i-=1 min=$i 
            flag=1 // took care of numbers
          }} 
    if (!flag && na>=1) { 
        if (argtype(na)==0) { 
            i=na na-=1
            if ($i>=0) max=$i else min=max+$i // allow printing the end
          }
      } 
    // reuse flag -- means printing only certain cols
    fout=flag=0 i=1 // fout==1 means print out to file
    if (na>=1) if (argtype(1)==2) if (fi($s1,"NOERR")==-1) { // call it a file name
        if (!tmpfile.wopen($s1)) printf("Can't open %s for printing\n",$s1)
        fout=1 i+=1
      }
    if (na>=i) if (argtype(i)==2 || argtype(i)==1) flag=1 // column names
    if (max>size(1)){ max=size(1)-1
        printf("NQS:pr WARNING: %d rows requested but %s size=%d\n",max,this,size(1)) }
    if (min>size(1)){printf("NQS:pr ERROR: %s size=%d < min %d\n",this,size(1),min) return 0}
    if (!fout) print ""
    if (flag) {
        scr[1].resize(0)
        if (argtype(i)==1) scr[1].copy($oi) else for (;i<=na;i+=1) scr[1].append(fi($si)) 
        for i=0,scr[1].size-1 {
            ii=scr[1].x[i]
            if (ii==-1) return -1
            if (fout) {
                if (ii<0) tmpfile.printf("is[-ii].s\t") else tmpfile.printf("%s(%d)\t",s[ii].s,ii)
              } else {
                if (ii<0) printf("is[-ii].s\t") else printf("%s(%d)\t",s[ii].s,ii)
              }
          }
        if (fout) tmpfile.printf("\n") else print ""
        for jj=min,max {
            for i=0,scr[1].size-1 { ii=scr[1].x[i]
                if (ii==-2) { printf("%g\t",cob.scr.x[jj]) 
                  } else if (ii==-3) { 
                    if (fout) tmpfile.printf("%g\t",cob.ind.x[jj]) else printf("%g\t",cob.ind.x[jj])
                  } else {
                    if (fout) prtval(tmpfile,(e=getval(ii,cob.v[ii].x[jj])),"\t") else {         
                                prtval(        (e=getval(ii,cob.v[ii].x[jj])),"\t") }
                    if (e==ERR) return ERR
                  }
              }
            if (fout) tmpfile.printf("\n") else print ""
          }
      } else {
        if (fout) for ii=0,m-1 tmpfile.printf("%4.4s  ",s[ii].s) else {
                   for ii=0,m-1 printf("%4.4s  ",s[ii].s)}
        if (fout) tmpfile.printf("\n") else print ""
        for jj=min,max {
            for ii=0,m-1 { 
                if (fout) prtval(tmpfile,e=getval(ii,cob.v[ii].x[jj]),"  ") else {
                            prtval(        e=getval(ii,cob.v[ii].x[jj]),"  ") }
                if (e==ERR) return  ERR
              }
            if (fout) tmpfile.printf("\n") else print ""
          }
      }
    if (fout) tmpfile.close
    return max-min+1
  }

//** prn() print out single index from vectors
proc prn () { local jj,ii,ix,max,e
    ix=$1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (numarg()==2) max=$2 else max=ix
    for jj=ix,max {
        if (jj<0 || jj>=cob.v[0].size) { 
            printf("prn: Index out of range (%d)\n",cob.v[0].size) return }
        for ii=0,m-1 {
            printf("%s:",s[ii].s)
            prtval(e=getval(ii,cob.v[ii].x[jj])," ")
            if (e==ERR) return
          }
        print ""
      }
  }

//** zvec() -- clear -- resize all the vectors to 0
proc clear () { if (numarg()==1) zvec($1) else zvec() }
proc zvec () { local ii
    cob=this
    // fcds.remove_all fcds.append(new String("`EMPTY'"))
    if (isassigned(fcdo)) fcdo.remove_all
    for ii=0,m-1 { 
        if (numarg()==1) { v[ii].resize($1) v[ii].fill(0) }// resize the buffer if desirable
        v[ii].resize(0) 
      }
  }

//** pad() -- bring all vectors up to same length (of v[0])
func pad () { local sz,ii
    cob=this
    sz=-1
    if (numarg()==1) sz=$1 else for ii=0,m-1 if (v[ii].size>sz) sz=v[ii].size
    for ii=0,m-1 { 
        // if (v[ii].size>sz) printf("NQS.pad WARNING: neg padding %d\n",ii)
        v[ii].resize(sz)
      }
    return sz
  }

//** size() -- return num of vectors and size of each vector
func size () { local ii,sz
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (numarg()==1) {
        sz=cob.v.size // with 1 arg don't print anything
        for ii=1,m-1 if (cob.v[ii].size!=sz) {
            printf("NQS size ERR: cols are not same length: %s:%d %d\n",s[ii].s,cob.v[ii].size,sz) 
            sz=-1 } // generate err
        return sz
      }
    if (m==0) { print "0 x 0" return 0 } // empty
    printf("%d x %d",m,cob.v.size)
    for ii=1,m-1 printf(",%d",cob.v[ii].size)
    print ""
    return cob.v.size
  }

//** resize(#cols[,#rows]) -- augment or dec the number of vectors
// resize("LABEL1","LABEL2",...)
// resize("LABEL1",VEC1,"LABEL2",VEC2) ... put on some vecs of same size
func resize () { local oldsz,newsz,i,ii,jj,vsz,na,appfl
    na=numarg()
    vsz=-1
    if (na==1) { 
        if        (argtype(1)==0) { newsz=$1 appfl=0 
          } else if (argtype(1)==2) { newsz=m+1 appfl=2 }
      } else {
        if (argtype(1)==0 && argtype(2)==0) { 
            newsz=$1 appfl=0 
            vsz=$2
          } else if (argtype(1)==2 && argtype(2)==2) { 
            newsz=m+na appfl=2
          } else {
            if (int(na/2)!=na/2) { print "NQS Resize ERR: require even # of args"  return -1}
            newsz=m+numarg()/2
            appfl=1
          }
      }
    oldsz=m
    if (m==newsz) { printf("No resize -- same size: %s\n",this) 
        return m
      } else if (newsz>m) {
        tmplist.remove_all vlist.remove_all
        for ii=0,m-1 { 
            tmplist.append(v[ii]) tmplist.append(s[ii]) 
            tmplist.append(out.v[ii])
          }
        objref v[newsz],s[newsz]
        if (isassigned(out)) out.resize2(newsz) // create vectors for .out
        jj=-1
        for ii=0,m-1 { 
            v[ii]=tmplist.object(jj+=1) out.s[ii]=s[ii]=tmplist.object(jj+=1) 
            out.v[ii]=tmplist.object(jj+=1)
          }
        for ii=m,newsz-1 { 
            v[ii]=new Vector() out.s[ii]=s[ii]=new String() 
            out.v[ii]=new Vector()
          }
        out.m=m=newsz
        tmplist.remove_all
      } else {
        for (ii=m-1;ii>=newsz;ii-=1) { out.v[ii]=v[ii]=nil out.s[ii]=s[ii]=nil }
        out.m=m=newsz
      }
    x.resize(m) x.fill(0) fcd.resize(m)
    out.x.resize(m) out.x.fill(0) out.fcd=fcd
    if (vsz>=1) for ii=0,m-1 v[ii].resize(vsz)
    if (appfl==1) { // append
        for (ii=1;ii<=na;ii+=2) { i=ii
            if (argtype(i)!=2) { printf("NQS RESIZE ERR: arg %d should be str\n",i) return -1}
            s[oldsz+(ii-1)/2].s=$si  i+=1
            if (argtype(i)==0) { 
                if ($i>0) v[oldsz+(ii-1)/2].resize($i)
              } else if (argtype(i)==1) { 
                v[oldsz+(ii-1)/2].copy($oi)
              } else {  printf("NQS RESIZE ERR2: arg %d should be num or obj\n",i) return -1}
          }
      } else if (appfl==2) { 
        for (i=1;i<=na;i+=1) {
            if (argtype(i)!=2) { printf("NQS RESIZE ERR3: arg %d should be str\n",i) return -1}
            s[oldsz+i-1].s=$si
          }
      }
    cob=this
    return m
  }

// for resizing the vector for .out
proc resize2 () { local newsz
    newsz=$1
    objref v[newsz],s[newsz]
  }

// grow(NQS) append NQS of same size to this one
func grow () { local ii
    if (m==0) { cp($o1)
      } else if (m!=$o1.m) { printf("%s,%s off different size: %d %d\n",this,$o1,m,$o1.m) return 0 
      } else if (eqobj(cob,out)) {printf("NQS ERR: run grow on full db\n")  return 0.
      } else for ii=0,m-1 v[ii].append($o1.v[ii])
    return v.size
  }

//** keepcols("LABEL1",...)
func keepcols () { local i,fl
    scr.resize(0)
    for i=1,numarg() {
        if (argtype(i)==2) { 
            if ((fl=fi($si))==-1) return -1 
          } else fl=$i
        scr.append(fl)
      }
    for (i=m-1;i>=0;i-=1) if (! scr.contains(i)) delcol(i)
    return m
  }

//** delcols("LABEL1",...)
func delcols () { local i,fl
    scr.resize(0)
    for i=1,numarg() {
        if (argtype(i)==2) { 
            if ((fl=fi($si))==-1) return -1 
          } else fl=$i
        scr.append(fl)
      }
    for (i=m-1;i>=0;i-=1) if (scr.contains(i)) delcol(i)
    return m
  }

//** delcol("LABEL1")
func delcol () { local oldsz,ii
    tog("DB") // start at full db
    if (argtype(1)==2) { 
        if ((fl=fi($s1))==-1) return -1
      } else fl=$1
    for (ii=fl;ii<m-1;ii+=1) { 
        v[ii]=v[ii+1] s[ii]=s[ii+1] 
        out.s[ii]=s[ii+1] 
      }
    v[m-1]=nil s[m-1]=nil 
    out.v[m-1]=nil out.s[m-1]=nil 
    x.remove(fl) fcd.remove(fl)
    if (isobj(fcdl,"List")) fcdl.remove(fl)
    m -= 1
    out.m=m
    return m
  }

//** delrow(#)
func delrow () { local ii,jj,kk
    if (numarg()==1) {
        if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
        kk=$1
        if (kk<0 || kk>=cob.v.size) {printf("delrow %d OOR (%d)\n",kk,cob.v.size-1) return -1}
        for ii=0,m-1 cob.v[ii].remove(kk)
      } else { // remove selected
        tog("DB")
        if (ind.size>1) {
            sprint(sstr,"Remove %d rows from main table?",ind.size)
            if (!boolean_dialog(sstr,"OK","Cancel")) { print "Cancelled" return -1 }
          }
        for ii=0,m-1 for (jj=ind.size-1;jj>=0;jj-=1) { kk=ind.x[jj]
            v[ii].remove(kk)
          }
      }
    return v.size
  }

//** getrow(#,VEC)
obfunc getrow () { local ii localobj v1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (numarg()==2) v1=$o2 else v1=new Vector()
    v1.resize(0)
    for (ii=0;ii<m;ii+=1) v1.append(cob.v[ii].x[$1])
    return v1
  }

//** getcol("name"[,VEC]) -- returns copy 
// getcol("name",flag) -- returns pointer
obfunc getcol () { local fl localobj v1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    if (fl==-1) return
    if (numarg()<2) { // default returns copy 
        v1=new Vector()
        v1.copy(cob.v[fl])
        return v1
      } else if (argtype(2)==1) { // copy into a preexisting vector
        $o2.copy(cob.v[fl])
        return $o2
      } else {
        return cob.v[fl]   // return pointer
      }
  }

//** renamecol("LABEL1","NEWNAME") -- rename column
func renamecol () { local oldsz
    if (argtype(1)==2) { 
        if ((fl=fi($s1))==-1) return
      } else fl=$1
    s[fl].s=$s2
    out.s[fl].s=$s2
    return 1
  }

//** sv(FNAME[,APPEND]) save the NQS
// to sv selected -- NQS.select(...) NQS.cp(NQS.out,1) NQS.sv()
proc sv () { local i,j,cd1,vers,a,aflag
    file=$s1
    aflag=cd1=0 // flags cd1=1 -- no single value vec compression;
    a=allocvecs(1)
    if (numarg()>=2) aflag=$2
    if (numarg()>=3) cd1=$3 // 1:flag for not compressing
    if (aflag) { tmpfile.aopen(file)
      } else {
        if (tmpfile.ropen(file)) {
            if (batch_flag) {
                printf("NQS sv WARNING overwriting %s\n",file)
              } else if (!boolean_dialog("File exists","Overwrite","Cancel")) { 
                  print "Cancelled" return
              }
          }
        if (! tmpfile.wopen(file)) { printf("NQSsvERR: can't open file\n") return }
      }
    mso[a].resize(m) mso[a].fill(0)
    if (cd1==0) for i=0,m-1 if (v[i].ismono(0)) { // will be saved without full vectors
        cd1=2 // 2 flag for using compression
        mso[a].x[i]=1
      }
    if (isassigned(fcdo)) foc=fcdo.count else foc=-1
    // only save an object list if all of the objects are vecs
    for i=0,foc-1 if (!isojt(fcdo.object(i),v)) {foc=0 break} 
    if (isassigned(fcdo)) if (fcdo.count>0 && foc==0) {
        printf("NQS:sv() WARNING: Can't save objlist for %s (eg %s)\n",this,fcdo.object(0))
      }
    vers=version(1) // will assist for identifying file type if change format in future
    savenums(m,fcds.count,(cnt=fcd.count(-1)),foc,size(1),cd1,vers,0,0) // extra for codes
    wrvstr(file) wrvstr(comment)
    for i=0,m-1 wrvstr(s[i].s)
    fcd.vwrite(tmpfile)
    for i=0,fcds.count-1 wrvstr(fcds.object(i).s)
    for i=0,foc-1 if (isojt(fcdo.object(i),v)) fcdo.object(i).vwrite(tmpfile,3)
    if (cnt>0) for i=0,fcd.size-1 if (fcd.x[i]==-1) { 
        savenums(fcdl.object(i).count)
        for j=0,fcdl.object(i).count-1 wrvstr(fcdl.object(i).object(j).s)
      }
    for i=0,m-1 {
        if (cd1==2 && mso[a].x[i]==1) {
            savenums(-1e9,v[i].size,v[i].x[0])
          } else if (fcd.x[i]==10) {
            v[i].vwrite(tmpfile,4) // must save CODE fully
          } else {
            v[i].vwrite(tmpfile,svsetting)
          }
      }
    x.vwrite(tmpfile)
    tmpfile.close
    dealloc(a)
  }

//** rd(FNAME[,FLAG]) read format saved by sv()
// flag==2 - only read header
func rd () { local n,hflag,cd1,cd3,cd4,ii
    hflag=0
    if (numarg()>=1) if (argtype(1)==2) {
        if (!tmpfile.ropen($s1)) { printf("NQSrdERR: can't open file\n") return 0 }
      } // else continue reading from current point in file
    if (numarg()>=2) hflag=$2 // only read header 
    cnt=fc=foc=0 
    // backward compatible -- if only 2 vals then cnt=0, cd1-4 unused at present
    n=readnums(&ii,&fc,&cnt,&foc,&v0sz,&cd1,&svvers,&cd3,&cd4)
    if (n<9) v0sz=cd1=svvers=cd3=cd4=-1
    if (cd1==2 && hflag==1) printf("NQSrdWARN0: can't do partial reads on compressed\n")
    if (ii!=m) resize(ii)
    rdvstr(file) rdvstr(comment)
    if (sfunc.len(file)==0) file=$s1
    for i=0,m-1 rdvstr(s[i].s)
    fcd.vread(tmpfile)
    fcds.remove_all
    if (isassigned(fcdl)) fcdl.remove_all
    for i=0,fc-1 {  fcds.append(Xo=new String()) rdvstr(Xo.s) }
    if (foc>=0) { fcdo=new List() out.fcdo=fcdo }
    for i=0,foc-1 { fcdo.append(Xo=new Vector()) Xo.vread(tmpfile) } // assume vecs for now
    if (cnt>0) for i=0,fcd.size-1 if (fcd.x[i]==-1) { 
        readnums(&cnt)
        Yo=new List()
        for j=0,cnt-1 {Xo=new String() Yo.append(Xo) rdvstr(Xo.s)}
        useslist(i,Yo)
      }
    if (hflag==1) { // v0sz will tell size of all vectors
        tell=tmpfile.tell
        tmpfile.seek(0,2)
        tellend=tmpfile.tell()
        if (v0sz==-1) printf("NQSrdERRA: rd header: can't do seeks since v's not same size\n")
        return v0sz
      } else {
        v0sz=-1 // indicates that the everything has been read in
        for i=0,m-1 { 
            v[i].vread(tmpfile)
            if (v[i].x[0]==-1e9) { v[i].resize(v[i].x[1]) v[i].fill(v[i].x[2]) }
          }
        x.vread(tmpfile)
      }
    if (foc==0) for ii=0,fcd.size-1 if (fcd.x[ii]==1) v[ii].fill(-1) // clear obj pointers
    out.cp(this,0) // leave vectors empty
    return 1
  }

//** rdpiece() read a section of each vector
func rdpiece () { local ii,ix,end,jump,loc,bswap
    ix=$1
    if (numarg()>=2) bswap=$2 else bswap=0
    tmpfile.seek(tell+8) // start of first one
    if (ix<0) {printf("NQS:rdpiece ERR: no room: neg index\n") return 0}
    if (ix*chunk>v0sz) return 0
    if ((ix+1)*chunk>v0sz) end=v0sz-ix*chunk else end=chunk
    for ii=0,m-1 {
        loc=tell+8+ii*(v0sz*4+8)+ix*4*chunk
        tmpfile.seek(loc)
        if (loc+end*4>tellend){printf("NQS:rdpiece ERRA: ran out: %d %d",loc+end,tellend) return 0}
        v[ii].fread2(tmpfile,end,3+bswap)
      }
    return 1
  }
    

//** func rdcols()
// reads columns of ascii with labels at the top
func rdcols () { local ii,cols,li,errflag,num,hflag
    errflag=0
    if (! tmpfile.ropen($s1)) { printf("\trdcols ERR0: can't open file \"%s\"\n",$s1) return 0}
    if (tmpfile.scanstr(sstr)==-1) {printf("\trdcols ERR1: file \"%s\"\n",$s1) return 0}
    if (isnum(sstr)) hflag=0 else hflag=1 // hflag=0 -> no header
    if (!hflag) printf("No Header for %s\n",$s1)
    cols=0
    if (hflag) {
        while (! isnum(sstr)) { cols+=1 tmpfile.scanstr(sstr) }
      } else cols=m // assume that NQS was set up ahead
    li=file_len($s1)
    printf("%d cols; %d lines of data in %s.\n",cols,li,$s1)
    tmpfile.ropen($s1)
    if (hflag) tmpfile.gets(sstr) // remove first line
    num=scr.scanf(tmpfile,li*cols)
    if (num!=li*cols) { // err not reached since scanf dumps out
        printf("WARNING: expected %d vals; found %d\n",li*cols,num) errflag=3 }
    if (tmpfile.scanstr(sstr)>-1) { 
        printf("WARNING: %s found after reading in %d vals\n",sstr,li*cols) errflag=4 }
    resize(cols)
    tmpfile.seek(0)
    for ii=0,cols-1 { 
        if (hflag) tmpfile.scanstr(s[ii].s)
        v[ii].resize(li)
        v[ii].copy(scr,0,ii,li*cols-1,1,cols) // v[ii].mcol(scr,ii,cols)
      }  
    if (errflag) { printf("rdcols ERR%d\n",errflag) return 0 }
    return cols
  }

//** func svcols(filename)
// currently only saves numeric columns
func svcols () { local ii,jj,cols,li,errflag,num
    errflag=0
    if (! tmpfile.wopen($s1)) { printf("\trdcols ERR0: can't open file \"%s\"\n",$s1) return 0}
    sstr2="\t"  // delimiter
    for ii=0,m-1 tmpfile.printf("%s%s",s[ii].s,sstr2)
    tmpfile.printf("\n")
    for ii=0,size(1)-1 {
        for jj=0,m-1 {
            getval(jj,v[jj].x[ii]) 
            tmpfile.printf("%g%s",nval,sstr2)
          }
        tmpfile.printf("\n")
      }
    tmpfile.close
    return ii
  }

//** join(nqs2,"PIVOT"[,"COLA",...]) 
// [selected fields of] nqs2 will be appended to this
// index field should only appear once in nqs2
func join () { local vn,vn1,vn2,i,ii,jj,kk,val localobj al,bl
    al=new List() bl=new List()
    if ((vn1=fi($s2))==-1 || (vn2=$o1.fi($s2))==-1) { 
        printf("NQS::join() %s not found in both %s %s\n",$s2,$o1,this) return -1 }
    if (!v[vn1].ismono) {   print "Sorting A..."  sort(vn1) }
    if (!$o1.v[vn2].ismono){print "Sorting B..."  $o1.sort(vn2) }
    if (!$o1.v[vn2].ismono(2)){ printf("Pivot B has repeats\n") return -1 }
    scr.resize($o1.m) scr.fill(-1)
    if (numarg()>2) for i=3,numarg() { 
        if ((vn=$o1.fi($si))==-1) return -1
        if (fi($si,"NOERR")!=-1) sprint(tstr,"%sB",$si) else tstr=$si
        scr.x[vn]=resize(tstr)-1 // index for this
      } else for ii=0,$o1.m-1 if (! strcmp($o1.s[ii].s,$s2)==0) { // don't add pivot field
        if ($o1.fcd.x[ii]!=0) {printf("NQS:join ERRA not double field\n") return -1}
        if (fi($o1.s[ii].s,"NOERR")!=-1) sprint(tstr,"%sB",$o1.s[ii].s) else tstr=$o1.s[ii].s
        scr.x[ii]=resize(tstr)-1 // index for this
      } 
    pad()
    for jj=0,scr.size-1 { kk=scr.x[jj]
        if (kk!=-1) { al.append(v[kk]) bl.append($o1.v[jj]) }
      }
    v[vn1].join($o1.v[vn2],al,bl)
    return m
  }

//** cp(NQS[,VEC_COPY]) copy 1 NQS to another
// default: VEC_COPY==1; side effect of NO_VEC_COPY is no fcd,fcds creation
proc copy () { if (numarg()==2) cp($o1,$2) else cp($o1) }
proc cp () { local ii,csz,veccp,outcp
    csz=$o1.m
    outcp=0
    if (numarg()==2) veccp=$2 else veccp=1
    if (m!=csz) if (isassigned(out)) resize(csz) else {
        resize2(csz)
        outcp=1
      }
    objl.remove_all
    for ii=0,$o1.objl.count-1 { objl.append($o1.objl.object(ii)) }
    file=$o1.file comment=$o1.comment
    if (outcp) for ii=0,m-1 { 
        s[ii]=up.s[ii]
        v[ii]=new Vector()
      } else for ii=0,m-1 { 
        s[ii].s=$o1.s[ii].s 
        if (veccp) v[ii].copy($o1.v[ii]) // 2nd arg to not copy vectors
      }
    if (veccp==1) {  // full copy
        fcd.copy($o1.fcd) 
        for ii=0,$o1.fcds.count-1 fcds.append($o1.fcds.object(ii))
        if (isobj($o1.fcdl,"List")) { fcdl=new List() out.fcdl=fcdl
            for ii=0,$o1.fcdl.count-1 fcdl.append($o1.fcdl.object(ii)) }
        if (isobj($o1.fcdo,"List")) { fcdo=new List() out.fcdo=fcdo
            for ii=0,$o1.fcdo.count-1 fcdo.append($o1.fcdo.object(ii)) }
      } else if (! isassigned(fcd)) { // use pointers for .out
        fcd=$o1.fcd fcds=$o1.fcds fcdl=$o1.fcdl tmplist=$o1.tmplist
      } 
    x.copy($o1.x) x.resize(m)
    scr.copy($o1.scr) ind.copy($o1.ind)
  }

//** eq(NQS) -- just check the vecs
func eq () { local ii,jj,af,ix localobj v1
    if (numarg()==2) af=1 else af=0 // af is flag for approx eq
    if ($o1.m!=m) { printf("# of cols differ %d vs %d\n",m,$o1.m) return 0 }
    for ii=0,m-1 if (strcmp($o1.s[ii].s,s[ii].s)!=0) { 
        printf("%d col names differ: %s vs %s",ii,s[ii].s,$o1.s[ii].s) return 0 }
    for ii=0,m-1 if ($o1.v[ii].size != v[ii].size) { 
        printf("%d col lengths differ: %d vs %d",ii,v[ii].size,$o1.v[ii].size) return 0 }
    if (af) {
        a=allocvecs(v1)
        for ii=0,m-1 {
            v1.copy(v[ii])
            v1.sub($o1.v[ii])
            v1.abs()
            if (v1.max>1e-5) {
                ix=v1.max_ind
                printf("%s cols differ: \n",s[ii].s,ix,v[ii].x[ix],$o1.v[ii].x[ix])
              }
          }
        dealloc(a)
      } else for ii=0,m-1 if (! $o1.v[ii].eq(v[ii])) { 
        printf("%s cols differ at ",s[ii].s)
        for jj=0,v[ii].size-1 if ($o1.v[ii].x[jj] != v[ii].x[jj]) {
            printf("element %d: %g vs %g",jj,v[ii].x[jj],$o1.v[ii].x[jj])
            return 0
          }
      }
    if (! fcdseq($o1)) return 0
    if (! fcdoeq($o1)) return 0
    return 1
  }

//** fcdseq() -- check that string lists are identical in two NQSs -- this is
// sufficient but not nec for comparing string columns for JOIN
// in order to use JOIN must share same fcds by setting up with strdec(NQS,...)
// (could break out separate lists for each str column -- tried in nqs.hoc220;
//  but separate lists would be problem: two columns might require same indices if 
//  either could be used to for "JOIN" to another nqs
func fcdseq () { local ii,jj,cnt
    cnt=fcds.count
    if (eqobj(fcds,$o1.fcds)) {
        printf("%s %s already share string list fcds\n",this,$o1)
        return 1
      }
    if (cnt!=$o1.fcds.count) {
        printf("DIFFERING (1) string lists (fcds) %d %d\n",fcds.count,$o1.fcds.count)
        return 0
      }
    for ii=0,cnt-1 if (!strcmp(fcds.object(ii).s,$o1.fcds.object(ii).s)==0) {
        printf("DIFFERING (2) string lists (fcds) %d:%s vs %s",ii,fcds.object(ii).s,$o1.fcds.object(ii).s)
        return 0
      }
    if (numarg()==2) return 1 // just check fcds and not fcd and fcdl
    if (! fcd.eq($o1.fcd)) {
        printf("DIFFERING (3) col keys (fcd) ") vlk(fcd) vlk($o1.fcd)
        return 0
      }
    if (! isassigned(fcdl) && isassigned($o1.fcdl)) {
          printf("DIFFERING (4) uselists() string lists: absent in %s\n",this)
          return 0
      }
    if (isassigned(fcdl)) {
        if (! isassigned($o1.fcdl)) {
            printf("DIFFERING (5) uselists() string lists absent in %s\n",$o1)
            return 0
          }
        if (fcdl.count!=$o1.fcdl.count) {
            printf("DIFFERING (6) uselists() list list counts %d vs %d",fcdl.count,$o1.fcdl.count)
            return 0
          }
        for ii=0,fcdl.count-1 if (fcd.x[ii]==-1) {
            if (!isobj(fcdl.object(ii),"List") || !isobj($o1.fcdl.object(ii),"List")) {
                printf("DIFFERING (7) uselists() string lists (fcdl.obj) %d:%s vs %s",ii,\
                           fcdl.object(ii),$o1.fcdl.object(ii))
                return 0
              }
            if (fcdl.object(ii).count != $o1.fcdl.object(ii).count) {
                printf("DIFFERING (8) uselists() string lists counts (fcdl.obj) %d:%d vs %d",ii,\
                           fcdl.object(ii).count,$o1.fcdl.object(ii).count)
                return 0
              }
            for jj=0,fcdl.object(ii).count-1 {
                if (!strcmp(fcdl.object(ii).object(jj).s,$o1.fcdl.object(ii).object(jj).s)==0) {
                    printf("DIFFERING (9) uselists() string lists (fcdl.obj) %d,%d:%s vs %s",ii,jj,\
                           fcdl.object(ii).object(jj).s,$o1.fcdl.object(ii).object(jj).s)
                    return 0
                  }
              }
          }
      }
    return 1
  }

//** fcdoeq() -- check that object lists are identical in two NQSs
func fcdoeq () { local ii,jj,cnt
    if (! isassigned(fcdo) && ! isassigned($o1.fcdo)) return 1
    if (! isassigned(fcdo)) {
        printf("No object list in %s\n",this)
        return 0
      }
    if (! isassigned($o1.fcdo)) {
        printf("No object list in %s\n",$o1)
        return 0
      }
    cnt=fcdo.count
    if (cnt!=$o1.fcdo.count) {
        printf("DIFFERING (1) object lists (fcdo) %d %d\n",fcdo.count,$o1.fcdo.count)
        return 0
      }
    for ii=0,cnt-1 if (!isojt(fcdo.object(ii),v) || !isojt($o1.fcdo.object(ii),v)) {
        printf("DIFFERING (2) obj lists (fcdo) -- non vector found %s,%s (%s,%s)",fcdo.object(ii),$o1.fcdo.object(ii),this,$o1)
        return 0
      }
    for ii=0,cnt-1 if (! fcdo.object(ii).eq($o1.fcdo.object(ii))) {
        printf("DIFFERING (2) obj lists (fcdo) -- vectors differ %s,%s (%s,%s)",fcdo.object(ii),$o1.fcdo.object(ii),this,$o1)
        return 0
      }
    return 1
  }

//** strdec() -- declare these columns to be strings
func strdec () { local i,min
    min=1
    if (eqobj(cob,out)) {
        printf("strdec() ERR: string fields can only be declared at top level\n") return 0}
    if (numarg()==0) { 
        printf("strdec(NAME[,NAME1 ...])\n\tdeclare these field to be string fields\n") return 0}
    out.fcd=fcd
    if (argtype(1)==1) {
        if (fcds.count>0) if (! fcdseq($o1,1)) {  // just check fcds and not fcd, fcdl
            printf("Pre-existing string lists differ; unable to join %s %s\n",this,$o1)
            return 0
          }
        fcds=$o1.fcds // share string list to allow JOIN on a string field
        min=2 
      }
    for i=min,numarg() { fl=fi($si)
        if (fl>-1) {
            fcd.x[fl]=2
            sval="`EMPTY'"
            newval(2,fl)   // don't want to put on more than one
          }
      }
    return 1
  }

//** coddec() -- declare these columns to be strings
func coddec () { local i,min
    min=1
    if (eqobj(cob,out)) {
        printf("coddec() ERR: CODE fields can only be declared at top level\n") return 0}
    if (numarg()==0) { 
        printf("coddec(NAME[,NAME1 ...])\n\tdeclare these field to be code fields\n") return 0}
    out.fcd=fcd
    for i=min,numarg() { 
        fl=fi($si)
        if (fl>-1) fcd.x[fl]=10
      }
    return 1
  }

//** odec() -- declare these columns to be objects
func odec () { local i,min
    min=1
    if (eqobj(cob,out)) {
        printf("odec() ERR: object fields can only be declared at top level\n") return 0}
    if (numarg()==0) { 
        printf("odec(NAME[,NAME1 ...])\n\tdeclare these field to be object fields\n") return 0}
    out.fcd=fcd
    for i=min,numarg() { fl=fi($si)
        if (fl>-1) fcd.x[fl]=1
      }
    if (! isobj(fcdo,"List")) { fcdo=new List() out.fcdo=fcdo }
    return 1
  }

//** mo([flag][,STAT1,...]) -- create global objectvars that point to the vectors
// first time use flag=1 to create new global objrefs, else just shift them
// flag=1 reassign objl but don't care if they already exist
// flag=2 don't print out the assignments
// flag=3 reassign objl; make sure they're unique
// flag=4 clear the vectors
// should we also create a set of global scalars to assign to in an iterator?
proc mo () { local ii,flag,i,hf
    if (numarg()>=1) flag=$1 else flag=0 // flag:create objrefs
    if (flag==1 || flag==3) {
        if (objl.count>0) {
            if (flag==3) if (batch_flag) {
                printf("NQS mo(3) WARNING: Renamed object pointers.\n")
              } else if (! boolean_dialog("New name object pointers?","YES","NO")) return
            if (flag==1) if (batch_flag) {
                printf("NQS mo(1) WARNING: Rassigned object pointers.\n")
              } else if (! boolean_dialog("Reassign object pointers?","YES","NO")) return
          }
        objl.remove_all
        for ii=0,m-1 if (sfunc.len(s[ii].s)>0) {
            sstr=s[ii].s
            repl_mstr(sstr,"[^A-za-z0-9]","",execstr)
            sprint(sstr,"%sv",sstr)
            if (flag==3) { // make sure it's unique
                hf=0
                while (name_declared(sstr)) { hf=1
                    printf("%s exists ... ",sstr)
                    sprint(sstr,"%sv",sstr) 
                  } 
                if (hf) printf(" -> %s\n",sstr)
              } else if (name_declared(sstr)) printf("%s reassigned: ",sstr)
            printf("%s -> v[%d] (%s)\n",sstr,ii,s[ii].s)
            sprint(execstr,"objref %s",sstr) execute(execstr)
            sprint(execstr,"%s=%s",sstr,v[ii]) execute(execstr)
            objl.append(new String(sstr))
          }
        sprint(execstr,"objref indv") execute(execstr)
        sprint(execstr,"indv=%s",ind) execute(execstr)
      } else {
        if (objl.count==0) { 
            printf("Must create vecs with mo(1)\n") 
          } else if (objl.count>m) { 
            printf("STAT:mo ERR: wrong objref count in objl: %d vs %d\n",objl.count,m)
            return
          } else {
            if (objl.count<m) { 
                printf("STAT:mo WARNING: unreferenced vecs for %s: refs %d<m %d\n",this,objl.count,m) }
            for ii=0,objl.count-1 {
                Xo=objl.object(ii)
                if (flag==0) printf("%s -> %s.v[%d] (%s)\n",Xo.s,this,ii,s[ii].s)
                if (flag==4) {sprint(execstr,"%s=nil",Xo.s) 
                  } else        sprint(execstr,"%s=%s",Xo.s,v[ii]) 
                execute(execstr)
              }
          }
        sprint(execstr,"objref indv") execute(execstr)
        if (flag!=4) { sprint(execstr,"indv=%s",ind) execute(execstr) }
      }
    if (numarg()>1) for i=2,numarg() { // propagate the objl to other STATs
        $oi.objl.remove_all
        for ii=0,objl.count-1 $oi.objl.append(objl.object(ii))
      }
  }

func version () { local x
    if (numarg()==0) print nqsvers
    sfunc.tail(nqsvers,",v [1-9]*.",tstr)
    sscanf(tstr,"%d",&x)
    return x
  }

//* endtemplate
endtemplate NQS

//* array template
begintemplate OARR
public o,max,count,object,append,copy,name,id
objref o[1]
strdef name

proc init () {
    max=$1 id=count=0
    objref o[max] 
  }
obfunc object () { // pretend to be a list
    if ($1<0 || $1>=max) {printf("OOB for OARR: %d >= %d\n",$1,max) return 1e9} 
    if ($1>=count) printf("OARR WARNING: %d not assigned\n",$1)
    return o[$1]
  }
func append () {
    o[count]=$o1 count+=1
    return count
  }
proc copy () { local jj
    if (numarg()==3) {min=$2 max=$3} else {min=0 max=count}
    for jj=min,max $o1.append(o[jj])
  }
endtemplate OARR

//* ancillary routines
//* sopset() returns symbolic arg associated with a string
proc sopset() { local i
    for i=1,19 { sops[i-1]=$i } // AUGMENT TO ADD NEW OPSYM
  }
sopset(ALL,NEG,POS,CHK,NOZ,GTH,GTE,LTH,LTE,EQU,EQV,EQW,NEQ,SEQ,RXP,IBE,EBI,IBI,EBE) // ADD NEW OPSYM NAME

proc sofset () {
    for scase(XO,"ALL","NEG","POS","CHK","NOZ","GTH","GTE","LTH","LTE","EQU","EQV","EQW","NEQ","SEQ","RXP","IBE","EBI","IBI","EBE") for j=1,5 { 
        sprint(tstr,"%s%d=%s*%d",XO.s,j,XO.s,j+1)
        execute(tstr)
      }
  }
sofset()

//** whvarg
func whvarg () { local ret
    ret=-1
    // ADD NEW OPSYM STRING
            // ALL  NEG   POS  CHK  NOZ   GTH  GTE  LTH LTE EQU   EQV   EQW   NEQ  SEQ  RXP  IBE  EBI  IBI   EBE
    for scase("ALL","<0",">0","CHK","!=0",">",">=","<","<=","==","EQV","EQW","!=","=~","~~","[)","(]","[]","()") {
        if (strcmp($s1,temp_string_)==0) {ret=i1 break}
      }
    if (ret==-1) return ret else return sops[ret]
  }

//** whkey(KEY,STR) 
// place name of KEY from vecst.mod in temp_string_
func whkey () { local key
    for scase("ALL","NEG","POS","CHK","NOZ","GTH","GTE","LTH","LTE","EQU","EQV","EQW","NEQ","SEQ","RXP","IBE","EBI","IBI","EBE") { // ADD NEW OPSYM NAME
        sprint(tstr,"x=%s",temp_string_) execute(tstr)
        if (x==$1) {
            if (numarg()==2) $s2=temp_string_ else print temp_string_
            break
          }
      }
    return x
  }

//** varstr(tstr) -- make a variable out of string by removing nonalphanumeric characters
func varstr () { local a,z,A,Z,a0,a9,a_,len,ii,sflag
    a=97 z=122 A=65 Z=90 a0=48 a9=57 a_=95 // ascii codes
    if (numarg()==2) sflag=1 else sflag=0
    len = sfunc.len($s1)
    for ({x=0 ii=0};ii<len && !((x>=a&&x<=z)||(x>=A&&x<=Z));ii+=1) { // allowed first char
        sscanf($s1,"%c%*s",&x)
        sfunc.right($s1,1)
      }
    if (ii==len) { printf("varstr() ERR: no useable characters") return 0}
    sprint($s1,"%c%s",x,$s1)
    for (;ii<=len;ii+=1) {
        sscanf($s1,"%c%*s",&x)
        sfunc.right($s1,1)
        if ((x>=a&&x<=z)||(x>=A&&x<=Z)||(x>=a0&&x<=a9)||(x==a_)) { // allowed chars
            sprint($s1,"%s%c",$s1,x)
          }
      }
    if (sflag) { 
        sprint($s1,"strdef %s",$s1) 
        execute($s1) 
        sfunc.right($s1,7) // strip leading "strdef"
      } else {
        sprint($s1,"%s=0",$s1) 
        execute($s1) 
        sfunc.left($s1,sfunc.len($s1)-2) // strip the =0
      }
    return 1
  }

strdef h1
h1="Select operators: \nALL <0  >0  CHK !=0  >  >=  <   <=  ==  EQV EQW !=  =~  ~~  [)  (]  []  ()\nALL NEG POS CHK NOZ GTH GTE LTH LTE EQU EQV EQW NEQ SEQ RXP IBE EBI IBI EBE\nmost are obvious; those that are not\nEQV: value equal to same row value another column (takes string arg)\nEQW: value found in other vector (takes vector or NQS arg)\nSEQ: string equal (takes string)\nRXP: regular expression comparison (takes string)\nIBE,EBI...: I=inclusive, E=exclusive for ranges\n"

proc nqshelp () {
    if (numarg()==0) {
      } else {
        if (strcmp($s1,"select")==0) {
            // ed=new TextEditor(h1,9,160) ed.map
            printf("%s",h1)
          }
      }
  }

//* nqsdel(NQS_objref) fully delete an nqs
proc nqsdel () {
    $o1.out.cob=nil  $o1.out=nil
    $o1.cob=nil $o1=nil
  }
// END nqs.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/decnqs.hoc
// =Id=  decnqs.hoc,v 1.22 2007/10/11 16:38:35 billl Exp 

objref nq[5]

//** prl2nqs(NQS[,min,max,nointerp]) -- transfer printlist to NQS
proc rename () {}
// eg proc rename () { sprint($s1,"P%d",objnum($s1)) }
proc prl2nqs () { local tstep localobj st
    st=new String2()
    if (!isassigned($o1)) $o1=new NQS() else $o1.resize(0)
    if (numarg()>=2) min=$2 else min=0
    if (numarg()>=3) max=$3 else max=printlist.count-1
    if (numarg()>=4) interp=$4 else interp=0 // no interp when looking at spk times
    if (interp) $o1.resize(max-min+2)
    if (interp) {
        tstep=0.1 // 0.1 ms step size for interpolation
        $o1.s[0].s="time"
        $o1.v[0].indgen(0,printlist.object(0).tvec.max,tstep)
        for ii=min,max {
            XO=printlist.object(ii)
            $o1.s[ii+1-min].s = XO.var
            rename($o1.s[ii+1-min].s)
            $o1.v[ii+1-min].resize($o1.v.size)
            $o1.v[ii+1-min].interpolate($o1.v[0],XO.tvec,XO.vec)
          }
      } else {
        for ii=min,max {
            XO=printlist.object(ii)
            st.s=XO.name
            sprint(st.t,"%s-time",XO.name)
            rename(st.s) rename(st.t)
            $o1.resize(st.s,st.t)
            $o1.setcols(XO.vec,XO.tvec)
          }
      }
  }

//** pvp2nqs(NQS) -- transfer grvec data file to NQS
proc pvp2nqs () { local tstep,tv1,v1
    if (! read_vfile(1,$s1)) { printf("Can't open %s\n",$s1) return }
    if (numarg()>=3) min=$3 else min=0
    if (numarg()>=4) max=$4 else max=panobj.llist.count-1
    if (numarg()>=5) interp=$5 // no interp when looking at spk times
    if (interp) $o2.resize(max-min+2) else $o2.resize(2*(max-min+1))
    if (interp) {
        tv1=v1=allocvecs(2)  v1+=1
        tstep=0.1 // 0.1 ms step size for interpolation
        $o2.s[0].s="time"
        for ii=min,max {
            XO=panobj.llist.object(ii)
            $o2.s[ii+1-min].s = XO.name
            rename($o2.s[ii-min+1].s)
            panobj.tmpfile.seek(XO.loc)
            mso[tv1].vread(panobj.tmpfile)
            mso[v1].vread(panobj.tmpfile) // or use rv_readvec
            if (ii-min==0) $o2.v[0].indgen(0,mso[tv1].max,tstep)
            $o2.v[ii+1-min].resize($o2.v.size)
            $o2.v[ii+1-min].interpolate($o2.v[0],mso[tv1],mso[v1])
          }
        dealloc(tv1)
      } else for ii=min,max {
        XO=panobj.llist.object(ii)
        $o2.s[2*(ii-min)].s = XO.name
        rename($o2.s[2*(ii-min)].s)
        sprint($o2.s[2*(ii-min)].s,"%s-time",$o2.s[2*(ii-min)].s)
        $o2.s[2*(ii-min)+1].s = XO.name
        rename($o2.s[2*(ii-min)+1].s)
        panobj.tmpfile.seek(XO.loc)
        $o2.v[2*(ii-min)].vread(panobj.tmpfile)
        $o2.v[2*(ii-min)+1].vread(panobj.tmpfile)
      }
  }

//** veclist2nqs(nqs[,STR1,STR2,...])
proc veclist2nqs () { local flag,i
    if (numarg()==0) {printf("veclist2nqs(nqs[,STR1,STR2,...])\n") return}
    $o1.resize(veclist.count)
    if (numarg()==1+$o1.m) flag=1 else flag=0
    for ltr(XO,veclist) {
        $o1.v[i1].copy(XO)
        if (flag) {i=i1+2 $o1.s[i1].s=$si} else {sprint(tstr,"v%d",i1) $o1.s[i1].s=tstr}
      }
    $o1.cpout()
  }

// fudup(vec[,nq,#CUTS,LOGCUT,MIN]) -- use updown() to find spikes
// LOC(0) PEAK(1) WIDTH(2) BASE(3) HEIGHT(4) START(5) SLICES(6) SHARP(7) INDEX(8) FILE(9)
// other options
pos_fudup=1 // set to 1 to move whole curve up above 0
maxp_fudup=0.95 // draw top sample at 95% of max 
minp_fudup=0.05 // draw bottom sample at 5% of max
over_fudup=1    // turn over and try again if nothing found
allover_fudup=0 // turn over and add these locs (not debugged)
verbose_fudup=0 // give messages, can also turn on DEBUG_VECST for messages from updown()
obfunc fudup () { local a,ii,npts,logflag,min,x,sz localobj bq,cq,v1,v2,v3,bb,tl
    if (verbose_fudup) printf("MAXTIME appears to be %g (dt=%g)\n",$o1.size*dt,dt)
    npts=10 // n sample locations
    tl=new List()
    bq=new NQS("LOC","PEAK","WIDTH","BASE","HEIGHT","START","SLICES","SHARP","INDEX","FILE") 
    if (numarg()>1) cq=$o2 else cq=new NQS()
    if (cq.m!=10) { cq.resize(0) 
        cq.resize("LOC","PEAK","WIDTH","BASE","HEIGHT","START","SLICES","SHARP","INDEX","FILE") }
    if (numarg()>2) npts=$3
    if (numarg()>3) logflag=$4 else logflag=0
    if (numarg()>4) {
        if (npts!=$o5.size) printf("Correcting npts from %d to %d\n",npts,npts=$o5.size)
        if ($o5.ismono(1)) $o5.reverse
        if (! $o5.ismono(-1)) {printf("fudup: Arg 5 (%s) must be monotonic\n",$o5) return}
      }
    bq.listvecs(bb)
    bq.pad(5000)
    a=allocvecs(npts+3,2e4)
    v1=mso[a+0] v2=mso[a+1] v3=mso[a+2]
    for ii=0,npts-1 tl.append(mso[ii+a+3])
    v1.copy($o1)
    if (pos_fudup) {
        min=v1.min
        v1.sub(min) // make it uniformly positive
      } else min=0
    if (numarg()>4) v2.copy($o5) else {
        v2.indgen(2,2+npts-1,1)   // sampling at npts points, start at 2 to avoid log(1)=0
        if (logflag) v2.log() // log sampling
        v2.scale(-maxp_fudup*v1.max,-minp_fudup*v1.max) v2.mul(-1)
      }
    v1.updown(v2,tl,bb)
    if (pos_fudup) { bq.v[1].add(min) bq.v[3].add(min) }
    cq.append(bq)
    sz=bq.size(1)
    if (allover_fudup) { // do it upside down as well
        v1.mul(-1) // v2 will be upside-down
        if (pos_fudup) {min=v1.min v1.sub(min)}
        if (0) {  // can't see a rationale to recalc sampling points
            v2.indgen(2,2+npts-1,1)   // sampling at npts points
            if (logflag) v2.log() // log sampling
            v2.scale(-0.95*v1.max,-0.05*v1.max) v2.mul(-1)
          }
        v1.updown(v2,tl,bb)
        bq.v[8].add(sz) bq.v[4].mul(-1) // turn HEIGHT upside down
        cq.append(bq)
      } else if (over_fudup && sz==0) { // turn it over an try again
        print "fudup() checking upside-down"
        v1.mul(-1) // v2 will be upside-down
        v1.updown(v2,tl,bb)
      } 
    for case(&x,0,2,5) cq.v[x].mul(dt)
    nqsdel(bq)
    dealloc(a)
    return cq
  }

//** listsort(LIST[,START,REV]) sorts list of strings numerically
// optional start gives a regexp to start at
proc listsort () { local x,rev localobj nq,st,xo
    if (numarg()==0) { 
        print "listsort(LIST[,RXP,REV]) numerically, optional RXP starts after there" return}
    if (numarg()==3) if ($3) rev=-1 else rev=0
    nq=new NQS("STR","NUM") nq.strdec("STR")
    st=new String()
    for ltr(xo,$o1) {
        if (numarg()>=2) sfunc.tail(xo.s,$s2,st.s) else st.s=xo.s
        if (sscanf(st.s,"%g",&x)!=1) print "listsort ERR: num not found in ",st.s
        nq.append(xo.s,x)
      } 
    nq.sort("NUM",rev)
    $o1.remove_all
    for nq.qt(st.s,"STR") $o1.append(new String(st.s))
  }

// stat(VEC) print stats for the vector
// stat(VEC1,VEC2) append stats of VEC1 on VEC2
// stat(VEC1,NQS) append stats of VEC1 on NQS (create if necessary)
proc stat () { local sz
    sz=$o1.size
    if (sz<1) {printf("decnqs::stat() WARN: %s size %d\n",$o1,$o1.size) return}
    if (numarg()==1 && sz>1) {
        printf("Sz:%d\tmax=%g; min=%g; mean=%g; stdev=%g\n",$o1.size,$o1.max,$o1.min,$o1.mean,$o1.stdev)
      } else {
        if (!isassigned($o2)) { $o2=new NQS("SIZE","MAX","MIN","MEAN","STDEV")
          } else if (isobj($o2,"NQS")) { 
            if ($o2.m!=5) {$o2.resize(0) $o2.resize("SIZE","MAX","MIN","MEAN","STDEV")}
          } else if (isobj($o2,"Vector")) revec($o2)
        if (sz>2) {$o2.append($o1.size,$o1.max,$o1.min,$o1.mean,$o1.stdev) // .append for Vector or NQS
          } else   $o2.append($o1.size,$o1.max,$o1.min,$o1.min,0) // no sdev
      }
  }

//* fil2nqs(FILE,NQS) reads lines of file and places all numbers in NQS
func fil2nqs () { local a,n localobj v1
    $o2.clear
    a=allocvecs(v1)
    tmpfile.ropen($s1)
    for (n=1;tmpfile.gets(tstr)!=-1;n+=1) {
        if (n%1e3==0) printf("%d ",n)
        parsenums(tstr,v1)
        if (v1.size!=$o2.m) {
            printf("Wrong size at line %d (%d)  ",n,v1.size)  vlk(v1)
            return
          }
        $o2.append(v1)
      }
    dealloc(a)
    return $o2.size(1)
  }

//** plnqs(file,NQS) reads output of txt2num.pl
// format ascii 'rows cols' then binary contents
proc plnqs () { local a,rows,cols localobj v1,v2
    a=allocvecs(v1,v2)
    tmpfile.ropen($s1)
    tmpfile.gets(tstr)
    sscanf(tstr,"%d %d",&rows,&cols)
    printf("%s: %d rows x %d cols\n",$s1,rows,cols)
    v1.fread(tmpfile,rows*cols) // could now use .transpose
    v2.indgen(0,rows*cols,cols)
    $o2.resize(cols,rows)
    for ii=0,cols-1 {
        v2.add(ii)
        $o2.v[ii].index(v1,v2)
      }
    dealloc(a)
  }
    
// DEST=maxem(SRC,MIN,WIDTH) -- keep looking for maxima till get down to min
obfunc maxem () { local a,min,wid,ii,ix,beg,end localobj v1,aq
    a=allocvecs(v1)
    aq=new NQS("max","loc") aq.clear(v1.size/2)
    v1.copy($o1)
    min=$2 wid=$3
    while(v1.max>min) {
       aq.append(v1.max,ix=v1.max_ind)
       beg=ix-wid if (beg<0) beg=0
       end=ix+wid if (end>=v1.size) end=v1.size-1
       for ii=beg,end v1.x[ii]=-1e9
      }
    dealloc(a)
    return aq
  }

// nqo=percl(nq,"COLA", ..) generates NQS of percentile values (10..90) for these cols
// nqo=percl(nq,min,max,step,"COLA", ..) -- eg percl(nq,50,70,5,"COLA","COLB")
obfunc percl () {  local i,ii,a,p localobj v1,v2,v3,aq,xo
    a=allocvecs(v1,v2,v3)
    aq=new NQS(numarg())
    if (argtype(2)==0) {
        v3.indgen($2,$3,$4) 
        aq.resize(aq.size(1)-3)
        i=5 j=4 // start at arg i and aq col #j
      } else {
        v3.indgen(10,90,10)
        i=2 j=1
      }
    aq.setcol(0,"PERCL",v3)
    for (;i<=numarg();i+=1) {
        $o1.getcol($si,v1)
        v1.sort()
        v2.resize(0)
        for vtr(&ii,v3) {ii/=100 v2.append(v1.x[round(ii*v1.size)])}
        aq.setcol(i-j,$si,v2)
      }
    dealloc(a)
    return aq
  }

// pqunq(NQS) returns columns of sorted nique values corresponding to the arg
// NB: does not produce a rectangular array
obfunc pqunq () { local a localobj v1,v2,aq
    aq=new NQS()
    a=allocvecs(v1,v2,1e5)
    aq.sethdrs($o1)
    aq.resize(-2) 
    for ii=0,aq.m-1 {
        $o1.getcol(ii,v1)
        v1.sort 
        v2.redundout(v1)
        aq.v[ii].copy(v2)
      }
    dealloc(a)
    return aq
  }

//** aa=seqind(ind) -- find beginning and end of sequential indices with 
obfunc seqind () { local a,n,skip,ii,x,last localobj vi,oq
    vi=$o1
    if (numarg()>=2) skip=$2+1 else skip=1
    if (numarg()>=3) oq=$o3
    if (!isassigned(oq)) {oq=new NQS() if (numarg()>=3) $o3=oq}
    if (oq.m!=3) { oq.resize(0) oq.resize("beg","end","diff") }
    oq.clear()
    n=last=0
    for ii=1,vi.size(1)-1 {
        if (vi.x[ii]-vi.x[ii-1]>skip) {
            if (n>0) oq.append(vi.x[last],vi.x[ii-1],0)
            last=ii
            n=0
          } else n+=1
      }
    if (n>0) oq.append(vi.x[last],vi.x[ii-1],0)
    oq.pad()
    oq.calc("<diff>.copy(<end>.c.sub(<beg>))")
    return oq
  }

//** list_transpose
proc list_transpose () { localobj aq,mat,xo,inlist,outlist
    aq=new NQS() inlist=$o1 outlist=$o2
    if (!isojt(outlist,inlist)) {outlist=new List() $o2=outlist}
    for ltr(xo,inlist) aq.resize("",xo)
    mat=aq.tomat(1) // transpose
    aq.frmat(mat)
    outlist.remove_all
    aq.listvecs(outlist)
    delnqs(aq)
  }
// END /usr/site/nrniv/local/hoc/decnqs.hoc
//================================================================
//================================================================
// INSERTED syncode.hoc
// =Id=  syncode.hoc,v 1.351 2006/06/08 14:43:01 billl Exp 

proc syncode () {}
 // mo(1) will assign these
objref NCv,CODEv,PRv,POv,DISTv,DELv,WT0v,WT1v,CTYP,STYP,cp,svs
objref ivspks,vspks,wvspks,ncl[1][1]
objref sp[3], c[1], nc[1], cells[10] // enough room for 10 cell types
objref vite
Incol=2

//* setup
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/labels.hoc
// =Id=  labels.hoc,v 1.65 2007/05/31 20:14:33 billl Exp 

objref NCv,CODEv,DELv
objref PRIDv,POIDv,PRv,POv,DISTv,WT0v,WT1v // mo(1) will assign these
objref CPLA,CTYP,snsm,STYP,TPA
//* utility functions
// plmin(val,var)
func plmin() { return $1 + $2*(2*u_rand() - 1) } 

//* cell types: 
CTYP=new List()
for scase2(XO,"NU","NU","SM","SM","DP","DP","SU","SU","IN","IN","TC","TC","RE","RE",\
           "NS","NS","BU","BU","RF","RF","CL","CL") {
    sprint(tstr,"%s=%d",XO.t,i1) execute(tstr)
    CTYP.append(XO)
  }
CTYPi=CTYP.count  // number of cell types

// 1 cmp nrn, 2 cmp nrn, multi cmp nrn, intfire1, INTF, invlfire, nstim
CPLA=new List()
for scase2(XO,"1-CMP","CMP1","2-CMP","CMP2","MULTI-CMP","MC","IntFire1","IF1","INTF","IF",\
          "INVLF","IFV","NStim","STM") { CPLA.append(XO)
    sprint(tstr,"%s=%d",XO.t,i1) execute(tstr) }
CPLAi=CPLA.count // count of cell templates

TPA=new List()
for scase2(XO,"REAL","RL","ARTC","AC","SOMA","SO","DEND","DN") {TPA.append(XO)}
TPAi=TPA.count

ncells=0
objref nm
nm=new List() 

STYP=new List()
for scase2(XO,"AMPA","AM","NMDA","NM","GABAA","GA","GABAB","GB","GABAB2","GB2",\
           "IClamp","IC","AMPA/NMDA","EX","GABAA/GABAB2","IX","Exp2Syn","E2") {
    STYP.append(XO)  sprint(tstr,"%s=%d",XO.t,i1) execute(tstr) }
STYPi= STYP.count

objref ZTYP
ZTYP=new List()
for scase(XO,"DG","CA3","CA1","SUB","PSUB","MEC","LEC") {
    sprint(tstr,"%s=%d",XO.s,i1) execute(tstr) ZTYP.append(XO)
  }

objref INCOL
INCOL=new List()
for scase2(XO,"RIGHT","RIT","INCOL","INC","LEFT","LFT") { INCOL.append(XO)
    sprint(tstr,"%s=%d",XO.t,i1) execute(tstr) }
INCOLi=INCOL.count
// END /usr/site/nrniv/local/hoc/labels.hoc
//================================================================
ncl = new List()
sp = new NQS()
strdef syn1,syn2

thresh = -20
// for ltr(XO,cvode.netconlist("", "", "")) print XO.precell,XO.postcell,XO.syn
//* synapse linking -- old routines not using NQS
//** geolink(s1,s2,s3) s1 for presyns and s2 for postsyns, connect s3's
// only checks for INTF as a possible pre/post point process
// connects a layer to another assuming 1 dim netgeom
proc geolink() { local i,ii,a,sav,nowrap,noself
    if (numarg()==0) { print "\tgeolink(s1,s2,s3,DEFCON)"
        print "  make connections from s1 to s2 connecting onto s3 type PPs."
        print "  DEFCON struct defines connection"
        return
      }
    // default to yes wrap; yes within-column connect unless $s1==$s2
    nowrap = !$o4.wrap  noself=!$o4.self
    if (strcmp($s1,$s2)==0) $o4.self=0
    tmpobj=new List($s1)
    // object containing a receive/event PP need fflag=1 and intf as name of PP
    if (tmpobj.object(0).fflag) { // presynaptic object flag
        sprint(temp_string_,"ncl.append(new NetCon(XO.intf, YO.%s))",$s3)
      } else {
        sprint(temp_string_,"XO.soma ncl.append(new NetCon(&v(.5), YO.%s))",$s3)
      }
    for ltr (XO,tmpobj,&y) { // presyn list
        $o4.grot(y)
        for lvtr (YO,&x,new List($s2),$o4.scr) { // postsyn list and vector
            if (x==1) { // connect
                print "connecting ",XO," to ",YO
                execute(temp_string_)
              }
          }
      }
    XO=nil YO=nil
  }

//** glink() same as geolink but takes lists statt strings
proc glink() { local i,ii,a,sav,nowrap,noself
    if (numarg()==0) { print "\tgeolink(l1,l2,DEFCON)"
        print "  make connections from items in l1 to items in l2."
        print "  DEFCON struct defines connection"
        return
      }
    // default to yes wrap; yes within-column connect unless $s1==$s2
    nowrap = !$o4.wrap  noself=!$o4.self
    // object containing a receive/event PP need fflag=1 and intf as name of PP
    if ($o1.object(0).fflag) { // presynaptic object flag
        sprint(temp_string_,"ncl.append(new NetCon(XO.intf, YO.%s))",$s3)
      } else {
        sprint(temp_string_,"XO.soma ncl.append(new NetCon(&v(.5), YO.%s))",$s3)
      }
    for ltr (XO,$o1,&y) { // presyn list
        $o4.grot(y)
        for lvtr (YO,&x,$o2,$o4.scr) { // postsyn list and vector
            if (x==1) { // connect
                // print "connecting ",XO," to ",YO
                execute(temp_string_)
              }
          }
      }
    XO=nil YO=nil
  }

//** synlink(s1,s2,s3,[gmax,del]) s1 for presyns and s2 for postsyns, connect s3's
//  eg synlink("PYR","INH","AMPA")
// provides full connectivity
proc synlink() { local gm,dl
    if (numarg()==0) { print "\tsynlink(s1,s2,s3)"
        print "  make connections from all of type s1 to one of type s2 "
        print "     only connecting onto s3 type PPs."
        print "  Matching done with regexps."
        return
      }
    if (numarg()==5) { gm=$4 dl=$5 } else { gm=0 dl=1 }
    tmplist = new List($s3) // list of postsyn point processes 
    for ltr (XO,new List($s1)) { // presyn list
        for ltr (YO,tmplist) {
            if (pp_loc(YO,$s2,syn2)) { 
                sfunc.head(syn2,"\\.",syn2)
                sprint(syn1,"%s",XO)
                if (strcmp(syn1,syn2)!=0) { // don't allow self connects
                    print "connecting ",XO," to ",syn2
                    XO.soma ncl.append(new NetCon(&v(.5), YO, thresh, gm, dl))
                  }
              }
          }
      }
  }
      
// run NQS.mo(1) first to set up PRIDv ... vectors

//** simple netconnect routines: netconn(), netgen()
proc netconn () { local pre,post,syn,pri,poi
    pre=$1 post=$2 
    if (numarg()==5) { syn=$3 pri=$4 poi=$5 } else { syn=0 pri=$3 poi=$4 }
    cells[pre].object(pri).conn(cells[post].object(poi).syns[syn])
  }

proc netgen () { ncl.append(new NetCon($o1, $o2)) }

//** syncopy() copies from one set of syns to another for colocalization
proc syncopy () { 
    if (numarg()==0) { printf("syncopy(to_type,[]): copy from type, post/type, pre/post/type\n") return }
    sprint(temp_string_,"XO.precell.soma ncl.append(new NetCon(&v(.5),XO.postcell.%s",$s1)
    if (numarg()==1) tmplist = cvode.netconlist("", "" , $s2)
    if (numarg()==2) tmplist = cvode.netconlist("", $s2, $s3)
    if (numarg()==3) tmplist = cvode.netconlist($s2, $s3, $s4)
    for ltr(XO,tmplist) execute(temp_string_)
  }

//** syn1to1(PRE,POST,SYN)
proc syn1to1 () { local pre,post,syn
    pre=$1 post=$2
    if (numarg()==3) syn=$3 else syn=0
    if (cells[pre].count !=cells[post].count) { 
        printf("\tERROR: 1-to-1 connectivity requires same # of %s (=%d) and %s (=%d).\n",\
               CTYP.object(pre).s,cells[pre].count,CTYP.object(post).s,cells[post].count) return }
    for ltr2(XO,YO,cells[pre],cells[post]) {
        printf("SRC: %s -> TRG: %s (%s)\n",XO,YO,YO.syns(syn))
        XO.conn(YO.syns[syn])
      }
  }

//* synconn() synapse linking -- NQS routines
//** synconn(preid,postid,pre#,post#,%div)
// eg synconn(PYRi,PYRi,AMPAi,pmat[PYR][PYR])
// provides % connectivity based on C/pre==%div==%conv==D/post
// S==C*post==D*pre %conv=S/(post*pre)=C/pre=D/post
objref convec,convec1,convec2  // vectors to count how much div is from each nrn
convec = new Vector(1e3)
convec1 = convec.c // a scratch vector
convec2 = convec.c // copy of convec to blot out self-connect and redundent connects

proc synconn () { local preid,posid,pdiv,con,div,ii,jj,prn,pon,targ,sz,styp1,styp2
    if (numarg()==0) { print "\tsynconn(preid,postid,prn,pon,pdiv)" return }
    preid=$1 posid=$2 prn=$3 pon=$4 pdiv=$5
    CODEv=sp.v[sp.fi("CODE")] PRv=sp.v[sp.fi("PR")] POv=sp.v[sp.fi("PO")]
    sz=PRv.size
    if (pdiv==1) {
        if (preid==posid) div=pon-1 else div=pon
        con=div
      } else {
        con=int(pdiv*prn+1) div=int(pdiv*pon)
      }
    if (isobj(CTYP,"List")) {
        printf("%s->%s:\tdiv=%d,conv=%d (%d syns)\n",CTYP.object(preid).s,CTYP.object(posid).s,div,con,prn*div)
      } else {
        printf("%d->%d:\tdiv=%d,conv=%d (%d syns)\n",preid,posid,div,con,prn*div)
      }
    if (prn*div==0) return
    sp.pad(sz+prn*div)
    if (pdiv==1) {
        convec.indgen(0,pon-1,1)
        for ii=0,prn-1 {
            if (preid==posid) {convec.indgen(0,pon-1,1) convec.remove(ii)}
            POv.copy(convec,sz+ii*div)
            PRv.fill(ii,sz+ii*div,sz+(ii+1)*div-1)
          }
      } else {
        convec.resize(pon) convec.fill(0) // counter for convergence
        for ii=0,prn-1 { // sources
            convec2.copy(convec) 
            if (preid==posid) convec2.x[ii]=1e10 // block self-connect
            for jj=1,div POv.set(sz+ii*div+jj-1,pickpost(pon,con)) // pick desired target
            PRv.fill(ii,sz+ii*div,sz+(ii+1)*div-1)
          }
      }
    CODEv.fill(mkcodf(preid,posid,0,0,0),sz,PRv.size-1)
  }

//** synconn2() uses elimrepeats() and shuffle methods
proc synconn2 () { local preid,posid,pdiv,con,div,ii,jj,prn,pon
    if (numarg()==0) { print "\tsynconn2(preid,postid,prn,pon,pdiv)" return }
    preid=$2 posid=$3 prn=$4 pon=$5 pdiv=$6
    $o1.clear()
    PRv=$o1.v[$o1.fi("PR")] POv=$o1.v[$o1.fi("PO")]
    con=int(pdiv*prn+1) div=int(pdiv*pon)
    if (prn*div==0) return
    printf("%s->%s:\tdiv=%d,conv=%d (%d syns)\n",CTYP.object(preid).s,CTYP.object(posid).s,div,con,prn*div)
    if (pdiv==1) {
        $o1.pad(prn*div)
        convec.indgen(0,pon-1,1)
        for ii=0,prn-1 {
            POv.copy(convec,ii*div)
            PRv.fill(ii,ii*div,(ii+1)*div-1)
          }
      } else {
        $o1.pad(1.5*prn*div)
        rdm.discunif(0,prn-1)  PRv.setrand(rdm)
        rdm.discunif(0,pon-1)  POv.setrand(rdm)
        $o1.elimrepeats("PR","PO")
        $o1.shuffle()
        $o1.pad(prn*div)
      }
    $o1.fill("CODE",1,preid) $o1.fill("CODE",2,posid)
  }

//** synconn3() doesn't worry about eliminating repeats
proc synconn3 () { local preid,posid,pdiv,con,div,ii,jj,prn,pon
    if (numarg()==0) { print "\tsynconn2(preid,postid,prn,pon,pdiv)" return }
    preid=$2 posid=$3 prn=$4 pon=$5 pdiv=$6
    $o1.clear()
    PRv=$o1.v[$o1.fi("PR")] POv=$o1.v[$o1.fi("PO")]
    con=int(pdiv*prn+1) div=int(pdiv*pon)
    if (prn*div==0) return
    printf("%s->%s:\tdiv=%d,conv=%d (%d syns)\n",CTYP.object(preid).s,CTYP.object(posid).s,div,con,prn*div)
    $o1.pad(prn*div)
    rdm.discunif(0,prn-1)  PRv.setrand(rdm)
    rdm.discunif(0,pon-1)  POv.setrand(rdm)
    $o1.fill("CODE",1,preid) $o1.fill("CODE",2,posid)
  }

//*** pickpost() tries to reduce divergence variance
// pickpost(postlist,maxcon,YO)
// maxcon == -1 means to ignore convergence
// MUST do convec.resize() and convec.fill(0) before using
func pickpost () { local ran, maxcon, maxpo, min, indx
    maxcon = $2  // max convergence to be allowed
    maxpo = $1   // number of postsyn choices
    min = convec2.min  // convec should start all 0's
    if (min >= maxcon) { // all full up
        printf("Pickpost full WARNING: %d %d\n",min,maxcon) vlk(convec2) }
    convec1.indvwhere(convec2,"==",min)  // look for all the smallest to fill up first
    inx = convec1.x[rdm.discunif(0,convec1.size-1)]
    convec.x[inx]+=1
    convec2.x[inx]=1e10 // block from reconnecting here
    return inx
  }

//** smap()
// excitatory cells project to AMPA and inhibitory cells to GABA
// assumes PRIDv ... defined by sp.mo(1)
objref pro,poo // pre and post pointers
func smap () { local ct,sy,conv,prdx,podx,prx,pox,delx,w0x,w1x localobj nc,ty
    ty=new Union()
    ct=cp.fi("PRID") sy=cp.fi("STYP")
    sp.resize("NC")
    sp.odec("NC")
    sp.pad()
    sp.mo(1)
    for ii=0,PRv.size-1 {
        uncodf(CODEv.x[ii],&prdx,&podx) prx=PRv.x[ii] pox=POv.x[ii]
        delx=DELv.x[ii] w0x=WT0v.x[ii] w1x=WT1v.x[ii]
        pro=c[prdx].object(prx) poo=c[podx].object(pox)
        NCv.x[ii]=sp.fcdo.append(nc=smap1(prdx))-1
        for kk=0,nc.wcnt-1 nc.weight[kk]=0
        x=cp.fetch(ct,prdx,sy)
        syntyp(x,ty)
        nc.weight[ty.x]=w0x
        if (ty.x[1]>-1) nc.weight[ty.x[1]]=w1x
        nc.delay=delx
      }
    return ii
  }

//*** smap1(SYN#) poo has postsyn and pro has pre
obfunc smap1 () { localobj si
    if (poo.fflag) { YO=poo 
      } else {
        YO=poo.po[$1]
        if (isobj(YO,"List")) {
            snsr($1,poo)
            YO=YO.object(YO.count-1)
          }
      }
    if (pro.fflag) {            si=new NetCon(pro,    YO)
      } else {           pro.soma si=new NetCon(&v(0.5),YO) }
    return si
  }

//*** snsr() handles situation where multiple PPs must be hung onto postsyn objref
proc snsr () {
    printf("PROBLEM: replace snsr() which uses an execute\n")
    if (isobj($o2.po[$1],"List")) {
        sprint(tstr,"%s.soma %s.po[%d].append(new %s(0.5))",$o2,$o2,$1,STYP.object($1).s)
      } else {
        sprint(tstr,"%s.soma %s.po[%d] = new %s(0.5)",$o2,$o2,$1,STYP.object($1).s)
      }
    execute(tstr)
  }

//** umbrella(preid,postid,max,width[,shift])
// set lateral projections from pre to post out to width
// sets direct connection (jj==ii) iff preid!=posid
proc umbrella () { local ii,jj,preid,posid,width,sh,max,sz,styp1,styp2
    preid=$1 posid=$2 max=$3 width=$4 
    if (numarg()>=5) sh=$5 else sh=0
    sz=PRv.size styp1=styp2=-1
    if (width) { 
        for ii=0,max-1 for jj=ii-width+sh,ii+width+sh {
            if (jj>=0 && jj<max && (preid!=posid || jj!=ii)) {
                PRv.append(ii) POv.append(jj) 
                PRIDv.append(preid) POIDv.append(posid)
              }
          }
      } else { // just within column connections
        for ii=0,max-1 { PRv.append(ii) POv.append(ii) PRIDv.append(preid) POIDv.append(posid) }
      }
    sp.pad()
    // WID0v.fill(styp1,sz,PRv.size-1)
    // WID1v.fill(styp2,sz,PRv.size-1)
  }

//** umbflow(preid,postid,max,width[,shift])
// like umbrella but does 'flow' boundary conditions -- reflects back on sides
proc umbflow () { local ii,jj,ja,preid,posid,width,sh,max,sz,styp1,styp2
    preid=$1 posid=$2 max=$3 width=$4 
    if (numarg()>=5) sh=$5 else sh=0
    sz=PRv.size styp1=styp2=-1
    if (width) { 
        for ii=0,max-1 for jj=ii-width+sh,ii+width+sh {
            if (preid!=posid || jj!=ii) { ja=jj
                if (jj<0) ja=-jj
                if (jj>max-1) ja=2*max-jj-2
                PRv.append(ja) POv.append(ii) 
                PRIDv.append(preid) POIDv.append(posid)
              }
          }
      } else { // just within column connections
        for ii=0,max-1 { PRv.append(ii) POv.append(ii) PRIDv.append(preid) POIDv.append(posid) }
      }
    sp.pad()
    // WID0v.fill(styp1,sz,PRv.size-1)
    // WID1v.fill(styp2,sz,PRv.size-1)
  }

//** nqdiv(PRID,POID,PR,PO0[,PO1,...]) 
// nqdiv(PRID,POID,PR,POBEG,..,POEND)
proc nqdiv () { local i,beg,end
    if (numarg()==0) { 
        print "nqdiv(PRID,POID,PR,PO0[,PO1,...])\nnqdiv(PRID,POID,PR,POBEG,\"..\",POEND)" return }
    if (numarg()==6 && argtype(5)==2) {
        beg=$4 end=$6
        for i=beg,end sp.append("CODE",EQU1,$1,"CODE",EQU2,$2,"PR",$3,"PO",i)
      } else for i=4,numarg() sp.append("CODE",EQU1,$1,"CODE",EQU2,$2,"PR",$3,"PO",$i)
    sp.pad()
  }

//** nqconv(POID,PRID,PO,PR0[,PR1,...]) 
// nqconv(POID,PRID,PO,PRBEG,..,PREND)
proc nqconv () { local i,beg,end
    if (numarg()==0) { 
        print "nqconv(POID,PRID,PO,PR0[,PR1,...])\nnqconv(POID,PRID,PO,PRBEG,\"..\",PREND)" return }
    if (numarg()==6 && argtype(5)==2) {
        beg=$4 end=$6
        for i=beg,end sp.append("PRID",$2,"POID",$1,"PR",i,"PO",$3)
      } else for i=4,numarg() sp.append("PRID",$2,"POID",$1,"PR",$i,"PO",$3)
    sp.pad()
  }

//** proc nq1to1(PRID,POID,num)
proc nq1to1 () { umbrella($1,$2,$3,0) }

//* direct weight setting routines
//** scale gmax
proc synscgmax () {
    for ltr(XO,cvode.netconlist("" , "", $s1)) { XO.weight *= $2 }
  }
//** set/get gmax
proc synsetgmax () {
    if (numarg()==0) { print "synsetgmax(pre,post,type,wt)"
      } else if (numarg()==2) {for ltr(XO,cvode.netconlist("" , "", $s1)) XO.weight=$2
      } else if (numarg()==3) {for ltr(XO,cvode.netconlist("" , $s1, $s2)) XO.weight=$3
      } else if (numarg()==4) {for ltr(XO,cvode.netconlist($s1 , $s2, $s3)) XO.weight=$4
      } else { print "ERROR: too many args" }
    if (i1==0) printf("WARNING: nothing set in synsetgmax(%s ...)\n",$s1)
  }

// synnormgmax() -- like synsetgmax except normalizes the wt by convergence
proc synnormgmax () {
    for ltr(XO,cvode.netconlist($s1 , $s2, $s3)) {
        XO.weight=$4/cvode.netconlist($s1,XO.postcell,$s3).count
      }
  }

proc syngetgmax () {
    if (numarg()==1) {
        if (strcmp($s1,"help")==0) { printf("type,post/type,pre/post/type\n") } else {
            for ltr(XO,cvode.netconlist("" , "", $s1)) printf("%g ",XO.weight) }
      } else if (numarg()==2) {for ltr(XO,cvode.netconlist("" , $s1, $s2)) printf("%g ",XO.weight)
      } else if (numarg()==3) {for ltr(XO,cvode.netconlist($s1 , $s2, $s3)) printf("%g ",XO.weight)
      } else for ltr(XO,cvode.netconlist("","","")) printf("%g ",XO.weight)
    print ""
  }
 
//** set/get delay
proc synsetdel () {
    if (numarg()==2) {for ltr(XO,cvode.netconlist("" , "", $s1)) XO.delay=$2
      } else if (numarg()==3) {for ltr(XO,cvode.netconlist("" , $s1, $s2)) XO.delay=$3
      } else if (numarg()==4) {for ltr(XO,cvode.netconlist($s1 , $s2, $s3)) XO.delay=$4
      } else { print "ERROR: too many args" }
    if (i1==0) printf("WARNING: nothing set in synsetdel(%s ...)\n",$s1)
  }

proc syngetdel () {
    if (numarg()==1) {for ltr(XO,cvode.netconlist("" , "", $s1)) printf("%g ",XO.delay)
      } else if (numarg()==2) {for ltr(XO,cvode.netconlist("" , $s1, $s2)) printf("%g ",XO.delay)
      } else if (numarg()==3) {for ltr(XO,cvode.netconlist($s1 , $s2, $s3)) printf("%g ",XO.delay)
      } else for ltr(XO,cvode.netconlist("","","")) printf("%g ",XO.delay)
    print ""
  }
 
//** set/get thresh
proc synsetthr () {
    if (numarg()==1) {for ltr(XO,cvode.netconlist("" , "", "")) XO.threshold=$1
      } else if (numarg()==2) {for ltr(XO,cvode.netconlist($s1 , "", "")) XO.threshold=$2
      } else if (numarg()==3) {for ltr(XO,cvode.netconlist($s1, "", $s2)) XO.threshold=$3
      } else if (numarg()==4) {for ltr(XO,cvode.netconlist($s1 , $s2, $s3)) XO.threshold=$4
      } else { print "ERROR: too many args" }
    if (i1==0) printf("WARNING: nothing set in synsetthr(%s ...)\n",$s1)
  }

proc syngetthr () {
    if (numarg()==1) {for ltr(XO,cvode.netconlist($s1 , "", "")) printf("%g ",XO.threshold)
      } else if (numarg()==2) {for ltr(XO,cvode.netconlist($s1, "", $s2)) printf("%g ",XO.threshold)
      } else if (numarg()==3) {for ltr(XO,cvode.netconlist($s1 , $s2, $s3)) printf("%g ",XO.threshold)
      } else for ltr(XO,cvode.netconlist("","","")) printf("%g ",XO.threshold)
    print ""
  }
 
//** synremove: remove post, pre/post, pre/post/type; synshow
proc synremove () {
    if (numarg()==0) { printf("synremove: remove post, pre/post, pre/post/type\n") return }
    if (numarg()==1) tmplist = cvode.netconlist("", $s1 , "")
    if (numarg()==2) tmplist = cvode.netconlist("", $s1, $s2)
    if (numarg()==3) tmplist = cvode.netconlist($s1 , $s2, $s3)
    if (tmplist.count>0) for ltr(XO,tmplist) ncl.remove(ncl.index(XO))
    tmplist = nil // need to remove these references too
    if (numarg()==1) tmplist = cvode.netconlist("", $s1 , "")
    if (numarg()==2) tmplist = cvode.netconlist("", $s1, $s2)
    if (numarg()==3) tmplist = cvode.netconlist($s1 , $s2, $s3)
    if (tmplist.count>0) for ltr(XO,tmplist) printf("ERROR: %s removed from ncl but still exists\n",XO)
    tmplist = nil
  }
  
proc synshow () { 
    sprint(temp_string_,"x=XO.%s",$s2)
    for ltr(XO,cvode.netconlist("" , "", $s1)) { execute(temp_string_) printf("%g ",x) }
    print ""
  }

//* weight setting routines using NQS
//** stwt(PREID,POSTID,WT0[,WT1,norm])
// stwtnorm() causes dividing by individual convergence values
proc stwt () { local w0,w1
    if (sp.select(-1,"CODE",EQU1,$1,"CODE",EQU2,$2) ==0) {
        printf("WARNING NO CONNECTS FROM %d TO %d\n",$1,$2) return }
    w0=$3
    if (numarg()>=5) {  w0=$3/$5 w1=$4/$5 } else if (numarg()>=4) { w1=$4 }
    if (numarg()>=4) sp.fillin("WT0",w0,"WT1",w1) else sp.fillin("WT0",w0)
  }

//** strwt(PREID,POSTID,WT0,WT1,psdev[,norm])
proc strwt () { local w0,w1,psdev
    cnt=sp.select("CODE",EQU1,$1,"CODE",EQU2,$2)
    if (cnt==0) {printf("WARNING NO CONNECTS FROM %d TO %d\n",$1,$2) return }
    if (numarg()>=6) {  w0=$3/$6 w1=$4/$6 } else {  w0=$3 w1=$4 }
    psdev=$5
    rdm.lognormal(w0,psdev*psdev*w0*w0)
    sp.out.v[sp.fi("WT0")].setrand(rdm)
    if (w1!=0) {
        rdm.lognormal(w1,psdev*psdev*w1*w1)
        sp.out.v[sp.fi("WT1")].setrand(rdm)
      }
    sp.delect()
  }

//** strwt2(NQS,WT0,WT1,psdev[,norm])
proc strwt2 () { local w0,w1,psdev
    if (numarg()>=5) {  w0=$2/$5 w1=$3/$5 } else {  w0=$2 w1=$3 }
    psdev=$4
    rdm.lognormal(w0,psdev*psdev*w0*w0)
    $o1.v[$o1.fi("WT0")].setrand(rdm)
    if (w1!=0) {
        rdm.lognormal(w1,psdev*psdev*w1*w1)
        $o1.v[$o1.fi("WT1")].setrand(rdm)
      }
  }

//** strdel(PREID,POSTID,del,psdev)
proc strdel () { local del0,psdev
    if (numarg()==4) {
        cnt=sp.select("CODE",EQU1,$1,"CODE",EQU2,$2)
        if (cnt==0) {printf("WARNING NO CONNECTS FROM %d TO %d\n",$1,$2) return }
        del0=$3 psdev=$4
        rdm.lognormal(del0,psdev*psdev*del0*del0)
        sp.out.v[sp.fi("DEL")].setrand(rdm)
        sp.delect()
      } else { del0=$2 psdev=$3
        rdm.lognormal(del0,psdev*psdev*del0*del0)
        $o1.v[sp.fi("DEL")].setrand(rdm)
      }
  }

//** clrwt(PRID,POID,%clr)
proc clrwt () { local n
    n=round($3*sp.select("CODE",EQU1,$1,"CODE",EQU2,$2))
    sp.out.v[sp.fi("WT0")].fill(0,0,n)
    sp.delect()
  }

//** chksp() confirm correspondance between sp and ncl -- defunct if using multiple ncl
proc chksp () { local prid,poid,pr,po
    for ltr(XO,ncl,&x) {
        prid=sp.v[0].x[x] poid=sp.v[1].x[x] pr=sp.v[2].x[x] po=sp.v[3].x[x] 
        if (XO.pre.id!=pr || XO.pre.type!=prid ||  XO.syn.id!=po || XO.syn.type!=poid) {
            printf("%d %d %d %d %d %d %d %d\n",XO.pre.id,pr,XO.pre.type,prid,XO.syn.id,po,XO.syn.type,poid)  }}
  }

//** swtmap() -- redund code to permit it to run relatively fast
// no longer overloaded to set delay, delmap() or to clr clrwts()
proc swtmap () { local ii,ct,sy,conv,prx,pox,delx,w0x,w1x localobj nc,ty
    ty=new Union()
    ct=cp.fi("PRID") sy=cp.fi("STYP")
    if (PRv.size!=$o1.count) { 
        printf("swtmap ERR: size discrepency: %d vs %d\n",PRv.size,$o1.count)
        return }
    for ii=0,PRv.size-1 {
        prdx=PRIDv.x[ii] podx=POIDv.x[ii] prx=PRv.x[ii] pox=POv.x[ii]
        delx=DELv.x[ii] w0x=WT0v.x[ii] w1x=WT1v.x[ii]
        nc=$o1.object(ii)
        poo=nc.syn
        x=cp.fetch(ct,prdx,sy)
        syntyp(x,ty)
        nc.weight[ty.x]=w0x
        if (ty.x[1]>-1) nc.weight[ty.x[1]]=w1x
        nc.delay=delx
      }
  }

//** wmul(PRID,POID,SYNID,MUL) multiplies set of syns by a factor
// resets from weights stored in sp
proc wmul () { local prx,pox,sox,fac,a,err,num localobj v1
    prx=$1 pox=$2 sox=$3 fac=$4 
    err=0 a=allocvecs(v1)
    if (cp.fetch("PRID",prx,"STYP")==EX && !(sox==AM || sox==NM)) err=1
    if (cp.fetch("PRID",prx,"STYP")==IX && !(sox==GA || sox==GB)) err=1
    if (err) { printf("cell/syn discrepancy: %d -> %d\n",prx,sox) return }
    if (Incol==2) num=sp.select("CODE",EQU1,prx,"CODE",EQU2,pox) else {
        num=sp.select("CODE",EQU1,prx,"CODE",EQU2,pox,"CODE",EQU3,Incol)
      }
    if (num==0) { printf("wmul WARN: no syns selected:%d %d\n",prx,pox) return }
    if (sox==0 || sox==2) {
        v1.copy(sp.out.v[sp.fi("WT0")]) 
      } else {
        v1.copy(sp.out.v[sp.fi("WT1")]) // O is AM and 2 is GA
      }
    v1.mul(fac)
    vwtmap(v1,sp,sox)
    dealloc(a)
  }

//** wset(PRID,POID,SYNID,WT) resets weights to gaussian dist similar to strwt()
// uses sp to determine how many weights are needed
proc wset () { local num,prx,pox,sox,wet,a,err,psdev localobj v1
    prx=$1 pox=$2 sox=$3 wet=$4 
    if (numarg()==5) psdev=$5*$5 else psdev=0
    err=0 a=allocvecs(v1)
    if (cp.fetch("PRID",prx,"STYP")==EX && !(sox==AM || sox==NM)) err=1
    if (cp.fetch("PRID",prx,"STYP")==IX && !(sox==GA || sox==GB)) err=1
    if (err) { printf("cell/syn discrepancy: %d -> %d\n",prx,sox) return }
    if (Incol==2) num=sp.select(-1,"CODE",EQU1,prx,"CODE",EQU2,pox) else {
        num=sp.select(-1,"CODE",EQU1,prx,"CODE",EQU2,pox,"CODE",EQU3,Incol)
      }
    v1.resize(num)
    if (psdev) { 
        rdm.normal(wet,psdev*wet*wet) 
        v1.setrand(rdm)
      } else v1.fill(wet)
    vwtmap(v1,sp,sox)
    dealloc(a)
  }

//** wbim(PRID,POID,SYNID,PSDEV,%A,WTA,%B,WTB,...) bimodal weight setting routines
// uses sp to determine how many weights are needed
proc wbim () { local fsz,i,prx,pox,sox,wet,a,err,psdev,pcw,ptot localobj v1,v2
    prx=$1 pox=$2 sox=$3 psdev=$4*$4 pcw=$5 wet=$6 ptot=0
    err=0 a=allocvecs(v1,v2)
    if (cp.fetch("PRID",prx,"STYP")==EX && !(sox==AM || sox==NM)) err=1
    if (cp.fetch("PRID",prx,"STYP")==IX && !(sox==GA || sox==GB)) err=1
    if (err) { printf("cell/syn discrepancy: %d -> %d\n",prx,sox) return }
    fsz=sp.select(-1,"CODE",EQU1,prx,"CODE",EQU2,pox)
    for i=5,numarg() {
        pcw=$i i+=1 wet=$i // 
        if (pcw*fsz != int(pcw*fsz)){
            printf("wbim WARNING: %d->%d non-int %gx%g=%g\n",prx,sox,pcw,fsz,pcw*fsz) }
        v2.resize(int(pcw*fsz))
        rdm.normal(wet,psdev*wet*wet) 
        v2.setrand(rdm)
        v1.append(v2)
        ptot+=pcw // keep track of percent filled
      }
    if (ptot!=1) printf("wbim WARNING: %d->%d only %g filled\n",prx,pox,ptot)
    if (v1.size!=fsz) {
        printf("wbim WARNING: %d->%d size error %d->%d\n",prx,sox,v1.size,fsz)
        v1.resize(fsz) }
    vwtmap(v1,sp,sox)
    dealloc(a)
  }

//** vwtmap(VEC,NQS) -- copy weights from a vector onto ncl
//   vwtmap(NQS,VEC) -- copy weights from ncl into vector
func vwtmap () { local wix
    if (numarg()==3) wix=$3 else wix=0
    if (isojt($o2,sp)) { // copy from vector to sp.fcdo weights 
        if ($o1.size!=$o2.ind.size){
            printf("vwtmap ERR: size discrepency: %d vs %d\n",$o1.size,$o2.ind.size)
            return 0}
        for ii=0,$o1.size-1 $o2.fcdo.o[$o2.ind.x[ii]].weight[wix]=$o1.x[ii]
        return $o1.size
      } else { // copy from ncl weights to vector
        if ($o1.ind.size!=$o2.size){printf("vwtmap WARNING: resizing vec\n") $o2.resize($o1.ind.size)}
        for ii=0,$o2.size-1 $o2.x[ii]=$o1.o[$o1.ind.x[ii]].weight[wix]
        return $o2.size
      }
  }

//** wtstat(WIX) -- check id of weights directly from the ncs
// assume that have already been selected in sp.out
proc wtstat () { local wix,a,sz,fnc localobj v1
    a=allocvecs(v1)
    if (!eqojt(sp.cob,sp.out)) print "WARNING: no sp.select() done"
    sz=sp.size(1) fnc=sp.fi("NC")
    v1.resize(sz) v1.resize(0)
    if (numarg()==1) wix=$1 else wix=0
    // for sp.qt(XO,"NC") v1.append(XO.weight[wix]) // 5x slower
    for ii=0,sz-1 v1.append(sp.fcdo.o(sp.out.v[fnc].x[ii]).weight[wix])
    stat(v1)
    dealloc(a)
  }

// need to set delays 
proc delmap () { local ii,deli,nc0,nc1
    nc0=$o1.fi("NC0") nc1=$o1.fi("NC1","NOERR") deli=$o1.fi("DEL")
    for ii=0,$o1.v.size-1 {
        ncl.object($o1.v[nc0].x[ii]).delay=$o1.v[deli].x[ii]
        if (nc1!=-1) if ($o1.v[nc1].x[ii]!=-1) {
            ncl.object($o1.v[nc1].x[ii]).delay=$o1.v[deli].x[ii] }
      }
  }

// clrwtmap
proc clrwts () { local ii,jj,nc0,wt0,deli,nc1,wt1,typ,sy2,wid0,wid1,clr
    nc0=$o1.fi("NC0") wt0=$o1.fi("WT0") deli=$o1.fi("DEL") 
    wid0=$o1.fi("WID0") typ=$o1.fi("TYPE")
    nc1=$o1.fi("NC1","NOERR") wt1=$o1.fi("WT1","NOERR") wid1=$o1.fi("WID1","NOERR")
    tobj=ncl.object($o1.v[nc0].x[ii])
    for ii=0,$o1.v.size-1 { 
        tobj=ncl.object($o1.v[nc0].x[ii])
        for jj=0,tobj.wcnt-1 tobj.weight[jj]=0 // clear
        tobj.delay=1 tobj.threshold=0 
        if (nc1!=-1) if ($o1.v[nc1].x[ii]!=-1) for jj=0,tobj.wcnt-1 tobj.weight[jj]=0 // clear
      }
  }

// swtchk(sp,"WT0","NC0") compare weights to sp weights
func swtchk () { local ii,jj,nc0,wt0,n
    nc0=$o1.fi($s3) wt0=$o1.fi($s2)  n=0
    for ii=0,$o1.v.size-1 { 
        if ($o1.v[nc0].x[ii]==-1) continue
        tobj=ncl.object($o1.v[nc0].x[ii])
        if ($o1.v[wt0].x[ii]==tobj.weight) n+=1 else {
            printf("Mismatch %d: %g %g\n",ii,$o1.v[wt0].x[ii],tobj.weight) }
      }
    tobj=nil
    return n/ii
  }

// synchk() look for internal consistency
proc synchk () { 
    for ltr(XO,cvode.netconlist("","","")) if (isassigned(XO.postcell) && XO.weight<0) {
        printf("Error for %s with wt %g\n",XO.syn,XO.weight)
      }
  }

//** getwt() useful in eg sp.spr("<NC0>.c.apply('getwt')")
func getwt () { return NetCon[$1].weight }

spnormflag = 0 // set this flag to normalize weights by number of projections
//** actumb(PRID,POID,WIDTH) -- clears umbrella and then set sp.ind to chosen umbrella
proc actumb () { local width,flag,divisor
    width=$3
    if (width==-1) flag=1 else flag=0
    sp.select(-1,"CODE",EQU1,$1,"CODE",EQU2,$2) 
    if (! flag) { // width=-1 is flag for full connection
        if (sp.fi("WT1")!=-1) sp.fillin("WT0",0,"WT1",0) else sp.fillin("WT0",0)
        sp.select(-1,"CODE",EQU1,$1,"CODE",EQU2,$2,"DIST","()",-width,width)
      }
    if (! spnormflag) { // just set the values
        if (sp.fi("WT1")!=-1 && numarg()==5) sp.fillin("WT0",$4,"WT1",$5) else sp.fillin("WT0",$4)
      } else { // need to calculate convergence for individual cells here
      }
  }

//** inline(PRID,POID,WT) sets the in-column weights
proc inline () { local a
    sp.select(-1,"CODE",EQU1,$1,"CODE",EQU2,$2,"PR",EQV,"PO")
    if (numarg()==4) sp.fillin("WT0",$3,"WT1",$4) else sp.fillin("WT0",$3)
  }

// stwtnorm(PREID,POSTID,WT0[,WT1,CONVVEC])
func stwtnorm () { local cv,a,b,ret
    a=b=allocvecs(2) b+=1
    if (sp.select("CODE",EQU1,$1,"CODE",EQU2,$2)==0) {
        printf("WARNING NO CONNECTS FROM %d TO %d\n",$1,$2) return 0 }
    sp.uniq("PO") // only retains unique values of PO => cv>0
    mso[a].copy(sp.out.v[sp.fi("PO")])
    for vtr(&x,mso[a]) {
        cv=sp.select(-1,"CODE",EQU1,$1,"CODE",EQU2,$2,"PO",x) // do select without copy to out
        mso[b].append(cv) 
        if (cv>0) {
            if (numarg()==4) sp.fillin("WT0",$3/cv,"WT1",$4/cv) else sp.fillin("WT0",$3/cv)
          }
      }
    ret=mso[b].mean // mean convergence
    if (numarg()==4) if (argtype(4)==1) $o4.copy(mso[b])
    if (numarg()==5) if (argtype(5)==1) $o5.copy(mso[b])
    dealloc(a)
    return ret
  }

// wtnorm(PREID,POSTID) -- normalize the values according to convergence
func wtnorm () { local cv,a,b,ret,wt0,wt1
    wt0=sp.fi("WT0") wt1=sp.fi("WT1") 
    if (sp.select(-1,"CODE",EQU1,$1,"CODE",EQU2,$2)==0) {
        printf("WARNING NO CONNECTS FROM %d TO %d\n",$1,$2) return }
    a=b=allocvecs(2) b+=1
    sp.uniq("PO") // only retains unique values of PO => cv>0
    mso[a].copy(sp.out.v[sp.fi("PO")])
    for vtr(&x,mso[a]) {
        cv=sp.select("CODE",EQU1,$1,"CODE",EQU2,$2,"PO",x)
        mso[b].append(cv) 
        if (cv>0) {
            sp.out.v[wt0].div(cv)
            if (wt1>-1) sp.out.v[wt1].div(cv)
            sp.delect()
          }
      }
    ret=mso[b].mean // mean convergence
    dealloc(a)
    return ret
  }



proc setdist () { sp.spr("DIST","<PR>.c.sub(<PO>).apply('abs')") }

proc stwtvar() { local a,idr
    if (numarg()==5) idr=1 else idr=0
    a=allocvecs(1)
    mso[a].resize(sp.ind.size)
    rdm.uniform($3*(1-$4),$3*(1+$4))
    mso[a].setrand(rdm)
    if (spnormflag) mso[a].div(sp.ind.size)
    sp.wt[idr].indset(sp.ind,mso[a])
    dealloc(a)
  }

//** snc() -- set the actual netcons to the params in sp
DEL=DELD=1
proc snc () { local ii
    for ii=0,sp.size-1 {
        nc[sp.nc.x[ii]].threshold=0
        nc[sp.nc.x[ii]].weight=sp.wt.x[ii]
        nc[sp.nc.x[ii]].delay=DEL+DELD*sp.dist.x[ii]
        if (sp.nc[1].x[ii]>-1) {
            nc[sp.nc[1].x[ii]].weight=sp.wt[1].x[ii]
            nc[sp.nc[1].x[ii]].delay=DEL+DELD*sp.dist.x[ii]
          }
      }
  }
//** snci() -- take a vec of indices (eg sp.ind) as arg
proc snci () { local ii,jj
    for jj=0,$o1.size-1 {
        ii=$o1.x[jj]
        nc[sp.nc.x[ii]].weight=sp.wt.x[ii]
        nc[sp.nc.x[ii]].delay=DEL+DELD*sp.dist.x[ii]
        if (sp.nc[1].x[ii]>-1) {
            nc[sp.nc[1].x[ii]].weight=sp.wt[1].x[ii]
            nc[sp.nc[1].x[ii]].delay=DEL+DELD*sp.dist.x[ii]
          }
      }
  }

//* informational procs
//** proc print_pp_location(PP), from doc/html/refman/nocmodl.html
proc print_pp_location() { local x //arg1 must be a point process
     x = $o1.get_loc()
     sectionname(section)
     printf("%s located at %s(%g)\n", $o1, section, x)
     pop_section()
  }
//** pp_loc(PP,LOC,SCRATCH) returns true if point process PP is located in LOC (regexp match)
func pp_loc () { local x //arg1 must be a point process
     x = 0
     $o1.get_loc()
     if (numarg()==3) { sectionname($s3) }
     ifsec $s2 { x = 1 }
     pop_section()
     return x
  }
 

//* ndivo, ncono, sdivo, scono: objects; ndivs, ncons, sdivs, scons: strings
//** for use with INTF
iterator divr () { local ii
    for ii=0,ncl.count-1 {
        XO=ncl.object(ii)
        if (object_id(sfunc.obj(XO.pre.p))==object_id(cells[$1].object($2))) {
            iterator_statement
          }
      }
  }

iterator conr () { local ii
    for ii=0,ncl.count-1 {
        XO=ncl.object(ii)
        if (object_id(sfunc.obj(XO.syn.p))==object_id(cells[$1].object($2))) {
            iterator_statement
          }
      }
  }

//** iterators
// eg for syt("ns[0]","ns[1]") print XO,YO,nco
iterator syt () { local num,err
    err=0
    canobj($o1,"XO") canobj($o2,"YO") // canobj -- canonical object
    if ((num=cvode.netconlist(XO,"",YO).count)!=1) { 
        printf("syt() ERROR num==%d (%s,%s)\n",num,XO,YO) err=1 }
    if (!err) { 
        nco=cvode.netconlist(XO,"",YO).object(0)
        iterator_statement
      }
    XO=nil YO=nil nco=nil
  }

// nca makes list backwards -- syn, then postcell, then precell
iterator nca () { local ii
    tmplist.remove_all
    if (numarg()==0) { cvode.netconlist("", "", "",tmplist)}
    if (numarg()==1) { cvode.netconlist("", "",   $s1,tmplist)}
    if (numarg()==2) { cvode.netconlist("",  $s2, $s1,tmplist)}
    if (numarg()==3) { cvode.netconlist($s3, $s2, $s1,tmplist)}
    for ii=0,tmplist.count-1 {
        XO=tmplist.object(ii)
        iterator_statement
      }
  }

func wtvec () {
    revec(vec)
    for nca($s1) vec.append(XO.weight)
    vlk(vec)
    return vec.size
  }

func dlyvec () {
    revec(vec)
    for nca($s1) vec.append(XO.delay)
    vlk(vec)
    return vec.size
  }

iterator prtr () {  local ii
    tmplist.remove_all
    for ii=0,cvode.netconlist("", $s1, "").count-1 { 
        nco=cvode.netconlist("", $s1, "").object(ii)
        iterator_statement 
      }
  }
iterator potr () {  local ii
    for ii=0,cvode.netconlist($s1,"","").count-1 {
        nco=cvode.netconlist($s1,"","").object(ii)
        iterator_statement 
      }
  }
iterator sytr () {  local ii
    for ii=0,cvode.netconlist("","",$s1).count-1 { 
        nco=cvode.netconlist("","",$s1).object(ii)
        iterator_statement 
      }
  }

proc sdivo () {for ltr(XO,cvode.netconlist($o1, "", "")) prsxo() }
func ndivo () { return cvode.netconlist($o1, "", "").count }
func ncono () { return cvode.netconlist("", $o1, "").count }
proc scono () {for ltr(XO,cvode.netconlist("", $o1, "")) prsxo() }
func ndivs () { 
    if (numarg()==1) return cvode.netconlist($s1, "", "").count else {
                       return cvode.netconlist("" , "", "").count }
  }
func ncons () { return cvode.netconlist("", $s1, "").count }
proc sdivs () { for ltr(XO,cvode.netconlist($s1, "", "")) prsxo() }
proc scons () { 
    if (numarg()==0) for ltr(XO,cvode.netconlist("", "", ""))  prsxo()
    if (numarg()==1) for ltr(XO,cvode.netconlist("", $s1, ""))  prsxo()
    if (numarg()==2) for ltr(XO,cvode.netconlist("", $s1, $s2)) prsxo()
    if (numarg()==3) for ltr(XO,cvode.netconlist($s1, $s2,$s3)) prsxo()
  }
 
// print pre,post,syntype,threshold,weight,delay
proc prsxo () {
    if (isobj(XO.precell,"NULLobject")) {
        printf("%s:%s->%s (%s) (t%g,w%g,d%g)\n",XO,XO.pre,XO.postcell,XO.syn,XO.threshold,XO.weight,XO.delay)
      } else {
        printf("%s:%s->%s (%s) (t%g,w%g,d%g)\n",XO,XO.precell,XO.postcell,XO.syn,XO.threshold,XO.weight,XO.delay)
      }
  }

//* grvec addendum -- new_printlist_...
//** new_printlist_nc(obj,id[,NAME]) records spikes from obj to vitem in printlist
// with NAME creates a new vitem
warn_flag=1
obfunc new_printlist_nc () { local id,thresh,yoset localobj xo,yo
    id=$2 thresh=-20 yoset=0
    if (!isojt(ncl,tmplist)) ncl=new List()
    if (numarg()>=3) {
        if (argtype(3)==2) { 
            printlist.append(yo=new vitem($s3,0))
            yoset=1
          } else if (argtype(3)==0) { thresh=$3
          } else printf("new_printlist_nc arg 3 should be name or thresh\n")
      }
    if (numarg()>=4) thresh=$4
    if (!yoset) if (printlist.count==0) { 
        printlist.append(yo=new vitem("SPKS",0))
      } else { 
        yo=printlist.object(printlist.count-1) // continue with the last one
      }
    xo=cvode.netconlist($o1, "", "")
    if (xo.count==0) {
        if (! warn_flag) printf(".") else { 
            warn_flag=0 // only warn first time
            printf("WARNING (new_printlist_nc) creating NetCon for %s ",$o1) }
        if ($o1.fflag) {  xo=new NetCon($o1, nil)
          } else { $o1.soma xo=new NetCon(&v(x), nil) }
        xo.threshold=thresh
        ncl.append(xo)
      } else {
        xo=xo.object(0)
        if (xo.threshold!=thresh && isassigned(xo.precell)) {
            printf("Warning: new_printlist_nc resetting thresh for %s\n",xo)
            xo.threshold=thresh
          }
      }
    xo.record(yo.tvec,yo.vec,id)
    return yo
  }

//** proc new_printlist_nc2(VITEM,CELL,ID#) -- don't bother looking for an existing synapse
proc new_printlist_nc2 () { local id,thresh,yoset localobj xo
    id=$3 thresh=-20 yoset=0
    if ($o2.fflag) {  xo=new NetCon($o2, nil)
      } else { $o2.soma xo=new NetCon(&v(x), nil) }
    xo.threshold=thresh
    ncl.append(xo)
    xo.record($o1.tvec,$o1.vec,id)
  }

//** fipre(NETCON) find a presynaptic index for a netcon
func fipre () { local nu
    if (isassigned($o1.pre)) { // a point-process
        return objnum($o1.pre)
      } else {
        if ($o1.preloc==-1) {
            printf("fipre() ERR: %s\n",$o1) err() }
        sscanf(secname(),"%*[^[][%d]",&x) // find number of the cell
        // eg grvecstr="PYR2 sINT sTC  sRE" // use locations in this string as id
        if (sfunc.len(grvecstr)==0) {
            return x
          } else {
            sscanf(secname(),"%[^[]",tstr)
            nu=sfunc.substr(grvecstr,tstr)/5
            return nu*50+x
          }
        pop_section()
      }
  }

//** fspks (index,vec) put spike times for index in vec
// fspks (index,vec,num)  use printlist.object(num).vec
// fspks (index,vec,spkvec,tvec)
proc fspks () { local a,b,ix
    a=b=allocvecs(2) b+=1
    if (numarg()==2) { ix=$1 XO=printlist.object(0).vec YO=printlist.object(0).tvec }
    if (numarg()==3) { ix=$1 XO=printlist.object($3).vec YO=printlist.object($3).tvec }
    if (numarg()==4) { ix=$1 XO=$o3 YO=$o4 }
    revec($o2)
    mso[a].indvwhere(XO,"==",ix)
    $o2.index(YO,mso[a])
    dealloc(a)
  }

// fspks1(index,vec)
proc fspks1 () { local a,b,ix
    if (numarg()==2) { ix=$1 XO=printlist.object($1).vec YO=printlist.object($1).tvec }
    if (numarg()==4) { ix=$1 XO=$o3 YO=$o4 }
    $o2.resize(XO.size)
    $o2.xing(XO,YO,thresh) // times
  }

//** spktimes(plist#,cell#)  prints out spike times from a tvec/ivec printlist item
// spktimes(tvec,vec,cell#)
func spktimes () { local sz,wh,a,i localobj va,vb,tv,vv,o
    a=allocvecs(va,vb)
    i=0 // i serves as flag for saving to a vector
    if (numarg()==4) {
        tv=$o1 vv=$o2 wh=$3 i=4
      } else if (numarg()==3) {
        if (argtype(1)==1) {
            tv=$o1 vv=$o2 wh=$3
          } else {
            o=printlist.object($1) wh=$2 vv=o.vec tv=o.tvec
            i=3
          }
      } else {
        if (numarg()==2) {
            o=printlist.object($1) wh=$2
          } else if (numarg()==1) {
            o=printlist.object(0)  wh=$1
          } else wh=-1
        vv=o.vec tv=o.tvec
      }
    sz=vv.size
    if (wh==-1) { vlk(tv,vv) 
      } else {
        va.indvwhere(vv,"==",wh)
        vb.index(tv,va)
        sz=vb.size
        if (i) $oi.copy(vb) else vlk(vb)
      }
    dealloc(a)
    return sz
  }

//** ceqi() cvode.event_queue_info(3,...)
proc ceqi () { local flag,ii
    flag=$1
    tmplist.remove_all revec(ind,vec)
    printf("\n\n\t**** t=%g ****\n\n",t)
    if (flag==3) {
        cvode.event_queue_info(3, ind, vec, tmplist)
        for ltr(XO,tmplist,100) printf("t=%g flag=%d nc=%s\n",ind.x[i1],vec.x[i1],XO)
      } else if (flag==2) {
        cvode.event_queue_info(2, ind, tmplist)
        for ltr(XO,tmplist,100) { printf("t=%g %s->%s:",ind.x[i1],XO.pre,XO.syn)
            for ii=0,XO.wcnt-1 printf("%g ",XO.weight[ii])
            print ""
          }
      } else if (flag==0) {
        for ltr(XO,ncl,10) { printf("%s->%s:",XO.pre,XO.syn)
            for ii=0,XO.wcnt-1 printf("%g ",XO.weight[ii])
            print ""
          }
      }
  }

//** new_printlist_ac(obj,name[,NAME,num]) 
// adds params from an artificial cell with built-in vec dumping
proc new_printlist_ac () { local i,max,num,svloc,sz localobj lo
    npacsz=1.2
    vdt = vdt_INTF
    lo = new Union()
    if (numarg()>=4) num=$4
    if (numarg()==4) { sprint(lo.s,"%s%d.%s",$s3,$4,$s2) 
      } else {           sprint(lo.s,"%s.%s",$o1,$s2)  }
    sz=npacsz*tstop/vdt
    vite = new vitem(lo.s,sz)
    vite.o=$o1
    if ($o1.recflag==0) {  // record tvec
        vite.tvec=new Vector(sz)
        $o1.initrec("time",vite.tvec)
      } else {
        for ltr(YO,printlist) if (eqobj($o1,YO.o)) vite.tvec=YO.tvec
        if (!isassigned(vite.tvec)) printf("ERR INTF %s not found in printlist\n",$o1)
      }
    vite.tvflag=1
    $o1.initrec($s2,vite.vec)
    printlist.append(vite)
  }

objref pfih
psgchk = 1
proc psend () { local tt
    for ltr(XO,printlist) {
        if (strm(XO.var,"[()][()]$")) {
            revec(XO.vec,XO.tvec)
            for (tt=psgchk;tt<=tstop;tt+=psgchk) {
                sprint(tstr,"%s.append(%s)",XO.vec,XO.var)
                cvode.event(tt,tstr)
                sprint(tstr,"%s.append(t)",XO.tvec)
                cvode.event(tt,tstr)
              }
          }
      }
  }

// eg new_printlist_fc("intf.M1()")
// obsolete since intf.mod no longer defines M1(),M2(),...
proc new_printlist_fc () {
    if (! isassigned(pfih)) { pfih = new FInitializeHandler("psend()") }
    if (! strm($s1,"\\(\\)$")){print "Should be func eg intf.M1()" return }
    XO = new vitem($s1,0)
    printlist.append(XO)
  }
  

//* misc and commentary
// con=absolute convergence number, div=absolute div number
// con = %con * pre
// div * pre = con * post = S (total synapses)
// %div = div/post = S/(pre*post) = con/pre = %con
// div = %con * post
// maxdiv = int((1 + var) * div)
 
//** vari returns randomly chosen $1+/-$2, $2 is a percent
func frani () { return int(rdm.uniform($1,$2+1)) }
func uvari () { return $1 - $1*$2 + (rdm.uniform(0,1) * 2 * $1*$2) }
func gvari () { return $1 - (rdm.normal(0,1) * $1*$2) }

//** clearsyns() 
proc clearsyns () { 
    for ltr(XO,ncl) XO.active(0)
    ncl.remove_all 
    for ltr(XO,new List("NetCon")) printf("**** CLEARSYN WARNING %s STILL EXISTS ****\n",XO)
  }

// findstr() look thru list for a string and return the index
func findstr () { local flag
    flag = -1 // failure
    for ltr(XO,$o2) {
        if (strcmp($s1,XO.s) == 0) flag=i1
      }
    return flag
  }

//** syntyp() reads syntyps out of cp directory
proc syntyp () { local x 
    x=$1
    if (x==EX) {$o2.x=AM $o2.x[1]=NM  // excit
      } else if (x==IX) {$o2.x=GA $o2.x[1]=GB // inhib
      } else $o2.x[1]=-1
  }

//** excitp(PRE) -> T if cell is excitatory
func excitp () { 
    if ($1==SU || $1==DP || $1==TC) return 1
    if ($1==RE || $1==IN) return 0
    printf("ID not classified in excitp\n")
    return -1
  }

//* Saving and reading
//** svnet() rdnet()
proc svnet () { local ii
    ii=0
    if (numarg()==1) filename=$s1 else {
        sprint(filename,"data/%s%c.net",datestr,97+ii)
        while (tmpfile.ropen(filename)) sprint(filename,"data/%s%c.net",datestr,97+ii+=1)
        printf("nqsnet output to %s\n",filename)
      }
    XO=usefiles("nqs.hoc","syncode.hoc","nqsnet.hoc","labels.hoc")
    cp.comment=XO.s
    sp.comment=XO.s
    cp.sv(filename)
    sp.sv(filename,1)
    tmpfile.close()
  }

proc rdnet () {
    filename=$s1
    if (!isobj(cp,"NQS")) {cp=new NQS() sp=new NQS()}
    printf("reading network file %s\n",filename)
    cp.rd(filename)
    sp.rd() // continue reading
    tmpfile.close()
  }

//** svstate() rdstate() rerun()
proc svstate () {
    if (! isobj(svs,"SaveState")) svs=new SaveState()
    svs.save
    tmpfile.wopen($s1)
    svs.fwrite(tmpfile)
  }

proc rdstate () {
    if (! isobj(svs,"SaveState")) svs=new SaveState()
    tmpfile.ropen($s1)
    svs.fread(tmpfile)
    svs.restore
  }

proc initrr () { printf("WARNING: initrr() -- init for rerun() -- not defined\n") }

proc rerun () { local tstp,told
    tstp=tstop
    if (numarg()>0) rdstate($s1) else svs.restore
    if (numarg()==1) if (argtype(1)==0) tstp=$1
    if (numarg()>1) tstp=$2
    told=t
    initrr()
    if (t!=told) {
        printf("ERROR: initrr() appears to have reset t (finitialize()?) (%d->%d)\n",told,t) 
        return
      }
    sprint(tstr,"cvode.solve(%g)",t+tstp)
    time(tstr)
    finish()
  }

// mkvspks(NUMCELLS,NUMGROUPS,INVL1,SPREAD,[APPEND])
// produces ivspks index vector and vspks time vector for inserting activations
// groups are not stable -- they are reconstituted at each spiking time
// NUMCELLS   indices will be drawn from 0..NUMCELLS-1 
// NUMGROUPS  will give the separate groupings for simultaneous activation across a group
//            there will be NUMCELLS/NUMGROUPS cells in each group
// INVL1      is the average interval in ms between the inputs
// SPREAD     is the +/- SPREAD/2 sloppiness in this interval 
// APPEND     is a flag saying to add on to existing ivspks/vspks vectors
proc mkvspks () { local gcnt,numc,numg,inv1,inv2,a,ii,j,apflg localobj iv,tv
    numc=$1 numg=$2 inv1=$3 inv2=$4 apflg=0
    if (numarg()>=5) if ($5) apflg=1 // 5th arg is append flag
    if (!apflg) revec(ivspks,vspks)
    gcnt = int(numc/numg) // number of cells in each group
    a=allocvecs(iv,tv)
    for ({ii=20 j=0};ii<tstop-20;{ii+=inv1 j+=1e-8}) {
        iv.indgen(0,numc-1,1) // assume that start from intf#0
        shuffle(iv)
        iv.resize(gcnt) // now have a set of cells that need to spike at
        iv.add(j) // add a little bit to ensure that sortindex below preserves forward time
        tv.resize(gcnt)
        rdm.uniform(-inv2/2,inv2/2)
        tv.setrand(rdm)
        tv.add(ii)
        ivspks.append(iv) vspks.append(tv)
        if (j>=1-1e-8) printf("mkvspks ERR: j>=1\n") // should never happen
      }
    ivspks.sortindex(iv)
    tv.index(vspks,iv)  vspks.copy(tv)
    tv.index(ivspks,iv) ivspks.copy(tv)
    ivspks.rnd()
    wvspks.resize(ivspks.size)
    dealloc(a)
  }

obfunc netconlist () { 
    if (numarg()==1) {
        if (argtype(1)==1) return cvode.netconlist("","",$o1)
        if (argtype(1)==2) return cvode.netconlist("",$s2,"")
      }
    return cvode.netconlist("","","") 
  }
// END syncode.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/parset.hoc
// =Id=  parset.hoc,v 1.111 2006/11/08 01:13:56 billl Exp 

proc parset () {}

// load_file("parset.hoc")
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/boxes.hoc
// =Id=  boxes.hoc,v 1.55 2006/03/26 20:28:29 billl Exp 

// load_file("boxes.hoc")
proc boxes () {}

// factor(num) finds the factors that are closest together
// NB: must be at top since declared external in template BX
func factor () { local num, srt, ii
    num = $1
    srt = int(sqrt(num))
    for (ii=srt;ii<num && num/ii!=int(num/ii);ii+=1) {}
    if (ii>num/ii) ii=num/ii // return smaller factor
    return ii
  }

// template for putting up trays and decks
begintemplate BX
public mktray,mkdeck,name,boxes,map,unmap,closebox
public min,max,attrnum,rows,cols,trnum,gl,stub,label
external factor

objref boxes[3], ob, gitem,gl,XO,nil
double min[1],max[1],trnum[1]
strdef temp_string_,name

proc init () {
    min = -1 max = -1
    trnum=$1
    gl = new List()
  }

//mktray(panattr) graph out from llist of a panattr
proc mktray () { local ci, ri, gi, m1, m2, bi
    ob = $o1
    cols=$3 rows=$2
    if (numarg()==6) {xs=$4 ys=$5} else {xs=100 ys=50}
    ri = 0 // count the rows
    gi = 0 // count the graphs
    boxes[0] = new VBox()
    boxes[0].dismiss_action("closebox()")
    boxes[0].intercept(1)
    name=""
    xpanel("",1)
    xvarlabel(name)
    xpanel()
    for ri=0,rows-1 {
        boxes[2] = new HBox()
        boxes[2].intercept(1)
        for ci=0,cols-1 {
            gitem = new Graph(0)
            gitem.view(0,-100,1000,50,0,0,xs,ys)
            gl.append(gitem)
            ob.glist.append(gitem)
            gi = gi+1
          }
        boxes[2].intercept(0)
        boxes[2].map("")
      }
    boxes[0].intercept(0)
    if (strcmp(name,"")==0) name=ob.filename
    sprint(name,"%d:%s",trnum,name)
    boxes[0].map(name)
  }

proc map() { boxes[0].map() }
proc unmap() { boxes[0].unmap() }

proc closebox () { local ii
    for (ii=gl.count-1;ii>=0;ii-=1) {
        XO=gl.object(ii)
        XO.unmap
      }
    ob.glist.remove_all
    gl.remove_all
    boxes[0].unmap
    boxes[0]=nil
    boxes[2]=nil
  }

proc mkdeck () { local rows, cols, ci, ri, gi, m1, m2
    ob = $o1
    if (min==-1 || max==-1) {
        m1 = 0 m2 = ob.llist.count()-1
      } else { m1=min    m2=max }
    cnt = m2-m1+1
    cols=factor(cnt) rows=cnt/factor(cnt)
    ri = 0 // count the rows
    gi = 0 // count the graphs
    boxes[0] = new VBox()
    boxes[0].intercept(1)
    xpanel("",1)
    xbutton("Next","boxes[1].flip_to(decknum=decknum+1)")
    xbutton("Previous","boxes[1].flip_to(decknum=decknum-1)")
    xpanel()
    boxes[1] = new Deck()
    boxes[1].intercept(1)
    for ri=0,rows-1 {
        boxes[2] = new HBox()
        boxes[2].intercept(1)
        for ci=0,cols-1 {
            ob.rv(gi+m1)
            gi = gi+1
          }
        boxes[2].intercept(0)
        boxes[2].map("")
      }
    boxes[1].intercept(0)
    boxes[1].map("")
    boxes[0].intercept(0)
    boxes[0].map("Deck")
    decknum = 0
    boxes[1].flip_to(decknum)
    if (! ob.attr0) {
        for ii = 0,gi-1 { 
            ob.glist.object(ii).label(0.3,0.5,ob.llist.object(ii).name)
          }
      }
  }

endtemplate BX

objref boxer, boxerl
boxerl = new List()
proc mktray () { local i,na,namef localobj o
    if (numarg()==0) { print "mktray(attrnum,rows,cols[,xsize,ysize,label])"
        print "Create a tray for attr panel ATTRNUM to superimpose upon."
        return }
    boxer = new BX(boxerl.count)
    boxerl.append(boxer)
    trnum=boxer.trnum
    if (argtype(numarg())==2) { namef=1 na=numarg()-1 i=numarg() 
      } else                    { namef=0 na=numarg() }
    if (na==2) o=panobj else if (argtype(1)==0) o=GRV[$1] else o=$o1
    o.super = 1
    if        (na==5) { boxer.mktray(o,$2,$3,$4,$5)
      } else if (na==3) { boxer.mktray(o,$2,$3) 
      } else if (na==2) { boxer.mktray(o,$1,$2)
        printf("Mapping trays to %s\n",o)
      }
    if (namef) boxer.name=$si
  }

proc rmtray () { local ix
    ix=$1
    if (boxerl.count<=1) boxerl.remove_all else {
        for (ii=boxerl.count-1;ii>=0;ii-=1) {
            if (boxerl.object(ii).attrnum==attrnum) boxerl.remove(ii) 
          }}
    remgrs(attrnum)
    GRV[ix].super=0
  }

proc trsz () {
    if (boxerl.count>0) for ltr (XO,boxerl) printf("%d:%d x %d\n",XO.attrnum,XO.rows,XO.cols)
  }

proc mktrpanl () {
    xgetargs("Make Tray","mktray","Which","rows","cols","xsize","ysize","0,2,3,100,50")
  }

//* disptray() redisp() redispv()
proc disptray () { local ix,ii,jj,kk
    if (numarg()==0) {print "disptray(ix[,cols])" return}
    ix=$1
    ii=GRV[ix].llist.count 
    if (numarg()==2) jj=$2 else jj=factor(ii)
    kk=GRV[ix].glist.count
    mktray(GRV[ix],round(ii/jj),jj,100,50) 
    GRV[ix].grall(0,ii-1)
    for ltr(XO,GRV[ix].glist) if(i1>=kk) { 
        XO.size(&x[0]) 
        XO.size(x[0],x[1],x[2],x[3]) }
  }

proc redisp () { local supsav
    panobj=$o1
    if (numarg()>=2) trnum=$2
    supsav=panobj.super  panobj.super=1
    for ltr(graphItem,boxerl.object(trnum).gl) {
        graphItem.erase_all()
        panobj.rv(i1)
      }
    panobj.super=supsav
  }

// for bxit () {}  go through all the graphs in tray trnum
// for bxit (g1,g2,g3,g4) {}  go through selected graphs
// for bxit (-1,g1,g2) {}  go through g1-g2
bxn=-1
proc bxop () { g=boxerl.object(trnum).gl.object($1) graphItem=g}
proc bxinc () { 
    if (bxn>=boxerl.object(trnum).gl.count) bxn=0 else bxn+=1
    g=boxerl.object(trnum).gl.object(bxn) 
    graphItem=g
  }
iterator bxit () { local i,ii
    i1=0
    if (numarg()>0) {
        if (numarg()==3  && $1==-1) {
            for ii = $2, $3 {
                g=boxerl.object(trnum).gl.object(ii)
                graphItem=g
                iterator_statement
                i1+=1
              }
          } else {
            for i = 1, numarg() {
                if (numarg()==1) XO=$o1.object(ii)
                g=boxerl.object(trnum).gl.object($i)
                graphItem=g
                iterator_statement
                i1+=1
              }
          }
      } else {
        for ii=0,boxerl.object(trnum).gl.count-1 {
            g=boxerl.object(trnum).gl.object(ii)
            graphItem=g
            iterator_statement
            i1+=1
          }
      }
  }

// redispv(VEC,ATTRNUM,TRNUM) -- all args optional
proc redispv () { local supsav
    panobj=$o1
    if (numarg()>=2) trnum=$2
    supsav=panobj.super  panobj.super=1
    for bxit() {
        g.erase_all()
        if (numarg()>0) panobj.rv($o1.x[i1]) else panobj.rv(vec.x[i1])
      }
    panobj.super=supsav
  }

proc bxcomm () { 
    if (numarg()==1) boxerl.object(boxerl.count-1).name=$s1 else {
        boxerl.object(boxerl.count-1).name=comment }
  }

//* gin() search through param strings to graph particular members of llist
// eg regexp="SPCX SPTC SPSM " then 'gin(1)' to create regexp: 'SPCX.+%sSPTC.+%sSPSM.+%s'
// gin("5","","") will find examples with SPCX=5 and graph SPTC against SPSM
// ginpr() will search through llist and just print out the file names
// meant to be used after running dir2pr() to get a summary file
strdef regexp
proc gin () { local i,a
    a=allocvecs(1)
    revec(mso[a]) tstr=regexp
    for i=1,numarg() repl_str(tstr,"%s",$si,temp_string2_)  // replace sprint
    for ltr(XO,panobj.llist,&y) if (strm(XO.name,tstr)) mso[a].append(y)
    if (mso[a].size!=boxer.rows*boxer.cols) {
        printf("gin() ERR: %d!=%dx%d\n",mso[a].size,boxer.rows,boxer.cols)
        dealloc(a) return
      }
    geall(1)
    for bxit() panobj.rv(mso[a].x[i1]) 
    tstr=regexp 
    repl_mstr(tstr,".\\+%s","=%s,",temp_string2_)
    chop(tstr)
    for i=1,numarg() repl_str(tstr,"%s",$si,temp_string2_)
    sprint(tstr,"%s: %s",panobj.filename,tstr)
    bxcomm(tstr)  print tstr
    dealloc(a)
  }

proc ginpr () { local base,i
    if (numarg()==0) { 
        print "Set regexp to begin: eg\n\tregexp=\"SMTC SPSM NSTC \" (space at end)"
        print "Then call ginpr(regexp) to reset regexp"
        print "Then call eg ginpr(\"0.015\",\"\",\"\") to list or gin(...) to graph"
        return }
    if (numarg()==1) { 
        regexp=$s1 repl_mstr(regexp," ",".+%s,",tstr) 
        chop(regexp,",")
        print regexp return }
    base=1 tstr=regexp // where they start numbering
    for i=1,numarg() repl_str(tstr,"%s",$si,temp_string2_)  // replace sprint
    for ltr(XO,panobj.llist,&y) if (strm(XO.name,tstr)) printf("%03d %s\n",base+y,XO.name)
  }
// END /usr/site/nrniv/local/hoc/boxes.hoc
//================================================================

//* minimal usage
// load_file("soma.hoc")
// cvode_active(0)
// prsfor("AMP","stim.amp",1,1.8,.2)
// prsvals("LEAK","gl_hh",1e-3,3e-3,4e-3,5e-3)
// new_printlist_item("soma.v(0.5)")
// sims=setprs()
// exerun()
// xpospanl()

//* usage
//  ob=new PRS("PARAM NAME","clear command")
//  ob.append("allele1","set command #1")
//  ob.append("allele2","set command #1")
//     ... or
//  ob=new PRS("PARAM NAME","clear command","allele1","set command #1","allele2","set command #2",...)
//  see autorun() for calling sequence
// 
//  with setting simple params use 
//  ob=new PRS("PARAM NAME","stem_name=",num1,num2,...)
//  ob.appnums(num3,num4,num5,...)
//  NB: finish with sims=setprs()

objref prsl,prsl2,ob,prslp,bx,XX,YY,pc
strdef tt
prsl=new List()
prsl2=new List() // prsl2 is for reading -- includes dumped states as list
prslp = prsl // default for prsl pointer 
trnum=-1

// permit side effect outside of template
proc prsadd () { prslp.append($o1) }
// for ltr(XX,prsl) for ltr(YY,XX.l) print YY.s,YY.t
//* template PRS
begintemplate PRS
  public n,l,clr,name,clear,exe,exec,nam,com,comm,do,append,appnums,v,pcomm,post,ale
  strdef name,clr,stem,tstr
  double n[1],flag[1]
  objref l,ob,nil,v,this,pcomm
  external prsadd,sfunc,chop,String2

  proc init () { local i,j
      n=numarg()-2
      l=new List()
      v=new Vector() // v vector gives order in which to run the params
      name = $s1  clr=$s2
      pcomm=new String() // post command
      // if the clear command ends with equal sign this is a stem for all the param setting
      if (sfunc.tail(clr,"=",stem)>-1 && sfunc.len(stem)==0) { flag=1
          sfunc.head(clr,"=",stem) sprint(clr,"%s=0",stem) 
        } else { flag=0
          if (n%2!=0) { print "ERROR: Must give name/command pairs" return }
          n/=2
        }
      if (n>0) for i=3,numarg() {
          if (flag) { 
              ob = new String2()
              sprint(ob.s,"%g",$i) 
              sprint(ob.t,"%s=%g",stem,$i) 
            } else { ob=new String2($si) i+=1 ob.t=$si }
          l.append(ob)
        }
      prsadd(this)
    }

  proc append () { local i,nn
      nn=numarg()
      if (nn%2!=0) { print "ERROR: Must give name/command pairs" return }
      n+=(nn/2)
     for i=1,numarg() {
          ob = new String2($si)
          i+=1
          if (flag) sprint(ob.t,"%s=%s",stem,$si) else ob.t=$si
          l.append(ob)
        }
      ob=nil
    }
  proc post () { pcomm.s=$s1 }

  // use appnums() if have "name=" stem and not giving different names
  proc appnums () { local i
      if (! flag) { print "ERROR: Must have stem 'name='" return }
      n+=numarg()
      for i=1,numarg() {
          ob = new String2()
          sprint(ob.s,"%g",$i)
          sprint(ob.t,"%s=%g",stem,$i)
          l.append(ob)
        }
      ob=nil
    }
  // exec, clear and comm take object number for list l
  proc exe () { // set allele indicated in v vector
      sprint(tstr,"{%s %s}",l.object(v.x[$1]).t,pcomm.s)
      execute1(tstr) 
    } 
  proc exec () {   // set allele indicated by index
      sprint(tstr,"{%s %s}",l.object($1).t,pcomm.s)
      execute1(tstr) 
    }
  proc clear () { execute(clr) }   // run clear command for this
  proc nam () {        // append name of this param to comment
      if (sfunc.len($s1)) sprint($s1,"%s,%s",$s1,name) else $s1=name }
  proc com () {        // append comment indicated in v vector
      if (sfunc.len($s1)) sprint($s1,"%s, %s",$s1,l.object(v.x[$2]).s) else $s1=l.object(v.x[$2]).s }
  proc comm () {  // append comment by index
      if (sfunc.len($s1)) sprint($s1,"%s, %s",$s1,l.object($2).s) else $s1=l.object($2).s }
  obfunc ale () { return new String2(name,l.object(v.x[$1]).s) }
  proc do () { clear() exe($1) com($s2,$1) }   // clear,exe,com
endtemplate PRS

//* prsset(#[,print]) read and set params from comment
proc prsset () { local ii,sz localobj bb,name,val
    bb=new List()
    split(panobj.llist.o($1).name,bb,"[:_/=,]")
    sz=bb.count
    if (sz/2!=int(sz/2)) print "WARNING: not even # of name/num pairs: ",sz
    for (ii=bb.count-2;ii>=0;ii-=2) { name=bb.o(ii) val=bb.o(ii+1) 
        if (!isnum(name.s) && isnum(val.s)) { // name=val
            sprint(tstr,"%s=%s",name.s,val.s) 
            if (numarg()==2) print tstr else execute(tstr)
          } else {
            printf("WARNING: can't execute %s=%s\n",name.s,val.s)
          }
      }
  }

//* setprs() -- set parameters
// sets up v vector that gives order in which to run them
func setprs () { local nn,snum,flag,verbose
    if (numarg()==1) flag=1 else flag=0 // flag -- called during file parse
    verbose=0
    snum=1  nn=1
    if (verbose) temp_string_=""
    for ltr(XX,prsl) snum*=XX.n // total number of sims to be run
    if (verbose) for ltr(XX,prsl) sprint(temp_string_,"%s %d(%s) x",temp_string_,XX.n,XX.name)
    for ltr(XX,prsl) { // go through the parameters
        XX.v.resize(snum)
        divup(XX.v,XX.n,nn) // make ind a vector of indices for 
        nn *= XX.n
      }
    if (verbose) {chop(temp_string_) print temp_string_}
    // check that using cvode local
    if (cvode_local()==0 && flag==0) { // called before a run
        cvode_local(1)
        printlist.remove_all()
        print "WARNING: must recreate printlist before running exerun()"
      }
    return snum
  }

//** divup(vec,grp_size,sets) -- #_grps = vec.size/grp_size 
proc divup () { local sets,num,grp,sz,ii,jj,kk,ll
    sz=$o1.size grp=$2 sets=$3 num=sz/sets/grp  kk=-1
    for ll=1,sets for jj=0,grp-1 for ii=1,num $o1.x[kk+=1]=jj 
  }

//* autoset
//  sims = setprs()
//  if (ncells<sims) print "ERROR -- don't have enough cells."
//  eg: for ii=0,sims-1 for ltr(XX,prsl) cell[ii].soma XX.exe(ii)
//  for ltr(XX,prsl) XX.nam(tt) print tt
//  for ii=0,sims-1 { tt="" for ltr(XX,prsl) { XX.com(tt,ii) } print tt }

//* autorun puts out to different files -- NOT updated
proc autorun () { local ii
    sims = setprs()
    for ii=0,sims-1 {
        sprint(panobj.output_file,"v%s.s%02d",datestr,ii)
        comment=""
        for ltr(XX,prsl) XX.do(ii,panobj.comment)
        printf("%s %s\n",panobj.output_file,panobj.comment)
        tmpfile.aopen("index")  tmpfile.printf("%s %s\n",output_file,comment) tmpfile.close()  
        run()
        sprint(output_file,"data/%s",output_file)
        pvplist(output_file,comment)
      }
  }

//** exerun() appends to the same file
proc exeruncall () {}
proc run1 () { run() }
proc exerun () { local ii,ok localobj XX,YY,o,tl,st
    if (sims==0) {printf("parset not initialized\n") return }
    tl=new List() st=new String()
    if (numarg()>=1) st.s=$s1
    panobj=grv_
    system("date")
    prsnames(panobj.comment)
    for ltr(XX,printlist) tl.append(new String(XX.name))
    for ii=0,sims-1 { 
        for ltr(XX,prsl) XX.clear
        for ltr(XX,prsl) XX.exe(ii)
        exeruncall(ii)
        ok = execute1("run1()")
        if (ok) prsplist2(tl,ii,st.s)
        printf("%d/%d: %s (%d)\n",ii+1,sims,tt,ok)
        panobj.pvnext(ii)
      }
    for ltr2(XX,YY,printlist,tl) XX.name=YY.s // restore labels
    prssave()
    system("date")
    prsshow()
  }

proc mpirun () { local ii,ok localobj XX,YY,o,tl,st
    pc = new ParallelContext()
    if (sims==0) {printf("parset not initialized\n") return }
    tl=new List() st=new String()
    if (numarg()>=1) st.s=$s1
    panobj=grv_
    for ltr(XX,printlist) tl.append(new String(XX.name))
    for ltr(XX,prsl) XX.clear
    printf("Master launch: %s",tstr)
    pc.runworker()          // master returns immediately, workers wait for jobs
    for ii=0,sims-1 pc.submit("mpirun2",ii)
    while (pc.working) {}   // await results  
    pc.done                 // wait for workers to finish printing
  }

proc mpirun2 () { local ii
    ii=$1
    for ltr(XX,prsl) XX.exe(ii)
    sprint(output_file,"data/%s/v%s.%02d",datestr,datestr,runnum+ii)
    comment=output_file
    prsnames(comment,ii)
    exeruncall(ii)
    ok = execute1("run1()")
    printf("%s in %s from %d (%d,%d)\n",comment,output_file,ii,pc.id,ok)
    panobj.pvplist(output_file,comment)
  }

proc pard () {}
proc pardisp () { local ii
    tmpfile.wopen($s1)
    prsnames(comment)
    tmplist.remove_all // save the label names in tmplist
    for ltr(XX,printlist) {tmpobj=new String(XX.vec.label) tmplist.append(tmpobj)}
    // for ltr(XX,prsl) vlk(XX.v)
    for ii=0,sims-1 { 
        for ltr(XX,prsl) XX.clear
        for ltr(XX,prsl) { 
            XX.exe(ii)
            tmpfile.printf("\t%d:%d: %s :: %s\n",ii,i1,XX.l.object(XX.v.x[ii]).s,XX.l.object(XX.v.x[ii]).t)
          }
        exeruncall(ii)
        pard (ii) // callback stub
        tmpfile.printf("%d/%d: %s\n",ii+1,sims,tt)
      }
    for ltr2(XX,YY,printlist,tmplist) XX.vec.label=YY.s // restore labels
    tmpfile.close
  }

//** autopr() prints out a series of pictures, use cutps and ps2gif afterward
proc autopr () {
    for ltr(XX,dir) {
        geall(1)
        read_vfile(1,XX.s)
        grall(1)
        sprint(filename,"%s.ps",XX.s)
        print_session(0, filename)
      }
  }

//* xpostray(name1,name2): organize name1 vs name2 on a tray
objref xposvec
xposvec = new Vector()
xpf=1 // flag for new disp or superimpose
// ppo -- just show the comment
proc ppo () { local i
    for i=1,xposvec.size xposvec.x[i-1]=$i
    xpostray(-1)
  }
// execute the xposvec given as arguments -- allows setting for a run
proc expo () { local i
    for i=1,numarg() {
        XX=prsl.object(i-1)
        XX.clear
        XX.exec($i) // exec doesn't use the xposvec
        printf("%s:%s,%s\n",XX.name,XX.l.object($i).s,XX.l.object($i).t)
      }
    exeruncall()
  }

// display the xposvec given as arguments
proc xpo () { local i
    for i=1,xposvec.size xposvec.x[i-1]=$i
    if (xpf==1 && panobj.super==0) { 
        print "ERROR: no tray available to draw on" return }
    xpostray(xpf)
  }

// eliminate labels written by rv()
proc rv3 () { $s1="" }

proc xpostray () { local rows,cols,i,j,k,p,g1,flag,xs,ys,sz localobj grvecstr,XX,YY,ob
    if (numarg()==1) flag=$1 else flag=0
    if (vcount(xposvec,-1)!=1 || vcount(xposvec,-2)!=1) {
        sprint(mesg,"ERR: Rows/cols?: xpo(%d",xposvec.x[0])
        for vtr(&x,xposvec) if (i1>0) sprint(mesg,"%s,%d",mesg,x) sprint(mesg,"%s)",mesg)
        print mesg  return } 
    p = allocvecs(1)
    grvecstr=new String()
    g1 = panobj.glist.count
    grvecstr.s = ""
    for vtr(&x,xposvec,&y) {
        if (x==-1) XX=prsl2.object(y) else { // rows
            if (x==-2) YY=prsl2.object(y) else { // cols
                sprint(grvecstr.s,"%s%s %s;",grvecstr.s,prsl2.object(y).name,prsl2.object(y).l.object(x).s) }}}
    if (sfunc.len(grvecstr.s)>0) chop(grvecstr.s) 
    sprint(grvecstr.s,"%s - %s v %s:%s",panobj.filename,XX.name,YY.name,grvecstr.s)
    printf("xpo(%d",xposvec.x[0]) for vtr(&x,xposvec) if (i1>0) printf(",%d",x) print ")"
    print grvecstr.s
    rows=XX.n  cols=YY.n  sz=rows*cols
    // printf("%d x %d\n",rows,cols)
    if (flag==-1) { return }
    if (flag) {
        ob=boxerl.object(trnum) // specify tray
        ob.name = grvecstr.s
        if (rows!=ob.rows || cols!=ob.cols) { 
            sprint(mesg,"ERROR: tray %dx%d; not %dx%d\n",ob.rows,ob.cols,rows,cols) 
            print mesg return }
        for ltr(graphItem,ob.gl) graphItem.erase_all()
        g1 -= sz
      } else {
        if (cols>5) xs=1200/cols-50 else xs=200
        if (rows>7) ys=900/rows-50 else ys=100
        mktray(panobj,rows,cols,xs,ys)
        boxer.name=grvecstr.s
        trnum=boxerl.index(boxer)
        ob=boxer
      }
    mso[p].resize(sz)
    for vtr2(&x,&y,XX.v,YY.v,&y[1]) if (xprsok(y[1])) mso[p].x[x*cols+y]=y[1]
    for lvtr(graphItem, &x, ob.gl, mso[p]) {
        panobj.rv(x)
        sprint(grvecstr.s,"%s:%s v %s:%s",XX.name,XX.l.object(XX.v.x[x]).s,YY.name,YY.l.object(YY.v.x[x]).s)
        graphItem.label(0.1,0.9,grvecstr.s)
      }
    panobj.viewplot()
    dealloc(p)
  }

//** xprsok()
// need to avoid XX,YY,x,y globals since nested 
func xprsok () { local i,flag
    i=$1 flag=1
    for lvtr(tmpobj,&x[1],prsl2,xposvec) {
        if (x[1]!=-1 && x[1]!=-2 && x[1]!=tmpobj.v.x[i]) {flag=0 continue}
      }
    return flag
  }
  
proc xpostrmp () {
    ob=boxerl.object(boxerl.count-1) // last tray
    ob.boxes[0].unmap
    ob.boxes[0].map(ob.name)
  }

// prsfor(NAME,VAL,FROM,TO,INC)
// eg prsfor("LEAK","g_Pass",1e-3,9e-3,1e-3)
proc prsfor () { local from,to,inc,ii
    if (numarg()==0) { print "prsfor(NAME,VAL,FROM,TO,INC)" return }
    from=$3 to=$4 inc=$5 
    sprint(tt,"ob=new PRS(\"%s\",\"%s=\"",$s1,$s2)
    for (ii=from;ii<=to;ii+=inc) sprint(tt,"%s,%g",tt,ii)
    sprint(tt,"%s)",tt)
    execute(tt)
  }

// prsvals(NAME,VAL,val1,val2,...)
// eg prsvals("LEAK","g_Pass",1e-3,9e-3,30e-3,75e-3)
proc prsvals () { local i
    if (numarg()==0) { print "prsvals(NAME,VAL,val1,val2,...)" return }
    sprint(tt,"ob=new PRS(\"%s\",\"%s=\"",$s1,$s2)
    for i=3,numarg() sprint(tt,"%s,%g",tt,$i)
    sprint(tt,"%s)",tt)
    execute(tt)
  }

//** xpospanl() -- panel for choosing params to graph
proc xpospanl () { local ii localobj ob
    bx=new VBox()
    bx.intercept(1)
    if (0) if (attrnum==0 && sims!=printlist.count)  {
        printf("WARNING: not enough printlist items (%d); read from file\n",sims) 
        prsread() }
    labelm = 0 // xpostray() will do own labeling
    if (0) if (attrnum==0 && printlist.count>1) { prsl2prsl2() ob=prsl2 } else ob = prsl
    ob = prsl
    xposvec.resize(ob.count)
    xpanel("Set params")
    xvarlabel(mesg)
    for ltr(XX,ob,&x) {
        xmenu(XX.name)
        for ltr(YY,XX.l,&y) {
            sprint(temp_string_, "xposvec.x[%d]=%d",x,y)
            xradiobutton(YY.s, temp_string_)
          }
        sprint(temp_string_, "xposvec.x[%d]=%d",x,-1)
        xradiobutton("ROWS", temp_string_)
        sprint(temp_string_, "xposvec.x[%d]=%d",x,-2)
        xradiobutton("COLS", temp_string_)
        xmenu()
      }
    xbutton("Make tray","xpostray()")
    xbutton("Reuse tray","xpostray(1)")
    xvalue("Tray #","trnum",1)
    xbutton("Remove trays","rmtray(attrnum)")
    xbutton("Limits","panobj.wvpanl()")
    xbutton("Read file","prsread()")
    xpanel()
    sprint(tstr,"PARSET:%s",filename)
    bx.intercept(0) bx.map(tstr)
    if (xposvec.size>1) { 
        xposvec.fill(0) xposvec.x[0]=-1 xposvec.x[1]=-2
      } else { print "Something wrong in parset." }
  }

//** prsl2prsl2() adds the printlist onto prsl2
proc prsl2prsl2 () { local p,prct,ii,jj
    p=allocvecs(1)
    print "Adding printlist items onto parameter lists"
    prct = printlist.count  
    prscp(prsl2,prsl)
    for ltr(XX,prsl2,&x) {   // expand out each of the param entries
        mso[p].copy(XX.v)      // save temporarily 
        XX.v.resize(sims*prct) // intersperse 'pointers' to printlist items
        for vtr(&x,mso[p]) for ii=0,prct-1 XX.v.x[i1*prct+ii]=x
      }
    ob = new PRS("states","{}")
    prsl.remove(prsl.count-1) // automatically added on to prsl, take it off
    for ltr(XX,printlist) if (sfunc.len(XX.vec.label)==0) {
        ob.append(XX.name,"{}") } else ob.append(XX.vec.label,"{}")
    ob.v.resize(sims*prct)
    for ii=0,sims-1 for jj=0,prct-1 ob.v.x[ii*prct+jj]=jj
    prsl2.append(ob)
    dealloc(p)
  }

//** proc prscp(p1,p2) -- copy from p2 to p1
proc prscp () {
    $o1.remove_all
    tmpobj=prsl  prslp=$o1 
    for ltr(XX,$o2) {
        ob = new PRS(XX.name,XX.clr)
        for ltr(YY,XX.l) ob.append(YY.s,YY.t)
        ob.v.copy(XX.v)
      }
    prslp=tmpobj // restore the pointer
  }

//* prsnames,-vals,-show,-show2
proc prsnames () {  localobj XX,st
    if (numarg()==2) for ltr(XX,prsl) {
        st=XX.ale($2)
        sprint($s1,"%s, %s=%s",$s1,st.s,st.t)
      } else for ltr(XX,prsl) XX.nam($s1) 
  }
proc prsvls () {  $s1="" for ltr(XX,prsl) XX.com($s1,$2) }
proc prsshow () { local flag
    if (numarg()==1) flag=$1 else flag=0
    prsnames(tt) print tt
    if (flag==2) for ii=0,sims-1 { 
        tt="" prsvls(tt,ii) printf("%s; ",tt) 
      } else for ltr(XX,prsl) {
        tt=""
        sprint(tt,"%s: %d (",XX.name,XX.n)
        for ltr(YY,XX.l) sprint(tt,"%s%s,",tt,YY.s)
        sfunc.left(tt,sfunc.len(tt)-1)
        printf("%s)\n",tt)
      }
  }

//** prsplist() -- rename the items in printlist
proc prsplist () { local min,max,flag
    prsnames(tt) comment=tt
    if (printlist.count != sims) { print "ERROR prsplist" return }
    for ltr(YY,printlist,&x) {
        tt="" 
        for ltr(XX,prsl) sprint(tt,"%s,%s:%s",tt,XX.name,XX.l.object(XX.v.x[x]).s)
        sfunc.right(tt,1)
        sprint(YY.name,"%s",tt)
      }
  }

//** prsplist2() -- used by exerun
// put a suitable combination title on the printlist item.vec.label
proc prsplist2 () { local ii,x localobj XX,YY
    ii=$2
    if (numarg()==3) sprint(tt,",%s",$s3) else tt=""
    for ltr(XX,prsl) sprint(tt,"%s,%s=%s",tt,XX.name,XX.l.object(XX.v.x[ii]).s)
    sfunc.right(tt,1) // get rid of leading ,
    for ltr(YY,printlist,&x) sprint(YY.name,"%s:%s",tt,$o1.o(x).s)
  }

//** prspars(#) show the params for that exe #
proc prspars () {
    ii=$1  tt=""
    for ltr(XX,prsl) sprint(tt,"%s,%s:%s",tt,XX.name,XX.l.object(XX.v.x[ii]).s)
    sfunc.right(tt,1)
    print tt
  }

//** prsid(str) find the exe # for the param string
func prsid () { local ii
    for ii=0,sims-1 { 
        tt=""
        for ltr(XX,prsl) sprint(tt,"%s,%s:%s",tt,XX.name,XX.l.object(XX.v.x[ii]).s)
        sfunc.right(tt,1)
        if (strc($s1,tt)) break
      }
    if (ii==sims) return -1 else return ii
  }

//* prssave,prsread
proc prssave () { local ii
    if (numarg()==1) file_with_p($s1,temp_string_,temp_string2_) else {
        file_with_p(panobj.output_file,temp_string_,temp_string2_) }
    tmpfile.wopen(temp_string_)
    print "Writing ",temp_string_
    if (printlist.count<=1) ob=prsl else { prsl2prsl2() ob=prsl2 }
    for ltr(XX,ob) {
        tmpfile.printf("%s\n",XX.name)
        if (sfunc.len(XX.clr)) tmpfile.printf("%s\n",XX.clr) else tmpfile.printf("{}\n")
        tmpfile.printf("%d\n",XX.l.count)
        for ltr(YY,XX.l) {
            tmpfile.printf("%s\n",YY.s)
            if (sfunc.len(YY.t)) tmpfile.printf("%s\n",YY.t) else tmpfile.printf("{}\n")
          }
      }
    tmpfile.close()
  }

// run prsread() after reading in file
proc prsread () { local ii,num
    if (0) {
        file_with_p($s1,tt,temp_string2_) 
        read_vfile(1,$s1)
      } else { 
        file_with_p(panobj.filename,tt,temp_string2_) 
      }
    prsparsef(tt)
    prscp(prsl2,prsl)
    xpospanl()
  }

//** parse files; used by prsread() 
// usage: for ltr(XX,dir) {prsparsef(XX.s) prsshow() }
proc prsparsef () { local ii,num
    print "Reading ",$s1
    prsl.remove_all
    if (! tmpfile.ropen($s1)) { print $s1," not found."  return }
    while ((numr = tmpfile.scanstr(temp_string_)) != -1) { 
        tmpfile.gets(temp_string2_)
        chop(temp_string2_)
        ob = new PRS(temp_string_,temp_string2_)
        num = tmpfile.scanvar()
        for ii=1,num {
            tmpfile.gets(temp_string_)
            tmpfile.gets(temp_string2_)
            chop(temp_string_) chop(temp_string2_)
            ob.append(temp_string_,temp_string2_)
          }
      }
    sims = setprs(1)
  }

// showpars() prs explorer using dired
proc showpars () {
    dired(dir,"data/p*")
    lbrw(dir,"showpars1")
  }
proc showpars1 () { local outv
    tstr=dir.object(hoc_ac_).s
    prsparsef(tstr)
    if (strcmp(prsl.object(prsl.count-1).name,"states")==0) {
        outv=prsl.object(prsl.count-1).l.count
        printf("%d sims x %d states\n",sims/outv,outv)
      } else printf("%d sims\n",sims)
    prsshow() 
  }

//** file_with_p(filename,result,scratch): replace v99 with p99 in result
proc file_with_p() {
    if (sfunc.substr($s1,"/") == -1) {
        sprint($s2,".%s",$s1)
      } else {
        sfunc.tail($s1,".*/v",$s3)
        sfunc.head($s1,"/[^/]+$",$s2)
        sprint($s2,"%s/p%s",$s2,$s3)
      }
  }
// END /usr/site/nrniv/local/hoc/parset.hoc
//================================================================
// END init.hoc
//================================================================
//================================================================
// INSERTED nqsnet.hoc
// =Id= nqsnet.hoc,v 1.77 2006/04/11 20:10:21 billl Exp $

// load_file("nqsnet.hoc")
objref sp[5],nq[5]
system("datestring",datestr)
chop(datestr)
obfunc cobj(){} // return cell given gid (defined in network.hoc)

//* Numbers and connectivity params
// %con (con/pre) = %div (div/post)
ncols=10
scale=2
double numc[CTYPi],ix[CTYPi]
for ii=0,CTYPi-1 numc[ii]=0
{numc[DP]=500*scale  ix[DP]=0}
{numc[SU]=1000*scale ix[SU]=ix[DP]+numc[DP]}
{numc[IN]=250*scale  ix[IN]=ix[SU]+numc[SU]}
allcells=numc[DP]+numc[SU]+numc[IN]
double pmat[CTYPi][CTYPi]
pmat[DP][DP] =  0.1
pmat[DP][SU] =  0.1
pmat[DP][IN] =  0.1
pmat[SU][DP] =  0.05
pmat[SU][SU] =  0.05
pmat[SU][IN] =  0.1
pmat[IN][DP] =  0.22
pmat[IN][SU] =  0.22
pmat[IN][IN] =  0.22
wid=1
if (1) {snum=0 for case(&x,IN,SU,DP) for case(&y,IN,SU,DP) snum+=int(pmat[x][y]*numc[x]*numc[y]+1)}

//* weight params
//** delay
DELM=2.2   // minimum delay
DELD=0.1   // added delay per unit distance

//** strengths
double wmat[CTYPi][CTYPi][2]
double thresh[CTYPi]
thresh[DP]=20
thresh[SU]=20
thresh[IN]=35
wmat[DP][DP][0]=1.0/scale
wmat[DP][DP][1]=0.2/scale
wmat[DP][SU][0]=4.00/scale
wmat[DP][SU][1]=0.5/scale
wmat[DP][IN][0]=0.1/scale
wmat[DP][IN][1]=0.001/scale
wmat[IN][DP][0]=0.2/scale
wmat[IN][DP][1]=0.2/scale
wmat[SU][SU][0]=1.0/scale
wmat[SU][SU][1]=1.0/scale
wmat[SU][DP][0]=0.02/scale
wmat[SU][DP][1]=0.02/scale
wmat[SU][IN][0]=0.01/scale
wmat[SU][IN][1]=0.001/scale
wmat[IN][SU][0]=1.0/scale
wmat[IN][SU][1]=0.01/scale
wmat[IN][IN][0]=0.5/scale
wmat[IN][IN][1]=0.001/scale

// pmat[SM][DP] =  0.2 pmat[SM][SU] =  0.2 pmat[SM][IN] =  0.5
// wmat[SM][SU][0]=0.2 wmat[SM][DP][0]=0.2 wmat[SM][IN][0]=0.2

//* routines
//* mkcp()
obfunc mkcp0 () { localobj lo
  lo = new NQS("PRID","POID","STYP","PIJ","DIV","CONV","NSYN","NPRE")
  lo.useslist("PRID",CTYP) lo.useslist("POID",CTYP) lo.useslist("STYP",STYP)
  return lo
}

proc mkcp () { local ii,jj,n,cn,cnum
  cp=mkcp0()
  cp.tog("DB")
  cp.zvec()
  for ii=0,CTYPi-1 for jj=0,CTYPi-1 if (pmat[ii][jj]!=0) {
    cp.append(ii,jj,styp(ii,jj),pmat[ii][jj],pmat[ii][jj]*numc[jj],pmat[ii][jj]*numc[ii],pmat[ii][jj]*numc[ii]*numc[jj],numc[ii])
  }
  sprint(tstr,"data/%sS%02d.cpnqs",datestr,scale)
  cp.sv(tstr)
} 

//** styp() sets synapse type based on presynaptic cell
func styp () { local pr,po
  pr=$1 po=$2
  if (pr==IN && po==IN) { return GA 
  } else if (pr==IN) { return IX
  } else if (pr==SU || pr==DP) { return EX
  } else if (pr==SM) { return AM
  } else printf("styp ERR %s->%s not classified",CTYP.object(pr).s,CTYP.object(po).s)
}

for ii=0,2 {sp[ii]=new NQS("PR","PO","WT","WT1","DEL") sp[ii].clear(1e5*scale)}
batch_flag=1
for ii=0,2 sp[ii].mo(1)
batch_flag=0
// mkspmat() uses sp and sp[1], returns sp
proc mkspmat () { local a,sn,ii,jj,n,x,y localobj vr,vo
  x=$1 y=$2 // z=$3
  rdm.ACG(903342)
  a=allocvecs(vr,vo)
  sn=pmat[x][y]*numc[x]*numc[y] // number of synapses
  for ii=0,1 sp[ii].clear
  sp.mo(2)
  sp.pad(1.5*sn) // leave room
  rdm.discunif(ix[x],ix[x]+numc[x]-1) // randomly chosen presynaptic cells
  PRv.setrand(rdm)
  rdm.discunif(ix[y],ix[y]+numc[y]-1)  // randomly chosen postsynaptic cells
  POv.setrand(rdm)
  // if (z==EX) z1=AM else z1=z  sytyp(c[y],z1,vr) SIDv.vfill(vr)
  rdm.normal(wmat[x][y][0],(0.5*wmat[x][y][0])^2) // calc random weights
  WTv.setrand(rdm)   // set the weight column
  if (wmat[x][y][1]!=0) {
    rdm.normal(wmat[x][y][1],(0.5*wmat[x][y][1])^2) // calc random weights
    WT1v.setrand(rdm)   // set the weight column
  } else WT1v.fill(0)
  rdm.normal(DELM,DELD) // random delays
  DELv.setrand(rdm)    
  sp.elimrepeats("PR","PO") // so don't have 2 connections between same cells
  sp.shuffle()  // randomize again
  sp.pad(sn) // reduce the length down to desired
  sp.mo(2) // reset the PRv,POv,... pointers
  WTv.negwrap()  WT1v.negwrap() // take any neg weights and make them positive
  dealloc(a)
}

// mkpomat() only make the array for a single postsynaptic cell
proc mkpomat () { local a,sn,ii,jj,n,x,y,yid localobj vr,vo
  x=$1 y=$2 yid=$4
  // rdm.ACG(903342)
  a=allocvecs(vr,vo)
  sn=pmat[x][y]*numc[x]*1 // number of synapses
  if (sn<1) { // treat sn<1 as a prob of connecting rather than a density
    if (rdm.uniform(0,1)<sn) sn=1 else sn=0 // flip coin
  } else if (sn<5) sn=round(sn) // possibly round it up
  if (sn==0) { dealloc(a) return }
  for ii=0,1 sp[ii].clear
  sp.mo(2)
  sp.pad(1.5*sn) // leave room
  rdm.discunif(ix[x],ix[x]+numc[x]-1) // randomly chosen presynaptic cells
  PRv.setrand(rdm)
  POv.fill(yid)
  // if (z==EX) z1=AM else z1=z  sytyp(cobj(yid),z1,vr) SIDv.vfill(vr)
  rdm.normal(wmat[x][y][1],(0.5*wmat[x][y][0])^2) // calc random weights
  WTv.setrand(rdm)   // set the weight column
  if (wmat[x][y][1]!=0) {
    rdm.normal(wmat[x][y][1],(0.5*wmat[x][y][1])^2) // calc random weights
    WT1v.setrand(rdm)   // set the weight column
  } else WT1v.fill(0)
  rdm.normal(DELM,DELD) // random delays
  DELv.setrand(rdm)    
  sp.elimrepeats("PR","PO") // so don't have 2 connections between same cells
  sp.shuffle()  // randomize again
  sp.pad(sn) // reduce the length down to desired
  sp.mo(2) // reset the PRv,POv,... pointers
  // take any small weights and push them up
  WTv.negwrap((0.5*wmat[x][y][0])^2) WT1v.negwrap((0.5*wmat[x][y][0]))
  dealloc(a)
}

proc mkall () {  local x,y,z localobj fname
  fname=new String()
  for case(&y,DP,SU,IN) { // 
    sp[2].clear
    for case(&x,DP,SU,IN) {
      if (pmat[x][y]!=0) {
        mkspmat(x,y) 
        sp[2].grow(sp)
      }
    }
    sprint(fname.s,"%s%sS%02d.spnqs","CONNTABLE",CTYP.o(y).s,scale)
    print "Writing ",fname.s
    sp[2].x.x[0]=y
    sp[2].sv(fname.s)
  }
}

// nqs2txt()
proc nqs2txt () { local ii,last,lnum,n,fl1 localobj f,fn
  nq=new NQS("GID","LINE","NUML","TELL")
  fn=new String()
  fl1=lnum=n=0
  f=new File()
  sprint(tstr,"data/%sS%02d.syns",datestr,scale)
  f.wopen(tstr)
  for case(&y,FP) { // FP,TP,B5 need proper order
    sprint(fn.s,"data/%s%sS%02d.nqs",datestr,CTYP.o(y).s,scale)
    sp.rd(fn.s)
    sp.sort("SID") sp.sort("PR") sp.sort("PO")
    if (fl1==0) {  
      last=sp.v[1].x[0]
      nq.append(last,lnum+1,-1,f.tell)
      fl1=1
    }
    for ii=0,sp.size(1)-1 {
      PR=sp.v[0].x[ii] PO=sp.v[1].x[ii] SID=sp.v[2].x[ii] WT=sp.v[3].x[ii] DEL=sp.v[4].x[ii]
      if (PO==last) {
        lnum+=1 n+=1
        f.printf("%d %d %d %g %g\n",PO,PR,SID,WT,DEL)
      } else {
        nq.set("NUML",-1,n)
        n=0
        if (PO==last+1) {
          nq.append(PO,lnum+1,-1,f.tell+1)
        } else { 
          printf("%d is not a target\n")
          nq.append(PO,lnum+1,0,f.tell+1)
        }
        last=PO
        ii-=1 // do this one again
      } 
    }
    nq.set("NUML",-1,n)
  }
  sprint(tstr,"data/%sS%02d.index",datestr,scale)
  f.wopen(tstr)
  for ii=0,nq.size(1)-1 {
    f.printf("%d %d %d %d\n",nq.v[0].x[ii],nq.v[1].x[ii],nq.v[2].x[ii],nq.v[3].x[ii])
  }
  f.close
}

// nqssplit(file,N) // read in large file and split in N pieces
proc nqssplit () { local n,ii,last,lnum,fl1 localobj f,stem,qq
  stem=new String() f=new File()
  qq=new NQS($s1)
  n=$2
  sz=qq.size(1)
  sscanf($s1,"%[^.].nqs",stem.s)
  each=int(sz/n)
  for ii=0,n-1 {
    sprint(tstr,"%s%c.nqs",stem.s,ii+97)
    print tstr
    qq.select("IND_","[]",ii*each,(ii+1)*each-1)
    qq.out.sv(tstr)
  }
  nqsdel(qq)  
}

proc ncl2mat () { local ii,wt,del,pc,pr,po,prid,poid,ps,sy,syn localobj Xo
  if (!isassigned(sp)) {
    sp=new NQS("PRID","POID","PR","PO","SYNID","DEL","WT0","THRESH") }
  for ii=0,ncl.count-1 { 
    Xo=ncl.o(ii)
    pc=id(Xo.pre) prid=id(Xo.precell) sy=id(Xo.syn) poid=id(Xo.postcell)
    pr=ojtnum(Xo.precell) po=objnum(Xo.postcell)
    if (!isojt(Xo.postcell,nil)) syn=Xo.postcell.synlist.index(Xo.syn)
    if (poid==-1 && sy==-1) {  // nil targ
    } else if (poid==-1) { // ACELL targ -- not implemented
    } else if (prid==-1) { // ACELL src
      sp.append(pc,poid,ojtnum(Xo.pre),po,syn,Xo.delay,Xo.weight,Xo.threshold)
    } else {
      sp.append(prid,poid,pr,          po,syn,Xo.delay,Xo.weight,Xo.threshold)
    }
  }
}

//* fill everything in and save it
// mkcp()
time("mkall()")

// END nqsnet.hoc
//================================================================
// INSERTED network.hoc
// =Id=  network.hoc,v 1.195 2006/04/16 20:20:37 billl Exp 

//* Numbers and connectivity params
// %con (con/pre) = %div (div/post)
objref ce,ncl[CTYPi][CTYPi]
double numc[CTYPi],ix[CTYPi],ixe[CTYPi]
for ii=0,CTYPi-1 ix[ii]=numc[ii]=0
if (name_declared("redo")) reload=1 else reload=0

if (reload) {
    print "reloading"
    for ltr(XO,new List("NetCon")) XO.active(0)
    printlist.remove_all
    ncl.remove_all
    ce.remove_all
  } else redo=1

//* Artificial cell home -- don't need geom.hoc
create acell_home_
access acell_home_

//* read .net file
strdef netstem
scale=2
netstem="CONNTABLE"
{sp = new NQS() cp = new NQS()}

//* CREATE CELLS
// %con (con/pre) = %div (div/post)
ce=new List()
proc creatns () { local ii,ty,n,m
    sprint(tstr,"%sS%02d.cpnqs",netstem,scale)
    print tstr
    cp.rd(tstr)
    cp.tog("DB")
    ce.remove_all
    m=0
    for vtr(&ty,uniq(cp.find("PRID"))) {
        n=cp.fetch("PRID",ty,"NPRE")    
        numc[ty]=n
        for ii=0,n-1 {
            sprint(tstr,"ce.append(new %s(%d,%d))","INTF",m,ty) 
            execute(tstr)
            m+=1
          }
      }
    n=ix[0]=0
    for ii=1,CTYPi-1 if (numc[ii]>0) {
        ix[ii]=(n+=numc[ii-1]) 
        ixe[ii]=ix[ii]+numc[ii]-1
      } else ix[ii]=-1
    // for ii=0,CTYPi-1 print CTYP.o(ii).s,":",ix[ii]
    ncells=m
  }

//    // needs to be fixed to use single cell list
//    proc creatss () {
  //    cp.select("IDENT",CMP2)
  //    for cp.qt(&n,"NUM",&ty,"CTYP") {
    //    c[ty].object(n).dend c[ty].object(n).po[AM]=new AMPA(0.5)
    //    c[ty].object(n).dend c[ty].object(n).po[NM]=new NMDA(0.5)
    //    c[ty].object(n).soma c[ty].object(n).po[GA]=new GABAA(0.5) 
    //    c[ty].object(n).soma c[ty].object(n).po[GB]=new GABAB(0.5) 
    //    }
  //    }

// need to count values in both WT and WT1 cols
proc countsyns () {
    sum=0
    sprint(tstr,"%s*.spnqs",netstem)
    dired(tstr,2)
    for ltr(XO,dir) {
        sp.rd(XO.s)
        sum+=sp.select("WT","!=",0)
        sum+=sp.select("WT1","!=",0)
      }
    print sum
  }

// smap() replace one in syncode.hoc
sp.resize("PR","PO","WT","WT1","DEL")
sp.mo(1)
for case(&x,DP,SU,IN) for case(&y,DP,SU,IN) ncl[x][y]=new List()
proc smap () { local ii,sz,pr1,po1 localobj xo,o,pro,poo
    sprint(tstr,"%s*.spnqs",netstem)
    dired(tstr,2)
    for ltr(xo,dir) {
        sp.rd(xo.s)
        print xo.s," ",sz=PRv.size
        for ii=0,PRv.size-1 {
            pro=ce.o(PRv.x[ii]) poo=ce.o(POv.x[ii])
            ncl[pro.type][poo.type].append((nc=new NetCon(pro,poo)))
            // NetCon(source, target, threshold, delay, weight)
            nc.delay=DELv.x[ii]
            for kk=0,4 nc.weight[kk]=0
            if (pro.type==IN) {
                nc.weight[GA]=WTv.x[ii]
                if (WT1v.x[ii]>0) nc.weight[GB]=WT1v.x[ii]
              } else {
                nc.weight[AM]=WTv.x[ii]
                if (WT1v.x[ii]>0) nc.weight[NM]=WT1v.x[ii]
              }
          }
      }
  }

creatns()  // create cells
time("smap()")
// END network.hoc
//================================================================
//================================================================
// INSERTED params.hoc
// =Id=  params.hoc,v 1.786 2006/07/10 13:26:12 billl Exp 

// $runnum=500;
// @INSUGA = (3.9,5.0)
// @INSUGB = (0.3,0.5)
// @SUINNM = (0.0)
// @SUINAM = (0.7,1.0)
// @SUSUAM = (2.5)
// @SUSUNM = (450)
// @SUDPAM = (15,22)
// @SUDPNM = (80)
// @INDPGA = (0.1,0.15)
// @INDPGB = (0.3,0.5)
// @DPINNM = (0.02)
// @DPINAM = (3,5)
// @DPSUAM = (1,1.5)
// @DPSUNM = (300,600)
// @DPDPAM = (80,180)
// @DPDPNM = (320)

if (name_declared("dstr")) batch_flag=1 else batch_flag=0
if (!batch_flag) {
    DPDPNM=1
    DPDPAM=1
    DPSUNM=10
    DPSUAM=1.5
    DPINAM=40e-8
    DPINNM=1
    INDPGB=1
    INDPGA=1
    SUDPAM=1
    SUDPNM=1
    SUSUNM=1
    SUINAM=80e-8
    SUINNM=1
    INSUGB=10
    INSUGA=1
    SUSUNM=1e-6
    SUSUAM=1
    SCTH=1
    SCAHP=1
  }

SPONTINVL=100
BURINVL=200
SPONTBACK=5
BURSZ=4
BURP=0.01
DPP=0.1 // percent DP cells

//* Declarations
objref p,jspks,wvspks0,dwvspks0,fih,intf,nstim,ncs,vq
intf=ce.o(0) // use for global calls
{wvspks0=new Vector(1e3) dwvspks0=wvspks0.c jspks=wvspks0.c}
vseed(223481)

//* general params
tstop = 1e3
v_init=1000 // so keep v's as set randomly

//* ARTC params
mg_INTF=1.6
EAM_INTF=50 // these are deviations above RMP
ENM_INTF=35
AMdec_INTF=0.5

iterator ixt () { local ii
    for ii=ix[$1],ix[$1]+numc[$1]-1 { XO=ce.o(ii)
        iterator_statement
      }
  }

proc setDP () { local ii,ty
    ty=DP
    rdm.ACG(33020319)
    ind.resize(numc[ty])
    rdm.uniform(0,1)
    ind.setrand(rdm)
    for ii=ix[ty],ix[ty]+numc[ty]-1 { XO=ce.o(ii)
        XO.ahpwt=0.43556944
        XO.tauahp=301.67708 
        XO.RMP=-70
        XO.VTH = -34.832292 
        XO.refrac = 8.0335416 
        XO.Vblock=-30
        XO.tauGA=80
        XO.tauGB=100
        XO.VGBdel=50
        XO.rebound=0.0
      }
  }

proc setSU () { local ii,ty
    ty=SU
    rdm.ACG(913233)
    ind.resize(numc[ty])
    rdm.uniform(0,1)
    ind.setrand(rdm)
    for ii=ix[ty],ix[ty]+numc[ty]-1 { XO=ce.o(ii)
        XO.ahpwt = 1.6893033 
        XO.tauahp = 385.92038 
        XO.RMP=-70
        XO.VTH = -51.407962 
        XO.refrac = 5.0194028 
        XO.Vblock=-30
        XO.tauGA=70
        XO.tauGB=100
        XO.VGBdel=50
        XO.rebound=0.0
      }
  }

proc setIN () { local ii,ty
    ty=IN
    for ii=ix[ty],ix[ty]+numc[ty]-1 { XO=ce.o(ii)
        XO.ahpwt=0.5
        XO.tauahp=50
      }
  }
{setDP() setSU() setIN()}

//* REAL params

//* stim
ncs=new List()
nstim=new NStim(0.5,0,SM)
nstim.number=0
nstim.start=40
nstim.interval=10
// ncs.remove_all
sample(vec,ix[SU],ix[SU]+numc[SU]-1,0.1*numc[SU])
rdm.uniform(0,20)
ind.resize(vec.size)
ind.setrand(rdm)
for vtr(&x,vec) { 
    XO=ce.object(x)
    ncs.append(nc=new NetCon(nstim,XO,0,0,30))
  }
for ltr(nc,ncs) {
    for ii=0,nc.wcnt-1 nc.weight[ii]=0
    nc.weight[0]=30
    nc.weight[1]=30
  }
// for ltr(XO,ncs) XO.weight=30
// for ltr(XO,ncs,50) XO.weight=0

sample(vec,ix[SU],ix[SU]+numc[SU]-1,BURP*numc[SU])
for ii=ix[SU],ix[SU]+numc[SU]-1 { XO=ce.o(ii) XO.invlset(0) }
if (0) for vtr(&x,vec) { 
    XO=ce.object(x)
    XO.invl=BURINVL
    XO.invlset(1)
    XO.WINV=35
    XO.nbur=BURSZ
  }

// mkvspks(NUMCELLS,NUMGROUPS,INVL1,SPREAD,[APPEND])
// mkvspks(sgrpsz,sgrpsz/SPONTBACK,SPONTINVL,10)
vq=new NQS("ind","time","wt") 
proc randspkset () { local a,nsu,ndp localobj dvq
    a=allocvecs(1)
    // rdvspks("05mar11_11_4.vspks") // could save and restore
    nsu=1 ndp=5
    vq.clear(nsu*numc[SU]+ndp*numc[DP])
    mso[a].indgen(ix[SU],ix[SU]+numc[SU]-1,1)
    for ii=0,nsu-1 vq.v.append(mso[a]) // each cell will get input N x
    vq.pad()
    rdm.uniform(0,tstop) vq.v[1].setrand(rdm) // at some random time between 0 and 7500
    rdm.uniform(0.6,1.0) vq.v[2].setrand(rdm)
  
    dvq=new NQS("ind","time","wt") 
    mso[a].indgen(ix[DP],ix[DP]+numc[DP]-1,1)
    for ii=0,ndp-1 dvq.v.append(mso[a]) // each cell will get input 50x
    dvq.pad()
    {rdm.uniform(0,tstop) dvq.v[1].setrand(rdm) }// at some random time between 0 and 700
    {rdm.uniform(30,40) dvq.v[2].setrand(rdm)}
    // dvq.v[2].fill(-1) // guarantee spiking
    vq.grow(dvq)
    nqsdel(dvq)
    vq.sort("time") vq.sort("ind")
    dwvspks0.copy(vq.v[2],0,ndp*numc[DP]-1) wvspks0.copy(vq.v[2],ndp*numc[DP],-1)
  
    ty=SU sgrpsz=numc[SU]
    for ii=ix[ty],ix[ty]+numc[ty]-1 { XO=ce.o(ii) XO.vinset(0) } // turn everything off first
    for ii=ix[ty],ix[ty]+sgrpsz-1 { XO=ce.o(ii) XO.initvspks(vq.v,vq.v[1],vq.v[2]) }
    ty=DP sgrpsz=numc[DP]
    for ii=ix[ty],ix[ty]+numc[ty]-1 { XO=ce.o(ii) XO.vinset(0) } // turn everything off first
    for ii=ix[ty],ix[ty]+sgrpsz-1 { XO=ce.o(ii) XO.initvspks(vq.v,vq.v[1],vq.v[2]) }
    dealloc(a)
  }

proc randrewt () { local a,ty,mul
    a=allocvecs(1)
    ty=$1 mul=$2
    if (ty==SU) {
        mso[a].copy(wvspks0)
        mso[a].mul(mul)
        vq.v[2].copy(mso[a],dwvspks0.size)
      } else if (ty==DP) {
        mso[a].copy(dwvspks0)
        mso[a].mul(mul)
        vq.v[2].copy(mso[a],0)
      }
    dealloc(a)
  }
  
time("randspkset()")

rdm.uniform(0,0.3)
jspks.setrand(rdm)
// in[0].initjitter(jspks) // global

//* syns
double wd0[CTYPi][CTYPi][STYPi] // prior weight delta
for ii=0,CTYPi-1 for jj=0,CTYPi-1 for kk=0,STYPi-1 wd0[ii][jj][kk]=1
proc wmul () { local ii,pr1,po1,sy1,w1,wd,sy2
    pr1=$1 po1=$2 sy1=$3 w1=$4
    if (wd0[pr1][po1][sy1]==0) {
        if (w1!=0) printf("\nWARNING: %s->%s(%s) set to 0 can't reset\n",\
                          CTYP.o(pr1).s,CTYP.o(po1).s,STYP.o(sy1).s)
        return
      }
    wd=w1/wd0[pr1][po1][sy1]
    if (wd!=1) {
        XO=ncl[pr1][po1]
        for ii=0,XO.count-1 XO.o(ii).weight[sy1]*=wd
        wd0[pr1][po1][sy1]=w1
      } else printf(".")
  } 

proc rewt () {
    rdm.ACG(913342)
    wmul(SU,SU,AM,SUSUAM)
    wmul(SU,SU,NM,SUSUNM)
    wmul(SU,DP,AM,SUDPAM)
    wmul(SU,DP,NM,SUDPNM)
  
    wmul(DP,DP,AM,DPDPAM)
    wmul(DP,DP,NM,DPDPNM)
    wmul(DP,SU,AM,DPSUAM)
    wmul(DP,SU,NM,DPSUNM)
  
    wmul(SU,IN,AM,SUINAM)
    wmul(DP,IN,AM,DPINAM)
    wmul(SU,IN,NM,SUINNM)
    wmul(IN,IN,GA,2)
  
    wmul(IN,SU,GA,INSUGA)
    wmul(IN,DP,GA,INDPGA)
    wmul(IN,IN,GA,0.5)
    wmul(IN,SU,GB,INSUGB)
    wmul(IN,DP,GB,INDPGB)
    wmul(IN,IN,GB,0.0)
    randrewt(SU,3)
    randrewt(DP,1)
  }

time("rewt()")
// END params.hoc
//================================================================
//================================================================
// INSERTED run.hoc
// =Id=  run.hoc,v 1.418 2006/07/10 13:38:34 billl Exp 

objref wf1,wf2,wrec
// {wf1=new File() wf2=new File()}
// wrec = new NQS("time","ID","SYN","WT")
// wrec.zvec(2e7) // make big enough?

method("local")
cvode.atol(1e-3) 
cvode.condition_order(1)
// fih = new FInitializeHandler("send()")
gapchk=10
proc send () { cvode.event(28,"redwt()") }
proc send () { }
proc redwt () {}

proc a () { local sh,sv
    if (!isobj(aa,"Graph")) if (isobj(g,"Graph")) aa=g else {gg() aa=g}
    if (aa.view_count==0) aa.view(0,0,tstop,ncells,200,200,400,300)
    sv=gnum gnum=ojtnum(g)
    graphItem=g
    sh=0 grv_.super=1 g.erase_all
    grv_.gveraseflag=0  grv_.gvmarkflag=grv_.super=1 // gnum=0
    gv(0,1+sh,2) gv(1,3+sh,2) gv(2,2+sh,2)
    grv_.gvmarkflag=grv_.super=0
    gnum=sv
  }
proc b () { rewt() time() a() }

proc init () { 
    initMisc1()
    vseed(392426)
    finitialize() 
    cvode.re_init()
  }

proc initrr () {  // for doing a rerun
    rewt()
    intf.global_init()
    nstim.global_init()
    vseed(392426)
  }

proc setMemb () {}

proc initMisc1 () { 
    intf.global_init()
  }

objref ww // global ww for post processing
proc wrecon () { localobj tl,vit
    tl=new List()
    for scase(XO,"Field_SU","FIELD_DP","FIELD_IN") {
        printlist.append(vit=new vitem(XO.s,tstop/vdt_INTF,vdt_INTF))
        tl.append(vit.vec)
      }
    for ltr(tl) XO.resize(tstop/vdt_INTF+10)
    intf.initwrec(tl) // done once globally
    for ixt(SU) XO.wrec(1)
    for ixt(DP) XO.wrec(2)
    for ixt(IN) XO.wrec(3)
    wwht_INTF=5000 wwwid_INTF=100
  }

proc wrecoff () {
    ty=SU
    for ii=ix[ty],ix[ty]+numc[ty]-1 { XO=ce.o(ii) XO.wrec(0) }
    ty=DP
    for ii=ix[ty],ix[ty]+numc[ty]-1 { XO=ce.o(ii) XO.wrec(0) }
  }

proc finishMisc () { local ii
    for ltr(XO,printlist) if (isassigned(XO.o)) if (XO.o.fflag) XO.o.fini
    intf.global_fini
  }

//** snapsv() save after printlist items min-max to fixed dt
proc snapsv () { local a,vdt,min,max localobj v1,o
    grv_.bst(3,3)
    vdt=0.2 
    a=allocvecs(v1)
    v1.resize(tstop/vdt)
    for ltr(o,printlist) { 
        if (o.code!=3) continue
        v1.snap(o.vec,o.tvec,vdt)
        o.vec.copy(v1)
        o.pstep=vdt
        o.tvflag=0
      }
    if (numarg()==0) grv_.pvall()
    dealloc(a)
  }

proc exeruncall () { for ltr(XO,printlist) if (XO.code==3) XO.tvflag=1 }
proc pvout2 () { snapsv(1) }

p=printlist
proc prlclr () { 
    for ltr(XO,printlist) if (isassigned(XO.o)) if (XO.o.fflag) XO.o.recclr
    intf.wwfree(0)
    for ltr(XO,printlist) XO.vec.play_remove XO.tvec.play_remove
    printlist.remove_all
  }

proc prl () { local a,ii,jj,offst,ty localobj vit
    offst=0
    prlclr()
    if (1) for case(&ty,DP,SU,IN) {
        for ii=ix[ty],ix[ty]+numc[ty]-1 { XO=ce.o(ii) 
            if (ii==ix[ty]) { 
                vit=new_printlist_nc(XO, offst+ii, CTYP.object(ty).s) 
              } else { 
                new_printlist_nc2(vit, XO, offst+ii) 
              }
          }
        offst=0
      }
    npacsz=20
    if (1) for case(&ty,SU) {
        for jj=10,20 { XO=ce.o(ix[ty]+jj)
            XO.recclr
            new_printlist_ac(XO,"V",  CTYP.object(ty).s,XO.id)
            // new_printlist_ac(XO,"VGB",  CTYP.object(ty).s,XO.id)
            // new_printlist_ac(XO,"VGA",  CTYP.object(ty).s,XO.id)
            // new_printlist_ac(XO,"AHP",  CTYP.object(ty).s,XO.id)
            printlist.o(printlist.count-1).code=3 // use code 3 for snapping
          }
      }
    if (0) for case(&ty,SU) for jj=10,11 {
        XO=ce.o(ix[ty]+jj)
        new_printlist_ac(XO,"V",  CTYP.object(ty).s,XO.id)
        printlist.o(printlist.count-1).code=2
      }
    wrecon()
  }

prl()

//* rub() -- multi-run with saving to veclist
// saves vspks(1), SM(2), SU(2), IN(2)
proc rub () { local ii localobj so
    so=new String()
    clrveclist()
    for ii=0,9 {
        sprint(so.s,"%d",ii)
        shuffle(vspks)
        savevec(vspks)
        time()
        savevec(p.object(0).vec,p.object(0).tvec)
        savevec(p.object(1).vec,p.object(1).tvec)
        savevec(p.object(2).vec,p.object(2).tvec)
      }
  }

// spri(#) puts up graph of just one class
// 0->SM 1->SU 2->IN
// map 0,1,2 onto 1,3,5 ii*2+1
proc spri () { local ii,a,jj
    a=allocvecs(1)  ge(0)
    for ii=0,9 { jj=7*ii+$1*2+1
        mso[a].copy(veclist.object(jj))
        mso[a].add(1.5*ii*(mso[a].max-mso[a].min)-mso[a].min)
        mso[a].mark(g,veclist.object(jj+1),"O",4,cg(ii))
      }
  }
// sprj(#) puts up SM,SU,IN for 1 run (cp a() above)
proc sprj () { local ii,jj
    jj=7*$1+1
    for ii=0,2 veclist.object(jj+ii*2).mark(g,veclist.object(jj+ii*2+1),"O",2,cg(ii))
  }

//** calcadd() just look at 1 V
proc calcadd () { local a,tt,ii,jj,kk,vdt localobj t0,tv,iv,sv,wv,tau,vv
    vdt=vdt_INTF
    if (numarg()>=1) { a=$1 kk=$2 } else a=allocvecs(7) 
    tau=mso[4] vv=mso[5] t0=mso[6]
    vrsz(4,tau,vv,t0,0)
    tv=wrec.out.v[0] iv=wrec.out.v[1] sv=wrec.out.v[2] wv=wrec.out.v[3]
    tau.x[0]=intf.tauAM tau.x[1]=intf.tauNM tau.x[2]=intf.tauGA tau.x[3]=intf.tauGB
    mso[kk].resize(tstop/vdt+10) mso[kk].fill(-1)
    // ii thru wrec, tt from 0 to tstop, jj thru output vec, kk for AM,NM,GA,GB
    for ({ii=0 tt=0 jj=0};tt<=tstop;{tt+=vdt jj+=1}) {
        mso[kk].x[jj]=vv.x[kk]*exp(-(tt - t0.x[kk])/tau.x[kk])
        if (ii<tv.size) if (tt>tv.x[ii]) { 
            vv.x[kk]*=exp(-(tt - t0.x[kk])/tau.x[kk])
            for (;tt>tv.x[ii] && ii<tv.size-1;ii+=1) vv.x[kk] += wv.x[ii] // forget about last value
            mso[kk].x[jj] = vv.x[kk]
            t0.x[kk]=tt
          }
      }
    mso[kk].resize(jj)
  }

//** set up to run multiple simulations using exerun()
proc parset () {
    prsl.remove_all
    prsvals("SCAHP","SCAHP",0.8,1,1.2)
    prsvals("SCTH","SCTH",0.8,1,1.2)
    ob.post("setSU() setDP()")
    prsvals("SUSUAM","SUSUAM",1,2,3,5)
    ob.post("wmul(SU,SU,AM,SUSUAM)")
    prsvals("SUSUNM","SUSUNM",250,450,900)
    ob.post("wmul(SU,SU,NM,SUSUNM)")
    sims=setprs()
    prsshow()
  }

parset()
// END run.hoc
//================================================================
//================================================================
// INSERTED go.hoc
// =Id=  go.hoc,v 1.13 2007/12/18 00:35:40 billl Exp 

// used to make 06jul10.04 [195.786.418] for modeldb
// rcsopen("network.hoc,195,params.hoc,786,run.hoc,418")
run()
panobj.super=0
panobj.gvmarkflag=1
func rv2() { }
gv(0,2,2)
func rv2() { $o1.add(100) }
panobj.super=1
gv(1,3,2)
panobj.gvmarkflag=0
func rv2() { $o1.scale(3100,4100) }
gv(14,1,4)
func rv2() { $o1.scale(-3000,0) }
gv(3,1,2)
func rv2() { $o1.scale(-4000,-1000) }
gv(10,2,2)
panobj.glist.o(0).size(0,tstop,-4000,4000)
panobj.super=0
ap()
// END go.hoc
//================================================================
// END batch.hoc
//================================================================