// Created 10/31/10 23:24:42 by "/usr/site/scripts/loadfiles -d -o mosinit.hoc mdb.hoc"
load_file("nrngui.hoc")
//================================================================
// INSERTED /usr/site/nrniv/simctrl/hoc/setup.hoc
// =Id=  setup.hoc,v 1.25 2006/12/26 22:34:47 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/simctrl/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 2010/11/01 01:50:24 samn Exp 

xwindows=1
show_panel=0
pwd()

//================================================================
// INSERTED /usr/site/nrniv/local/hoc/xgetargs.hoc
// =Id=  xgetargs.hoc,v 1.20 2008/05/11 17:19:11 billl Exp 

xgahfl=0
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/decvec.hoc
// =Id=  decvec.hoc,v 1.422 2010/05/03 16:52:52 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,xtmp
{dblform="%.4g" tabform=" "}

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.156 2009/08/25 14:31:59 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
// 2 ways of storing strings: directly in XO.s (t,u,v) OR 
//   using XO.set("NAME","STR") which is returned by XO.get("NAME").s
// 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
// declared() not yet declared
if (!name_declared("isobj")) execute1("func isobj(){return 0}") // place holder
if (!name_declared("isassigned")) execute1("func isassigned(){return 0}") // place holder
if (!name_declared("llist")) execute1("proc llist(){}") // place holder
begintemplate Union
public ty,x,s,t,u,v,o,xptr,xg,xs,optr,og,os,get,set,xl,ol,fi,inc,list,err,pr,sz
strdef s,t,u,v,tstr
objref o[10],xl,ol,this,xo
double x[10],sz[1],err[1]
external sfunc,isobj,isassigned,nil,DBL,llist
// 1arg -- store a num, string or obj
// 2arg -- pick up type out of list
proc init () { local ii,i,ox,xx,sx,flag
    ox=xx=sx=0 ty=argtype(1) // 'type' of Union defined by 1st arg on creation
    sz=10 // 10 is default size of arrays; for ii=0,sz-1 
    for ii=0,sz-1 x[ii]=ERR
    // special case of number in a vector or something in a list -- 2 args: list or vec,index
    err=1 flag=0
    if (numarg()/2==int(numarg()/2)) for (i=1;i<numarg();i+=2) {
        if (argtype(i)!=2 || argtype(i+1)==2) break
        flag=1
      }
    if (flag) { // "name",val,etc
        for (i=1;i<numarg();i+=1) {
            tstr=$si i+=1 
            if (argtype(i)==0) set(tstr,$i) else set(tstr,$oi)
          }
        s="" // used as temp storage only
      } else if (argtype(1)==1 && argtype(2)==0 && argtype(3)==-1) {
        ii=$2
        // printf("Union WARNING: taking single element out of a Vector or List\n")
        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
          }
      } else for i=1,numarg() {
        ii=argtype(i)
        if (ii==0) { 
            if (xx<sz) { 
                x[xx]=$i xx+=1 
              } else printf("Only have %d doubles available so can't store %g\n",sz,$i)
          } else if (ii==2) { 
            if (sx==0) s=$si else if (sx==1) t=$si else if (sx==2) u=$si else if (sx==3) v=$si else {
                printf("Only have 4 strings available so can't store %s\n",$si) }
            sx+=1
          } else if (ii==1) { 
            if (ox<sz) { o[ox]=$oi ox+=1
              } else printf("Only have %d objects available so can't store %s\n",sz,$oi)
          } else printf("Union ERR: argtype not recognized numarg %d %d\n",i,ii)
      }
    err=0
  }

proc pr () { print "Use Union[].list" }

proc list () { local flag
    flag=0
    if (ol!=nil) {
        for ii=0,sz-1 if ((! isojt(ol,ol.o(ii)))||o[ii]!=nil) {
            if (isojt(ol,ol.o(ii))) printf("%10s\t%s\n","NO NAME", o[ii]) else {
                                      printf("%10s\t%s\n",ol.o(ii).s,o[ii]) }
          }
        printf("%s\n","================================") 
        flag=1
      }
    if (xl!=nil) {
        for ii=0,sz-1 if ((! isojt(xl,xl.o(ii)))||x[ii]!=ERR) {
            if (isojt(xl,xl.o(ii))) printf("%10s\t%g\n","NO NAME", x[ii]) else {
                                      printf("%10s\t%g\n",xl.o(ii).s,x[ii]) }
          }
        printf("%s\n","================================") 
        flag=1
      }
    if (!flag) {
        printf("%s\nSCALARS: ","================================") 
        for ii=0,sz-1 if (x[ii]!=ERR) printf("%d:%g ",ii,x[ii])
        printf("\n%s\nOBJECTS: ","================================") 
        for ii=0,sz-1 if (o[ii]!=nil) printf("%d:%s ",ii,o[ii])
        printf("\n%s\n","================================") 
      }
    if (sfunc.len(s)>0) printf("%10s\t%s\n","s",s)
    if (sfunc.len(t)>0) printf("%10s\t%s\n","t",t)
    if (sfunc.len(u)>0) printf("%10s\t%s\n","u",u)
    if (sfunc.len(v)>0) printf("%10s\t%s\n","v",v)
  }

// full List
obfunc newl () { localobj o
    o=new List() 
    for ii=0,sz-1 o.append(o)
    return o
  } 
proc repl () { 
    if (isobj($o1.o($2),"String")) { $o1.o($2).s=$s3
      } else { $o1.remove($2) $o1.insrt($2,new String($s3)) }
  }

func fi () { local ii
    fif=-1
    for ii=0,sz-1 {
        if ($o1.o(ii)==$o1) {
            if (fif==-1) fif=ii // first empty slot if any
          } else if (strcmp($o1.o(ii).s,$s2)==0) return ii
      }
    return ERR
  }
// put in pointers for the x values
func xptr () { local i,ii
    if (numarg()>sz) {printf("More names (%d) than x items (%d) in %s:xptr\n",numarg(),sz,this) 
        error()}
    if (!isassigned(xl)) xl=newl()
    for i=1,numarg() repl(xl,i-1,$si)
    return xl.count
  }
func optr () { local i,ii
    if (numarg()>sz) {printf("More names %d than o items (%d) in %s:optr\n",numarg(),sz,this) error()}
    if (!isassigned(ol)) ol=newl()
    for i=1,numarg()  repl(ol,i-1,$si)
    return ol.count
  }
// xg() associative get of a num
func xg () { local ii
    ii=fi(xl,$s1)
    if (ii==ERR) {printf("Union:og (num get) failed -- \"%s\" not found\n",$s1) return ERR}
    return x[ii] 
  }
// xg() associative get of an obj
obfunc og () { local ii
    ii=fi(ol,$s1)
    if (ii==ERR) {printf("Union:og (obj get) failed -- \"%s\" not found\n",$s1) return nil}
    return o[ii] 
  }
// xs(index,"label",num) set a specific location using a string -- see set()
// xs("label",num) set an existing one only
func xs () { local ii,i
    if (!isassigned(xl)) xl=newl()
    if (argtype(1)==0) {
        i=3 ii=$1 // an index
        repl(xl,ii,$s2)
      } else {
        i=2 ii=fi(xl,$s1)
        if (ii==ERR) {printf("Union:xs (num set) failed -- no %s found\n",$s1) return ERR}
      }
    if (argtype(i)!=0) {printf("Union:xs err -- arg %d must be object\n",i) return ERR}
    x[ii]=$i
    return $i
  }
// os(index,"label",obj) set a specific location using a string -- see set()
// os("label",obj) set an existing one only
obfunc os () { local ii,i
    if (!isassigned(ol)) ol=newl()
    if (argtype(1)==0) {
        i=3 ii=$1 // $1 is an index
        repl(ol,ii,$s2)
      } else {
        i=2 ii=fi(ol,$s1)
        if (ii==ERR) {printf("Union:os (obj set) failed -- \"%s\" not found\n",$s1) return nil}
      }
    if (argtype(i)!=1) {printf("Union:os err -- arg %d must be object\n",i) return nil}
    o[ii]=$oi
    return $oi
  }

// get() get any type
obfunc get () { local ii
    if        ((ii=fi(ol,$s1))!=ERR) { 
        return o[ii] 
      } else if ((ii=fi(xl,$s1))!=ERR) { 
        if (argtype(2)==3) { $&2=x[ii] return this } else { return new DBL(x[ii]) }
      } else {
        // printf("Union:get() \"%s\" not found\n",$s1) 
        return nil // make returning nil the unique error
      }
  }

// increment or with neg decrement something
func inc () { local n
    if (numarg()==2) n=$2 else n=1
    if ((ii=fi(xl,$s1))==ERR) {printf("Union:inc ERR: %s %s\n",this,$s1) return ERR}
    return x[ii]+=n
  }

// set() set any type
func set () { local ii,i,ty,fo,fx
    if (xl==nil) xl=newl() if (ol==nil) ol=newl()
    for (i=1;i<numarg();i+=1) {
        tstr=$si i+=1 
        if ((ty=argtype(i))==0) xo=xl else if (ty==1 || ty==2) xo=ol // use String() for strings
        ii=fi(xo,tstr)
        if (ii==ERR) {
            if (fif==-1) {printf("UNION:set() ERRB: %s full for type %d\n",this,ty)  return ERR}
            repl(xo,(ii=fif),tstr)
          }
        if (ty==0) x[ii]=$i else if (ty==1) o[ii]=$oi else if (ty==2) { // don't use s,t,u,v
            o[ii]=new String($si)
          }
      }
    return ii
  }
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()   ret=1
    if (argtype(1)==2) st.s=$s1 else st.s=$o1.s
    // 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
  }

//** simopen()
proc simopen () { local x localobj o,xo
    o=new List()
    if (numarg()==1) split(allfiles,o) else split(simfiles,o)
    for ltr(xo,o,&x) xopen(xo.s)
  }

//** 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") error()}
    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)
  }

func assoc () { local i,ty,ii localobj xo
    // object_push(xo) ty=name_declared("s",1) object_pop() // strdef:4, dbl:5
    for ltr(xo,$o2,&ii) {
        if (argtype(1)==2) {
            if (strcmp(xo.s,$s1)==0) break
          } else if (argtype(1)==0) {
            if (xo.x==$1) break
          }
      }
    if ($o2.count==ii) return -1 else return ii
  }

// assoco() like assoc but returns the object instead of the index
obfunc assoco () { local i,ty,ii localobj xo
    // object_push(xo) ty=name_declared("s",1) object_pop() // strdef:4, dbl:5
    for ltr(xo,$o2,&ii) {
        if (argtype(1)==2) {
            if (strcmp(xo.s,$s1)==0) break
          } else if (argtype(1)==0) {
            if (xo.x==$1) break
          }
      }
    if ($o2.count==ii) return nil else return xo
  }

// excu() does the associative search and executes the resultant string 
// eg excu("key",list) excu("key",list,"arg1"[,"arg2","arg3"...]) 
func excu () { local i,ty,ii localobj xo,o,st
    o=$o2
    // object_push(xo) ty=name_declared("s",1) object_pop() // strdef:4, dbl:5
    for ltr(xo,o,&ii) {
        if (argtype(1)==2) {
            if (strcmp(xo.s,$s1)==0) break
          } else if (argtype(1)==0) {
            if (xo.x==$1) break
          }
      }
    if (o.count!=ii) {
        if (sfunc.len(xo.t)==0) return 0 // empty string
        st=strcat(st,"hoc_ac_=",xo.t,"(")
        if (numarg()>2) { 
            for i=3,numarg() {
                if (argtype(i)==2) { sprint(st.s,"%s%s,",st.s,$si)
                  } else if (argtype(i)==0) { sprint(st.s,"%s%g,",st.s,$i)
                  } else if (argtype(i)==1) { sprint(st.s,"%s%s,",st.s,$oi) }
              }
            chop(st.s)
          }
        strcat(st,")")
        execute(st.s)    // print st.s
        return hoc_ac_
      } else return 0
  }

// LAR: list_array is list used as an array
begintemplate LAR
public l,set,x,size,nil,resize,get,lt
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
  }

iterator lt () { local ii
    for ii=0,size-1 if (!eqojt(l,l.o(ii))) { 
        $o1=l.o(ii)
        iterator_statement
      }
  }
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.x=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_
  }

//* 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'
//   dired([list,]file,3) do recursive search
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 0 }
    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 || f==3) o.remove_all
    if (f==1) {
        tmpfile.ropen(st.s) 
      } else { // f!=1
        rmxtmp()
        if (f==3) {
            printf("Search starting in ") system("pwd")
            sprint(st.t,"sh -fc \"find . -name %s > %s\"",st.s,xtmp)
          } else {
            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
      } 
    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
          }
        XO=nil
     } else {
        for i = 2, numarg() {
            $o1 = $oi
            iterator_statement
            i1+=1
          }
      }
    XO=nil
  }

//* 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 ""
  }

// vpr2(v1,v2) to print out 2 vecs in parallel
proc vpr2 () { local i,fl2,max,min,newline localobj v1,v2
    newline=80
    v1=$o1 v2=$o2 min=0 max=v1.size if (v2.size!=max) {print "vpr2 diff szs" return}
    for ({i=min fl2=0}; i<max; i+=1) {
        if (v1.x[i]==BVBASE || v2.x[i]==BVBASE) {
            if (!fl2) printf(" ")  
            fl2=1  
          } else { 
            fl2=0
            printf("\n%5.1g %5.1g [%d]",v1.x[i],v2.x[i],i)
          }
      }
    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,x localobj o,st // clear vector then append
    if (! isobj($o1,"Vector")) $o1=new Vector(100)
    if (argtype(2)==2) {
        o=$o1 o.resize(0)
        st=new String2($s2)
        if (strm(st.s,",")) { // use split
            split(st.s,o)
          } else if (strm(st.s," ")) {
            split(st.s,o," ")
          } else while (sfunc.len(st.s)>0) { // assume binary vector, could generalize for hex and base64
            sscanf(st.s,"%1d",&x)
            o.append(x)
            sfunc.tail(st.s, ".", st.t)
            st.s=st.t
          }
      } else for (i=1;i<=numarg();i+=1) { 
        ty=argtype(i)
        if (ty==1) {        o=$oi o.resize(0)
          } else if (ty==0) { o.append($i)
          } else if (ty==3) { o.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
//   vrsz(VEC or NUM,VEC1,NUM,VEC2,etc)  -- vector resize -- to size of first arg (vec or num)
// or prior NUM
// optional final number is fill
func 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
        if (argtype(2)==0) {printf("vrsz(vec,num) backwards ERR\n") return -1}
      } 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)
    if (sz<0) sz+=$o2.size // reduce size
    if (sz<0) {printf("vrsz ERR: can't resize %s to %d\n",$o2,sz) return sz}
    for i=2, max { 
        if (argtype(i)==0) sz=$i else {
            $oi.resize(sz)  
            if (rsz0) $oi.resize(0) else if (flag) $oi.fill(fill) 
          }
      }
    return sz
  }

//** 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)
    if (argtype(1)==3) {
        mso[vv].from_double($2,&$&1)  
      } else for i=1, numarg() mso[vv].append($i)
    mso[vv].vwrite(tmpfile)
    dealloc(vv)
  }

//** readnums(&x[,&y...]) recover nums from tmpfile via a vector
func readnums () { local a,i,cnt localobj v1
    a=allocvecs(v1)
    v1.vread(tmpfile)
    cnt=0
    if (numarg()==1 && v1.size>1) {
        cnt=v1.size
        if (verbose) printf("readnums WARNING: reading %d vals into presumed double array\n",cnt)
        v1.v2d(&$&1)
      } else {
        if (numarg()>v1.size && verbose) {
            printf("readnums() WARNING: too many args %d>%d\n",numarg(),v1.size) }
        for (i=1; i<=numarg() && i<=v1.size; i+=1) $&i = v1.x[i-1]
        cnt=i-1
      }
    dealloc(a)
    return cnt
  }

//** 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)
        v1.label($oi.label)
        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 () { localobj xo
    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()
  }

// prvl2(filename[,list]) --- save using a more standard fwrite
proc prvl2 () { localobj xo,o
    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) o=$o2 else o=veclist
    for ltr(xo,o) {tmpfile.printf("%d\n",xo.size) xo.fwrite(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==nil) $oi=new Vector()
        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)
    clrveclist()
  }
  
// 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,flag
    a = allocvecs(1)
    revec(ind,vec)
    if (numarg()>=1) tmpfile.ropen($s1) else tmpfile.ropen("aa")
    if (numarg()>=2) flag=$2 else flag=2
    mso[a].scanf(tmpfile)
    if (flag==2) {
        for vtr2(&x,&y,mso[a]) {ind.append(x) vec.append(y)}
      } else {
        ind.copy(mso[a])
      }
    print ind.size," points read"
    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,xo
    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 localobj xo
    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,na localobj o
    if (numarg()==0) { 
        print "p=allocvecs(#) or p=allocvecs(v1,v2,...), access with mso[p], mso[p+1]..." return 0 }
    sz=MSOSIZ  na=numarg()
    lflg=0
    if (argtype(1)==0) {
        aflg=0 newv=$1
        if (na>=2) if (argtype(2)==0) sz=$2 else {lflg=1 o=$o2} // append to list in arg2
        if (na>=3) if (argtype(3)==0) sz=$3 else {lflg=1 o=$o3} 
        if (lflg) o.remove_all
      } else {
        aflg=1
        if (argtype(na)==0) {
            i=na sz=$i newv=i-1
          } else newv=na 
      }
    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,...)
// vecconcat(vec1,list) puts concat all vecs from list
// destructive: concatenates all vecs onto vec1
// performs a list2vec() functionality
proc vecconcat () { local i,max localobj xo
    max=numarg()
    if (numarg()<2) { 
        print "vecconcat(v1,v2,...) puts all into v1" return 
      }
    if (argtype(max)==0) {max-=1 $o1.resize(0)}
    if (isobj($o2,"List")) {
        $o1.resize(0)
        for ltr(xo,$o2) $o1.append(xo)
      } else 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,x,y localobj v1,v2,v3,v4
    a=allocvecs(v1,v2,v3,v4)
    if (argtype(2)==0) v2.append($2) else v2=$o2
    if (argtype(3)==0) v3.append($3) else v3=$o3
    vrsz($o1,v4)
    for vtr2(&x,&y,v2,v3) { // x -> y
        v1.indvwhere($o1,"==",x)
        $o1.indset(v1,y)
      }
  }

//** 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)

//** declare goes through a list of scalars and assigns them if they don't already exist
// eg declare("adj",nil,"vd",nil,"vc",nil,"allcells",0,"div","d[1][1]")
func declare () { local i,nd,min,verbose,ty,tye,ret localobj st,ut
    if (argtype(1)==0) {verbose=0 min=2} else {min=verbose=1}
    if (numarg()==0) {
        printf("eg declare(\"obj\",new Vector(),\"num\",0,\"arr\",\"d[2][2]\",\"vec\",\"o[5]\",\"str\",\"\")\nfirst arg num means quiet")
        return 0 }
    st=new String2() ut=new String2() ret=0
    ut.s="^[do]\\["  ut.t="^[A-Z][A-Za-z]+[(][^)]*[)]$" // for declaring arrays and objects
    for i=min,numarg() {
        st.s=$si     i=i+1
        ty=argtype(i)
        nd=name_declared(st.s)
        if (nd==1) { nd=0
            if (verbose) {
                printf("declare WARN defining '%s' despite prior existence in symbol table\n",st.s) }}
        if ((nd==5 && ty==0) || (nd==4 && ty==2) || (nd==2 && ty==1)) { // OK -- DO NOTHING
            if (i==min+1) ret=1
            if (verbose) printf("'%s' predeclared\n",st.s)
          } else if (nd != 0) { // different type codes from name_declared() bzw argtype()
            if ((nd==5 && ty==2) || (nd==2 && ty==2)) {
                if (strm($si,ut.s)) { // name_declared gives 2 for either objref and objarray
                    if (nd==5) st.t="DOUBLE" else st.t="OBJ"
                    if (verbose) {
                        printf("'%s' predeclared as %s array: WARN: no check on type or dims\n",st.s,st.t)}
                    continue  // declaration for a double or obj array 
                  } else  if (strm($si,ut.t)) { 
                    if (verbose) printf("'%s' predeclared\n",st.s)
                    continue  // declaration for an object
                  }
              }
            if (nd==5) tye=0 else if (nd==4) tye=2 else if (nd==2) tye=1 
            if (verbose) printf("Declared ERR %s predeclared as a %d statt %d\n",st.s,tye,ty)
          } else { // declare it
            if (ty==0) { 
                sprint(st.t,"%s=%g",st.s,$i)
              } else if (ty==1) { 
                if ($oi==nil) {  sprint(st.t,"objref %s\n%s=nil",st.s,st.s)
                  } else           sprint(st.t,"objref %s\n%s=%s", st.s,st.s,$oi)
              } else if (ty==2) { // key strings are eg d[5][5] or o[5][5] for double or obj array
                if (strm($si,ut.s)) {
                    if (strm($si,"^d")) ty=0 else ty=1
                    sfunc.tail($si,"[do]",st.t) 
                    if (ty==0) sprint(st.t,"double %s%s",st.s,st.t) else \
                               sprint(st.t,"objref %s%s",st.s,st.t) 
                  } else if (strm($si,ut.t)) {
                    sprint(st.t,"objref %s\n%s = new %s",st.s,st.s,$si) 
                  } else sprint(st.t,"strdef %s\n%s=\"%s\"",st.s,st.s,$si)
              }
            execute1(st.t)
          }
      }
    return ret
  }

//** 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,min,flag
    if (argtype(1)==0) {flag=$1 min=2} else {flag=0 min=1}
    for i=min,numarg() {
        nd=name_declared($si)
        if (nd==0 || (flag==1 && nd==1)) { // declare it or clear 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]*$") }

// fln(num,STR_OBJ) move forward line n lines, chop string at end, remove quotes if present
// fln("rxp",STR_OBJ) move forward to regexp rxp; with arg3 use exact search
// fln("rxp OR n",STR_OBJ,obj) return union in obj with more data
// uses tmpfile; assumes that file is open for reading
fln_lnum=0 // use to count lines; must be rest by calling routine
func fln () { local n,nn,x,y localobj o,st,un
    n=nn=0 y=OK o=$o2
    if (argtype(1)==0) nn=$1 // if need to back up
    if (argtype(3)==1 || argtype(4)==1) { un=new Union(tmpfile.tell())
        if (argtype(3)==1) $o3=un else $o4=un 
      }
    if (nn) {
        while(n<nn) { tmpfile.gets(o.s) n+=1 }
      } else { // look for a string
        st=new String2()
        if (argtype(3)!=0) { // default regexp search
            if (strc(o.s,"A")) o.s="B" else o.s="A" // start with something different
            while (! strm(o.s,$s1)) {tmpfile.gets(o.s) n+=1}
          } else {  // exact string search
            sprint(st.s,"%s\n",$s1) // look for this string
            o.s=$s1 // make sure not somehow starting with exactly the same thing
            while (strcmp(o.s,st.s)!=0) {tmpfile.gets(o.s) n+=1} // might want to return line cnt
          }
      }
    sfunc.left(o.s,sfunc.len(o.s)-1) // get rid of newline
    if (sfunc.head(o.s,"\"","")==0) { // find quote at beginning
        sfunc.left(o.s,sfunc.len(o.s)-1) // assume quote at end
        sfunc.right(o.s,1)
      } else if (sscanf(o.s,"%g,%g",&x,&y)==2) { // specifically used by NQS.rddif
      } else if (sscanf(o.s,"%g",&y)==1) { }
    if (un!=nil) {un.x[1]=tmpfile.tell() un.x[2]=n un.x[3]=x un.x[4]=y un.s=o.s}
    fln_lnum+=n
    return y
  }

// 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 } // print "AA:",$s1," ",sfunc.len($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
split_interp=1
func split () { local i,vf,x,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 
    if (argtype(2)!=1) {
        o=new Vector() vf=2 i=2
      } else { 
        o=$o2 i=3
        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(i)==2) {st.s=$si i+=1} else st.s="[, ]+"
    if (argtype(i)==0) { // length split into a list eg c2 c2 c2 etc
        if (vf) {printf("Split err: attempting to do length split into vector: %s",o) return 0}
        num=$i
        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 (split_interp) 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 && split_interp) { // try to interpret as a variable
                hoc_ac_=ERR // global hoc_ac_ for execute1()
                sfunc.head(s.t,st.s,s.s)
                if (sfunc.len(s.s)==0) s.s=s.t // the end
                sprint(st.t,"hoc_ac_=%s",s.s)
                execute1(st.t,0) // no error
                if (hoc_ac_==ERR) {
                    printf("split WARNING skipping non-parsable value: %s\n",s.s)
                  } else {
                    o.append(hoc_ac_) 
                  }
                done=1
              }
            if (vf==2) if (o.size==0) return ERR else return o.x[0]
          } 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
  }

//** splitmatch(str,strlist) returns which string in strlist matches the str
func splitmatch () { local ii,x,ret localobj ll,xo
    ll=$o2 ret=-1
    for ltr(xo,ll,&x) {
        if (strm($s1,xo.s)) {ret=x
            break }
      }
    return ret
  }

// parsenums(STR[,VEC]) find first or all the numbers in a string
func parsenums () { print "Use split(\"str\") instead" }

// 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]) 
obfunc downcase () { local len,ii,let,diff,min,max localobj st
    diff=32 min=65 max=90 st=new String2()
    if (argtype(1)==2) st.s=$s1 else st.s=$o1.s
    if (numarg()==2) { diff=-diff min=97 max=122 } // if flag -> upcase
    len = sfunc.len(st.s)
    for ii=1,len {
        sscanf(st.s,"%c%*s",&x)
        sfunc.right(st.s,1)
        if (x>=min&&x<=max) {
            sprint(st.s,"%s%c",st.s,x+diff)
          } else sprint(st.s,"%s%c",st.s,x) // just rotate the letter
      }
    if (argtype(1)==2) $s1=st.s
    return st
  }

// 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
// rdmuniqm4=1 to use setrnd() statt setrand()
rdmuniqm4=0
proc rdmuniq () { local i,max,min,n,a3,a,see localobj ro,v1,v2,vin,l
    if (numarg()==0) {
        printf("rdmuniq(vec,n,rdm) - augment vec by n unique vals from rdm\
      rdmuniq(vec,n) - augment vec by n unique vals 0-99\
      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\
      rdmuniq(vec,n,min,max,seed) - augment vec by n unique vals min-max using seed\n") 
      return }
    if (rdmuniqm4 && argtype(5)!=0) {
        printf("flag set: rdmuniqm4==1: should use all 5 args: rdmuniq(vec,n,min,max,seed)\n") return }
    vin=$o1 min=max=0 see=0 n=int($2) // round down
    a3=argtype(3)
    if (a3==1) {
        ro=$o3  // random previously setup, min,max unknown
      } else if (a3==-1) {
          min=0 max=99
      } else {
         max=$3
        if (argtype(4)==0){min=$3 max=$4}
        if (argtype(5)==0) see=$5
      }
    if (max>0) { // else rdm was an arg with unknown min,max
        if (max-min+1==n) {
            vin.indgen(min,max,1)
            return
          } else if (n>max-min+1) {
            printf("rdmuniq ERR incompatible: min=%d max=%d n=%d (%g vs %d)\n",min,max,n,$2,max-min+1) 
            return 
          }
      }
    if (!rdmuniqm4) {
        if (ro==nil) ro=new Random()
        if (see) ro.ACG($5) // seed it
        ro.discunif(min,max)
      }
    vin.resize(0)
    a=allocvecs(v1,v2) l=new List() l.append(v2) l.append(vin)
    for (ii=1;vin.size<n && ii<5;ii+=1) {
        v1.resize(n*4*ii)
        if (rdmuniqm4) { 
            v1.setrnd(5,max-min+1,see) 
            v1.add(min)
          } else v1.setrand(ro)
        v1.uniq(l,1) // preserve order
      }
    if (vin.size<n) {
        printf("rdmuniq ERR unable to find %d uniq values [%d,%d] -- only \n",n,min,max,vin.size)
      }
    vin.resize(n)
    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 oo.copy(oi)} else oo=oi
    oo.shuffle()
    return oo
  }

// colshuf(ind,veclist) shuffle the 'transpose' of indexed vecs -- ie not the vecs themselves
// shuffle items from list of vectors across the list rather than across the vectors
// all vecs should be same size, eg colshuf(nq.ind,nq.fcdo) after a select
func colshuf () { local a,x,ii,cols,rows  localobj v1,v2,oi,ol
    oi=$o1 ol=$o2 cols=ol.o(oi.x[0]).size rows=oi.size
    if (rows==0 || cols==0) {printf("ERRA:a 0") return -1}
    a=allocvecs(v1,v2)
    vrsz(rows*cols,v1,"O") 
    for vtr(&x,oi) v1.append(ol.o(x))
    v1.transpose(cols) v1.mshuffle() v1.transpose() // shuffle in the other direction
    for vtr(&x,oi,&ii) ol.o(x).copy(v1,ii*cols,(ii+1)*cols-1)
    dealloc(a)
    return cols
  }

// 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
  }

//* Matrix things
// msize() print size of a matrix
proc msize () { printf("%d x %d\n",$o1.nrow,$o1.ncol) }

//** l2m() turn a vector list into a matrix
obfunc l2m () { local ii,m,n localobj mat,l,xo
    l=$o1
    n=l.o(0).size m=l.count // rows x cols (data in cols)
    mat=new Matrix(n,m)
    for ltr(xo,l,&ii) mat.setcol(ii,xo)
    return mat
  }

//** m2l() turn a matrix into a vector list
obfunc m2l () { local ii,m,n localobj mat,l,xo
    l=new List() mat=$o1 m=mat.ncol n=mat.nrow
    for ii=0,m-1 l.append(mat.getcol(ii))
    return l
  }

//** reind(ind,filter0[,ifilter1,...]) goes through a series of vectors or values 
// to translate an index if filter is a vec then get vec.x[x] else get x+val
func reind () { local i,x
    x=$1 
    for i=2,numarg() if (argtype(i)==0) x+=$i else x=$oi.x[x]
    return x
  }

// rmxtmp() sets xtmp string
proc rmxtmp () { localobj st
    if (wopen("xtmp")) { 
        xtmp = "xtmp" 
      } else if (wopen("/tmp/xtmp")) {
        xtmp="/tmp/xtmp" 
      } else {  
        xtmp=strcat(1,getenv("HOME"),"/.xtmp").s 
        if (!wopen(xtmp)) printf("Can't open an xtmp file anywhere: . /tmp ~/ \n")
      }
    wopen() // close the file
  }
rmxtmp()

//* matrix functions using matrix.mod stuff
//** getdiag(matvec,destvec) 
proc getdiag () { local a localobj v1
    a=allocvecs(v1)
    v1.indgen(0,ROWS*COLS,COLS+1)
    $o2.index($o1,v1)
    dealloc(a)
  }

//** setdiag(matvec,value) 
proc setdiag () { local a localobj v1
    a=allocvecs(v1)
    v1.indgen(0,ROWS*COLS,COLS+1)
    $o1.indset(v1,$2)
    dealloc(a)
  }

func msetrc () { local x
    if ((x=sqrt($o1.size))==int(x)) ROWS=COLS=x else printf("Unable to set ROWS,COLS\n")
    return x
  }

for scase(XO,"o","t","s","O","T","S","+") clrsym.o.append(new String(XO.s))
// END /usr/site/nrniv/local/hoc/decvec.hoc
//================================================================
strdef mesg
objref xgabxl,xgabxo

//* xgetargs()
// xgetargs(panel_name,command,arg1[,arg2,...],defaults) // existing or new params -- flag 2
//   may have no named params in this case since just set with call to command
//   eg xgetargs("New","redo","do this","do that","1,2")
// xgetargs(panel_name,command,"a1,a2,..") // existing params -- flag 1
// xgetargs(panel_name,command,strlist)
// xgetargs(1,...) // dismiss after setting
// xgetargs(list,...) // list of helper functions returned by xgetclrfunc()
// eg xgetargs("Random session","newrand","# of patts","patt size  ","overlap   ","5,33,7")
// optional 1st arg flag=1 means to remove panel after command is called
// Union contains: o[0]=VBox, o[1]=argv, [o[2]=param name list] o[3]=orig update
//                 o[4]=helper functions
//                 x[0]=#args, x[1]=flag, x[2]=dismiss x[3-5] reserved for future use
//                 s=panel/button name,t=quit call,u=varlable,v=scratch
obfunc xgetargs () { local i,j,args,flag,dismiss,na localobj o,argv,vb,l,st,xo
    if (!isassigned(xgabxl)) xgabxl=new List()
    st=new String2()
    na=numarg()  
    dismiss=0 i=1 
    xgabxl.append(o=new Union())
    if (argtype(i)==0) { dismiss=$1 i+=1 }
    if (argtype(i)==1) {xo=$oi i+=1} else xo=xgetclrfunc()
    o.os(4,"funcs",xo) // list of helper functions
    o.xs(2,"dismiss",dismiss) // dismiss=1 means dismiss at end
    o.os(1,"argv",argv=new Vector(na))
    argv.resize(0)
    o.os(0,"vb",vb=new VBox())
    sprint(o.t,"xgaqt(%s)",o)
    vb.dismiss_action(o.t)
    o.s=$si i+=1 o.t=$si i+=1
    vb.intercept(1)
    xpanel(o.s)
    xvarlabel(o.u)
    sprint(o.v,"xgetexec(%s)",o)
    xbutton(o.s,o.v)
    excu("xgetbuttn",o.o[4],o)
    if (i==na) { // this should be a list of existing params
        o.xs(1,"flag",flag=1) // flag -- variables have names
        o.os(2,"plist",l=new List()) // list of param names
        if (argtype(i)==2) {
            split_interp=1
            split($si,l) // list of strings
            split($si,argv) // list of values
          } else if (argtype(i)==1) {
            for ltr(xo,$oi) {
                l.append(xo)
                argv.append(str2num(xo.s))
              }
          } else { printf("xgetargs ERRA\n") xpanel() return o=nil}
        args=argv.size
        if (args==0) { // create them
            for ltr(xo,l) {
                sprint(st.s,"%s=1",xo.s) execute(st.s)
                args=l.count argv.resize(args) argv.fill(1)
              }
          } else if (args!=l.count) {printf("xgetargs ERRB %d %d\n",args,l.count) xpanel() return o=nil}
        o.os(3,"orig",argv.c)   // save original values
        o.xs(0,"nargs",args)
        excu("xgetlabl",o.o[4],o)
        for j=0,args-1 {
            sprint(o.v,"%s.x[%d]",argv,j)
            sprint(st.s,"xgetchg(%s,%d)",o,j)
            xvalue(l.o(j).t, o.v, 1, st.s, 1)
          }
      } else {
        j=i i=na
        if (strm($si,"^[a-z]")) { // a named variable; should all be name vars
            o.xs(1,"flag",flag=3) // flag -- variables have names and routine is called with args
            split_interp=1
            split($si,argv)
            o.os(2,"plist",l=new List()) // list of param names
            split($si,l) // list of strings
          } else {
            split_interp=0
            split($si,argv)
            o.xs(1,"flag",flag=2) // flag -- variables may have no names; are just args to a function
          }
        i=j // restore i
        o.xs(0,"nargs",args=argv.size)
        if (args!=na-i) { printf("xgetargs ERRC: mismatch %d %d\n",args,na-i) xpanel() return o=nil }
        o.os(3,"orig",argv.c)   // save original values
        for j=0,args-1 {
            sprint(o.v,"%s.x[%d]",argv,j)
            sprint(st.s,"xgetchg(%s,%d)",o,j)
            xvalue($si,o.v,1,st.s,1)
            if (flag==3) l.o(j).t=$si
            i+=1
          }
      }
    o.u=o.s // start with this label
    // xbutton("Help (2 clicks)","xgah()")
    xpanel()
    vb.intercept(0)
    vb.full_request(1)
    vb.map(o.s)
    xgabxo=o // global for current xgab object
    return o
  }

//* xgah() should provide help -- doesn't
proc xgah () { 
    if (xgahfl==1) {
        continue_dialog("Press help button first, then elsewhere for button-specific help")
        xgahfl=0
      } else xgahfl=1
  }

//* xgetclrfunc() -- set up the callbacks as empty functions
obfunc xgetclrfunc () { local flag localobj st,xo,o
    flag=0
    if (numarg()==1) if (isobj($o1,"List")) flag=1
    if (flag) { // just clear the functions
        for ltr(xo,$o1) xo.t="" // clear
        return $o1
      } else { // create
        st=new String() o=new List()
        for scase(st,"xgetchg2","xgetexec2","xgaqt2","xgetlabl","xgetbuttn") {
            o.append(new String2(st.s)) }
        if (numarg()==1) $o1=o
        return o
      }
  }

//* xgetchg() done after a value is changed
proc xgetchg () { local i localobj o
    o=$o1 i=$2
  print "A",o,i,o.o[4]
    if (excu("xgetchg2",o.o[4],o,i)) return
    sprint(o.u,"Press '%s' button for effect",o.s)
  }

//* xgetexec() done when the 'make changes' button is pressed
proc xgetexec () { local i,args,dismiss,flag localobj o,l,av,vb,xo
    o=$o1
    if (excu("xgetexec2",o.o[4],o)) return
    args=o.x flag=o.x[1] dismiss=o.x[2] av=o.o[1] vb=o.o
    if (flag==1 || flag==3) {
        l=o.o[2]
        if (args!=l.count || args!=av.size) {
            printf("xgetexec() ERRA %d,%d,%d\n",args,l.count,av.size) return
          }
        for ltr(xo,l,&i) {
            sprint(o.v,"%s=%g",xo.s,av.x[i])
            execute(o.v)
          }
        if (flag==1) { // call the routine -- else will call below
            if (strm(o.t,"[(]")) o.v=o.t else sprint(o.v,"%s(%s)",o.t,o) // no args passed to function
          }
      }
    if (flag==2 || flag==3) {
        sprint(o.v,"%s(",o.t)
        for i=0,args-2 sprint(o.v,"%s%g,",o.v,av.x[i])
        sprint(o.v,"%s%g)",o.v,av.x[i]) 
      }
    execute(o.v)
    o.u="Changes submitted"
    if (dismiss) { xgaqt(o) // get rid of the box
      } else { o.o[3].copy(o.o[1]) } // new set of origs
  }
  
//* xgaqt() called when the panel is dismissed
proc xgaqt () { local x localobj av,vb,o
    o=$o1 
    if (excu("xgaqt2",o.o[4],o)) return
    av=o.o[1] vb=o.o
    vb.unmap()
    if ((x=xgabxl.index(o))!=-1) xgabxl.remove(x)
    if (xgabxo==o) xgabxo=nil
  }
// END /usr/site/nrniv/local/hoc/xgetargs.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/grvec.hoc
//* =Id=  grvec.hoc,v 1.658 2010/07/21 14:17:33 billl Exp 

// argtype: 0:double; 1:obj; 2:str; 3:double pointer
objref g[10],printlist,grv_,panobj,panobjl
strdef symb
symb = "O"
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/nqs.hoc
// =Id=  nqs.hoc,v 1.670 2010/05/05 20:24:42 billl Exp 

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

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

//* stubs for ancillary programs
double sops[21]  // AUGMENT TO ADD NEW OPSYM
declared("whvarg","whkey","varstr","nqsdel","chsel2","grsel2","oform")
proc oformoff () { execute1("func oform(){return NOP}") } // default no operation
proc oform64(){execute1("func oform(){{$o1.vpr(64,1)}return OK}")} // vec.vpr(64)
oformoff()
nqsselcp=1

//* 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,fcdv,fcdl,sstr // strings and vecs
public objl,verbose,tmplist,vlist,vl,vlc,nval,sval,oval,selcp,rxpstr,slorflag,stub,chunk,rdpiece
public sv,rd,append,pr,pri,prs,zvec,resize,size,fi,sets,set,setcol,setcols,gets,get,fetch,tog
public cp,copy,mo,aind,it,qt,ot,ut,vt,appi,eq,fcdseq,fcdoeq,sort,select,stat,map,apply,applf
public calc,pad,unpad,delect,fill,uniq,gr,clear,strdec,coddec,odec,fdec,vdec
public join,fillin,fillv,otl,selall
public unuselist,useslist,delrow,elimrepeats,grow,shuffle,fewind,listvecs,loose,rdcols
public percl,psel,svsetting,getrow,getcol,resize2,find,family,delcol,keepcols,selone
public sethdrs,gethdrs,version,svvers,i2,ay,svcols,svR,scpflag,unref,refs,qtset,keylook,cpout
public deriv,interval,renamecol,renamecols,info,getsel,tomat,frmat,marksym,vsort,hash,unnan
public cindx,mkind,cindcol,mset,mget,covarc,tomatc,noheader,csel,newval,rddif,rdatf,transpose
objref v[1],s[1],is[4],x,nil,ind,scr[3],fcd,fcds,fcdo,fcdv,fcdl,this,objl
objref cob,out,up,Xo,Yo,oval,tmplist,otl,vlist,vl,vlc,info,cindx

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

//** init()
proc init () { local i,ii,flag,ofl,scnt,na,fl,rdflag
    refs=-1 CODTY=10 FUNTY=11 VECTY=12 verbose=1
    noheader=nval=fl=scnt=ofl=flag=rdflag=ni=0 // flag set if creating the internal NQS
    selcp=nqsselcp
    svsetting=4 loose=1e-6
    for ii=2,3 is[ii]=new String()
    is[3].s="INDEX"  is[2].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 else if (argtype(1)==1) rdflag=2
    if (na>=1) if (argtype(1)==0) {
        fl=1 // 1 arg taken care of
        if ($1<=-10) {
            flag=1 up=$o2 fl=2 ofl=-($1+10)
            m=up.m 
            if (ofl) {
                objref v[m]
                for ii=0,m-1 v[ii]=new Vector()
              } else 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 fcdv=up.fcdv // finish creation of .out here
          } else if ($1<0) { // flag to create a large set of vectors with no labels and no .out
            fl=2 noheader=ofl=-$1 
            if (argtype(2)==0) m=$2 else m=$o2.count()
            objref v[m]
            for ii=0,m-1 v[ii]=new Vector() // no s[ii] strings
            if (argtype(2)==1) for ii=0,m-1 v[ii].copy($o2.o(ii))
          } 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 String2($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
    qtset=0
    chunk=100
    info=new Union()
  nqsvers="=Id=  nqs.hoc,v 1.670 2010/05/05 20:24:42 billl Exp " svvers=-1
    if (!flag && ofl!=2) { 
        out=new NQS(-10-ofl,this)
        if (rdflag==1) rd($s1)
        if (rdflag==2) copy($o1)
      } 
    chk()
  }

// deallocate the attached nqs if destroyed
// after build NQS should have external pointer and out.up pointer +/- cob
// NB: 'this' is created and destroyed as needed
proc unref () {
    return
    // if (isassigned(out)) printf("AA:%d ",$1) else printf("BB:%d ",$1)
    if ($1<=refs) { // don't bother if have more than 2 refs or if currently building
        if (m>=0 && isassigned(out)) { // only do it on a live master nqs
            if ($1<2 || eqobj(cob,out.up)) { // means that only up are left
                m=-7  // indicate have started the process so don't reenter here
                printf("Entering destructor for %s: %d %d %s %s %s\n",out.up,$1,refs,cob,out,out.up)
                out.unref(-1) // take care of out first
              }
          }
      }
    if ($1==-1) { // for .out
        cob=nil
        up=nil
      } else if (m==-7) { // should only be done once
        m= -8
        // printf("Removal of %s on call %d\n",out.up,$1)
        if (isassigned(fcdo)) fcdo.remove_all
        if (isassigned(fcds)) fcds.remove_all
        if (isassigned(fcdv)) fcdv.resize(0)
        cob=nil
        up=nil
      }
  }


//** make sure there are no inconsistencies -- also set vl
func chk () { local ii,jj,ret
    ret=1
    if (out!=nil && !noheader) {
        for ii=0,m-2 for jj=ii+1,m-1 {
            if (sfunc.len(s[ii].s)>0 && strcmp(s[ii].s,s[jj].s)==0) {
                printf("NQS:chk ERRA: %s col: %s(%d) %s(%d) with same name\n",this,s[ii].s,ii,s[jj].s,jj)
                ret=0
              }
          }
      }
    listvecs(vl)
    return ret
  }

//** tog() toggle flag that determines whether actions are on out or this
func tog () { local ret
    if (eqobj(cob,out)) ret=20 else ret=10 // report old value
    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) {
            if ($1>=10) { // set 
                if ($1==10) cob=this else if ($1==20) cob=out else printf("tog ERRA:%d\n",$1)
              } else {  // 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
              }
          }
      }
    return ret
  }

//** sethdrs() set the column names to given args
// sethdrs(#,"NAME") sethdrs("NAME1","NAME2",...)  sethdrs(nq) -- copy from nq
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) {
        if ($1==-1) { // set the strings
            if (!batch_flag && sfunc.len(s[0].s)!=0) {
                printf("Overwrite headers for %s? (y/n) ",this)
                getstr(tstr) chop(tstr)
                if (strcmp(tstr,"y")!=0) return
              }
            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)
              }
          } else if ($1==1) { // show the types of fields
            for ii=0,m-1 printf("%s(%d) ",s[ii].s,fcd.x[ii])
          } else if ($1==2) { // just the names
            for ii=0,m-1 printf("%s ",s[ii].s)
          }
      } else {
        for ii=0,m-1 printf("%s(%d) ",s[ii].s,ii) // field numbers
      }
  }

//* selone(COL,VAL[,FLAG]) -- uses vec.slone 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
  }
  
//* ay() is an n-dim associative array with p return values
// emulate a high-dim sparse array with optional string args, eg
// nq.ay("SU","IN",7,2,12).x // like nq_array["SU"]["IN"][7][2][12]
// an associative array could do same with non-numeric indices
// here if we have m cols can use any n of them as indices and rest are return values up to
// what a Union() can hold (2 strings, 2 objs, 2 doubles)
// if want to ignore one index can use OK as a globbing value
// for SET use an explicit set aa[5][4][7][2][12]=17 -> nq.ay(5,4,7,2,12,SET,17)
// select based on first n cols and always using EQU or SEQ
// gives more feel of an array -- assumes columns are IND0,IND1,...,VAL
// keys are SET to begin setting values, and OK to leave a value as is
// noninteger must be a set value
// eg XO=ncq.ay(SU,SU,AM,INC,SET,OK,List[35])
// alternate use with specific labels for things to be set eg
// eg XO=ncq.ay(SU,SU,AM,SET,"del",2.2,"wt")
obfunc ay () { local a,b,i,j,jo,k,na,flag,done,ix,nx,sx,ox,fl localobj key,arg,o
    if (numarg()==0) {
        printf("ay(I0,I1 ...[SET,V1,V2 ...])\n") return o }
    tog("DB") // start at full db
    a=allocvecs(key,arg)
    o=new Union() o.err=1 // assume .err set to return errors
    na=numarg()
    vlist.remove_all
    ind.resize(v.size)
    if (argtype(1)==1) for ii=0,$o1.size-1 {
        key.append(EQU) arg.append($o1.x[ii],0) vlist.append(v[ii])
        flag=0 j=b=$o1.size 
        if (numarg()>1) if ($2==SET) {i=3 flag=1}
      } else {
        for ({i=1 flag=0 done=0} ; i<=na && !flag; {i+=1 done=0}) {
            if (argtype(i)==2) {
                if (fi($si,"NOERR")!=-1) break else if (fcd.x[i-1]!=2) {
                    printf("ay ERRA: %d %d\n",fcd.x[i-1],argtype(i)) dealloc(a) return o
                  }
                for (j=0;j<fcds.count && !done;j+=1) if (strcmp(fcds.o(j).s,$si)==0) {
                    key.append(EQU) arg.append(j,0) vlist.append(v[i-1]) done=1
                  }
                if (!done) {printf("%s ay ERRE: %s not found in col %s\n",this,$si,s[i-1].s) 
                    dealloc(a) return o }
              } else if (argtype(i)==0) {
                if ($i==GET) { flag=2 // this is a value to start retrieval
                  } else if ($i==SET) { flag=1 // this is a value to set
                  } else if ($i!=OK) {  // ignore an OK
                    key.append(EQU) arg.append($i,0) vlist.append(v[i-1])
                  }
              }
          }
        b=i-1 // will begin again here -- these are v[] indices hence 0- statt 1-offset
        j=i-2 // have also had a SET arg to go behind
      }
    ind.slct(key,arg,vlist)
    if (ind.size>1) printf("%s ay WARNING: mult rows %d (using %d)\n",this,ind.size,ind.x[0])
    if (ind.size==0) { // printf("%s ay ERRBB: none selected\n",this)
        dealloc(a) return o }
    ix=ind.x[0] // just getting the first row of this
    if (i==na && argtype(i)==2) if ((fl=fi($si,"NOERR"))!=-1) { // return just 1 with col label
        j=getval(fl,v[fl].x[ix],ix)
        if (j==0) o.x=nval else if (j==1) o.o=oval else if (j==2) o.s=sval
        dealloc(a)
        o.err=0
        return o
      }
    for (;i<=na && flag==1;{i+=1 j+=1 jo=0}) { // set using the rest of the args
        if (argtype(i)==0) if ($i==OK) continue // don't set this one
        if (argtype(i)==2) {
            if (strcmp($si,"")==0) continue // don't set this one
            if ((k=fi($si,"NOERR"))!=-1) {jo=j j=k i+=1}
          }
        if (argtype(i)!=fcd.x[j]) {
            printf("%s ay ERRC: %d %d %d\n",this,i,fcd.x[j],argtype(i)) dealloc(a) return o }
        if (argtype(i)==0) { v[j].x[ix]=$i 
          } else if (argtype(i)==1) { set(j,ix,$oi) print $oi,ix
          } else if (argtype(i)==2) { set(j,ix,$si)
          } else {printf("%s ay ERRD: set %d not implemented\n",this,argtype(i)) dealloc(a) return o}
        if (jo) j-=1 // back up: perhaps can but would be a bad idea to mix setting stuff
      }
    nx=sx=ox=-1
    if (flag==2) {i=b if ((b=fi($si,"NOERR"))==-1) {
            printf("nqs:ay() GET ERR %s not found\n",$si) return o }}
    for (i=b;i<m;i+=1) { // return values -- get 10 of each
        j=getval(i,v[i].x[ix],ix)
        if (j==0) { 
            nx+=1 
            if (nx>=10) continue
            o.set(s[i].s,nval)
          } else if (j==1 || j==2) { 
            ox+=1 // string is handled as String obj
            if (ox>=10) continue
            if (j==2) o.set(s[i].s,sval) else o.set(s[i].s,oval)
          }
      }
    dealloc(a)
    o.err=0
    return o
  }

//* 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("%s:select ERR0: cols not all same size\n",this) 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 (argtype(i)==1 && argtype(i+1)==1) { // 3 vectors in a row are preset info for slct()
            if (numarg()!=3) { printf("%s:select ERR0: 3 vecs should be mso[key],mso[arg],cols\n",this) 
                dealloc(key) return -1 }
            if ($o1.size!=$o3.size || $o1.size*2!=$o2.size) {
                printf("%s:select ERR0c: size problem %d %d %d\n",this,$o1.size,$o2.size,$o3.size) 
                dealloc(key) return -1 }
            i=4 // have sucked up all the args
            mso[key].copy($o1) mso[arg].copy($o2)
            for ii=0,$o3.size-1 vlist.append(v[$o3.x[ii]])
          } else if (isobj($o1,"Vector")) { ind.copy($o1) savind=1 union=0 // assume &&
          } else { 
            printf("%s:select ERR0a: first vec obj should be ind vector\n",this) 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("%s:select ERR0b: can't ident arg %d: %d\n",this,i,vn) dealloc(key) return -1}
            if (s[vn]!=nil) sstr=s[vn].s else sstr="UNDEFINED"
          } else {printf("%s:select ERR1: arg %d should be col name or num\n",this,i) dealloc(key) return -1}
        if (vn>=0) if (fcd.x[vn]==1) { 
            if (oform(fcdo.o(v[vn].x[0]))!=NOP) { // look at obj list
                scr[1].resize(0)      
                for ii=0,v[vn].size-1 scr[1].append(oform(fcdo.o(v[vn].x[ii])))
                vn=-1e9   tmplist.prepend(scr[1])
              } else {
                printf("NQS:select WARNING selecting on indices in an obj column: %d (?oform)\n",vn)
              }
          }
        mso[vc].append(vn)                        i+=1 
        if (argtype(i)==0) {
            if ((isv=isvarg($i))!=-1) { 
                lk=$i 
              } else { // arg2 is a regular number use "~"
                  mso[key].append(IBI) // approximately equal -- generate a range
                  tmp=$i-loose tmp1=$i+loose
                  if (tmp<tmp1) mso[arg].append(tmp,tmp1) else mso[arg].append(tmp1,tmp)
                  i+=1
                  continue
              }
          } else if (argtype(i)==2) { isv=isvarg(lk=whvarg($si))
            if (isv==-1) { 
                if (strcmp($si,"==")==0 || strcmp($si,"~")==0) {
                    mso[key].append(IBI) // approximately equal -- generate a range
                    i+=1
                    tmp=$i-loose tmp1=$i+loose
                    if (tmp<tmp1) mso[arg].append(tmp,tmp1) else mso[arg].append(tmp1,tmp)
                    i+=1
                    continue
                  } else {
                    printf("%s:select ERR1a: operator %s not recognized\n",this,$si) dealloc(key) return -1 
                  }
              }
          } else {
            printf("%s:select ERR2: arg should be symbolic (eg GTE, EQU ...) or string (eg '[)','<=') op \n",this,i)
            dealloc(key) return -1 
          }
        mso[key].append(lk)                       i+=1
        // pick up ARGS
        for ii=0,isv-1   {  
            if (argtype(i)==0) { 
                if (lk==EQV) {
                    if ($i<0 || $i>=m) printf("ERRQ\n") else {
                        mso[arg].append(0)
                        mso[vc].append($i)
                      }
                  } else 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("%s:select ERR2a EQV but what col?\n",this) 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("%s:select ERR2a1\n",this) dealloc(key) return -1}
                    if (rxpflg==1) {printf("%s:select ERR2a2: RXP twice\n",this) dealloc(key) return -1}
                    ret=tmplist.prepend(scr[2])
                    if (rxpstr(vn,$si,scr[2])==0) {
                        printf("%s:select WARNING: No RXP matches for %s\n",this,$si) }
                    mso[vc].append(-1e9)                  i+=1
                  } else {printf("%s:select ERR2b string arg needs EQV,SEQ or RXP?\n",this)
                    dealloc(key) return -1}
              } else if (argtype(i)==1) { 
                if (lk>=EQW && lk<=EQY) { // pick up a vector
                    if (isobj($oi,"Vector")) {
                        if ($oi.size==0) {printf("%s:select ERR2a3: EQ[WXY] with empty vec %s\n",this,$oi) 
                            dealloc(key) return -1}
                        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("%s:select ERR2c: can't find %s in %s?\n",this,$si,o)
                                dealloc(key) return -1 }
                            tmplist.prepend(o.out.v[tmp])
                          }
                        mso[vc].append(-1e9)                  i+=1
                      } else { printf("%s:select ERR2c1: EQ[WXY] needs Vec or NQS not %s?\n",this,$oi)
                        dealloc(key) return -1
                      }
                  } else { printf("%s:select ERR2d only EQ[WXY] takes obj arg: %d:%d?\n",this,i,argtype(i))
                    dealloc(key) return -1}
              } else {
                whkey(lk,sstr) printf("%s:select ERR3 arg %d should be arg for %s",this,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 (verbose==2) keylook(key) // look at the keys
    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) {
        out.ind.copy(ind) 
        if (ind.size==0) { 
            if (verbose) printf("None selected\n") 
          } else {
            aind()
            cob=out
          }
      } else cob=this
    dealloc(key)
    selcp=selcpsav
    slorflag=0
    return ret
  }

//** keylook()
proc keylook () { local key,arg,vc,ii
    if (numarg()==0) key=0 else key=$1
    arg=key+1 vc=key+2
    printf("slct(keys,args,cols)\n")
    for ii=0,mso[key].size-1 {
        whkey(mso[key].x[ii],tstr)
        for jj=0,m-1 if (eqobj(v[jj],vlist.o(ii))) break
        if (jj==m) jj=-1
        printf("KEY: %s; ARGS: %g %g; COL: %d (%s)\n",\
               tstr,mso[arg].x[2*ii],mso[arg].x[2*ii+1],jj,vlist.o(ii))
      } // vlk(mso[key]) vlk(mso[arg])
  }

//** 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")
  }

// csel() puts col#s in ind
// csel(colname) select by column header
// csel("OP",arg1[,arg2]) runs oform() on each col then runs OP() on result
// eg with oform(){return $o1.count(0)} then csel("==",3) finds cols with 3 zeros
func csel () { local a,ii localobj v1
    a=allocvecs(v1,m)
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    if (numarg()==1) {
        for ii=0,m-1 if (strm(s[ii].s,$s1)) v1.append(ii)
        ind.copy(v1)
      } else {
        for ii=0,m-1 v1.append(oform(cob.v[ii]))
        if (numarg()==2) { ind.indvwhere(v1,$s1,$2)
          } else           { ind.indvwhere(v1,$s1,$2,$3) }
      }
    dealloc(a)
    return ind.size
  }

//** 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.size==0) { return 0
      } 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+=50) { // sindx() can only handle vecst.mod:VRRY vecs at a time
        tmplist.remove_all vlist.remove_all
        for ii=beg,beg+49 if (ii<m) tmplist.append(v[ii])
        for ii=beg,beg+49 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,"NOERR")  suppress error message
//  fi(STR,"EXACT")  string match
//  fi(STR,"ALL") return vector of all indices that match regexp
func fi () { local num,flag,ii,ret,err,ext
    if (refs==-1) if (isassigned(out)) { // calculate refs
        // refs=sfunc.references(this,1)-1 // make sure 'this' is turned on
        // printf("%d refs\n",refs)
      }
    ext=noerr=err=num=flag=all=0
    if (numarg()>=2) if (argtype(2)==2) {
        if (strcmp($s2,"NOERR")==0) noerr=1 // use "NOERR" string
        if (strcmp($s2,"EXACT")==0) ext=1 // string match statt regexp
        if (strcmp($s2,"ALL")==0) {all=1 $o3.resize(0)} // all regexp matches
      }
    for ii=0,m-1 if (strcmp(s[ii].s,$s1)==0) {flag=1 ret=ii break} // exact match
    if (ext) if (flag) return ret else return -1
    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 { // make sure $s1 could be a regexp to avoid regexp error
        if (sfunc.len($s1)<sfunc.len(s[ii].s) && !strm($s1,"[()]")) if (strm(s[ii].s,$s1)) { 
            if (num>=1) {
                if (all) $o3.append(ii) else {
                    err=1 
                    printf("%s fi ERR: regexp matches more than once: %d %s\n",this,ii,s[ii].s)
                  }
              } else {
                if (all) $o3.append(ii)
                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("%s:fi ERRa copy what?\n",this) return ret
                  } else $o2=v[ret] 
              } else if (argtype(2)==0) { 
                if ($2<0 || $2>=v[ret].size) { 
                    printf("%s:fi ERR index out of bounds: %d %d\n",this,$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("%s:fi WARNING 2nd arg ignored\n",this) }
          }
        return ret
      } else {
        if (!noerr) printf("%s.fi() ERR '%s' not found\n",this,$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]
  }

//** mkind(COL) sort by COL and then use mkind to put index of a single col in cindx vector
obfunc mkind () { local fl
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    if (cindx==nil) cindx=new Vector(1e3)
    if (argtype(1)==0) fl=$1 else fl=fi($s1)
    cindcol=fl
    sort(fl)
    v[fl].mkind(cindx)
    if (argtype(2)==1) $o2.copy(cindx)
    return cindx
  }

//** set("name",IND,VAL)
proc set () { local fl,ix,sel
    sel=0
    if (eqojt(cob,out)) { sel=1
        if (verbose) printf("NQS set() WARNING: setting value in Selected db\n") }
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    ix=$2 
    if (fl==-1) return
    if (ix<0) ix=cob.v[fl].size+ix
    // 2 LINE 'SET' MACRO
    if        (ix> cob.v[fl].size) {  // nonexistent row
        printf("%s set ERRA: col %s size %d<%d\n",this,s[fl].s,v[fl].size,ix) return
      } else if (ix==cob.v[fl].size) {  // single col expansion
        if (sel) {printf("%s set() ERR: can't expand Selected db\n",this) return}
        cob.v[fl].resize(ix+1)
      }
    if (argtype(3)==0) { cob.v[fl].x[ix]=$3
      } else {
        if (argtype(3)==1) oval=$o3 else if (argtype(3)==2) sval=$s3
        cob.v[fl].x[ix]=newval(argtype(3),fl)
      }
  }

//** sets(IND,COLA,VAL[,COLB,VAL,...])
proc sets () { local fl,ix,i,sel,sz
    sel=0 ix=$1
    if (eqojt(cob,out)) { sel=1
        if (verbose) printf("NQS set() WARNING: setting value in Selected db\n") }
    if (ix>=cob.v.size){
        printf("NQS sets ERRA: OOB %s: %d (size %d)\n",this,v[0].size,cob.v.size) return }
    if (ix<0) ix=cob.v.size+ix
    for i=2,numarg() {
        if (argtype(i)==2) fl=fi($si) else fl=$i
        if (fl==-1) return
        i+=1 
        if (argtype(i)==0) { cob.v[fl].x[ix]=$i // shortcut
          } else { 
            if (argtype(i)==1) oval=$oi else if (argtype(i)==2) sval=$si
            cob.v[fl].x[ix]=newval(argtype(i),fl)
          }
      }
  }

//** setcol("name",VEC)
//   setcol(num,VEC)
//   setcol(num,"name",VEC)
//   setcol(num,"name",VEC,flag) // with flag==1 use pointer to vec instead of copying
scpflag=0
proc setcol () { local fl,flag localobj vo
    if (eqobj(cob,out) && verbose) { 
        printf("%s setcol() ERR: attempting to set column in Selected db\n",this)
        return  }
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    if (fl==-1) return
    if (v[fl].size!=0) {
        sprint(sstr,"WARNING %s col not empty (size %d)",s[fl].s,v[fl].size)
        if (boolean_dialog(sstr,"Clear col","Cancel")) { v[fl].resize(0) } else {
            printf("%s (%s) setcol() canceled\n",this,s[fl].s) return  
          }}
    if (argtype(2)==2) { s[fl].s=$s2 
      } else if (argtype(2)==1) { 
        if (scpflag) v[fl].copy($o2) else v[fl]=$o2
        return 
      } else { sprint(tstr,"%d",$2) s[fl].s=tstr }
    if (numarg()>=3) vo=$o3
    if (numarg()>=4) flag=$4 else flag=0
    if (!flag || scpflag) v[fl].copy(vo) else v[fl]=vo
    chk()
  }

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

//** 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
// NB: makes a copy of a Vector or an NQS so DON'T do eg nq.append(new Vector())
func newval () { local ret,typ,ty,fl,ii localobj o
    typ=$1 fl=$2 ty=fcd.x[fl] // arg type may not be same as field type
    if (ty==typ||ty==-1||(ty==FUNTY&&typ==2)||(ty==VECTY&&typ==1)) { // OK
      } else { printf("nqs::newval() ERRa %d statt %d\n",typ,ty) return ERR }
    if (typ==0 || ty==-1) { 
        return nval
      } else if (ty==1) { // object handling
        if (! isassigned(oval)) return -1
        if (isojt(oval,v)) { o=new Vector(oval.size) o.copy(oval) 
          } else if (isojt(oval,this)) { o=new NQS() o.cp(oval) 
          } else {
            for (ii=0;ii<fcdo.count;ii+=1) if (eqojt(fcdo.object(ii),oval)) { // already on list?
                printf("nqs %s WARNING: 2nd pointer to same %s on fcdo\n",this,oval)
                return ii
              }
            o=oval      
          }
        return fcdo.append(o)-1
      } else if (ty==FUNTY) { // method handling
        for ({ii=0 ret=-1};ii<fcds.count;ii+=1) { 
            if (strcmp(fcds.object(ii).s,sval)==0) {ret=ii break}
          }
        if (ret==-1) ret=fcds.append(new String(sval))-1
        o=new Union(ret) // .x is pointer to the string
        return fcdo.append(o)-1
      } else if (ty==VECTY) { // append to a vector
        if (!isojt(oval,v)) { printf("nqs:newval ERRB -- put vectors in vdec col\n") return ERR }
        ret=fcdv.size()
        fcdv.append(oval)
        return ret
      } else if (ty==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,ed,nacc
    fl=$1 ix=$2 flag=0
    typ=fcd.x[fl] // argtype
    if (typ==0) { 
        nval=ix
      } else if (typ==CODTY) { 
        if (numarg()==3) nval=uncodf($3,ix) else {scr.resize(5) scr.uncode(ix)}
      } else if (typ==VECTY) { 
        if (ix>fcdv.size-1) { printf("nqs::getval() ERR fcdv index OOB %d, %d\n",ix,fcdv.size) 
            return ERR 
          } else if (ix<0) { printf("nqs::getval() WARNING empty VECTY ptr\n\t") sval="nil" typ=2
          } else {
            nacc=$3 // direct index only needed here
            if (nacc+1<cob.v[fl].size) ed=cob.v[fl].x[nacc+1]-1 else ed=fcdv.size-1
            oval = fcdv.c(ix,ed)
          }
      } 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")
            sval="nil"
            typ=2
          } 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("%s getval ERRa\n",this) return -1}
        if (! isobj(fcdl.object(fl),"List")) {printf("%s getval ERRb\n",this) return -1}
        if (fcdl.object(fl).count<=ix) {printf("%s getval ERRc\n",this) return -1}
        if (ix==-1) sval="XX" else {
            if (!isobj(fcdl.object(fl).object(ix),"String")){printf("%s getval ERRd\n",this) 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()
obfunc listvecs () { local ii,i,b localobj ol
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    if (argtype(1)==1) {ol=$o1 b=2} else b=1
    if (!isassigned(ol)) { 
        ol=new List()
        if (argtype(1)==1) $o1=ol
      }
    ol.remove_all
    if (numarg()>=b) {
        for i=b,numarg() {
            if (argtype(i)==2) ii=fi($si) else ii=$i
            if (ii==-1) return
            ol.append(cob.v[ii])
          }
      } else {
        for ii=0,m-1 ol.append(cob.v[ii])
      }
    return ol
  }

//*** hash([COLA],[COLB] etc.) put the vecs in the list for use with eg uncode()
proc hash () { local ii,i,fl localobj o
    if (eqobj(cob,out) && verbose) {
        printf("hash() ERR: can't create hash col in 'Selected'\n") return }
    o=new List()
    if (numarg()==0) { // do all columns
        resize("hashall")
        for ii=0,m-2 o.append(v[ii])
      } else {
        tstr="hash"
        for i=1,numarg() {
            if (argtype(i)==0) fl=$i else fl=fi($si)
            if (fl==-1) return
            sprint(tstr,"%s_%s",tstr,s[fl].s)
            o.append(v[fl])
          }
        resize(tstr)
      }
    pad()
    v[m-1].hash(o)
  }

//*** mat=tomat([MAT]) put the cols in cols of matrix
// mat=tomat(MAT,1) or mat=tomat(1) puts the cols in rows of matrix
obfunc tomat () { local ii,transpose,fo,sz localobj mat
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    fo=transpose=0 sz=size(1)
    if (numarg()>=1) {
        if (argtype(1)==0) transpose=$1 else {mat=$o1 fo=1}
      } 
    if (numarg()>=2) transpose=$2
    if (!isassigned(mat)) { 
        if (transpose) mat=new Matrix(m,sz) else mat=new Matrix(sz,m)
        if (fo) $o1=mat
      } else {
        if (transpose) mat.resize(m,sz) else mat.resize(sz,m)
      }
    if (transpose) {for ii=0,m-1 mat.setrow(ii,cob.v[ii])
      } else          for ii=0,m-1 mat.setcol(ii,cob.v[ii])
    return mat
  }

//*** frmat(MAT) gets cols from cols of matrix
// frmat(MAT,1)  gets the cols from rows of matrix
proc frmat () { local ii,transpose,rows,cols localobj mat
    if (eqobj(cob,out)) {printf("frmat() ERR cannot reset 'Selected' to matrix\n") return}
    fo=transpose=0
    mat=$o1
    if (numarg()>=2) transpose=$2
    rows=mat.nrow cols=mat.ncol
    if (transpose) {
        if (cols!=size(1)) pad(cols)
        if (rows!=m) resize(rows)
        for ii=0,m-1 mat.getrow(ii,cob.v[ii])
      } else {
        if (rows!=size(1)) pad(rows)
        if (cols!=m) resize(cols)
        for ii=0,m-1 mat.getcol(ii,cob.v[ii])
      }
  }

//*** newnqs=transpose() create a new nqs that is the transpose of this one
obfunc transpose () { localobj mat,m2,oq
    mat=tomat()
    oq=new NQS()
    oq.frmat(mat,1)
    return oq
  }

//*** prtval() use %g or %s to print values
proc prtval () { local i,typ,flag,otmp localobj f1
    if (argtype(1)==0) {typ=$1 flag=0 i=2} else {f1=$o1 flag=1 typ=$2 i=3}
    // oform() returns a double for printing an object
    if ((typ==1 || typ==VECTY) && isassigned(oval)) {
        otmp=oform(oval)
        if (otmp==NOP) {       typ=1
          } else if (otmp==OK) { return // print nothing since being printed as side effect
          } else {               typ=0 nval=otmp // print a single numeric value
          }
      }
    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,be,en 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 lo }
    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("%s::get ERR ix %d out of range for %s (%s)\n",this,ix,sstr2,cob) return lo }
    ty=fcd.x[fl]
    if (ty==0) {lo=new Union(cob.v[fl].x[ix]) if (numarg()==3) $&3=lo.x
      } else if (ty==1) {lo=new Union(fcdo,cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o
      } else if (ty==FUNTY) {lo=methget(fl,cob.v[fl].x[ix])  if (numarg()==3) $o3=lo.o
      } else if (ty==VECTY) { be=cob.v[fl].x[ix] 
        if (ix+1<cob.v[fl].size) en=cob.v[fl].x[ix+1]-1 else en=cob.v[fl].size-1
        lo=new Union(fcdv.c(be,en)) if (numarg()==3) $o3=lo.o
      } else if (ty==2) {lo=new Union(fcds,cob.v[fl].x[ix])  if (numarg()==3) $s3=lo.s
      } else if (ty==-1){lo=new Union(fcdl.object(fl),cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o}
    return lo
  }

//** mget(row,col) 
obfunc mget () { local ty,fl,ix,outf localobj lo
    outf=0
    ix=$1 fl=$2 
    if (ix<0 || ix>=cob.v[fl].size) {printf("%s::get ERR no %d,%d\n",this,fl,ix) return lo}
    ty=fcd.x[fl]
    if (ty==0) {lo=new Union(cob.v[fl].x[ix]) if (numarg()==3) $&3=lo.x
      } else if (ty==1) {lo=new Union(fcdo,cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o
      } else if (ty==2) {lo=new Union(fcds,cob.v[fl].x[ix])  if (numarg()==3) $s3=lo.s
      } else if (ty==FUNTY) {lo=methget(fl,cob.v[fl].x[ix])  if (numarg()==3) $o3=lo.o
      } else if (ty==-1){lo=new Union(fcdl.object(fl),cob.v[fl].x[ix]) if (numarg()==3) $o3=lo.o}
    return lo
  }

//** mset(row,col) 
proc mset () { local ty,fl,ix,outf localobj lo
    outf=0
    ix=$1 fl=$2 
    if (ix<0 || ix>=cob.v[fl].size) {printf("%s::get ERR no %d,%d\n",this,fl,ix) return}
    ty=fcd.x[fl]
    if (ty==0) cob.v[fl].x[ix]=$3 else \
    if (ty==1) fcds.o(cob.v[fl].x[ix])=$o3 else \
    if (ty==2) fcds.o(cob.v[fl].x[ix]).s=$s3 else \
    if (ty==-1)fcdl.object(fl).o(cob.v[fl].x[ix])=$o3
  }

//** fetch(COLA,VAL,COLB) does fast select where COLA is VAL and returns value in COLB
// fetch(COLA,VAL) return the row number
// fetch(COLA,VAL,COLB,XO) places COLB object in XO
// ambiguity -- if 1,3 args can fetch from full db or selected else must do select first
func fetch () { local fl1,fl2,max,i localobj st,v0
    if (eqobj(cob,out)) if (verbose) printf(" *Selected* ")
    if (numarg()==1) {
        if (argtype(1)==2) fl1=fi($s1) else fl1=$1
        return cob.v[fl1].x[0]
      } else if (numarg()==2) { // return the index
        if (argtype(1)==2) fl1=fi($s1) else fl1=$1
        if ((i=cob.v[fl1].indwhere("==",$2))<0){
            printf("fetch ERR %d not found in %s\n",$2,s[fl1].s) return -1 }
        return i
      } else if (numarg()==3 || argtype(4)==1) {
        if (argtype(1)==2) fl1=fi($s1) else fl1=$1
        if (argtype(3)==2) fl2=fi($s3) else if (argtype(3)==0) fl2=$3 else {v0=$o3 fl2=-1}
        if ((i=cob.v[fl1].indwhere("==",$2))<0) {
            printf("fetch ERR %d not found in %s\n",$2,s[fl1].s) return -1 }
        if (fl2>=0) {
            if (numarg()==4) $o4=fcdo.o(cob.v[fl2].x[i])
            return cob.v[fl2].x[i] 
          } else { // return row as a vector
            v0.resize(0) for (ii=0;ii<m;ii+=1) v0.append(cob.v[ii].x[i])
            return cob.v[0].x[i]
          }
      } else {
        st=new String("select(-1,")
        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 (ind.size!=1 && verbose) printf("NQS fetch WARNING -- %d lines found\n",ind.size)
        if (ind.size>0) return v[fl2].x[ind.x[0]] else return ERR
      }
  }

//** stat("COL","operation")
//   stat("COL",VEC) // save into a vector: max,min,mean,sdev
//   stat(NQS) // save all of them into another NQS
proc stat () { local i,vn
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (numarg()==0) {
        for i=0,m-1 { 
            if (noheader) printf("%d:\t",i) else printf("%s:\t",s[i].s) 
            stat(i) // recursive call
          }
        return
      }
    if (argtype(1)==1) {
        $o1.resize(5)
        $o1.sethdrs("NAME","MAX","MIN","MEAN","SDEV") 
        $o1.strdec("NAME")
        $o1.clear
        for i=0,m-1 { 
            stat(i,scr[1]) // recursive call
            $o1.append(scr[1],1)
            $o1.set(0,i,s[i].s)
          }
        return
      }
    if (argtype(1)==0) vn=$1 else vn=fi($s1)
    i=2
    if (cob.size(1)<2) { printf("NQS:stat small NQS: %d\n",cob.size(1)) ok=0 } else ok=1
    if (vn==-2) {
        sprint(sstr2,"%s",cob.scr) 
      } else if (vn<0||vn>=m) {
        return
      } else if (fcd.x[vn]==CODTY) { 
        scr[1].resize(cob.v.size)
        field=$i i+=1
        cob.v[vn].uncode(scr[1],field)
        sprint(sstr2,"%s",scr[1]) 
      } else if (fcd.x[vn]==1) { // looking at a list of vectors
    //if (oform()==NOP){printf("%s:stat ERR: set oform() to do stats on vectors or nqs\n",this)return}
        scr[1].resize(0)
        for ii=0,cob.v[vn].size-1 scr[1].append(oform(fcdo.o(cob.v[vn].x[ii])))
        sprint(sstr2,"%s",scr[1]) 
      } 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)
        if (ok) sprint(sstr,"%s printf(\"mean=%%g; \",%s.mean) ",sstr,sstr2)
        if (ok) sprint(sstr,"%s printf(\"stdev=%%g; \",%s.stdev) ",sstr,sstr2)    
        execute(sstr)
        print ""
      } else if (argtype(i)==1) { // a vector
        $oi.resize(0)
        if (ok) {$oi.append(cob.v[vn].max,cob.v[vn].min,cob.v[vn].mean,cob.v[vn].stdev)
          } else  {$oi.append(cob.v[vn].max,cob.v[vn].min,cob.v[vn].min,0) }
      } else if (!ok) { return
      } 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,nostr localobj st
    nostr=i2=0
    st=new String()
    if (argtype(1)==2) st.s=$s1 else nostr=1 // regexp
    for ii=0,m-1 {
        if (nostr || strm(s[ii].s,st.s)) {
            XO=cob.v[ii] execstr=s[ii].s i1=ii
            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,...) 
// qt(&x1,NAME1,&x2,NAME2,...,&x)  
// qt(&x1,NAME1,&x2,NAME2,...,5,7,&x) // just from 5 to 7
// qt(&x1,NAME1,&x2,NAME2,...,8) // ending at 8
// note &x arg location is opposite to that for ltr
// eg for sp.qt(&x,"PRID",&y,"POID",&z,"NC1",&ii,"WID1",&jj,"WT1") print x,y,z,ii,jj
// NB set qtset if resetting values
iterator qt () { local a,i,j,ii,na,val,noset,min,max,cntr localobj cols,cd
    na=numarg()
    cols=new Vector() cd=new Vector()
    min=0 max=size(1)-1
    if (argtype(na)==3) {i=cntr=na $&i=0 na-=1} else cntr=-1
    if (argtype(na-1)==0) { // 2 values for min and max
          i=na-1 min=$i i=na max=$i na-=2
      }
    if (na/2!=int(na/2)) { // odd number
        if (argtype(na)==0) { i=na max=$i na-=1 
          } else {printf("%s::qt() needs even # of args\n",this) return }
      }
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
  //*** pick up column numbers
    for (i=2;i<=na;i+=2) { 
        if (argtype(i)!=2) val=$i else val=fi($si)
        cols.append(val) // cols has col #s
        if (val<0 || val>=m) { if (argtype(i)==2) printf("(%s)",$si)
            printf("%s::qt() ERR %d not found\n",this,val) return }
      }
    cd.copy(fcd)          // cd gives codes for col's
  //*** pick up the arguments
    for (i=1;i<=na;i+=2) { 
        // can't do iteration over externally defined strings (eg -1) see useslist()
        if (cols.x[int(i/2)]<0) continue
        if (cd.x[cols.x[int(i/2)]]!=0) { 
            if (argtype(i)==3) {
                printf("NQS::qt() WARNING using list index statt str for col %s\n",s[cols.x[int(i/2)]].s) 
                cd.set(cols.x[int(i/2)],0)
              }
          }
        if (cd.x[cols.x[int(i/2)]]==2 && argtype(i)!=2) {
            printf("%s::qt() ERR %s is strdec but arg %d not string\n",this,s[cols.x[int(i/2)]].s,i) return }
        if (cd.x[cols.x[int(i/2)]]==1 && argtype(i)!=1) {
            printf("%s::qt() ERR %s is odec but arg %d not obj\n",this,s[cols.x[int(i/2)]].s,i) return }
      }
  //*** iterate through setting local variables to values in NQS
    for (ii=min;ii<=max;ii+=1) {
        for (i=1;i<=na;i+=2) { j=cols.x[int(i/2)]
            if (cd.x[j]==0) {
                $&i=cob.v[j].x[ii]
              } else if (cd.x[j]==2) {
                $si=fcds.object(cob.v[j].x[ii]).s
              } else if (cd.x[j]==1) {
                $oi=fcdo.object(cob.v[j].x[ii])
              } else {
                printf("%s qt ERRA: %d %d\n",this,i,j)
                continue
              }
          }
        // for i=0,m-1 qtv.x[i]=v[i].x[ii] // if want these values need a separate vector
        iterator_statement
    //*** if qtset -> iterate through resetting NQS according to changed variables
        if (qtset) for (i=1;i<=na;i+=2) { j=cols.x[int(i/2)]
            if (cd.x[j]==0) {
                cob.v[j].x[ii]=$&i
              } else if (cd.x[j]==2) {
                fcds.object(cob.v[j].x[ii]).s=$si
              } else if (cd.x[j]==1) {
                if (!eqojt(fcdo.object(cob.v[j].x[ii]),$oi)) {
                    printf("%s qt ERRB: can't reassign obj: %d %s %s\n",this,\
                           i,fcdo.object(cob.v[j].x[ii]),$oi)
                  }
              }
          }
        if (cntr>-1) {i=cntr $&i+=1}
      }
    qtset=0 // turn back off
  }


//** iterator ut(&x1,NAME1,&x2,NAME2,...) 
// like qt but iterates over selected items without a copy (ie with selcp=0)
// ut(&x1,NAME1,&x2,NAME2,...,&x)  
// ut(&x1,NAME1,&x2,NAME2,...,5,7,&x) // just from 5 to 7
// ut(&x1,NAME1,&x2,NAME2,...,8) // ending at 8
// note &x arg location is opposite to that for ltr
// eg for sp.ut(&x,"PRID",&y,"POID",&z,"NC1",&ii,"WID1",&jj,"WT1") print x,y,z,ii,jj
// NB set qtset if resetting values
iterator ut () { local a,i,j,ii,jj,na,val,noset,min,max,cntr localobj cols,cd
    na=numarg()
    a=allocvecs(cols,cd)
    min=0 max=ind.size-1
    if (argtype(na)==3) {i=cntr=na $&i=0 na-=1} else cntr=-1
    if (argtype(na-1)==0) { // 2 values for min and max
          i=na-1 min=$i i=na max=$i na-=2
      }
    if (na/2!=int(na/2)) { // odd number
        if (argtype(na)==0) { i=na max=$i na-=1 
          } else {printf("%s::ut() needs even # of args\n",this) return }
      }
    if (eqobj(cob,out)) {printf("NQS WARNING: ut() called after full select(); switching\n") 
        cob=this }
  //*** pick up column numbers
    for (i=2;i<=na;i+=2) { 
        if (argtype(i)!=2) val=$i else val=fi($si)
        cols.append(val) // cols has col #s
        if (val<0 || val>=m) { if (argtype(i)==2) printf("(%s)",$si)
            printf("%s::ut() ERR %d not found\n",this,val) return }
      }
    cd.copy(fcd)          // cd gives codes for col's
  //*** pick up the arguments
    for (i=1;i<=na;i+=2) { 
        // can't do iteration over externally defined strings (eg -1) see useslist()
        if (cols.x[int(i/2)]<0) continue
        if (cd.x[cols.x[int(i/2)]]!=0) { 
            if (argtype(i)==3) {
                printf("NQS::ut() WARNING using list index statt str for col %s\n",s[cols.x[int(i/2)]].s) 
                cd.set(cols.x[int(i/2)],0)
              }
          }
        if (cd.x[cols.x[int(i/2)]]==2 && argtype(i)!=2) {
            printf("%s::ut() ERR %s is strdec but arg %d not string\n",this,s[cols.x[int(i/2)]].s,i) return }
        if (cd.x[cols.x[int(i/2)]]==1 && argtype(i)!=1) {
            printf("%s::ut() ERR %s is odec but arg %d not obj\n",this,s[cols.x[int(i/2)]].s,i) return }
      }
  //*** iterate through setting local variables to values in NQS
    for (jj=min;jj<=max;jj+=1) { ii=ind.x[jj]
        for (i=1;i<=na;i+=2) { j=cols.x[int(i/2)]
            if (cd.x[j]==0) {
                $&i=cob.v[j].x[ii]
              } else if (cd.x[j]==2) {
                $si=fcds.object(cob.v[j].x[ii]).s
              } else if (cd.x[j]==1) {
                $oi=fcdo.object(cob.v[j].x[ii])
              } else {
                printf("%s ut ERRA: %d %d\n",this,i,j)
                continue
              }
          }
        iterator_statement
    //*** if qtset -> iterate through resetting NQS according to changed variables
        if (qtset) for (i=1;i<=na;i+=2) { j=cols.x[int(i/2)]
            if (cd.x[j]==0) {
                cob.v[j].x[ii]=$&i
              } else if (cd.x[j]==2) {
                fcds.object(cob.v[j].x[ii]).s=$si
              } else if (cd.x[j]==1) {
                if (!eqojt(fcdo.object(cob.v[j].x[ii]),$oi)) {
                    printf("%s ut ERRB: can't reassign obj: %d %s %s\n",this,\
                           i,fcdo.object(cob.v[j].x[ii]),$oi)
                  }
              }
          }
        if (cntr>-1) {i=cntr $&i+=1}
      }
    dealloc(a)
    qtset=0 // turn back off
  }

//** iterator vt("proc",&x1,NAME1,&x2,NAME2,...) 
proc vt () { local a,i,j,ii,na,val,noset,min,max,cntr localobj cols,cd,at
    na=numarg()
    a=allocvecs(cols,cd)
    min=0 max=size(1)-1
    if (argtype(na)==3) {i=cntr=na $&i=0 na-=1} else cntr=-1
    if (argtype(na-1)==0) { // 2 values for min and max
          i=na-1 min=$i i=na max=$i na-=2
      }
    if (na/2==int(na/2)) { // odd number
        if (argtype(na)==0) { i=na max=$i na-=1 
          } else {printf("%s::vt() needs odd # of args\n",this) return }
      }
    if (eqobj(cob,out)) { printf(" vt() err: run .vt() on full set") return }
  //*** pick up column numbers
    for i=2,na { 
        if (argtype(i)!=2) val=$i else val=fi($si)
        cols.append(val) // cols has col #s
        if (val<0 || val>=m) { if (argtype(i)==2) printf("(%s)",$si)
            printf("%s::vt() ERR %d not found\n",this,val) return }
        if (fcd.x[val]!=0 && fcd.x[val]!=1) {
            printf("%s::vt() ERR %d not handled (%d)\n",this,fcd.x[va],val) return }
      }
  //*** iterate through setting local variables to values in NQS
    sprint(tstr,"%s.nqsvt(\"%s\",%s,%s,%s,%s)",cols,$s1,fcdo,fcd,vl,ind)
    execute(tstr)
    dealloc(a)
  }

//** 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,exec
    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
    exec=1
    if (argtype(2)==2) if (strcmp($s2,"NOEXEC")==0) exec=0
    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 (isnum(sstr2)) {
            sscanf(sstr2,"%d",&vn)
            sprint(sstr3,"%s",cob.v[vn])
          } else if ((vn=fi(sstr2))==-1) {
            return // error 
          } else {
            sprint(sstr3,"%s",cob.v[vn])      
          }
        sprint(sstr2,"<%s>",sstr2)
        repl_mstr(sstr,sstr2,sstr3,sstr4)
      }
    repl_mstr(sstr,"'","\"",sstr4)
    if (exec) 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
    if (fcd.x[vn]==1) {
        cob.scr.resize(0)
        for ii=0,cob.v[vn].size-1 cob.scr.append(oform(fcdo.o(cob.v[vn].x[ii])))
        if (cob.scr.x[0]==NOP) { // looking at a list of vectors
            printf("NQS:sort ERR define oform to sort obj field %s\n",s[vn].s) return 0 }
        cob.scr.sortindex(cob.ind)    
      } else {
        if (cob.v[vn].ismono() && numarg()==1) {
            printf("NQS sort %s already ordered\n",cob.v[vn]) return vn }
        cob.v[vn].sortindex(cob.ind)
      }
    if (numarg()==2) if ($2==-1) cob.ind.reverse
    fewind()
    return vn
  }  

//** vsort(vec) sort according to vec which may have redundancy
func vsort () { local beg,ii,x localobj o
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    o=$o1
    if (numarg()==2) if ($2==-1) o.reverse
    cob.scr.resize(cob.v.size)
    for (beg=0;beg<m;beg+=50) { // fewind() can only handle vecst.mod:VRRY vecs at a time
        tmplist.remove_all
        for (ii=beg;ii<beg+50 && ii<m;ii+=1) tmplist.append(cob.v[ii])
        x=cob.scr.fewind(o,tmplist,1)
      }      
    return x
  }  

//** 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("%s pselERR: unable %d%% of %d\n",this,$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
            if (verbose) 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
        if (verbose) 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") 
    if (verbose) 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 cob.ind.size
  }

//** elimrepeats(COLA[,COLB,...])
func elimrepeats () { local a,b,i,ii,indflag localobj sl,tl,v1
    if (eqobj(cob,out)) {printf("%s ERR: run elimrepeats on full db\n",this)  return 0.}
    if (size(1)==0) { printf("%s:elimirepeats Empty NQS\n",this) 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 (argtype(i)==0) ii=$i else if ((ii=fi($si))==-1) return 0
        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
  }

//** covarc("vCol") -- generate covariance matrix from vectors in a single column
obfunc covarc () { local a,fl,n,m localobj mat,xo,v1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if ((fl=fi($s1))==-1) return -1
    if (fcd.x[fl]!=1) {printf("Must be an obj column\n") return -1}
    xo=get(fl,0).o
    if (!isojt(xo,ind))  {printf("Must be an vec column\n") return -1}
    n=size(1) // number of data vectors
    m=xo.size    // size of vector 
    a=allocvecs(v1)
    mat=new Matrix(m,m)
    cob.v[fl].covar(fcdo,v1)
    mat.from_vector(v1)
    dealloc(a)
    return mat
  }

//** tomatc("vCol") -- return matrix of vectors from a single column; load into rows of mat
obfunc tomatc () { local a,fl,n,m,ii localobj mat,xo,v1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if ((fl=fi($s1))==-1) return -1
    if (fcd.x[fl]!=1) {printf("Must be an obj column\n") return -1}
    xo=get(fl,0).o
    if (!isojt(xo,ind))  {printf("Must be an vec column\n") return -1}
    n=size(1) // number of data vectors
    m=xo.size    // size of vector 
    mat=new Matrix(n,m)
    for qt(xo,fl,&ii) mat.setrow(ii,xo)
    return mat
  }

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

//** fewind () -- index all of the vecs in place using vecst.mod::fewind()
proc fewind () {
    cob.scr.resize(cob.v.size)
    for (beg=0;beg<m;beg+=50) { // fewind() can only handle vecst.mod:VRRY vecs at a time
        tmplist.remove_all
        for (ii=beg;ii<beg+50 && ii<m;ii+=1) 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,jj,i,flag,begin,o1fcd localobj xo
    cob=this
    if (m==0) { printf("%s append ERR0, attempted append to uninitialized NQS\n",this) return }
    if (argtype(1)==1 && fcd.x[0]!=1) {
        if (isobj($o1,"Vector")) { // a vector of values
            if (numarg()>1) begin=$2 else begin=0
            if (begin+$o1.size>m) { 
                printf("%s append ERR1: vec %s too large; doing nothing: %d>%d",this,$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("%s append ERR1a, %s size %d!= %s size %d?\n",this,this,m,$o1,$o1.m)
                return }
            for ii=0,m-1 { 
                o1fcd=$o1.fcd.x[ii]
                if (o1fcd==0) { v[ii].append($o1.cob.v[ii])
                  } else for jj=0,$o1.size(1)-1 { 
                    xo=$o1.get(ii,jj)
                    if (o1fcd==1) oval=xo.o else sval=xo.s
                    v[ii].append(newval(o1fcd,ii))
                  }
              }
          } else { printf("%s append ERR1b, what is %s?\n",this,$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) {
                v[ii].append($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) { printf("%s append ERR2: args>m; doing nothing\n",this) 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) {
                v[ii].append($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,n
    cob=this 
    if (argtype(1)==2) ix=fi($s1) else ix=$1
    if (numarg()==2 && argtype(2)==1 && fcd.x[ix]==0) { // a vector
        if ($o2.size>m-ix) { 
            printf("%s appi ERR1: vec too large; doing nothing %d %d %d %d\n",this,m,$o2.size,ix,m-ix)
          } else {
            n=-1
            for i=ix,ix+$o2.size-1 v[i].append($o2.x[n+=1])
          }
      } else {
        if (numarg()-1>m-ix) {
            printf("%s appi ERR2: args>m; doing nothing",this)
            return
          } 
        for i=2,numarg() {
            if (argtype(i)==0) { 
                v[ix+i-2].append($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 (fcd.x[vn]==1) { // look at a list of obj's
                cob.scr.resize(0)
                for ii=0,cob.v[vn].size-1 cob.scr.append(oform(fcdo.o(cob.v[vn].x[ii])))
                if (cob.scr.x[0]==NOP) {
                    printf("map WARNING: oform not set for %s interp; replacing with fcdo indices\n",$si)
                    cob.scr.copy(cob.v[vn])
                  }
                sprint(sstr,"%s%s,",sstr,cob.scr) 
              } 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
    // print sstr
    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,st
    nm=numarg() gn=0 f3d=-1 st=new String2()
    col=2 lne=4 stone=0 
    done=0
    if (sfunc.len(marksym)==0) marksym="o"
    sprint(tstr,"symb=\"%s\"",marksym) execute(tstr) // set global symb
    if (argtype(1)==2) st.s=$s1 else if (argtype(1)==0) st.s=s[$1].s
    if (argtype(2)==2) st.t=$s2 else if (argtype(2)==0) if ($2>=0) st.t=s[$2].s else {
        stone=1 } // use -1 as place
    if (nm==0) { 
        print "gr(\"Y\",\"X\"[,\"Z\",g#,col,line]); Y or X can be col# or col#,-1; 'Z' must be str"
        return
      } else if (nm==1) {  map("gg",0,st.s,1,col,lne)               stone=done=1
      } else if (nm==2) {  map("gg",0,st.s,st.t,col,lne)            done=1 }
    i=3
    if (! done)  {
        if (argtype(i)==2) {f3d=fi($si) 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("%s gr ERR: 3D and gvmarkflag=0\n",this) return}
            y=fi(st.s) x=fi(st.t)
            if (lne==1) lne=2 else lne-=2 // will augment below
            if (x==-1 || y==-1) {printf("%s gr ERR: %s,%s not fi()\n",this,st.s,st.t) 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],marksym,lne,cob.v[f3d].x[i]%9+1,4)
              }
          } else if (stone) {
            map("gg",gn,st.s,1,col,lne)
          } else { // print gn,col,lne
            map("gg",gn,st.s,st.t,col,lne)
          }
      }
    g[gn].color(col)
  //  g[gn].label(0.05,0.95,st.s)
  //  if (nm>=2) g[gn].label(0.85,0.05,st.t)
    g[gn].color(1)
    if (!stone) {
        setgrsel(g[gn],fi(st.s),fi(st.t))
        setchsel(g[gn],fi(st.s),fi(st.t))
      }
  }

//** 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 (argtype(i)==0) fl=$i else if ((fl=fi($si))==-1) return
        if (fl==-2) sprint(sstr2,"%s",cob.scr) else sprint(sstr2,"%s",cob.v[fl]) 
        if (strm($s1,"^\\.")) sprint(sstr,"%s%s"  ,sstr2,$s1) else {
                                sprint(sstr,"%s(%s)",$s1,sstr2) }
        execute(sstr)
      }
  }

//** applf(FUNC,COL) function or .op which returns a value
func applf () { local min,max,a,i,fl,ret,na,flag localobj v1,v2
    na=numarg()
    if (na==0) { 
        printf("applf(FUNC,'COLA'[,...,vec]) apply function or .op to selected cols.\n")
        printf("applf(FUNC,vec) apply function or .op to all cols.\n")
        printf("with more than one column need a final vector to copy results to\n")
        printf("must use function, not proc, since will keep return value.\n")
        return -1 }
    a=allocvecs(v1,v2)
    v1.resize(1)
    if (eqobj(cob,out) && verbose) printf(" *Selected* ")
    if (argtype(na)==1) {flag=na na-=1} else flag=0 // flag to copy onto an output vector
    if (na==1) { min=0 max=m-1 } else { min=2 max=na } 
    for i=min,max {
        if (na==1) { fl=i
          } else {if (argtype(i)==0) fl=$i else if ((fl=fi($si))==-1) return -1}
        if (fl==-2) sprint(sstr2,"%s",cob.scr) else sprint(sstr2,"%s",cob.v[fl]) 
        if (strm($s1,"^\\.")) sprint(sstr,"%s.x[0]=%s%s"  ,v1,sstr2,$s1) else {
                                sprint(sstr,"%s.x[0]=%s(%s)",v1,$s1,sstr2) }
        execute(sstr)
        v2.append(v1.x[0])
      }
    if (flag) {i=flag $oi.copy(v2)}
    ret=v2.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]==CODTY) { // 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("%s:fill() ERRa: only fill with vector: %s\n",this,$oi) return -1}
            if ($oi.size!=cob.v.size){
                printf("%s:fill() ERRb: wrong vec size: %d!=%s:%d\n",this,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("%s:fill() ERRc: trying to fill field %s with string %s\n",this,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
// can also do after a regular select() ie selcp==1 and avoid needing a delect
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)
// last args are max or min-max rows
// first set of args can be any of: col_names, file object, file name (not same as col name),
//      vector giving col numbers
func pr () { local ii,i,min,max,na,flag,jj,e,fout,sz,nohdr
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (m==0) {printf("%s EMPTY",this) return 0}
    scr[1].resize(0)
    nohdr=fout=flag=min=0 max=cob.v.size-1 na=numarg()
    nohdr=noheader
    if (argtype(na)==0 && argtype(na-1)==0) {  // pick up the limits first
        i=na na-=2
        max=$i i-=1 min=$i 
      } else if (argtype(na)==0) {
        i=na na-=1
        if ($i>=0) max=$i else min=max+$i // allow printing the end
      } 
    for i=1,na {
        if (argtype(i)==1) {  
            if (isobj($oi,"Vector")) {      flag=1 // column indices in a vector
                scr[1].copy($oi) 
              } else if (isobj($oi,"File")) { fout=1
              } else { printf("NQS::pr() Unknown object: %s\n",$oi) return 0 }
          } else if (argtype(i)==2) {
            if (fi($si,"NOERR")!=-1) { // column identifier to pick up
                scr[1].append(fi($si)) flag=1 
              } else if (strcmp($si,"NOHEADER")==0) { nohdr=1
              } else if (strm($si,"[<>]")) { flag=2  // something to calculate
              } else { // assume it's a file name
                if (fout) { fi($si) return 0 } // already picked up a filename
                if (!tmpfile.wopen($si)) printf("%s:Can't open %s for printing\n",this,$si)
                fout=1 
                printf("==== WARNING: printing ascii to file %s ====\n",$si)
              }
          }
      }
    if (flag==0) scr[1].indgen(0,m-1,1) // didn't pick up any columns
    if (scr[1].min<0 || scr[1].max>m-1) { printf("NQS:pr() bad col values: ") vlk(scr[1]) return 0 }
    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 && flag!=2) print ""
    if (flag==2) {
        calc($s1,"NOEXEC")
        sprint(sstr,"XO=%s",sstr)
        execute(sstr)
        vlk(XO,min,max)
      } else {
        sz=scr[1].size-1
        if (!nohdr) { 
            printf("%s",tabform)
            for i=0,sz {
                ii=scr[1].x[i]
                if (ii==-1) return -1
                if (fout) {
                    if (ii<0) tmpfile.printf("%s%s",is[-ii].s,tabform) else {
                        tmpfile.printf("%s(%d)%s",s[ii].s,ii,tabform) }
                  } else {
                    if (ii<0) printf("%s%s",is[-ii].s,tabform) else printf("%s(%d)%s",s[ii].s,ii,tabform)
                  }
              } 
            if (fout) tmpfile.printf("\n") else printf("\n") 
          }
        for jj=min,max {
            printf("%s",tabform)
            for i=0,sz { ii=scr[1].x[i]
                if (ii==-2) { printf(dblform,cob.scr.x[jj]) 
                  } else if (ii==-3) { 
                    if (fout) tmpfile.printf(dblform,cob.ind.x[jj]) else printf(dblform,cob.ind.x[jj])
                  } else {
                    if (fout) { prtval(tmpfile,(e=getval(ii,cob.v[ii].x[jj],jj)),tabform) 
                      } else if (sz) { prtval(   (e=getval(ii,cob.v[ii].x[jj],jj)),tabform) 
                      } else {         prtval(   (e=getval(ii,cob.v[ii].x[jj],jj)),tabform)  }
                    if (e==ERR) return ERR
                  }
              }
            if (fout) tmpfile.printf("\n") else if (sz) print "" else printf(" ")
          }
      }
    if (fout) tmpfile.close
    return 0
  }

//** prs() print out vectors
// eg prs("COLA","COLB",3,7)
func prs () { local ii,i,min,max,na,flag,jj,kk,e,fout,sz,nohdr
    if (eqobj(cob,out)) printf("NQS WARNING: prs() called after full select(); switching\n")
    cob=this
    if (m==0) {printf("%s EMPTY",this) return 0}
    nohdr=flag=min=0 max=ind.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("%s:Can't open %s for printing\n",this,$s1)
        fout=1 i+=1
        printf("==== WARNING: printing ascii to file %s ====\n",$s1)
        if (numarg()==2) if (argtype(2)==2) if (strcmp($s2,"NOHEADER")==0) {nohdr=1 i+=1}
      }
    if (na>=i) if (argtype(i)==2 || argtype(i)==1) flag=1 // column names
    if (max>ind.size()){ max=ind.size()-1
        printf("NQS:prs WARNING: %d rows requested but %s size=%d\n",max,this,ind.size()) }
    if (min>size(1)){printf("NQS:prs 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)) 
        sz=scr[1].size-1
        if (!nohdr) { for i=0,sz {
              ii=scr[1].x[i]
              if (ii==-1) return -1
              if (fout) {
                  if (ii<0) tmpfile.printf("%s\t",is[-ii].s) else tmpfile.printf("%s(%d)\t",s[ii].s,ii)
                } else {
                  if (ii<0) printf("%s\t",is[-ii].s) else printf("%s(%d)\t",s[ii].s,ii)
                }
            } if (fout) tmpfile.printf("\n") else printf("\n") }
        for kk=min,max { jj=ind.x[kk]
            for i=0,sz { ii=scr[1].x[i]
                if (ii==-2) { printf(dblform,cob.scr.x[jj]) 
                  } else if (ii==-3) { 
                    if (fout) tmpfile.printf(dblform,cob.ind.x[jj]) else printf(dblform,cob.ind.x[jj])
                  } else {
                    if (fout) { prtval(tmpfile,(e=getval(ii,cob.v[ii].x[jj],jj)),tabform) 
                      } else if (sz) { prtval(   (e=getval(ii,cob.v[ii].x[jj],jj)),tabform) 
                      } else {         prtval(   (e=getval(ii,cob.v[ii].x[jj],jj)),tabform)  }
                    if (e==ERR) return ERR
                  }
              }
            if (fout) tmpfile.printf("\n") else if (sz) print "" else printf(" ")
          }
      } else {
        if (!nohdr) {
            if (fout) for ii=0,m-1 tmpfile.printf("%4.4s(%d)  ",s[ii].s,ii) else {
                for ii=0,m-1 printf("%4.4s(%d)  ",s[ii].s,ii) }
            if (fout) tmpfile.printf("\n") else print ""
          }
        for kk=min,max { jj=ind.x[kk]
            for ii=0,m-1 { 
                if (fout) prtval(tmpfile,e=getval(ii,cob.v[ii].x[jj],jj),tabform) else {
                    prtval(        e=getval(ii,cob.v[ii].x[jj],jj),"") 
                    printf("(%d)%s",ii,tabform)
                  }
                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],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,sz
    cob=this
    if (numarg()==1) sz=$1 else sz=0
    // fcds.remove_all fcds.append(new String("`EMPTY'"))
    if (isassigned(fcdo)) fcdo.remove_all
    if (isassigned(fcdv)) fcdv.resize(0)
    if (sz>0) vlsz(vl,sz,0)
    vlsz(vl,0)
  }

//** pad() -- bring all vectors up to same length (of v[0])
func pad () { local sz,ii localobj v1
    sz=-1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    info.set("pads",v1=new Vector(m))
    for ii=0,m-1 v1.x[ii]=cob.v[ii].size
    for ii=0,m-1 if (cob.v[ii].size>sz) sz=cob.v[ii].size
    if (argtype(1)==0) sz=$1 else for ii=0,m-1 if (cob.v[ii].size>sz) sz=cob.v[ii].size
    if (argtype(2)==0) vlsz(cob.vl,sz,$2) else vlsz(cob.vl,sz) // optional fill value
    return sz
  }

obfunc unpad () { local sz,ii localobj v1
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    v1=info.get("pads")
    for ii=0,m-1 cob.v[ii].resize(v1.x[ii])
    return v1
  }

//** size() -- return num of vectors and size of each vector
func size () { local ii,sz,fl,sum
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (m==0) { print "0 x 0" return 0 } // empty
    sz=cob.v.size fl=0
    for ii=1,m-1 if (cob.v[ii].size!=sz) {fl=ii break}
    if (numarg()==1) {
        if ($1==2) {
            tog("DB") sum=0
            printf("\t%d cols x %d rows",m,sum+=v.buffer_size)
            for ii=1,m-1 printf(",%d",cob.v[ii].buffer_size)
            if (out!=nil) {
                printf("\nOUT:\t%d cols x %d rows",m,sum+=out.v.buffer_size)
                for ii=1,m-1 printf(",%d",sum+=out.v[ii].buffer_size)
              }
            printf("\nApprox. usage: %g kB\n",sum*8/1e3)
          } else if ($1==1 && fl && !noheader) { // warn about discrepant sizes
            printf("%s size WARN: cols are not same length: %s:%d %d\n",this,s[fl].s,cob.v[fl].size,sz) }
      } else { // print basic info when have no args
        printf("%d cols x %d rows",m,cob.v.size)
        if (fl) 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
// resize("COL1","COL2"...) if these col names already exist just make a new copy of col
// resize(NQS) -- a horizontal 'append'
func resize () { local oldsz,newsz,i,ii,jj,kk,vsz,na,appfl,o1m,padfl
    cob=this padfl=0
    na=numarg()
    vsz=-1
    if (argtype(na)==2) { i=na
        if (strcmp($si,"PAD")==0) { padfl=1 na-=1 }
      }
    if (na==1) { 
        if        (argtype(1)==0) { 
            appfl=0 
            if ($1<0) newsz=m+$1 else newsz=$1 
          } else if (argtype(1)==2) { 
            newsz=m+1 appfl=2 
          } else if (argtype(1)==1) { // an NQS
            if (size(1)!=$o1.size(1)) {
                printf("NQS resize(NQS) warning: rows differ %d %d\n",size(1),$o1.size(1))}
            o1m=$o1.m
            newsz=m+o1m
            appfl=3
          }
      } 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) { printf("%s Resize ERR: require even # of args",this)  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("%s RESIZE ERR: arg %d should be str\n",this,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("%s RESIZE ERR2: arg %d should be num or obj\n",this,i) return -1}
          }
      } else if (appfl==2) { 
        for (i=1;i<=na;i+=1) {
            if (argtype(i)!=2) { printf("%s RESIZE ERR3: arg %d should be str\n",this,i) return -1}
            tstr=$si
            if ((jj=fi(tstr,"EXACT"))!=-1) {
                while (fi(tstr,"EXACT")!=-1) sprint(tstr,"%s0",tstr) // find unique name
              }
            kk=oldsz+i-1
            s[kk].s=tstr
            if (jj>=0) { 
                if (fcd.x[jj]==1) {
                    if (verbose) printf("NQS::Resize: converting OBJ Col '%s' to DBL Col '%s'\n",$si,tstr) 
                    v[kk].resize(v[jj].size)
                    for ii=0,v[jj].size-1 v[kk].x[ii]=oform(fcdo.o(v[jj].x[ii]))
                  } else {
                    if (verbose) printf("NQS::Resize copying Col %s to %s\n",$si,tstr) 
                    v[kk].copy(v[jj]) 
                  }
              }
          }
      } else if (appfl==3) {
        for i=0,o1m-1 {
            tstr=$o1.s[i].s
            while (fi(tstr,"NOERR")!=-1) sprint(tstr,"%s0",tstr)
            s[oldsz+i].s=tstr
            v[oldsz+i].copy($o1.v[i])
          }
      }
    chk()
    if (padfl) pad()
    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("%s ERR: run grow on full db\n",this)  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
  }

//** delcol("LABEL1"[,"LABEL2",...])
func delcol () { local ii,i,a localobj v1
    tog("DB") // start at full db
    a=allocvecs(v1)
    if (argtype(1)==1) {
        v1.copy($o1)
      } else for i=1,numarg() {
        if (argtype(i)==2) { if ((fl=fi($si))==-1) {dealloc(a) return -1} } else fl=$i
        v1.append(fl)
      }
    v1.sort v1.reverse // get rid of last ones first
    for i=0,v1.size-1 { fl=v1.x[i]
        if (fl>m-1 || fl<0) { printf("%s ERR: delcol OOB:%d\n",this,fl)  dealloc(a) return -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 
        // if ((x=fcd.x[fl])!=0) {} // ideally should go through and remove all objs or strs
        x.remove(fl) fcd.remove(fl)
        m -= 1
      }
    out.m=m
    chk()
    dealloc(a)
    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])
// getrow("COL",val[,vec]) // return 1st row where "COL" is val
obfunc getrow () { local i,ii,ix,fl,flag localobj v1
    if (argtype(2)==0) { // fetch first matching row according to arg
        if (argtype(1)==2) fl=fi($s1) else fl=$1
        if (fl==-1) return
        if (numarg()==3) v1=$o3 else v1=new Vector()
        v1.resize(m)
        v[fl].fetch($2,vl,v1)
      } else {
        if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
        ix=$1 i=2
        if (argtype(i)==1) {v1=$oi i+=1} else v1=new Vector()
        v1.l2p(cob.vl,ix)
        for (ii=0;argtype(i)!=-1 && ii<v1.size;{i+=1 ii+=1}) if (argtype(i)==3) $&i=v1.x[ii]
      }
    return v1
  }

//** getcol("name") getcol("name",1) returns pointer
// getcol("name"[,VEC]) copies to VEC
// getcol("name",0) -- copies to new vector and returns it
obfunc getcol () { local a,fl,ii localobj v1,vo,l
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    if (fl==-1) return nil
    v1=vo=cob.v[fl]   //  default returns pointer
    if (fcd.x[fl]==1) {
        if (oform(fcdo.o(vo.x[0]))==NOP) {
            printf("NQS getcol Warning: returning indices for an object field\n")
          } else if (oform(fcdo.o(vo.x[0]))==OK) {
            l=new List()
            for ii=0,vo.size-1 l.append(fcdo.o(vo.x[ii]))
            return l
          } else {
            v1=new Vector(vo.size)
            for ii=0,vo.size-1 v1.x[ii]=oform(fcdo.o(vo.x[ii]))
            if (argtype(2)==1) {$o2.copy(v1) v1=$o2}
          }
      } else if (argtype(2)==0) {
        if ($2==0) v1=vo.c
      } else if (argtype(2)==1) { // copy into a preexisting vector
        v1=$o2
        v1.copy(vo)
      }
    return v1
  }

//** getsel("name"[,vec]) returns the select(-1,...) values
obfunc getsel () { local ii,fl localobj v1
    if (eqobj(cob,out)) printf("NQS WARNING: getsel() called after full select()\n")
    if (argtype(1)==2) fl=fi($s1) else fl=$1
    if (fl==-1) return v1
    if (numarg()<2) v1=new Vector(ind.size) else {v1=$o2 v1.resize(ind.size)}
    for ii=0,ind.size-1 v1.x[ii]=v[fl].x[ind.x[ii]]
    return v1
  }

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

//** renamecols("LABEL1","LABEL2"...) -- rename all column
proc renamecols () { local oldsz,i
    if (numarg()<m) printf("Renaming only %d/%d cols\n",numarg(),m)
    for i=1,numarg() s[i-1].s=$si
  }

//** sv(FNAME[,APPEND]) save the NQS
// to sv selected -- NQS.select(...) NQS.cp(NQS.out,1) NQS.sv()
proc sv () { local i,j,cd,cd1,vers,a,aflag,nx,no,ns,svinfo localobj xo,v1,v2
    aflag=cd1=0 // flags cd1=1 -- no single value vec compression;
    if (eqobj(cob,out) && verbose) printf("==== WARNING: Saving selected only ====\n") 
    a=allocvecs(v1,v2)
    if (numarg()>0) file=$s1 else aflag=2
    if (numarg()>=2) aflag=$2
    if (numarg()>=3) cd1=$3 // 1:flag for not compressing
    if (aflag==2) { // will just continue saving in the current file
      } else if (aflag==1) { 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("%s: can't open file\n",this) return }
      }
    v1.resize(m) v1.fill(0)
    // will be saved without full vectors
    if (cd1==0) for i=0,m-1 if (cob.v[i].ismono(0) && cob.v[i].size>10) {
        cd1=2 // 2 flag for using compression
        v1.x[i]=1
      }
    if (isassigned(fcdo)) foc=fcdo.count else foc=-1
    vers=version(1) // will assist for identifying file type if change format in future
    // dump info
    svninfo=nx=no=ns=0
    for ii=0,info.sz-1 {
        if(info.x[ii]!=ERR) nx+=1 
        if(info.o[ii]!=nil) { xo=info.o[ii]
            if (isojt(xo,v)) no+=1 else printf("NOT SAVING info %s\n",xo) }
      }
    ns=(sfunc.len(info.s)>0)+(sfunc.len(info.t)>0)+(sfunc.len(info.u)>0)+(sfunc.len(info.v)>0)
    if (nx>0 || no>0 || ns>0) { svinfo=1  if (verbose) {
            printf("%s.sv() WARN: saving info but ... 1.assumed sequential; 2. no labels:%d %d %d\n",\
                 this,nx,no,ns) }} else svinfo=0
    cd=mkcodf(cd1,noheader,svinfo,vers) // stuff flags in 1 place
    savenums(m,fcds.count,(cnt=fcd.count(-1)),foc,size(1),cd,vers,0,0) // extra for codes
    wrvstr(file) wrvstr(comment)
    if (!noheader) for i=0,m-1 wrvstr(s[i].s)
    if (svinfo) {
        savenums(nx,no,ns) 
        if (nx>0) savenums(&info.x,nx)
        for ii=0,no-1 {xo=info.o(ii) if (isojt(xo,v)) xo.vwrite(tmpfile) }
        if (ns>0) wrvstr(info.s) if (ns>1) wrvstr(info.t) 
        if (ns>2) wrvstr(info.u) if (ns>3) wrvstr(info.v) 
      }
    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)) { 
            fspitchar(1,tmpfile)  // 1 for vector
            fcdo.o(i).vwrite(tmpfile)
          } else if (isojt(fcdo.object(i),this)) { 
            fspitchar(2,tmpfile)  // 2 for NQS
            fcdo.o(i).sv()
          } else {
            printf("NQS:sv() WARNING: Can't save obj %s for %s\n",fcdo.o(i),this)
            fspitchar(0,tmpfile) // 0 for nil
          }
      }
    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 && v1.x[i]==1) {
            savenums(-1e9,cob.v[i].size,cob.v[i].x[0])
          } else if (fcd.x[i]==CODTY) {
            cob.v[i].vwrite(tmpfile,4) // must save CODE fully
          } else {
            cob.v[i].vwrite(tmpfile,svsetting)
          }
      }
    x.vwrite(tmpfile)
    if (aflag!=2) tmpfile.close 
    dealloc(a)
  }


//** rd(FNAME[,FLAG]) read format saved by sv()
// flag==2 - only read header
func rd () { local n,vers,hflag,cd,cd1,cd3,cd4,ii,oco,nx,no,ns,svinfo localobj v1,xo
    hflag=0 cob=this
    a=allocvecs(v1)
    if (numarg()>=1) if (argtype(1)==2) {
        if (!tmpfile.ropen($s1)) { printf("%s: can't open file %s\n",this,$s1) dealloc(a) 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,&cd,&svvers,&cd3,&cd4)
    if (n==0) {dealloc(a) return 0}
    if (n<9) v0sz=cd1=svvers=cd3=cd4=-1
    if (svvers<640) { 
        cd1=cd noheader=cd3 svinfo=0
      } else { 
        uncodf(cd,&cd1,&noheader,&svinfo,&vers)
        if (vers!=svvers) printf("INT DECODE VERS ERR in NQS.rd(): %d %d\n",svvers,vers)
      }
    if (cd1==2 && hflag==1) printf("NQSrdWARN0: can't do partial reads on compressed: %s\n",$s1)
    if (ii!=m) resize(ii)
    rdvstr(file) rdvstr(comment)
    if (sfunc.len(file)==0 && numarg()>0) file=$s1
    if (!noheader) for i=0,m-1 rdvstr(s[i].s)
    if (svinfo) {
        readnums(&nx,&no,&ns) 
        if (nx>0) readnums(&info.x[0])
        for ii=0,no-1 {info.o(ii)=new Vector() info.o(ii).vread(tmpfile) }
        if (ns>0) rdvstr(info.s) if (ns>1) rdvstr(info.t) 
        if (ns>2) rdvstr(info.u) if (ns>3) rdvstr(info.v) 
      }
    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 { 
        oco=fgchar(tmpfile)
        if (oco==1) {
            fcdo.append(Xo=new Vector()) 
            Xo.vread(tmpfile) 
          } else if (oco==2) {
            fcdo.append(Xo=new NQS())
            Xo.rd() 
          } else if (oco==0) {
            printf("NQS:rd() WARNING: Nil being read for %s\n",this)
          } else {
            printf("NQS:rd() ERROR: unrecognized char %d for %s\n",oco,this)
          }
      }
    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("%s: rd header: can't do seeks since v's not same size:%s\n",this,file)
        dealloc(a)
        return v0sz
      } else {
        v0sz=-1 // indicates that everything has been read in
        for i=0,m-1 { 
            v[i].vread(tmpfile)
            if (v[i].size>2) if (v[i].x[0]==-1e9) { 
                ii=v[i].x[2]
                v[i].resize(v[i].x[1]) 
                v[i].fill(ii) 
              }
          }
        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
    chk()
    dealloc(a)
    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("%s:rdpiece ERR: no room: neg index\n",this) 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("%s:rdpiece ERRA: ran out: %d %d",this,loc+end,tellend) return 0}
        v[ii].fread2(tmpfile,end,3+bswap)
      }
    return 1
  }

// rddif(filename) reads a .dif (data interchange format) file as can be exported from eg Excel
// NB to save to .dif from ooffice use File->Save as
// to save other than sheet#1 need to delete first (select didn't work): Edit->Sheet->Delete
proc rddif () { local a,ii,x,done,val,sz localobj oq,st
    st=new String2()
    empn=0 fln_lnum=1
    file=$s1 
    tmpfile.ropen(file)
    fln(3,st) // move forward 3 to pick up name
    sprint(comment,"'%s' from %s",st.s,file)
    x=fln(2,st) resize(x)
    x=fln(3,st) clear(x)  // should be 1 larger in size, fill with ERR
    fln("BOT",st,0) // look for precise string "BOT"
    for ii=0,m-1 {
        fln(2,st) 
        if (sfunc.len(st.s)>0) { repl_mstr(st.s," ","_") s[ii].s=st.s
          } else s[ii].s="UUEMPUU" // code for later
      }
    fln("BOT",st,0)
    // now pick up line pairs which are "text"\n1,0 OR 0,val\nV
    done=0
    while (!done) {
        for ii=0,m-1 {
            x=fln(1,st) val=x st.t=st.s // don't need to save st.t?
            y=fln(1,st)
            if (strcmp(st.s,"V")==0) {
                v[ii].append(val)
              } else if (sfunc.len(st.s)==0) { // empty
                if (fcd.x[ii]==2) { v[ii].append(0) // empty string
                  } else v[ii].append(OK)
              } else { // a string
                if (fcd.x[ii]!=2) { printf("STRDEC:%d,%d ",ii,v[ii].size+1) fcd.x[ii]=2 }
                sval=st.s
                v[ii].append(newval(2,ii))
              }
            // print val,st.t,x,st.s
          }
        fln(2,st)
        if (strcmp(st.s,"EOD")==0) { done=1 break }
        if (strcmp(st.s,"BOT")!=0) {
            printf("ERR: should be at BOT at line#: %d %d %s\n",_lnum,v.size,st.s)
            done=1 break // done is redundant
          }
      }
    sz=v.size
    for (ii=m-1;ii>=0;ii-=1) { // check the empty columns
        if (strcmp(s[ii].s,"UUEMPUU")==0) {
            if (v[ii].count(OK)!=sz) {
                printf("WARN: nonempty vector with empty header for col %d\n",ii)
                sprint(s[ii].s,"COL%d",ii)
              } else delcol(ii)
          }
      }
  }

// read a .atf file which is the ascii version of a pCLAMP .abf file
proc rdatf () { local ii,rows,cols localobj st,v1,v2
    st=new String2() v1=new Vector() v2=v1.c
    fln_lnum=1
    file=$s1 rows=file_len($s1) tmpfile.ropen($s1)
    fln(2,st)
    sscanf(st.s,"%*d%*[^0-9]%d",&cols)
    resize(cols)
    clear(rows)
    fln("CURRENT",st)
    repl_str(st.s,"CURRENT","") repl_mstr(st.s,"\t",",") sfunc.right(st.s,1)
    split(st.s,v1)  info.o=v1
    fln("^Time",st)
    if (v1.size!=cols-1) {printf("rdatf() discrepancy in %s: %d %d\n",$s1,v1.size,cols-1) return }
    s[0].s="t" 
    for ii=1,m-1 {
        sprint(s[ii].s,"pA%d",v1.x[ii-1]) 
        if (strm(s[ii].s,"-")) repl_str(s[ii].s,"-","m")
      }
    while (tmpfile.gets(st.s)!=-1) {
        fln_lnum+=1
        repl_mstr(st.s,"\t",",")
        split(st.s,v2)
        if (v2.size!=m) printf("rdatf() prob at line %d: %s\n",fln_lnum-1,st.s) else append(v2)
      }
  }


//** func rdcols()
// reads columns of ascii with optional labels at the top
// still won't read strings -- prob not worth fixing any more
// -- may want to go back to v617 for this
func rdcols () { local i,ii,cols,li,errflag,num,hflag,loc localobj fi,st
    hflag=1 errflag=0 st=new String2()
    if (argtype(1)==2) {
        fi=tmpfile st.s=$s1 loc=0 tflg=0
        if (! fi.ropen(st.s)) { printf("\trdcols ERR0: can't open file \"%s\"\n",st.s) return 0}
      } else {fi=$o1 fi.getname(st.s) hflag=0 loc=fi.tell() tflg=1}
    if (fcd.count(2)+fcd.count(0)!=m) {printf("\trdcols ERRA: only rd strs and dbls\n") return 0}
    if (fi.scanstr(sstr)==-1) {printf("\trdcols ERR1: file \"%s\"\n",st.s) return 0}
    if (fcd.count(2)==0 && !isnum(sstr)) hflag=1 else hflag=0 // hflag=0 -> no header
    if (numarg()>1) { // names of columns
        resize(numarg()-1)
        for i=2,numarg() sethdrs(i-2,$si)
        if (hflag) {
            printf("Header in file %s: %s vs %s\n",st.s,sstr,s[0].s)
            hflag=2
          }
      } else if (!hflag) printf("No Header read for %s\n",st.s)
    cols=0
    if (hflag==1) {
        fi.seek(0)
        fi.scanstr(sstr) 
        while (! isnum(sstr)) { 
            cols+=1 
            resize(sstr)
            fi.scanstr(sstr) 
          }
        fi.seek(0) fi.gets(sstr) loc=fi.tell
        ncols=cols
      } else {
        ncols=fcd.count(0) // assume that NQS was set up ahead
        cols=fcd.size
      }
    li=file_len(st.s)
    if (hflag || tflg) li-=1 // hack -- assuming that threw away one line 
    printf("%d cols; %d lines of data in %s.\n",cols,li,st.s)
    fi.seek(loc) // back to top
    // WARN: this will screw up if numbers are to be included as strings
    num=scr.scanf(fi,li*ncols) // note that this will skip over non-nums
    if (num!=li*ncols) { // err not reached since scanf dumps out
        printf("WARNING: expected %d vals; found %d\n",li*ncols,num) errflag=3 }
    if (fi.scanstr(sstr)>-1) { 
        printf("WARNING: %s found after reading in %d vals\n",sstr,li*cols) errflag=4 }
    fi.seek(loc)
    for ii=0,cols-1 { 
        if (fcd.x[ii]>0) continue
        v[ii].resize(li)
        v[ii].copy(scr,0,ii,li*ncols-1,1,cols) // v[ii].mcol(scr,ii,cols)
      }  
    if (fcd.count(0)!=m) {
        fi.seek(loc) // need to pick up some strings
        for ii=0,li-1 for jj=0,cols-1 { 
            if (fi.scanstr(st.t)==-1) {printf("ERR reading at %d\n",fi.tell()) errflag=5 return 0}
            if (fcd.x[jj]==2) v[jj].append(newval(2,jj))
          }
      }
    if (errflag) { printf("rdcols ERR%d\n",errflag) return 0 }
    return cols
  }

//** func svR([filename])
// saves in a format that can be read by my rdnqs.R program
func svR () { local ii,jj,cols,li,errflag,num
    errflag=0
    if (eqobj(cob,out) && verbose) printf(" *Selected* ") 
    if (numarg()==1) sstr=$s1 else {
        sstr=file
        repl_mstr(sstr,"\.nqs$",".nqR")
      }
    if (tmpfile.ropen(sstr)) if (!boolean_dialog("File exists","Overwrite","Cancel")) { 
        print "Cancelled" return 0 }
    if (! tmpfile.wopen(sstr)) { printf("\tsvR ERR0: can't open file \"%s\"\n",sstr) return 0}
    tmpfile.printf("%d\n",m)
    for ii=0,m-1 tmpfile.printf("%s\n",s[ii].s)
    for ii=0,m-1 cob.v[ii].vwrite(tmpfile)
    tmpfile.close()
    return ii
  }

//** func svcols(filename)
// saves numeric columns for R -- read with aa=read.table("filename")
func svcols () { local ii,jj,cols,li,errflag,num
    errflag=0
    if (tmpfile.ropen($s1)) if (!boolean_dialog("File exists","Overwrite","Cancel")) { 
        print "Cancelled" return 0 }
    if (! tmpfile.wopen($s1)) { printf("\tsvcols 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 {
        tmpfile.printf("%d%s",ii,sstr2)
        for jj=0,m-1 {
            getval(jj,v[jj].x[ii],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("%s:join ERRA not double field\n",this) 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 cpout () { // copy .out to this
    cob=this
    for ii=0,m-1 v[ii].copy(out.v[ii])
  }
proc cp () { local ii,csz,veccp,outcp localobj o,oo
    cob=this
    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
      }
    noheader=$o1.noheader
    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 { 
        if (!noheader) s[ii]=up.s[ii]
        v[ii]=new Vector()
      } else for ii=0,m-1 { 
        if (!noheader) 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)) // strings not being copies
        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
            o=$o1.fcdo
            for ii=0,o.count-1 {
                if (isojt(o.o(ii),v)) { // a vector
                    oo=new Vector(o.o(ii).size) oo.copy(o.o(ii)) fcdo.append(oo) 
                  } else if (isojt(o.o(ii),out)) { // a vector
                    oo=new NQS() oo.cp(o.o(ii)) fcdo.append(oo) 
                  } else {
                    printf("Can't copy a %s\n",o.o(ii)) return 
                  }
              }
          }
      } 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,epsilon,sz localobj v1,v2,o,xo,yo
    o=$o1
    a=allocvecs(v1,v2)
    if (numarg()>=2) { 
        af=1 
        if ($2!=1) epsilon=$2 else epsilon=1e-5
      } else af=0 // af is flag for approx eq
    if (o.m!=m) { printf("# of cols differ %d vs %d\n",m,o.m) return 0 }
    if (!noheader) for ii=0,m-1 if (strcmp(o.s[ii].s,s[ii].s)!=0) { 
        printf("%d col names differ: %s vs %s",ii,s[ii].s,o.s[ii].s) return 0 }
    for ii=0,m-1 if (o.v[ii].size != v[ii].size) { 
        printf("%d col lengths differ: %d vs %d",ii,v[ii].size,o.v[ii].size) return 0 }
    if ((sz=info.sz)!=o.info.sz) printf("Info sz difference") else {
        v1.resize(sz) v2.resize(sz) v1.d2v(&info.x) v2.d2v(&o.info.x) 
        if (!v1.eq(v2)) {printf("info x's differ:") vlk(v1) vlk(v2)}
        for ii=0,sz-1 { xo=info.o[ii] yo=o.info.o[ii]
            if (!isojt(xo,yo)) {printf("Different info objs at %d: %s %s\n",ii,xo,yo)
              } else if (isojt(xo,v) || isojt(xo,this)) if (!xo.eq(yo)) {
                printf("Different info objs at %d: %s %s %d %d\n",ii,xo,yo,xo.size,yo.size)}
          }
        xo=o.info
        if (strcmp(info.s,xo.s)!=0 || strcmp(info.t,xo.t)!=0 || strcmp(info.u,xo.u)!=0 ||\
            strcmp(info.v,xo.v)!=0) { printf("Different strings:\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",\
                                               info.s,xo.s,info.t,xo.t,info.u,xo.u,info.v,xo.u) }
      }
    if (af) {
        for ii=0,m-1 {
            v1.copy(v[ii])
            v1.sub(o.v[ii])
            v1.abs()
            if (v1.max>epsilon) {
                ix=v1.max_ind
                if (noheader) {
                    printf("%d cols differ: \n",ii,ix,v[ii].x[ix],o.v[ii].x[ix])
                  } else printf("%s cols differ: \n",s[ii].s,ix,v[ii].x[ix],o.v[ii].x[ix])
              }
          }
        if (numarg()>=3) $o3.copy(v1)
      } else for ii=0,m-1 if (! o.v[ii].eq(v[ii])) { 
        if (noheader) { printf("%d cols differ at ",ii)
          } else printf("%s cols differ at ",s[ii].s)
        for jj=0,v[ii].size-1 if (o.v[ii].x[jj] != v[ii].x[jj]) {
            printf("element %d: %g vs %g",jj,v[ii].x[jj],o.v[ii].x[jj])
            if (o.v[ii].x[jj]-v[ii].x[jj]<1e-5) {
                printf("\n\tTry for approximately equal using flag: nq.eq(nq2,1)\n")}
            return 0
          }
      }
    if (! fcdseq(o)) return 0
    if (! fcdoeq(o)) return 0
    dealloc(a)
    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.o(ii),$o1.fcdo.o(ii))) {
            printf("DIFFERING (2) obj lists (fcdo) %s,%s (%s,%s)",fcdo.o(ii),$o1.fcdo.o(ii),this,$o1)
            return 0
          }
        if (1) { // vector and nqs both use .eq() a vector: isojt(fcdo.o(ii),v)
            if (! fcdo.o(ii).eq($o1.fcdo.o(ii))) {
                printf("DIFFERING obj lists (fcdo) : differ %s,%s (%s,%s)",\
                       fcdo.o(ii),$o1.fcdo.o(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() { 
        if (argtype(i)==2) fl=fi($si) else fl=$i
        if (fl>-1) {
            fcd.x[fl]=2
            sval="`EMPTY'"
            newval(2,fl)   // don't want to put on more than one
          }
      }
    return 1
  }

//** fdec() -- declare these columns to be files with methods
func fdec () { local i,j,na
    if (eqobj(cob,out)) {
        printf("fdec() ERR: object fields can only be declared at top level\n") return 0}
    na=numarg()
    if (na==0 || na%3!=0) { printf("fdec(\"COLNAME\",\"METHOD\",\"PATH\"[,...])\n") return 0 }
    out.fcd=fcd
    for (j=1;j<=na;j+=3) { 
        i=j
        if (argtype(i)==0) fl=$i else fl=fi($si)
        if (fl==-1) return 0 else fcd.x[fl]=FUNTY
        i+=1 s[fl].t=$si i+=1 
        if (sfunc.len($si)==0) { sprint(s[fl].t,"%s(\"",s[fl].t)
          } else sprint(s[fl].t,"%s(\"%s/",$si,s[fl].t)
      }
    if (! isobj(fcdo,"List")) { fcdo=new List() out.fcdo=fcdo }
    return 1
  }

obfunc methget () { local fl,ix localobj o
    fl=$1 ix=$2
    if ((o=fcdo.o(ix).o)!=nil) return o
    sprint(tstr,"tmpobj=%s%s\")",s[fl].t,fcds.o(fcdo.o(ix).x).s)
    execute(tstr)
    o=tmpobj // need to use external global tmpobj
    fcdo.o(ix).o=o
    return o
  }

//** coddec() -- declare these columns to be coded
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]=CODTY
      }
    return 1
  }

//** deriv("COLA",...) generates a col with differences between each row value and preceding
proc deriv () { local fl,i
    if (eqobj(cob,out)) { printf("Take deriv on whole set only\n") return }
    for i=1,numarg() { 
        if (argtype(i)==0) fl=$i else fl=fi($si)
        if (fl==-1) return
        sprint(tstr,"%s'",s[fl].s)   resize(tstr)
        v[m-1].deriv(v[fl],1,1)
        v[m-1].insrt(0,0)
      }
  }

//** odec() -- declare these columns to be objects
func odec () { local i
    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=1,numarg() { 
        if (argtype(i)==0) fl=$i else fl=fi($si)
        if (fl>-1) fcd.x[fl]=1
      }
    if (! isobj(fcdo,"List")) { fcdo=new List() out.fcdo=fcdo }
    return 1
  }

//** vdec() -- declare this column to be pointers to fcdv
func vdec () { local i
    if (eqobj(cob,out)) {
        printf("odec() ERR: vec ptr fields can only be declared at top level\n") return 0}
    if (numarg()==0) { 
        printf("vdec(NAME[,NAME1 ...])\n\tdeclare these field to be vec ptr fields\n") return 0}
    out.fcd=fcd
    for i=1,numarg() { 
        if (argtype(i)==0) fl=$i else fl=fi($si)
        if (fl>-1) fcd.x[fl]=VECTY // type for vec
      }
    if (! isobj(fcdv,"Vector")) { fcdv=new Vector(1e4) fcdv.resize(0) out.fcdv=fcdv }
    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))
      }
  }

//** unnan() gets rid of nans and inf's in numerical cols
proc unnan () { local ii
    for ii=0,m-1 if (fcd.x[ii]==0) v[ii].unnan(0)
  }

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 -- an array pretending to be a list
begintemplate OARR
public oo,max,count,o,object,append,o2l,l2o,name,id
objref oo[1]
strdef name

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

//* ancillary routines
//* sopset() returns symbolic arg associated with a string
proc sopset() { local i
    for i=1,21 sops[i-1]=$i // AUGMENT TO ADD NEW OPSYM
  }
sopset(ALL,NEG,POS,CHK,NOZ,GTH,GTE,LTH,LTE,EQU,EQV,EQW,EQX,EQY,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","EQX","EQY","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   EQX  EQY NEQ  SEQ  RXP  IBE  EBI  IBI   EBE
    for scase("ALL","<0",">0","CHK","!=0",">",">=","<","<=","===","EQV","EQW","EQX","EQY","!=","=~","~~","[)","(]","[]","()") {
        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","EQX","EQY","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 EQX EQY !=  =~  ~~  [)  (]  []  ()\nALL NEG POS CHK NOZ GTH GTE LTH LTE EQU EQV EQW EQX EQY 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)
          }
      }
  }

proc delnqs () { local i
    for i=1,numarg() nqsdel($oi) 
  }
proc nqsdel () { localobj iq,xo
    if (isassigned($o1)) {
        iq=$o1
        if (isassigned(iq.fcdo)) for ltr(xo,iq.fcdo) if (isojt(xo,iq)) nqsdel(xo)
        if (isassigned(iq.out)) {iq.out.cob=nil  iq.out=nil}
        iq.cob=nil iq=nil 
      }
    if (!istmpobj($o1)) $o1=nil
    tmpobj=nil
  }

//* pmap() maps a function arg1 onto multiple args or a , sep string of args
proc pmap () { local i,na localobj st
    st=new String()
    na=numarg()
    sprint(st.s,"%s(",$s1) // 1st arg is name of proc
    for i=2,na sprint(st.s,"%s%s,",st.s,$si)
    if (na>=2) chop(st.s)
    sprint(st.s,"%s)",st.s)
    execute1(st.s)
  }

func fmap () { local i,na localobj st,o
    st=new String() o=new DBL()
    na=numarg()
    sprint(st.s,"%s.x=%s(",o,$s1) // 1st arg is name of proc
    for i=2,na sprint(st.s,"%s%s,",st.s,$si)
    if (na>=2) chop(st.s)
    sprint(st.s,"%s)",st.s)
    execute1(st.s)
    return o.x
  }

// eg svnqss("filename","nq,nq[1],nq[2]")
proc svnqss () { local x localobj st,ol,xo
    st=new String2() ol=new List()
    st.s=$s2
    split(st.s,ol,",")
    for ltr(xo,ol,&x) {
        sprint(st.s,"%s.tog(\"DB\") %s.info.s=\"%s\"",xo.s,xo.s,xo.s)
        execute(st.s)
        if (x==0) { sprint(st.s,"%s.verbose=0 %s.sv(\"%s\") %s.verbose=1",xo.s,xo.s,$s1,xo.s) 
          } else      sprint(st.s,"%s.verbose=0 %s.sv(\"%s\",1) %s.verbose=1",xo.s,xo.s,$s1,xo.s)
        execute(st.s)
      }
  }

proc rdnqss () { localobj xo,st,ol
    xo=new NQS() st=new String2() ol=new List()
    xo.rd($s1)      
    ol.append(xo)
    xo=new NQS()
    while (xo.rd) { ol.append(xo) xo=new NQS() }
    delnqs(xo)
    st.s=ol.o(0).info.s
    declare(st.s,"o[10]") // make default array of 10 of them if not there
    for ltr(xo,ol) { printf("%s size ",xo.info.s) xo.size() 
        st.t=xo.info.s
        sprint(st.s,"delnqs(%s) %s=new NQS() %s=%s",st.t,st.t,st.t,xo)
        execute(st.s)
      }
  }

//* bugs and missing features
// 1. for NQS, does resize work with object columns? i.e. 
// >  >  nqs1 has an object column
// >  >  can i do nqs2.resize(nqs1) to add nqs1 to nqs2?
// >  looks like I haven't bothered with that case (nqs.hoc_579:2188)
// 2. oc>  for ii=2,3 nq[ii-2].resize(nq[ii]) -- meaningless err messages?
// (~/nrniv/place/load.hoc_54:60)
// NQS[48] fi ERR: regexp matches more than once: 1 spkstats.killp
// NQS[48] fi ERR: regexp matches more than once: 2 spkstats.prup
// END /usr/site/nrniv/local/hoc/nqs.hoc
//================================================================
gnum=-1
declare("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, ty
  strdef name,f
  double loc[1]
  proc init () { 
      segs=1 ty=4
      if (argtype(5)==0) segs=$5 else if (argtype(5)==2) 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)
      if (numarg()==2) { vec.resize($2)   // typically sizeup and then resize to 0
          if (isassigned(tvec)) tvec.resize($2) }
    }
endtemplate vitem

//* main template: GRV
// the attributes of a particular set of graphs including line colors,
// world coordinates, etc
// 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,labelm

  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,symb

// 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
                    tmpobj.ty=bvec
                    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,symb,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,symb,line,curcol)
          }
      } else if (o.num==-2) {
        nvplt(vrtmp,tvec)
        if (gvmarkflag) {
            if (! rvaltdisp(tvec,vrtmp,llist.object(inx).name)) {
                vrtmp.mark(graphItem,tvec,symb,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,symb,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,symb,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,symb,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,symb,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,bvec 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)
    bvec=o.ty
    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
          }
        if (bvec>5) {
            $o2.fread(tmpfile,o.size,bvec-5) $o3.fread(tmpfile,o.size,bvec-5) 
          } else {
            $o2.vread(tmpfile) $o3.vread(tmpfile) 
          }
      } else if (n==-2) {
        if (n==-2) {
            if (bvec>5) {
                tvec.fread(tmpfile,o.size,bvec-5) // no error check
              } else if (!tvec.vread(tmpfile)) {
                printf("rv_readvec tvec READ failure in %s %s %d\n",filename,o.name,inx) return 0 }
            if (bvec>5) {
                $o2.fread(tmpfile,o.size,bvec-5) // no error check
              } else  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
          }
      } else $o2.vread(tmpfile) // fixed dt
    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,etc])
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,symb,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,etc
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,tback) print out the printlist with comment at head
proc pvother () {}  // user can dump other vectors at top with prvec()
proc pvplist () { local inx,tmin,tmax,tback localobj oq,xo
    output_file=$s1
    if (! pvplist0()) return // open file(s)
    pvplist1($s2) // print string header
    if (numarg()==3) if ($3>1) {
        tback=$3 tmax=printlist.o(0).tvec.max
        if (tmax>tback) {
            tmin=tmax-tback
            oq=new NQS() 
            for ltr(xo,printlist) {
                oq.setcols(xo.tvec,xo.vec)
                oq.select(0,">",tmin)
                oq.cpout()
                oq.resize(0)
              }
          }
      }
    pvout() 
    if (numarg()<3) { // leave for appending if $3==1
                         tmpfile.close() tf1.close()
      } else if ($3>1) { 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
    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
    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") { etc }
// 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") { etc }
// 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,etc
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]
gvmarkflag=0
obfunc gg () { local gp,na,newgr,clr,a,stp,i,tmp localobj ty,ts,abs,ord,o,go
    if (argtype(1)==2) if (strc($s1,"help")) {
        printf("eg gg(g[i],vec) gg(vec,step) gg(vec,ind) gg(g,'FUNC','min,max') [color,line,symbol]\n")
        return nil
      }
    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) 
        if (!name_declared(ts.s)) { // look for an x that will become $1
            if (!strm(ts.s,"[$]1")) { printf("gg ERR Can't find '$1' in %s\n",ts.s) return nil }
            sprint(ts.s,"func _gg_f(){return %s}",ts.s) execute1(ts.s)
            print ts.s
            ts.s="_gg_f"
          }
        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,4)",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()
    if (argtype(1)==1) st.s=$o1.s else st.s=$s1
    st.t=st.s
    sfunc.head(st.s,"[^/]+$",st.s)
    sfunc.tail(st.t,st.s,st.t)
    if (numarg()==2) $s2=st.s
    return st
  }

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

//** filsuf()
obfunc filsuf () { localobj st
    st=new String2()
    if (argtype(1)==1) st.s=$o1.s else st.s=$s1
    sfunc.tail(st.s,"\\.",st.s)
    if (numarg()==2) $s2=st.s
    return st
  }

//** filstem()
// allows composition: filstem(filname(aa)).s
obfunc filstem () { localobj st
    st=new String2()
    if (argtype(1)==1) st.s=$o1.s else st.s=$s1
    sfunc.head(st.s,"\\.",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 () { local n localobj o
    o=panobjl.o(0)
    if (! o.attr0) { printf("pvall() ERR %s not attr0==0\n",o)
      } else { 
        n=numarg()
        if (n==1) o.pvall($s1) else if (n==2) o.pvall($s1,$s2) 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 world 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)}
// translate from world coordinates into view coordinates
// view coordinates are different from Graph model coordinates
//  3 coordinate systems: view, world, panel  -- ie the 0,1 used by g.label
obfunc mdl2view () { local a,ii,x0,y0 localobj o,v1,g
    g=$o1 x0=$2 y0=$3
    if (argtype(4)==1) v1=$o4 else {
        v1=new Vector(4)
        for ii=0,3 v1.x[ii]=g.size(ii+1) 
      }
    o=new Union()
    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])  
    o.x[2]=o.x[0]*0.8+0.1 
    o.x[3]=o.x[1]*0.8+0.1 // scale and move over to where graph usually is
    return o
  }

//* cart2north() -- identify 0-360 degree N up for cartesian vector
// cart2north(x0,y0,x1,y1[,vec]) -- with vec also return amplitude in vec.x[1]
// cart2north(delx,dely[,vec]) 
func cart2north () { local theta,delx,dely,i
    if (numarg()<4) {delx=$1 dely=$2 i=3} else {delx=$3-$1 dely=$4-$2 i=5}
    theta=atan2(dely,delx)
    theta*=(180/PI)
    if (theta<0) theta+=360
    if (theta>=0 && theta<90) { theta= abs(theta-90)
      } else if (theta>=90 && theta<=360) theta = abs(450 - theta)
    if (numarg()==i) revec($oi,theta,sqrt(dely*dely+delx*delx))
    return theta
  }

//** rmallgrs() gets rid of all extant graphs
proc rmallgrs () { local ii,cnt localobj xo,glist
    glist=new List("Graph")
    for ltr (xo,glist) xo.unmap()
  }

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 /usr/site/nrniv/local/hoc/labels.hoc
// =Id=  labels.hoc,v 1.97 2010/10/29 02:35:51 samn Exp 

// keep track of version number for future changes
// eg if (label_hoc_vers>88) rcsopen("labels.hoc",88) // go back to 88
labels_hoc_vers=find_num("=Id=  labels.hoc,v 1.97 2010/10/29 02:35:51 samn Exp ","1\\."," ")
objref NCv,CODEv,DELv
objref PRIDv,POIDv,PRv,POv,DISTv,WT0v,WT1v // mo(1) will assign these
declare("ce",nil,"CTYP",new List(),"CPLA",new List(),"TPA",new List(),"nm",new List())
declare("STYP",new List(),"ncells",0,"ZTYP",new List(),"INCOL",new List())
declare("DEND",0,"SOMA",1,"AXON",2) // compartment codes - only 3 for now

//* utility functions
// plmin(val,var)
func plmin() { return $1 + $2*(2*u_rand() - 1) } 

//* cell types: 
// iex(), returns numeric index associated with a string or string object
func iex () { 
    if (argtype(1)==2) sprint(tstr,"x=%s",$s1) else sprint(tstr,"x=%s",$o1.s)
    execute(tstr) return x 
  }
// ice(), returns whether cell is an inhib cell based on its name starting with I
func ice () { local x
    if (argtype(1)==2) return strm($s1,"^I")
    if (argtype(1)==0) x=$1 else if (argtype(1)==1) x=$o1.type 
    return strm(CTYP.o(x).s,"^I")
  }
//* GetLyr - return layer of type
func GetLyr () { local x localobj st
    st=new String()
    if (argtype(1)==2) st.s=$s1 else if (argtype(1)==0) st.s=CTYP.o($1).s else {
        st.s=CTYP.o($o1.type).s }
    sscanf(st.s,"%*1s%d",&x)
    return x
  }

proc printtype () { local i
    for (i=1;argtype(i)==0;i+=1) if ($i!=-1) printf("%s(%d) ",CTYP.o($i).s,$i)
    if (argtype(i)==2) printf("%s",$si) else print ""
  }
proc celltype () { localobj st
    st=new String("\n")
    if (argtype(2)==2) st.s=$s2
    if (argtype(1)==0) printtype(ce.o($1).type,st.s) else printtype($o1.type,st.s) 
  }

obfunc names2indices () { local x localobj lo,xo,st
    lo=new List() st=new String()
    split($s1,lo)
    for ltr(xo,lo,&x) { sprint(st.s,"%s=%d",xo.s,x) execute(st.s) }
    return lo
  }

// at some point may want to divide up this list into cell type -- eg RS,IB and location
CTYP=names2indices("NU,SM,DP,SU,IN,TC,IRE,E6,I6,I6C,I6L,E5B,E5R,I5,I5L,E4,I4,I4L,E2,E2B,I2,I2Q,I2C,I2L,RS,IB,LTS,FS,ECA1,ICA1,ICA1L,EDG,IDG,IDGL,ECA3,ICA3,ICA3L,E3,I3,I3L")
CTYPi=CTYP.count  // number of cell types

// 1 cmp nrn, 2 cmp nrn, multi cmp nrn, intfire1, INTF, invlfire, nstim
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

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

proc ae () { localobj xo
    STYP.remove_all
    for scase2(xo,"AMPA","AM","NMDA","NM","GABAA","GA","GABAB","GB",\
               "AMPA2","AM2","NMDA2","NM2","GABAA2","GA2","GABAB2","GB2",\
             "IClamp","IC","AMPA/NMDA","EX","GABAA/GABAB2","IX","Exp2Syn","E2Sy"){
        STYP.append(new String2(xo.t,xo.s)) // switch them around here
        sprint(tstr,"%s=%d",xo.t,i1)
        execute(tstr)
      }
    STYPi=STYP.count  // number of cell types
  }
ae()

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

for scase2(XO,"RIGHT","RIT","INCOL","INC","LEFT","LFT") { INCOL.append(new String(XO.s))
    sprint(tstr,"%s=%d",XO.t,i1) execute(tstr) }
INCOLi=INCOL.count

//* IsLTS - return if type is LTS
func IsLTS () {
    return $1 == I2L || $1 == I4L || $1 == I5L || $1 == I6L 
  }
//* IsBurst - return if type is intrinsically bursting
func IsBurst () {
    return $1 == E2B || $1 == E5B
  }
//* IsFRB - return true if type is fast regular bursting
func IsFRB () {
    return $1 == E2B
  }
//* IsRS - return true if type is regular spiking E cell
func IsRS () {
    return $1 == E2 || $1 == E4 || $1 == E5R || $1 == E6
  }
//* IsFS - return true if type is fast spiking interneuron
func IsFS () {
    return $1 == I2 || $1 == I4 || $1 == I5 || $1 == I6 || $1 == ICA3 || $1 == IDG || $1 == ICA1
  }

func isartcell () { return sfunc.is_point_process($o1) }

// END /usr/site/nrniv/local/hoc/labels.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/syncode.hoc
// =Id=  syncode.hoc,v 1.411 2010/07/12 15:32:09 samn Exp 

//* setup
strdef syn1,syn2
thresh = -20
objref cp,svs,ncq,intf,vq
objref ivspks,vspks,wvspks,ncl[1][1][1]
objref sp[3], c[1], ce, nc[1], cells[10] // enough room for 10 cell types
objref vite
double numc[CTYPi],ix[CTYPi],ixe[CTYPi],wmat[CTYPi][CTYPi][STYPi],wd0[CTYPi][CTYPi][STYPi]
Incol=2
ncl = new List()
sp = new NQS()

//* iterator ixt(),ctt(),stt()
iterator ctt () { local jj // global ii
    if (argtype(2)==3) $&2=0 else i1=0
    for jj=0,CTYPi-1 if (numc[jj]!=0) { 
        if (ce!=nil) if (ix[jj]<ce.count()) { 
            if (argtype(1)==1) $o1=ce.o(ix[jj]) else XO=ce.o(ix[jj]) 
          }
        if (argtype(1)==3) $&1=jj else ii=jj
        iterator_statement
        if (argtype(2)==3) $&2+=1 else i1+=1
      }
  }

//* iterator cttr() -- reverse iterator of ctt
iterator cttr () { local jj // global ii
    if (argtype(2)==3) $&2=0 else i1=0
    for(jj=CTYPi-1;jj>=0;jj-=1) if (numc[jj]!=0) { 
        if (ce!=nil) if (ix[jj]<ce.count()) { 
            if (argtype(1)==1) $o1=ce.o(ix[jj]) else XO=ce.o(ix[jj]) 
          }
        if (argtype(1)==3) $&1=jj else ii=jj
        iterator_statement
        if (argtype(2)==3) $&2+=1 else i1+=1
      }
  }


iterator stt () { local ia,ja,ka,ib,jb,im,jm // global ii,jj,kk
    i1=ib=jb=0 im=jm=CTYPi-1 
    if (argtype(1)==0) if ($1>=0) ib=im=$1
    if (argtype(2)==0) if ($2>=0) jb=jm=$2
    if (argtype(4)==3) $&4=0
    for ia=ib,im for ja=jb,jm if (numc[ia]!=0 && numc[ja]!=0) {
        if (ce!=nil) if (ix[ia]<ce.count()) {XO=ce.o(ix[ia]) YO=ce.o(ix[ja])}
        for ka=0,STYPi-1 if (wmat[ia][ja][ka]!=0) {
            if (argtype(3)==3) { $&1=ia $&2=ja $&3=ka } else { ii=ia jj=ja kk=ka }
            iterator_statement
            if (argtype(4)==3) $&4+=1 else i1+=1
          }
      }
  }

ixi=ixj=0 // ixi steps through cell#s and ixj is consecutive
for ii=0,CTYPi-1 ixe[ii]=-1
// ctype(#,TYPE)
func ctype () { local ii
    if (numarg()==2) {
        return ($1>=ix[$2] && $1<=ixe[$2]) 
      } else {
        for ii=0,CTYPi-1 if ($1>=ix[ii] && $1<=ixe[ii]) return ii 
        return -1
      }
  }
// ixt(type[,col,vec]); ixt(type,&x); ixt(type,col,&x)
iterator ixt () { local ty,col,a,lfl,ixa,i localobj o
    ty=$1 lfl=0
    if (argtype(2)==0) col=$2 else { col=-1 if (argtype(2)==3) lfl=2 }
    if (argtype(3)==1) { o=$o3 vrsz(numc[ty],o,"O") } else if (argtype(3)==3) lfl=3
    i=lfl
    if (col<0) {
        for ({ixa=ix[ty] ixj=0};ixa<=ixe[ty];{ixa+=1 ixj+=1}) { XO=ce.o(ixa)
            if (lfl) $&i=ixa else ixi=ixa
            iterator_statement
          }
      } else {
        if (col>=ncols) printf("ixt ERR: Only %d columns (%d)\n",ncols,col) else {
            a=ix[ty]+col*numc[ty]/ncols
            for ({ixa=a ixj=0};ixa<a+numc[ty]/ncols;{ixa+=1 ixj+=1}) { XO=ce.o(ixa)
                if (XO.col!=col) printf("ixt ERR: XO.col!=col, %d %d\n",XO.col,col)
                if (lfl) $&i=ixa else ixi=ixa
                iterator_statement
              }
          }
      }
    if (o!=nil) stat(o)
  }

// 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)
  }

proc syncnn () { local preb,pree,posb,pose,pdiv,con,div,ii,jj,prn,pon,targ,sz,styp1,styp2
    if (numarg()==0) { print "\tsyncnn(preb,pree,posb,pose,pdiv)" return }
    preb=$1 pree=$2 posb=$3 pose=$4  pdiv=$5
    CODEv=sp.v[sp.fi("CODE")] PRv=sp.v[sp.fi("PR")] POv=sp.v[sp.fi("PO")]
    sz=PRv.size
    prn=pree-preb+1  pon=pose-posb+1
    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)
          }
      }
    PRv.add(preb) POv.add(posb)
    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
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][0]
        for ii=0,XO.count-1 XO.o(ii).weight[sy1]*=wd
        wd0[pr1][po1][sy1]=w1
      } else printf(".")
  } 

//** 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)
      }
  }

//*  avwtsp(), actwsc(), avwt() to get proper weight values
obfunc sysel () { local pr,po,sy,co,vb,num
    if (numarg()==1) sy=$1 else { // already selected
        pr=$1 po=$2 sy=$3 co=$4
        num=sp.select("CODE",EQU1,pr,"CODE",EQU2,po,"CODE",EQU3,co)
        if (num==0) { vec0.resize(0) 
            return vec0} // kludge to get an error returned
      }
    if ((pr==IN && sy==GA) || sy==AM) return sp.getcol("WT0",0) else return sp.getcol("WT1",0)
  }

//** avwtsp(PR,PO,COL) looks at NQS db to determine weights -- 7x faster than avwt() below
//   avwtsp(sp) if do select before checking this
obfunc avwtsp () {  local a,s1,s2,pr,po,co,wd localobj sp0,v1,o,vr
    pr=$1 po=$2 co=$3 sp0=sp o=new Union()
    a=allocvecs(v1)
    if (name_declared("netstem")==4) {
        sprint(tstr,"%s%sS%02d.spnqs",netstem,CTYP.o(po).s,scale)
        if (! strm(tstr,sp0.file)) { printf("Reading %s (was %s)\n",tstr,sp0.file)
            sp0.rd(tstr)
          }
      }
    if (pr==IN) {s1=GA s2=GB} else {s1=AM s2=NM}
    if (numarg()==4) sp0=$o4.cob else {
        sp0.verbose=0
        vr=sysel(pr,po,s1,co)
        if (vr.size==0 && verbose) {printf("%s->%s EMPTY\n",CTYP.o(pr).s,CTYP.o(po).s) return sp0}}
    sp0.verbose=0
    wd=ncq.ay(pr,po,s1,co).x
    vr.mul(wd)
    stat(vr,v1) // 0size,1max,2min,3mean,4sdev
    o.x=v1.x[3]
    printf("%s->%s %s %s: max: %g; min: %g; mean: %g; sdev: %g\n",\
           CTYP.o(pr).s,CTYP.o(po).s,STYP.o(s1).s,INCOL.o(co).s,\
           v1.x[1],v1.x[2],v1.x[3],v1.x[4])
    wd=ncq.ay(pr,po,s2,co).x
    vr=sysel(s2)  vr.mul(wd)  stat(vr,v1)
    o.x[1]=v1.x[3]
    printf("%s->%s %s %s: max: %g; min: %g; mean: %g; sdev: %g\n",\
           CTYP.o(pr).s,CTYP.o(po).s,STYP.o(s2).s,INCOL.o(co).s,\
           v1.x[1],v1.x[2],v1.x[3],v1.x[4])
    sp0.verbose=1
    dealloc(a)
    return o
  }

//** actwsc(PR,PO,SY,COCODE,COL,[,tMIN,tMAX])
func actwsc () { local ret,f1,a,wd,we,pr,po,min,max,u,x,y,sy,co,col,prspks,th,conv,diff localobj v1,v2,vr,q,p
    if (numarg()==0) {
        printf(" actwsc(PR,PO,SY,COCODE,COL,[,tMIN,tMAX])\n") return 0 }
    pr=$1 po=$2 sy=$3 co=$4 col=$5
    // min,max: just look at activity during this period
    if (numarg()>5) {min=$6 max=$7} else {min=0 max=tstop}
    if (min==max) f1=0 else f1=1
    a=allocvecs(v1,v2) q=new NQS() q.verbose=0 p=printlist
    if (f1) {
        // find name for raster plot should be eg 'SU'
        for ltr(XO,printlist) if (strc(XO.name,CTYP.o(pr).s)) {x=i1 break} 
        for ixt(pr,col) v2.append(ixi) // get the values for this col
        q.resize("time",p.o(x).tvec,"ind",p.o(x).vec)
        u=q.select("time","[]",min,max,"ind","[]",v2.min,v2.max) // u=number of spikes in period
        min=q.applf(".min","time") max=q.applf(".max","time") 
        q.out.v.sort()  y=q.out.v.uniq() // y= uniq spikers
        if (max-min<10) diff=10 else diff=max-min
        // prspks = y/diff/numc[pr]*10 // number of spikes in 1 cell spike per 10ms
        prspks = y/diff/numc[pr]*ncols*10 // normalize by no. of cols
        x=prspks*(conv=cp.fetch("PRID",pr,"POID",po,"CONV")) // incoming spks over 10ms
      }
    sp.verbose=0  vr=sysel(pr,po,sy,co) sp.verbose=1
    if (vr.size==0) {dealloc(a) return -1}
    vrsz(ce,v1,"O")
    for ixt(po) v1.append(XO.VTH-XO.RMP)
    stat(v1,v2) th=v2.x[3] // threhold stats
    wd=ncq.ay(pr,po,sy,co).x // current scaling factor
    we=4 // 4 cells must fire at about same time to get thresh-level drive
    if (f1) {
        printf("%s:%d,%d spks/%.2fms ~ %.2f spks/10ms (%d/%d)\n",\
               CTYP.o(pr).s,u,y,max-min,prspks,x,conv)
        printf("Thresh: %.2f+/-%.2f PSP: %.2f+/-%.2f\n",th,v2.x[4],vr.mean,vr.stdev)
        printf("\tFor 1/%d continuous activation: ",we)
        // wd *= threshold/spks_in/<PSP>/weighting // wd is scaling_factor
        printf("\nwmul(%s,%s,%s,%s,%g)\n",\
               CTYP.o(pr).t,CTYP.o(po).t,STYP.o(sy).t,INCOL.o(co).t,\
               th/x/vr.mean/we*wd)
        ret=th/x/vr.mean/we*wd
      } else {
        printf("%s->%s %s,%s: %g\n",\
               CTYP.o(pr).s,CTYP.o(po).s,STYP.o(sy).s,INCOL.o(co).s,\
               vr.mean*wd/th*100) // percent of threshold
        ret=vr.mean*wd/th*100
      }
    dealloc(a)
    return ret
  }

//** avwt() goes through ncl list to sum weights
proc avwt () {  local pr,po,sy,co localobj nc,o
    pr=$1 po=$2 sy=$3 co=$4
    o=ncq.ay(pr,po,sy,co)
    vrsz(o.o.count,ind,"O")
    for ltr(nc,o.o) ind.append(nc.weight[sy])
    ind.mul(o.x) // mutiply by scale factor
    if (ind.mean!=0) {
        printf("%s%s %s: ",CTYP.o(pr).s,CTYP.o(po).s,STYP.o(sy).s) 
        stat(ind)
      }
  }

//* 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,ox,cvn
    ox=$o1 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,100))
            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",100))
      } else { 
        yo=printlist.object(printlist.count-1) // continue with the last one
      }
    if (isobj(ox,"NetCon")) {  xo=ox // use this NetCon
      } else {
        cvn=cvode.netconlist(ox, "", "")
        if (cvn.count==0) { // no netcons available
            if (! warn_flag) printf(".") else { 
                warn_flag=0 // only warn first time
                printf("WARNING (new_printlist_nc) creating NetCon for %s ",ox) }
              if (ox.fflag) {  xo=new NetCon(ox, nil)
                } else { ox.soma xo=new NetCon(&v(x), nil) }
              xo.threshold=thresh
              ncl.append(xo)
          } else {
            xo=cvn.object(0) // the first of the postsyn netcons
            if (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
obfunc new_printlist_nc2 () { local id,thresh,yoset localobj xo,ox
    ox=$o2 id=$3 thresh=-20 yoset=0
    if (isobj(ox,"NetCon")) {  xo=ox // use this NetCon
      } else {
        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(ox.tvec,ox.vec,id)
    return xo
  }

//** 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
obfunc new_printlist_ac () { local i,max,num,svloc,sz,tsz localobj lo,st
    npacsz=1.2 st=new String()
    if(name_declared("vdt_INTF")==5) {
        vdt = vdt_INTF
        st.s="INTF"
      } else if(name_declared("vdt_INTF6")==5) {
        vdt = vdt_INTF6
        st.s="INTF6"
      } else print "new_printlist_ac warning: no INTF/INTF6 found!"
    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)  }
    if (tstop<=1e4) tsz=tstop else tsz=1e4
    sz=npacsz*tsz/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 %s %s not found in printlist\n",st.s,$o1)
      }
    vite.tvflag=1
    $o1.initrec($s2,vite.vec)
    printlist.append(vite)
    return 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(),...
obfunc 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)
    return 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("","","") 
  }

//* mkncq() -- this may not be useful since will slow down smap() still more
proc smap () { } // stub
proc mkncq () { local pr,po,sy,co localobj o
    if (!isassigned(ncq)) {
        ncq=new NQS("PRID","POID","SYN","INCOL","SCALE","NCL")
        ncq.odec("NCL")
        ncq.useslist("PRID",CTYP) ncq.useslist("POID",CTYP) 
        ncq.useslist("SYN",STYP)  ncq.useslist("INCOL",INCOL) 
      }
    ncq.clear()
    sp.out.mo(1) // for smap
    // no syn specificity for ARTCELLs -- assume no NM w/out AM, no GB w/out GA
    for case(&pr,DP,SU,IN) for case(&po,DP,SU,IN) for case(&co,INC,RIT,LFT) {
        if (sp.select("CODE",EQU1,pr,"CODE",EQU2,po,"CODE",EQU3,co) == 0) {
            // printf("%s->%s (%s) EMPTY\n",CTYP.o(pr).s,CTYP.o(po).s,INCOL.o(co).s)
          } else {
            if (pr==IN) sy=GA else sy=AM
            o=ncl[pr][po][co]
            ncq.append(pr,po,sy  ,co,1,o) // AM,GA
            ncq.append(pr,po,sy+1,co,1,o) // NM,GB
            smap(pr,po,sy,co,o)
          }
      }
  }

proc smap () { local prdx,w0x,w1x,pr,po,sy,co localobj o
    pr=$1 po=$2 sy=$3 co=$4 o=$o5
    for ii=0,PRv.size-1 { // need prior sp.out.mo(1)
        w0x=WT0v.x[ii] w1x=WT1v.x[ii] 
        nc=new NetCon(ce.o(PRv.x[ii]),ce.o(POv.x[ii]),-10,DELv.x[ii],0)
        o.append(nc)
        for kk=0,nc.wcnt-1 nc.weight[kk]=0
        if (pr==IN) { 
            nc.weight[GA]=w0x
            if (w1x>0) nc.weight[GB]=w1x
          } else {
            nc.weight[AM]=w0x
            if (w1x>0) nc.weight[NM]=w1x
          }
      }
  }

proc smap () { printf("NOW using dedicated smap() routines in network.hoc") }

//* nrstim - stim cells with noise/random input
// nrstim(celltype,[,maxt,clear,seed,nqs])
// maxt specifies time after which input turned off
// clear specifies whether to clear nqs passed in (or vq if declared)
// global params are pvar,pwght,prate,ppos described below
declare("pvar",2)     //variance of noise input
declare("pwght",0)    //mean value of noise input
declare("prate",1000) //sampling rate for random input
declare("ppos",1)     //use abs value only -- should be 1 otherwise intf cant handle it!!!
func nrstim () { local a,tt,i,j,ti,maxt,ct localobj rdp,vr,vt,vi,nq
    rdp=new Random() nq=nil
    a=allocvecs(vr,vt,vi)
    if(numarg()>1) maxt=$2 else maxt=tstop
    if(numarg()>4) nq=$o5 else if(name_declared("vq")) nq=vq
    if(nq==nil) {
        printf("nrstim ERRA: input nq==nil!\n") dealloc(a) return 0
      }
    if(numarg()>2) {
        if($3) nq.clear() 
      } else nq.clear()  
    if(numarg()>3) rdp.ACG($4) else rdp.ACG(1234)
    rdp.normal(pwght,pvar)
    vt.indgen(0,maxt,1000/prate) vi.resize(vt.size) vr.resize(vt.size)
    for i=ix[$1],ixe[$1] {
        vr.setrand(rdp) if(ppos) vr.abs()
        vi.fill(i)   nq.v[0].append(vi)    nq.v[1].append(vt)    nq.v[2].append(vr)
      }
    nq.sort("time") nq.sort("ind")
    intf.initvspks(nq.v,nq.v[1],nq.v[2])
    dealloc(a)
    return 1
  }

//* subthstim(celltype,% of type,start,end,multiplier,bias,[nqs -- default is vq]) 
//this function takes the stim nqs , selects random % of cells (0-100), and between
//start and end times multiplies the stim values by multiplier and adds bias
//if the 7th argument is absent, the vq NQS should be declared, non-nil
//& should have been initialized with nrstim or setnrstim
func subthstim () { local startt,endt,fctr,ct,prc,bias,idx,a localobj vid,nq
    ct=$1 prc=$2 startt=$3 endt=$4 fctr=$5 bias=$6 a=allocvecs(vid) nq=nil
    if(numarg()>6) nq=$o7 else if(name_declared("vq")) nq=vq
    if(nq==nil) {
        printf("subthstim ERRA: input nq is nil!!\n")    dealloc(a)
        return 0
      }
    vid.resize(numc[ct]) vid.fill(0)
    vid.fill(1,0,int(numc[ct]*prc/100)) vid.shuffle()
    idx=nq.select(-1,"ind","[]",ix[ct],ixe[ct],"time","[]",startt,endt) printf("ni=%d\n",idx)
    for vtr(&idx,nq.ind) if(nq.v[2].x(idx)>0 && vid.x(nq.v[0].x(idx)-ix[ct])>0) {
        nq.v[2].x(idx) = nq.v[2].x(idx)*fctr+bias
      }
    dealloc(a)
    return 1
  }

// END /usr/site/nrniv/local/hoc/syncode.hoc
//================================================================

//================================================================
// INSERTED /usr/site/nrniv/local/hoc/decnqs.hoc
// =Id=  decnqs.hoc,v 1.31 2010/07/21 15:38:37 billl Exp 

objref nq[10],pq[10]

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

//** pvp2nqs(NQS) -- transfer grvec data file to NQS
obfunc pvp2nqs () { local tstep,tv1,v1 localobj oq,po
    if (argtype(1)==2) po=gvnew($s1)
    if (argtype(1)==0) po=panobjl.o($1)
    if (numarg()>=2) min=$2 else min=0
    if (numarg()>=3) max=$3 else max=po.llist.count-1
    if (numarg()>=4) interp=$4 // no interp when looking at spk times
    oq=new NQS()
    if (interp) oq.resize(max-min+2) else oq.resize(2*(max-min+1))
    if (interp) { // note DEBUGGED 10jul21
        tv1=v1=allocvecs(2)  v1+=1
        tstep=0.1 // 0.1 ms step size for interpolation
        oq.s[0].s="time"
        for ii=min,max {
            XO=po.llist.object(ii)
            oq.s[ii+1-min].s = XO.name
            rename(oq.s[ii-min+1].s)
            po.tmpfile.seek(XO.loc)
            mso[tv1].vread(po.tmpfile)
            mso[v1].vread(po.tmpfile) // or use rv_readvec
            if (ii-min==0) oq.v[0].indgen(0,mso[tv1].max,tstep)
            oq.v[ii+1-min].resize(oq.v.size)
            oq.v[ii+1-min].interpolate(oq.v[0],mso[tv1],mso[v1])
          }
        dealloc(tv1)
      } else for ii=min,max {
        XO=po.llist.object(ii)
        oq.s[2*(ii-min)].s = XO.name
        rename(oq.s[2*(ii-min)].s)
        sprint(oq.s[2*(ii-min)].s,"%s-time",oq.s[2*(ii-min)].s)
        oq.s[2*(ii-min)+1].s = XO.name
        rename(oq.s[2*(ii-min)+1].s)
        po.tmpfile.seek(XO.loc)
        oq.v[2*(ii-min)].vread(po.tmpfile)
        oq.v[2*(ii-min)+1].vread(po.tmpfile)
      }
    return oq
  }

//** 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) NESTED(10)
// 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,i,ii,npts,logflag,min,x,sz localobj bq,cq,v1,v2,v3,bb,tl,v5,eq
    if (verbose_fudup) printf("MAXTIME appears to be %g (dt=%g)\n",$o1.size*dt,dt)
    logflag=0  npts=10 // n sample locations by default
    bq=new NQS("LOC","PEAK","WIDTH","BASE","HEIGHT","START","SLICES","SHARP","INDEX","FILE","NESTED") 
    i=2
    if (argtype(i)==1) {i+=1 if ($o2==nil) {cq=new NQS() $o2=cq} else cq=$o2} else cq=new NQS()
    if (cq.m!=11) { cq.resize(0) 
      cq.resize("LOC","PEAK","WIDTH","BASE","HEIGHT","START","SLICES","SHARP","INDEX","FILE","NESTED")}
    if (argtype(i)==0){ npts=$i i+=1
        if (argtype(i)==0){ logflag=$i i+=1
            if (argtype(i)==1) { v5=$oi i+=1
                if (npts!=v5.size) printf("Correcting npts from %d to %d\n",npts,npts=v5.size)
                if (v5.ismono(1)) v5.reverse
                if (! v5.ismono(-1)) {printf("fudup: final arg (%s) must be monotonic\n",v5) return}
              }
          }
      }
    bq.listvecs(bb)
    bq.pad(5000)
    eq=new NQS(-2,npts) a=allocvecs(v1,v2,v3)
    tl=eq.vl
    eq.clear(2e4) vrsz(2e4,v1,v2,v3)
    v1.copy($o1)
    if (pos_fudup) {
        min=v1.min
        v1.sub(min) // make it uniformly positive
      } else min=0
    if (numarg()>4) v2.copy(v5) 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,eq)
    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)
  }

//* Sam's additions -- moved from nqs_utils.hoc
//get row of Vectors
//$o1 = nqs
//$2 = row number
//$s3 - $snumarg() - name of cols to get values for
//returns list with associated Vectors
obfunc getobjrow(){ local i,rowid localobj nq,vt,ls
    nq=$o1 rowid=$2
    ls=new List()
    vt=new Vector()
    for(i=3;i<=numarg();i+=1){
        nq.get($si,rowid,vt)
        ls.append(vt)
      }
    return ls
  }

//get column of objects as Vector using oform
//$o1 = nqs
//$s2 = col name
//$3=iff==1 return list of Vectors in column, else return vector of oform of each row in column
obfunc getobjcol(){ local idx,getl localobj nq,vt,vt2,ls
    nq=$o1
    if(numarg()>2) getl=$3 else getl=0
    if(getl){
        ls=new List()
        vt=new Vector()
        for idx=0,nq.size-1{
            nq.get($s2,idx,vt)
            ls.append(vt)
          }
        return ls
      } else {
        vt=new Vector(nq.size)
        vt.resize(0)
        vt2=new Vector()
        for idx=0,nq.size-1{
            nq.get($s2,idx,vt2)
            vt.append(oform(vt2))
          }
        return vt
      }
  }

//get correlation between 2 columns of an NQS
//$o1=nqs
//$s2=column name
//$s3=column name
//$4=pearson correlation iff == 1 (default), otherwise spearman
func nqcor(){ local pc localobj nq1,v1,v2
    if(numarg()>3) pc=$4 else pc=1
    nq1=$o1
    v1=nq1.getcol($s2)  v2=nq1.getcol($s3)
    if (pc) return v1.pcorrel(v2) else return v1.scorrel(v2)
  }

//func nqgrslice(){ local startidx,endidx localobj nq,vtmp
  //  nq=$o1 startidx=$2 endidx=$3
  //  vtmp=new Vector($3-$2+1)
  //  gg(
  //}

func MIN(){ if($1<$2)return $1 else return $2 }

//get correlation matrix/nqs of all columns to all columns
//$o1 = NQS
//$2 = num columns 0 - NQS.m
//$3 = start row/index
//$4 = end row/index
//$5 = index increment
//$6 = window size , iff <= 0, do full columns against each other
obfunc nqcolcor(){ local startidx,endidx,inct,wint,c1,c2,ncol localobj vhr,vhl,nqc,nqf
   if(numarg()<1){
       printf("nqcolcor usage: \n\t$o1 = NQS\
                               \n\t$2 = num columns 0 - NQS.m\
                               \n\t$3 = start row/index\
                               \n\t$4 = end row/index\
                               \n\t$5 = index increment\
                               \n\t$6 = window size , iff <= 0, do full columns against each other\n")
       return nil
     }
   nqf=$o1
   if(numarg()>1) ncol=$2 else ncol=nqf.m
   if(numarg()>2) startidx=$3 else startidx=0
   if(numarg()>3) endidx=$4 else endidx=nqf.size
   if(numarg()>4) inct=$5 else inct=50*2//50ms
   if(numarg()>5) wint=$6 else wint=100*2//50ms
  
   vhr=new Vector(wint) vhl=new Vector(wint)
  
   if(wint<=0){ //full column cross-correlation
       nqc=new NQS("ID0","ID1","cor") 
       for c1=0,ncol-1{
           for c2=c1+1,ncol-1{
               nqc.append(c1,c2,nqf.v[c1].pcorrel(nqf.v[c2]))
             }
         }
     } else { //cross correlation using slices of column
       nqc=new NQS("ID0","ID1","start","end","cor") 
       for c1=0,ncol-1{
           for c2=c1+1,ncol-1{
               for(startidx=0;startidx<endidx;startidx+=inct){
                   vhl.copy(nqf.v[c1],startidx,MIN(startidx+wint,endidx-1))
                   vhr.copy(nqf.v[c2],startidx,MIN(startidx+wint,endidx-1))
                   nqc.append(c1,c2,startidx,startidx+wint,vhl.pcorrel(vhr))
                 }
             }
         }
     }
  
   return nqc
  }

 
//read wmf ascii file (just skips header and calls rdcol)
//$s1 = wmf file path
//$2 = # of columns
// obfunc rdwmf(){ local idx,jdx,hdrlines localobj nq,myf,myftmp,strf,str,strtmp,lcols
  // myf=new File() myftmp=new File() strf=new StringFunctions() str=new String() lcols=new List()
  // strtmp=new String() hdrlines=6
  // myf.ropen($s1)
  // if(!myf.is_open()){
    //  printf("rdwmf ERRA: couldn't open wmf file %s for read\n",$s1)
    //  return nil
    // }
  // for idx=0,hdrlines-1{
    //  if(myf.gets(str.s)==-1){
      //    printf("rdwmf ERRB: corrupt header\n")
      //    return nil
      //  } else if(idx==2){
      //    jdx=strf.tail(str.s,"",strtmp.s)            
      //  }
    // }
  // myf.close()
  // return nq
  // }

//draw regression line
//$o1 = nqs, $s2 = column 1, $s3 = column 2
// or
//$o1 = Vector 1 , $o2 = Vector 2
//returns vo
obfunc drawregline(){ local x0,y0,x1,y1,gvtmp,r localobj vo,nq,v1,v2,vx,vy,str
    vo=new Vector(5)
    if(numarg()==3){
        nq = $o1
        v1=new Vector()  v2=new Vector()
        nq.getcol($s2,v1)
        nq.getcol($s3,v2)
      } else {
        v1=$o1 v2=$o2
      }
    v1.vstats(v2,vo)
    x0 = v2.min
    y0 = x0*vo.x(0)+vo.x(1)
    x1 = v2.max
    y1 = x1*vo.x(0)+vo.x(1)
    vx=new Vector(2)
    vx.x(0)=x0
    vx.x(1)=x1
    vy=new Vector(2)
    vy.x(0)=y0
    vy.x(1)=y1
    gvtmp=gvmarkflag
    gvmarkflag=0
    gg(vy,vx)
    gvmarkflag=gvtmp
    str=new String()
    r=v1.pcorrel(v2)
    if(name_declared("rpval_stats")){
        sprint(str.s,"r = %.2f, p = %g, N = %d",r,rpval_stats(v1.size,r),v1.size)
        g.label(0,0,str.s)
      }
    return vo
  }

// select from a vector handled as a matrix -- see matrix.mod
halfmat=0
obfunc mindsel () { local a,x,r,c localobj vm,vi,oq
    vm=$o1 
    a=allocvecs(vi)
    if (numarg()==4) vi.indvwhere(vm,$s2,$3,$4) else vi.indvwhere(vm,$s2,$3)
    oq=new NQS("row","col","val") 
    oq.clear(vi.size)
    for vtr(&x,vi) {
        r=int(x/COLS) c=x-r*COLS
        if (!halfmat || c>r) oq.append(r,c,vm.x[x])
      }
    dealloc(a)
    print oq.size(1)
    return oq
  }

//* return row $2 of nqs $o1 
obfunc nqrow () { local row,col localobj vout,nq
    nq=$o1
    row=$2
    vout=new Vector(nq.m)
    for col=0,nq.m-1 vout.x(col)=nq.v[col].x(row)
    return vout
  }

//* find row $o2 (vector) in $o1 (nqs) and return index
//  if not there return -1
func nqfindrow () { local idx,jdx,sz localobj nq,vf,vrow
    nq=$o1  vf=$o2
    sz=nq.size(-1)
    for idx=0,sz-1 {
        vrow = nqrow(nq,idx)
        if(vrow.eq(vf)) return idx
      }
    return -1
  }

//* nquniq(NQS) -- return a new NQS with unique rows in $o1
obfunc nquniq () { local sz,idx,outrow,jdx localobj nqin,nqout,vrow
    nqin=$o1
    nqout=new NQS()
    for idx=0,nqin.m-1{
        nqout.resize(nqin.s[idx].s)
        nqout.v[nqout.m-1].resize(nqin.v[idx].size)
      }
    sz=nqin.size(-1)
    jdx=0
    outrow=0
    for idx=0,sz-1{
        vrow=nqrow(nqin,idx)
        if(nqfindrow(nqout,vrow)==-1){
            for jdx=0,nqin.m-1 nqout.v[jdx].x(outrow) = vrow.x(jdx)
            outrow += 1
          }
      }
    for idx=0,nqout.m-1 nqout.v[idx].resize(outrow)
    return nqout
  }
// END /usr/site/nrniv/local/hoc/decnqs.hoc
//================================================================
if (! VECST_INSTALLED) install_vecst()
if (! INSTALLED_stats) install_stats()

//================================================================
// INSERTED /usr/site/nrniv/local/hoc/intfsw.hoc
// =Id=  intfsw.hoc,v 1.75 2010/09/12 02:02:50 samn Exp  
// load_file("intfsw.hoc")
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/drline.hoc
// =Id=  drline.hoc,v 1.36 2010/10/02 21:28:29 samn Exp 

// load_file("drline.hoc")

// click and drag left button to draw lines on top of a figure interactively
// select graph to draw on with setdrl(Graph[])
// set color with clr, line width with lne
// select 'Draw curve' for continuous drawing
// select 'Arrow' to place an arrow pointing according to direction of drag

drlflush=1 //whether to flush line drawings each drline call

//* drline(x0,y0,x1,y1,OPT graph or color) 
proc drline () { local color,line
    if (numarg()==0) { print "drline(x0,y0,x1,y1[,g,col,line])"
        return }
    if (numarg()>4) { 
        if (argtype(5)==0) { color=$5 
                               if (numarg()>5) line=$6
          } else {             graphItem = $o5 
                               if (numarg()>5) color=$6
                               if (numarg()>6) line=$7      }}
    graphItem.beginline(color,line)
    graphItem.line($1,$2)
    graphItem.line($3,$4)
    if(drlflush) graphItem.flush()
  }

//* set to drawlines on top of fig
proc setdrl () {
    g=$o1 // select this graph for further drawing
    xpanel("")
    $o1.menu_tool("Draw line","drl")
    $o1.menu_tool("Draw curve","drc")
    $o1.menu_tool("Label","drw")
    $o1.menu_tool("Arrow","dra")
    $o1.menu_tool("Circle","drci")
    $o1.menu_tool("Rectangle","drr")
    xvalue("Color","clr",1,"",1)
    xvalue("Line","lne",1,"",1)
    xbutton("Erase","g.erase_all()")
    xpanel()
    $o1.exec_menu("Draw line")
  }

//* draw line interactively on top of fig
// interesting that this should work at all since x0,y0 local but still preserving their
// values across multiple calls
proc drl ()  { local x0,y0,type,x,y,keystate
    type=$1 x=$2 y=$3 keystate=$4
    if (type==2) {x0=x y0=y}
    if (type==3) drline(x0,y0,x,y,clr,lne)
  }

//* draw circle interactively on top of fig
// drci(2,0,0,0) drci(3,1,0,0)
proc drci ()  { local a,x0,y0,type,x,y,keystate,ii,rad localobj xv,yv
    type=$1 x=$2 y=$3 keystate=$4
    if (type==2) {x0=x y0=y}
    if (type==3) { rad=sqrt((x-x0)^2+(y-y0)^2) 
        a=allocvecs(xv,yv) vrsz(360,xv,yv)
        print "Circle: ",x0,y0,rad
        yv.circ(xv,x0,y0,rad)
        yv.line(g,xv,clr,lne)
        dealloc(a)
      }
  }

//* draw retangle interactively on top of fig
proc drr ()  { local x0,y0,type,x,y,keystate
    type=$1 x=$2 y=$3 keystate=$4
    if (type==2) {x0=x y0=y}
    if (type==3) { drline(x0,y0,x0,y,clr,lne)
        drline(x,y0,x,y,clr,lne) drline(x,y,x0,y,clr,lne) drline(x,y0,x0,y0,clr,lne) }
  }

//* draw arrow interactively on top of fig
proc dra ()  { local x0,y0,xsz,ysz,type,x,y,keystate,rot
    type=$1 x=$2 y=$3 keystate=$4
    xsz=0.1*(g.size(2)-g.size(1)) // 10% of size
    ysz=0.1*(g.size(4)-g.size(3))
    if (type==2) {x0=x y0=y}
    if (type==3) {
        if (y==y0) {
            if (x>x0) rot=-90 else rot=90
          } else {
            rot=-atan((x-x0)/(y-y0))/2/PI*360
            if ((y-y0)<=0) rot+=180
          }
        g.glyph(arrow(),x,y,xsz,ysz,rot)
      }
  }

//* draw curve interactively on top of fig
proc drc ()  { local x0,y0,type,x,y,keystate
    type=$1 x=$2 y=$3 keystate=$4
    if (type==2) { x0=x y0=y
      } else if (type==1) {
        drline(x0,y0,x,y,clr,lne)
        x0=x y0=y
      } else if (type==3) drline(x0,y0,x,y,clr,lne)
  }

//* write label
proc drw ()  { local x0,y0,type,x,y,keystate
    type=$1 x=$2 y=$3 keystate=$4
    if (type==2) { 
       string_dialog("Label: ",tstr) 
       g.label(x,y,tstr,1,1,0.5,0.5,clr)
      }
  }

obfunc arrow () { localobj o
    o=new Glyph()
    o.m(0,0)  o.l(0,1) o.s(1,4) // draw vertical line
    o.m(-0.1,0.3) o.l(0,1) o.s(1,4)
    o.l(0.1,0.3) o.s(1,4)
    return o
  }

//* hist(g,vec,min,max,bins)
{clr=1 hflg=1 ers=1 sym=1 pflg=0 lin=4} 
declared("hfunc")
// clr:color, hflg=1 draw lines; 2 draw boxes; 3 fill in; ers=erase; 
// pflg=1 normalize hist by size of $o2, so will be probability instead of count
// pflg=2 turn hist upside down
// pflg=3 operate on values with hfunc()
// style determined by hflg
// hflg==0 lines with dots
// hflg==0.x offset lines with dots
// hflg==1 outlines but not down to zero
// hflg==2 outlines with lines down to zero
// hflg==3 just dots
// hflg==3.x lines between dots
func hist () { local a,b,c,min,max,wid,bins,ii,jj,offset,x,y
    if (numarg()==0) { printf("hist(g,vec,min,max,bins)\n") return 0}
    if ($o2.size<2)  { printf("hist: $o2 too small\n",$o2) return -1}
    if ($o2.min==$o2.max)  { printf("hist: %s all one value: %g\n",$o2,$o2.min) return -1}
    if (numarg()==5) {min=$3 max=$4 bins=$5 
      } else if (numarg()==4) { min=0 max=$3 bins=$4 
      } else if (numarg()<=3) { 
        if ((min=0.95*$o2.min)<0) min=1.05*$o2.min
        if ((max=1.05*$o2.max)<0) max=0.95*$o2.max
        bins=100
        if (min>0) min*=0.9 else min*=1.1
        if (max>0) max*=1.1 else max*=0.9
        if (numarg()==3) bins=$3
      }
    wid=(max-min)/bins
    // print min,max,max-wid,wid
    a=b=c=allocvecs(3) b+=1 c+=2
    offset=0 x=-1
    if (ers) $o1.erase_all()
    mso[c].hist($o2,min,bins,wid) // c has values
    if(pflg==1) mso[c].div(mso[c].sum) // normalize to sum to 1
    if(pflg==2) mso[c].mul(-1)
    if(pflg==3) hfunc(mso[c])
    mso[a].resize(2*mso[c].size())
    mso[a].indgen(0.5) 
    mso[a].apply("int") 
    mso[b].index(mso[c], mso[a]) 
    mso[a].mul(wid) mso[a].add(min)
    mso[b].rotate(1)
    mso[b].x[0] = 0 
    mso[b].append(mso[b].x[mso[b].size-1],0)
    mso[a].append(max,max)
    if (hflg==1 || hflg==2) { 
        mso[b].line($o1, mso[a],clr,lin)
        if (hflg==2) for vtr(&x,mso[a]) drline(x,0,x,mso[b].x[i1],$o1,clr,lin)
      } else if (int(hflg)==0 || hflg>=3) { 
        if (hflg%1!=0) offset=hflg*wid // use eg -0.5+ii/8 to move back to integer
        mso[a].indgen(min,max-wid,wid)
        mso[a].add(wid/2+offset)
        // print mso[a].min,mso[a].max
        // mso[c].mark($o1,mso[a],"O",6,clr,2) // this will place points where 0 count
        for jj=0,mso[a].size-1 if (mso[c].x[jj]!=0) {
            if (hflg!=3 && hflg%1!=0) drline(mso[a].x[jj],0,mso[a].x[jj],mso[c].x[jj],$o1,clr,lin)
            if (hflg==4) {
                if (x!=-1) drline(x,y,mso[a].x[jj],mso[c].x[jj],$o1,clr,lin)
                x=mso[a].x[jj] y=mso[c].x[jj]
              }
            $o1.mark(mso[a].x[jj],mso[c].x[jj],sg(sym).t,10,clr,2) // don't place points with 0 count
          }
      }
    $o1.flush()
    $o1.size(min,max,0,mso[b].max)
    dealloc(a)
    return 1
  }

// barplot(g,yvec,xvec[,bar_width]) 
// barplot(g,yvec,xvec[,bar_width,color_vec]) -- for multicolored bars -- each point has a color
// barplot(g,yvec,xvec[,bar_width,color_vec,error_vec]) -- error_vec plots the error
scribble=0
func barplot () { local a,sz,wid,ii,jj,x,y,mulcol localobj go,vx,vy,v1,vcol
    if (numarg()==0) {
        printf("barplot(g,yvec,xvec[,bar_width]), scribble=1 to 'fill in'\n") 
        printf("set scribble=1 to fill in with single color (based on clr)\n")
        printf("barplot(g,yvec,xvec[,bar_width,color_vec]):multicolored bars-each point has a color\n")
        printf("barplot(g,yvec,xvec[,bar_width,color_vec,error_vec]):add +/- error to each bar\n")
        return 0}
    if ((sz=$o2.size)!=$o3.size)  { printf("barplot: x,y vectors differ in size\n") return -1}
    go=$o1 $o3.sort
    if (argtype(4)==0)  wid=$4 else wid=1
    if (argtype(5)==1)  {vcol=$o5 mulcol=-1
        if (sz!=vcol.size) { printf("barplot: color vec wrong size: %d %d\n",sz,vcol.size) return -1}  
      } else if (argtype(5)==0) mulcol=$5 else mulcol=0
    wid/=2
    // print min,max,max-wid,wid
    a=allocvecs(vx,vy,v1)
    if (ers) go.erase_all()
    for vtr2(&x,&y,$o3,$o2,&ii)  { 
        vx.append(x-wid,x-wid,x+wid,x+wid)
        vy.append(0,y,y,0)
      }
    if (mulcol) {
        for vtr2(&x,&y,$o3,$o2,&jj)  { 
            if (mulcol==-1) clr=vcol.x[jj] else clr=mulcol
            vrsz(0,vx,vy)
            vx.append(x-wid,x-wid)
            vy.append(0,y)
            for (ii=0;ii<2*wid;ii+=(wid/100)) { 
                vx.add(wid/100) 
                vy.line(go, vx, clr, 4)
              }
          }
        vy.line(go, vx, clr, 4)
      } else if (scribble) {
        vrsz(0,vx,vy)
        for vtr2(&x,&y,$o3,$o2,&ii)  { 
            vx.append(x-wid,x-wid,x-wid)
            vy.append(0,y,0)
          }
        for (ii=0;ii<2*wid;ii+=(wid/100)) { 
            vx.add(wid/100) 
            vy.line(go, vx, clr, 4)
          }
        vy.line(go, vx, clr, 4)
      } else vy.line(go, vx, clr, lne)
    if(numarg()>5) $o2.ploterr(go, $o3, $o6, 15, 1, 3)
    go.flush()
    go.size(vx.min-wid,vx.max+wid,0,vy.max)
    dealloc(a)
    return 1
  }

proc smgs () { local a,b,c,min,max,wid,bins,ii,jj,offset,x,y localobj v1
    if ($o2.size<2)  { printf("smgs: $o2 too small\n",$o2) return -1}
    if ($o2.min==$o2.max)  { printf("smgs: %s all one value: %g\n",$o2,$o2.min) return -1}
    if (numarg()==5) {min=$3 max=$4 bins=$5 
      } else if (numarg()==4) { min=0 max=$3 bins=$4 
      } else if (numarg()<=3) { 
        if ((min=0.95*$o2.min)<0) min=1.05*$o2.min
        if ((max=1.05*$o2.max)<0) max=0.95*$o2.max
        bins=100
        if (min>0) min*=0.9 else min*=1.1
        if (max>0) min*=1.1 else max*=0.9
        if (numarg()==3) bins=$3
      }
    wid=(max-min)/bins
    // print min,max,max-wid,wid
    a=b=c=allocvecs(3,1e4) b+=1 c+=2
    offset=0 x=-1
    if (ers) $o1.erase_all()
    mso[a].indgen(min,max,wid)
    if (0) {
        mso[c].smgs($o2,min,max,wid,wid*wid/4) // c has values
        mso[c].line($o1, mso[a],clr,4)
      } else {
        v1=$o2.sumgauss(min,max,wid,wid/2) // c has values
        v1.line($o1, mso[a],clr,4)
      }
  }

//* a few drawing utilities from sam (not too spectacular)
 
//** drawhticks(ticksz,minx,maxx,linewidth,$5-$numarg() == y position of horizontal ticks)
// draw horizontal ticks of a view box along left/right of box
proc drawhticks () { local ticksz,minx,maxx,lw,i
    ticksz=$1 minx=$2 maxx=$3 lw=$4
    for i=5,numarg() {
        drline(minx,$i,minx+ticksz,$i,g,1,lw)    drline(maxx,$i,maxx-ticksz,$i,g,1,lw)
      }
  }

//** drawvticks(ticksz,miny,maxy,linewidth,$5-$numarg() == x position of vertical ticks)
// draw vertical ticks of a view box along top/bottom of box
proc drawvticks () { local ticksz,miny,maxy,lw,i
    ticksz=$1 miny=$2 maxy=$3 lw=$4
    for i=5,numarg() {
        drline($i,miny,$i,miny+ticksz,g,1,lw)    drline($i,maxy,$i,maxy-ticksz,g,1,lw)
      }
  }

//** drawbox(minx,maxx,miny,maxy[,line,graph]) - draw box
proc drawbox () { local minx,maxx,miny,maxy,ln localobj myg
    minx=$1 maxx=$2 miny=$3 maxy=$4
    if(numarg()>4)ln=$5 else ln=3
    if(numarg()>5)myg=$o6 else myg=g
    drline(minx,miny,minx,maxy,myg,1,ln) //bottom
    drline(minx,miny,maxx,miny,myg,1,ln) //left
    drline(minx,maxy,maxx,maxy,myg,1,ln) //top
    drline(maxx,miny,maxx,maxy,myg,1,ln) //right
  }
// END /usr/site/nrniv/local/hoc/drline.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/boxes.hoc
// =Id=  boxes.hoc,v 1.58 2010/08/12 14:20:15 billl Exp 

// load_file("boxes.hoc")
proc boxes () {}
objref boxer, boxerl
boxerl = new List()

// 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,size,trnum,gl,stub,label,getg
external factor,boxerl

objref boxes[3], ob, gitem,gl,XO, nil, this
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 size=rows*cols
    if (numarg()==5) {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)
    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)
            if (ob!=nil) ob.glist.append(gitem)
            gi = gi+1
          }
        boxes[2].intercept(0)
        boxes[2].map("")
      }
    boxes[0].intercept(0)
    if (strcmp(name,"")==0 && ob!=nil) 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,ix
    ix=boxerl.index(this)
    for (ii=gl.count-1;ii>=0;ii-=1) {
        XO=gl.object(ii)
        XO.unmap
      }
    if (ob!=nil) ob.glist.remove_all
    gl.remove_all
    boxes[0].unmap
    boxes[0]=nil
    boxes[2]=nil
    boxerl.remove(ix)
  }

obfunc getg () {
    return gl.o($1*cols+$2)
  }

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

obfunc mktray () { local i,na,rows,cols,xsz,ysz 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) { na=numarg()-1 i=numarg() boxer.name=$si 
      } else                    { na=numarg() }
    if (na==2) o=panobj else if (argtype(1)==0) o=GRV[$1] else if (argtype(1)==1) o=$o1
    if (o!=nil) o.super = 1
    if (argtype(1)==2) {
        boxer.name=$s1
        xsz=100 ysz=50
        if (na/2==int(na/2)) {rows=factor($2) cols=$2/rows i=3} else {rows=$2 cols=$3 i=4}
        if (argtype(i)==0) {xsz=$i i+=1 ysz=$i} // size of graphs
        boxer.mktray(nil,rows,cols,xsz,ysz)
      } else 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)
      }
    return boxer
  }

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
//================================================================

//////////////////////////////////////////////////////////////////////////////////////
//                               some usage 
//
//  adj=AdjList() //creates adjacency list used by other functions, it is global obj
//                //that other functions use internally
//
//  this is a variable, users can define their own, but it's not needed for hoc code:
//  subs = 640/numc[SU] //# btwn 0 and 1 specifying % of cells to use in computation
//  of path length and/or clustering coefficient, it can be passed into the functions
//  
//  this type of sequence gets excitatory path length for net:
//  vd=GetNetEXL(-1,subs) // -1 means get full path lengths of ALL distances
//  vd.gzmean // this will give you path length value for net
//
//  this type of sequence gets excitatory cell clustering coefficient for net:
//  vc=GetNetEXCC(ix[DP],ixe[SU],subs) //excitatory (DP,SU) cell clustering coefficient
//  vc.gzmean // this will give you clustering coefficient value for net
//
//
//////////////////////////////////////////////////////////////////////////////////////

declare("adj",nil,"vd",nil,"vc",nil,"allcells",0,"div","d[1][1]")
declare("nxadjg",nil,"vhistg","o[CTYPi+1]","vhistgd","o[CTYPi+1]","intfswb","nil")
declare("divnq",nil,"convnq",nil,"intfswbfl",1,"getactive",1,"loadednetworkx",0)
install_intfsw()

obfunc AdjTab () { local idx,jdx localobj adj,vid
    if (verbose) printf("generating adjacency matrix")
    adj=new List()
    for idx=0,allcells-1 adj.append(new Vector(allcells))
    for idx=0,allcells-1{
        if(verbose && idx%100==0)printf(".")
        vid=GetDiv(idx)
        for jdx=0,vid.size-1 adj.o(idx).x(vid.x(jdx))=1
      }
    if (verbose) printf("\n")
    return adj
  }

//* AdjList - get list of adjacency lists
//[optional] $1 = startid
//[optional] $2 = endid
//[optional] $3 = skip inhib cells from list
//[optional] $o4 = CE list - default uses global ce
obfunc AdjList () { local idx,jdx,startid,endid,ct,dv,skipinhib localobj adj,vid,vtmp,CE
    if (verbose) printf("generating adjacency list")
    if (numarg()>0) startid=$1 else startid=0
    if (numarg()>1) endid=$2 else endid=allcells-1
    if (numarg()>2) skipinhib=$3 else skipinhib=0
    if (numarg()>3) CE=$o4 else CE=ce
    adj=new List()
    for idx=0,CE.count-1 adj.append(new Vector(CE.o(idx).getdvi))
    CE.o(0).adjlist(adj,startid,endid,skipinhib)
    return adj
  }

//** adjstrg() -- get a string representation of adjacency list for use with dot
obfunc adjstrg () { local i,j localobj str,lc
    lc=new List()
    lc.append(new String("blue"))
    lc.append(new String("red"))
    str=new String2()
    str.s="digraph G {"
      for i=0,adj.count-1{ 
          for j=0,adj.o(i).size-1{
              sprint(str.t,"%d -> %d [color=%s];\n",i,adj.o(i).x(j),lc.o(ice(ce.o(i).type)).s)
              strcat(str.s,str.t)
            }
          sprint(str.t,"%d [color=%s];\n",i,lc.o(ice(ce.o(i).type)).s)
          strcat(str.s,str.t)
        }
      strcat(str.s,"}\n")
    return str
  }

//** net2txtf(path) -- save net to text file representation
func net2txtf () { local jdx,idx,syns localobj F,vid
    F = new File()
    F.wopen($s1)
    if(!F.isopen){
        printf("couldn't open for saving\n")
        return 0
      }
    syns = 0
    for idx=0,ce.count-1 syns += ce.o(idx).getdvi
    F.printf("%d\n",ce.count)//# of cells  
    F.printf("%d\n",syns)//# of synapses
    F.printf("%d\n",ecells)
    F.printf("%d\n",icells)
    for idx=0,ce.count-1{
        if(ice(ce.o(idx).type)) F.printf("I ") else F.printf("E ")
        F.printf("%g %g %g\n",ce.o(idx).xloc,ce.o(idx).yloc,ce.o(idx).zloc)
      }
    vid=new Vector(allcells)
    vid.resize(0)
    for idx=0,ce.count-1{
        ce.o(idx).getdvi(vid)
        for jdx=0,vid.size-1{
            if(ice(ce.o(idx).type)) F.printf("I ") else F.printf("E ")
            F.printf("%d %d\n",idx,vid.x(jdx))
          }
      }
    F.close
    return 1
  }

//write net to pajek .net file , can also be used in GUESS graph visualization program
//$s1=output file path, $o2=vector of cell types to add to output file
func writepajek () { local idx,jdx,ty,ndx localobj fp,vid,vdel,lc,vty,nqc
    fp=new File() vid=new Vector(allcells) vdel=new Vector(allcells)
    lc=new List() lc.append(new String("Red")) lc.append(new String("Blue")) vty=$o2
    fp.wopen($s1)
    if(!fp.isopen())return 0
    fp.printf("*Vertices %d\r\n",allcells)
    for idx=0,allcells-1{
        ty=ce.o(idx).type if(!vty.contains(ty))continue
        fp.printf("%d \"%s%d\" ic %s\r\n",idx+1,CTYP.o(ty).s,idx,lc.o(ice(ty)).s)
      }
    fp.printf("*Arcslist\r\n")  
    for idx=0,allcells-1 {
        ce.o(idx).getdvi(vid,vdel) ty=ce.o(idx).type
        if(!vty.contains(ty))continue
    
        fp.printf("%d ",idx+1)
        for ndx=0,vid.size/2 {
            jdx=vid.x(ndx)
            if(!vty.contains(ce.o(jdx).type))continue
            fp.printf("%d ",jdx+1)
          }
        fp.printf("1 c %s",lc.o(ice(ty)).s)
        fp.printf("\r\n")
    
        fp.printf("%d ",idx+1)
        for ndx=1+vid.size/2,vid.size-1 {
            jdx=vid.x(ndx)
            if(!vty.contains(ce.o(jdx).type))continue
            fp.printf("%d ",jdx+1)
          }
    //    for vtr(&jdx,vid) {
      //      if(!vty.contains(ce.o(jdx).type))continue
      //      fp.printf("%d ",jdx+1)
      //      fp.printf("%d %d 1 c %s\r\n",idx+1,jdx+1,lc.o(ice(ty)).s)
      //    }
        fp.printf("1 c %s",lc.o(ice(ty)).s)
        fp.printf("\r\n")
      }
    fp.close()
    return 1
  }



/////////////////////////////////////////////////////////////////////////
//get path existence/distance vector ==
// vector with:
//   d==0==no path between cell $1 and cell index
//               and
//   d>0==a path exists between cell $1 and cell index of distance d
//
// $1 = cell id to start search from
// $2 = minimum id of destination
// $3 = maximum id of destination
// $4 = max distance to search
obfunc GetPathEV () { local idx,myid,idist,startid,endid,maxdist localobj vd,vcheck,vtmp
    if(adj==nil)adj=AdjList()  
    myid=$1  
    if(numarg()>1)startid=$2 else startid=0
    if(numarg()>2)endid=$3 else endid=allcells-1
    if(numarg()>3)maxdist=$4 else maxdist=-1
    vd=new Vector(allcells)
    GetPathEV_intfsw(adj,vd,myid,startid,endid,maxdist)
    return vd
  }

//check if network is fully connected == any cell has a path
//to any other cell
//can use speedup/efficiency improvements
func FullyConnected () { local idx localobj vd
    for idx=0,allcells-1{
        if(idx%100==0)printf("checking path from cell %d to others\n",idx)
        vd=GetPathEV(idx)
        if(vd.count(0)>1){
            printf("cell %d not fully connected to other cells, only has path to %d cells\n",idx,allcells-vd.count(0))
            return 0
          }
      }
    return 1
  }

//approximate path length formula
//N=# of vertices
//$1=# of 1st degree neighbors
//$2=# of 2nd degree neighbors
func ApproxL () { local z1,z2,N
    N=$1  z1=$2 z2=$3
    return log(N/z1)/log(z2/z1)+1
  }

//get approximate path length by first getting # of
//1st & 2nd degree neighbors
func GetApproxL () { local z1,z2,i,subsamp localobj lvnn,vtmp
    if(numarg()>0)subsamp=$1 else subsamp=1
    if(adj==nil) if(numc[DP]) adj=AdjList(ix[DP],ixe[SU]) else adj=AdjList()
    lvnn=new List()
    for i=0,1{
        vtmp=GetNumNeighbors(i+1,ix[DP],ixe[SU],1,adj,subsamp)
        lvnn.append(vtmp)
      }
    {z1=lvnn.o(0).gzmean(ix[DP],ixe[SU]) printf("z1=%g\n",z1)}
    {z2=lvnn.o(1).gzmean(ix[DP],ixe[SU]) printf("z2=%g\n",z2)}
    return ApproxL((1-killDP)*numc[DP]+(1-killSU)*numc[SU],z1,z2)
  }

//returns vector of size allcells containing avg dist from that cell
//to all other cells it is connected to
obfunc GetNetL () { local from,gzm,sid,eid localobj vdist,vtmp
    if(numarg()>0)sid=$1 else sid=0
    if(numarg()>1)eid=$2 else eid=allcells-1
    vdist=new Vector(allcells) vtmp=new Vector(allcells)
    adj=AdjList(sid,eid) //make sure initialized properly in face of prup,killp,etc.
    printf("searching from id: ")
    for from=sid,eid{
        if(verbose && from%100==0)printf("%d...",from)
        if(ce.o(from).flag("dead"))continue
        vtmp=GetPathEV(from,sid,eid)
        if((gzm=vtmp.gzmean)>0){
            vdist.x(from)=gzm
          }
      }
    printf("\n")
    return vdist
  }

// ** GetNetEXLSubPops -- get path length between excitatory subpopulations
// returns Vector of size allcells, to see path length do Vector.gzmean
// $1 == from population
// $2 == to population
// $3 == subsamp [default == 1, optional]
// $4 == take into account self-loop-length [default == 0, optional]
obfunc GetNetEXLSubPops () { local subsampi,from,selfl localobj vd,vstart,vend
    from=$1 to=$2
    if(numarg()>2) subsamp=$3 else subsamp=1
    if(numarg()>3) selfl=$4 else selfl=0
    if(adj==nil) adj=AdjList(0,allcells-1,1)//get adjacency list
    {vstart=new Vector(allcells) vend=new Vector(allcells) vd=new Vector(allcells)}
    for i=ix[from],ixe[from] vstart.x(i)=1
    for i=ix[to],ixe[to] vend.x(i)=1
    GetPathSubPop_intfsw(adj,vd,vstart,vend,subsamp,selfl)
    printf("exl path from sub pop %s to %s = %g\n",CTYP.o(from).s,CTYP.o(to).s,vd.gzmean)
    return vd
  }

//returns vector of size allcells containing avg dist from that cell
//to all other excitatory(E) cells it is connected to
//only travels paths through E cells
//$1 == max dist , default == -1, to search all distances
//$2 == subsamp -- only use subsamp% of cells
//$3 == first turn off sub-pop to sub-pop [optional] default == -1
obfunc GetNetEXL () { local from,gzm,maxdist,subsamp localobj vdist,rdm,vuse
    if(numarg()>0)maxdist=$1 else maxdist=-1
    if(numarg()>1)subsamp=$2 else subsamp=1
    if(adj==nil)adj=AdjList(0,allcells-1,1) //make sure initialized properly in face of prup,killp,etc.
    vdist=new Vector(adj.count)
    GetPathR_intfsw(adj,vdist,0,adj.count-1,-1,subsamp)
    return vdist
  }

//import networkx python library
func initnetworkx () {
    if(loadednetworkx) return 1
    if(!nrnpython("import networkx")) {
        printf("initnetworkx ERRA: couldn't import networkx python library!\n")
        return 0
      }
    loadednetworkx=1
    return 1
  }

//get a PythonObject containing adjacency list adj, with variable name = $s1, $2==skip I cells
obfunc NXAdjG () { local idx,jdx,skipI localobj str,py  
    if(!initnetworkx()) return nil
    str=new String()
    sprint(str.s,"%s=networkx.XDiGraph()",$s1)
    py=new PythonObject()
    if(!nrnpython(str.s)){
        printf("NXAdjG ERRA: Couldn't evaluate %s in python!\n",str.s)
        return nil
      }
    if(numarg()>1)skipI=$2 else skipI=1
    for idx=0,allcells-1 if(!skipI || !ice(ce.o(idx).type)) {
        sprint(str.s,"%s.add_node(%d)",$s1,idx)
        if(!nrnpython(str.s)){
            printf("NXAdjG ERRB: Couldn't add node %d to %s\n",idx,$s1)
            return nil
          }
      }
  //  if(!adj)adj=AdjList(0,allcells-1,skipI)
  //  for idx=0,adj.count-1 for jdx=0,adj.o(idx).count-1 {
    //    sprint(str.s,
    //  }
    return py
  }

func tyfunc () { return ce.o($1).type }

//get between-ness centrality of all E cells, in output NQS
obfunc GetNetECent () { localobj vcent,centnq
    if(adj==nil)adj=AdjList(0,allcells-1,1)
    vcent=new Vector(adj.count) vcent.fill(0)
    GetCentrality_intfsw(adj,vcent)
    centnq=new NQS("id","type","C")
    centnq.v[0].indgen(0,adj.count-1,1)
    centnq.v[1].copy(centnq.v[0])
    centnq.v[1].apply("tyfunc")
    centnq.v[2].copy(vcent)
    return centnq
  }

//gets vector with loop/return path-lengths to each excitatory cell
// out.x(idx)=0 means no such path found to cell idx
obfunc GetNetELoop () { local idx localobj vdist,vloop,vf,vto
    vdist=new Vector(1) vloop=new Vector(allcells) vf=new Vector(1) vto=new Vector(1)
    if(adj==nil)adj=AdjList(0,allcells-1,1)//make sure initialized properly in face of prup,killp,etc.
    for idx=0,allcells-1 {
        if(ice(ce.o(idx).type)) {
            vloop.x(idx)=0
            continue
          }
        vf.x(0)=vto.x(0)=idx
        GetPairDist_intfsw(adj,vdist,vf,vto)
        vloop.x(idx)=vdist.x(0)
      }
    return vloop
  }

// ** wirenq -- get wiring nqs, preid, postid, delay, wt1, wt2
// iff numarg()>0 $1 == only store info on excitatory connections
obfunc wirenq () { local ii,jj,exonly localobj vid,vdel,vprob,vw1,vw2,nq,vpl
    if(numarg()>0) exonly=$1 else exonly=0
    {vid=new Vector() vdel=new Vector() vprob=new Vector() vw1=new Vector() vw2=new Vector()}
    nq=new NQS("preid","poid","del","wt1","wt2")
    if(exonly){
        for ii=0,allcells-1{
           if(ice(ce.o(ii))) continue
           ce.o(ii).getdvi(1,vid,vdel,vprob,vw1,vw2)
           for jj=0,vid.size-1{
               if(ice(ce.o[vid.x(jj)])) continue
               nq.append(ii,vid.x(jj),vdel.x(jj),vw1.x(jj),vw2.x(jj))
             }
          }
      } else {
        for ii=0,allcells-1{
            ce.o(ii).getdvi(1,vid,vdel,vprob,vw1,vw2)
            for jj=0,vid.size-1{
                if(ice(ce.o[vid.x(jj)])){
                    vw1.mul(-1)
                    vw2.mul(-1)
                  } 
                nq.append(ii,vid.x(jj),vdel.x(jj),vw1.x(jj),vw2.x(jj))
              }
          }
      }
    return nq
  }

// ** GetNetWEXL() -- get weighted network excitatory path length
// uses directed weighted graph where distance between nodes is == delay/weight
// done for AMPA,NMDA or BOTH -- $1 == ampa flag, $2 == nmda flag
// $o3 == wirenq , [optional]
// $4 == flip order of preid, poid (convergence instead of divergence lengths) [optional]
obfunc GetNetWEXL () { local ampa,nmda,edgef,flip\
                        localobj vid,vdel,vprob,vw1,vw2,nq,vpl,vs,vpre,vpo
    if(numarg()>0) ampa=$1 else ampa=1
    if(numarg()>1) nmda=$2 else nmda=1
    if(numarg()>2) nq=$o3 else nq = wirenq(1)
    if(numarg()>3) flip=$4 else flip=0
    vpl=new Vector(allcells)
    vdel=new Vector()
    if(flip){ // flip pre and po
        vpre=nq.getcol("poid")
        vpo=nq.getcol("preid")
      } else {
        vpre=nq.getcol("preid")
        vpo=nq.getcol("poid")
      }
    nq.getcol("del",vdel)
    if(ampa && nmda){
        vs=new Vector()
        vs.copy(nq.getcol("wt1"))
        vs.add(nq.getcol("wt2"))
        GetWPath_intfsw(vpre,vpo,vs,vdel,vpl)
      } else if(ampa){
        GetWPath_intfsw(vpre,vpo,nq.getcol("wt1"),vdel,vpl)
      } else if(nmda){
        GetWPath_intfsw(vpre,vpo,nq.getcol("wt2"),vdel,vpl)
      } else { 
        if(numarg()<=2)nqsdel(nq)
        return nil
      }
    if(numarg()<=2)nqsdel(nq)
    return vpl
  }

// ** GetNetWL() -- get weighted network path length, takes inhibitory contributions as
// weight/delay , and excitatory contributions as delay/weight
// only uses AMPA/GABAA or NMDA/GABAB
obfunc GetNetWL () { local ampagabaa localobj vid,vdel,vprob,vw1,vw2,nq,vpl
    if(numarg()>0) ampagabaa=$1 else ampagabaa=1
    nq = wirenq(0)
    vpl=new Vector(nq.size)
    if(ampagabaa){
        GetWPath_intfsw(nq.getcol("preid"),nq.getcol("poid"),nq.getcol("wt1"),nq.getcol("del"),vpl)
      } else {
        GetWPath_intfsw(nq.getcol("preid"),nq.getcol("poid"),nq.getcol("wt2"),nq.getcol("del"),vpl)
      }
    return vpl
  }


// ** GetNetEXCCSubPops -- get clustering coefficient between excitatory subpopulations
// returns Vector of size allcells, to see path length do Vector.gzmean
// $1 == from population
// $2 == to population
// $3 == subsamp [default == 1, optional]
obfunc GetNetEXCCSubPops () { local subsampi,from localobj vd,vstart,vend
    from=$1 to=$2
    if(numarg()>2) subsamp=$3 else subsamp=1
    if(adj==nil) adj=AdjList(0,allcells-1,1)//get adjacency list
    {vstart=new Vector(allcells) vend=new Vector(allcells) vd=new Vector(allcells)}
    for i=ix[from],ixe[from] vstart.x(i)=1
    for i=ix[to],ixe[to] vend.x(i)=1
    GetCCSubPop_intfsw(adj,vd,vstart,vend,subsamp)
    printf("excc from sub pop %s to %s = %g\n",CTYP.o(from).s,CTYP.o(to).s,vd.nnmean)
    return vd
  }

//get clustering coefficient vector for excitatory cells
//usage: vcc = GetNetEXCC()
//vcc.x(i) is clustering coefficient of cell i (must be >= 0.0 && <= 1.0)
//otherwise there was a problem...
//vcc.mean(ix[DP],ixe[SU]) is clustering coefficient of excitatory cells for entire network
obfunc GetNetEXCC () { local idx,sid,eid,subsamp localobj vcc,vuse
    if(adj==nil)adj=AdjList(0,allcells-1,1)
    if(numarg()>0)sid=$1 else sid=0
    if(numarg()>1)eid=$2 else eid=adj.count-1
    if(numarg()>2)subsamp=$3 else subsamp=1
    vcc=new Vector(adj.count)
    GetCCR_intfsw(adj,vcc,sid,eid,subsamp)
    return vcc
  }

//returns vector of size allcells containing num of neighbors <= $1 distance away
//for each cell
obfunc GetNumNeighbors () { local maxdist,startid,endid,exact,subsamp,sead localobj vdist,vtmp,vuse,rdm
    maxdist=$1
    if(numarg()>1)startid=$2 else startid=ix[DP]
    if(numarg()>2)endid=$3 else endid=ixe[SU]
    if(numarg()>3)exact=$4 else exact=0
    if(numarg()>4)adj=$o5 else if(adj==nil) adj=AdjList()//make sure initialized properly in face of prup,killp,etc.
    if(numarg()>5)subsamp=$6 else subsamp=1
    vdist=new Vector(allcells) vtmp=new Vector(allcells)
    printf("searching from id: ")
    CountNeighborsR_intfsw(adj,vdist,startid,endid,maxdist,subsamp)
    return vdist
  }

//returns vector of size allcells containing # of recurrent connections terminating on cell
//i in out.x(i)
//$1 == from type, -1 means from all E cells, -2 means all I cells, as a vec from all types in vec
//$2 == thru type, -1 means thru all E cells, -2 means all I cells, as a vec thru all types in vec
obfunc GetRecurVec () { local from,thru,ct localobj vRC,vfrom,vthru,vtmp
    vRC=new Vector(allcells) vfrom=new Vector(allcells) vthru=new Vector(allcells)
    vRC.fill(0) 
    if(adj==nil)adj=AdjList()
    if(numarg()>0) {
        if(argtype(1)==0) {
            if($1>=0) {
                vfrom.fill(1,ix[$1],ixe[$1]) //from only a specific type
              } else if($1==-1) { // E cells
                for ctt(&ct) if(!ice(ct)) vfrom.fill(1,ix[ct],ixe[ct])
              } else for ctt(&ct) if(ice(ct)) vfrom.fill(1,ix[ct],ixe[ct]) // I cells
          } else {
            for vtr(&from,$o1) vfrom.fill(1,ix[from],ixe[from]) //from a bunch of types
          }
      } else vfrom.fill(1)
    if(numarg()>1) {
        if(argtype(1)==0) {
            if($1>=0) {
                vthru.fill(1,ix[$2],ixe[$2])
              } else if($1==-1) { // E cells
                for ctt(&ct) if(!ice(ct)) vthru.fill(1,ix[ct],ixe[ct])
              } else for ctt(&ct) if(ice(ct)) vthru.fill(1,ix[ct],ixe[ct]) // I cells
          } else {
            for vtr(&thru,$o1) vthru.fill(1,ix[thru],ixe[thru]) //thru a bunch of types
          }
      } else vthru.fill(1)
    GetRecurCount_intfsw(adj,vRC,vfrom,vthru)
    return vRC
  }

//* DivNQS([cell list]) - gets NQS with # of outputs of a given type from each cell
obfunc DivNQS () { local a,idx,x,flag localobj nq,vc,vd,vo,vty,st,CE,vcnt,xo
    if(numarg()>0)CE=$o1 else CE=ce
    st=new String2()
    nq=new NQS("id","type")
    a=allocvecs(vc,vd,vty,vo,vcnt,CTYPi+1)
    vrsz(0,vc,vd,vo,vty) vcnt.resize(CTYPi)
    for ltr(xo,CE) vcnt.x(xo.type)+=1
    for x=0,CTYPi-1 if(vcnt.x(x)) {
        {sprint(st.s,"to%s",CTYP.o(x).s) nq.resize(st.s) vty.append(x)} // vty -- type vec
      }
    nq.clear(CE.count) // make big enough
    flag=getactive+0.2
    for idx=0,CE.count-1 {
        CE.o(idx).getdvi(flag,vc) // picks up for all existing (CTYP) cell types
        vo.index(vc,vty) // only take the ones for the relevant types
        revec(vd,idx,CE.o(idx).type) vd.append(vo) // put in the id and type values for the postcell
        nq.append(vd)
      }
    dealloc(a)
    return nq
  }

//* ConvNQS([cell list]) - gets NQS with # of inputs of a given type onto each cell
obfunc ConvNQS () { local a,idx,x,flag localobj nq,vc,vd,vo,vty,st,CE,vcnt,xo
    if(numarg()>0)CE=$o1 else CE=ce
    st=new String2()
    nq=new NQS("id","type")
    a=allocvecs(vc,vd,vty,vo,vcnt,CTYPi+1)
    vrsz(0,vc,vd,vty) vcnt.resize(CTYPi)
    for ltr(xo,CE) vcnt.x(xo.type)+=1
    for x=0,CTYPi-1 if(vcnt.x(x)) {
        {sprint(st.s,"f%s",CTYP.o(x).s) nq.resize(st.s) vty.append(x)} // vty -- type vec
      }
    nq.clear(CE.count) // make big enough
    flag=getactive+0.2
    for idx=0,CE.count-1 {
        CE.o(idx).getconv(flag,vc) // picks up for all possible cell types
        vo.index(vc,vty) // only take the ones for the relevant types
        revec(vd,idx,CE.o(idx).type) vd.append(vo) // put in the id and type values for the postcell
        nq.append(vd)
      }
    dealloc(a)
    return nq
  }

//display conv hists in graphs
proc ShowConvHists () { local from,to,jj,ii,num localobj vt,vt2,mystr,o,xo,yo
    mystr=new String()       hflg=2      ers=0
    if(numarg()<1 && convnq!=nil)nqsdel(convnq)
    if(convnq==nil) convnq=ConvNQS()
    convnq.verbose=0
    num=0
    for ctt(&to) num+=1 // count the active cells
    if (intfswbfl) {
        for ltr(yo,boxerl) if (strm(yo.name,"CONV")) o=yo
        if (o!=nil) { // reuse this box
            if (o.size!=num) {printf("ERR: wrong # of graphs in tray: %d %d\n",o.size,num) return}
            for ltr(xo,o.gl) xo.erase_all
          } else o=mktray("CONV",num)
        for ctt(&to,&ii) vhistg[to]=o.gl.o(ii)
      } else for ctt(&to) {
        if(vhistg[to]==nil || numarg()<1) vhistg[to]=new Graph() else vhistg[to].erase_all
      }  
    for ctt(&to) {
        sprint(mystr.s,"conv hist onto %s",CTYP.o(to).s)
        vhistg[to].color(to)
        vhistg[to].label(0.35,0.95,mystr.s)
        for ctt(&from,&ii){
            if(!div[from][to]) continue
            clr=from
            if(convnq.select("type",to)){
                sprint(mystr.s,"f%s",CTYP.o(from).s)
                vt=convnq.getcol(mystr.s)
                sprint(mystr.s,"from %s avg=%g",CTYP.o(from).s,vt.mean)
                if (vt.min==vt.max) {
                    vhistg[to].mark(vt.min,0,"S",10,clr,4)
                  } else {
                    hist(vhistg[to],vt)
                  }
                vhistg[to].color(clr)
                vhistg[to].label(0.5,0.88-0.05*ii,mystr.s)
              }
          }
        vhistg[to].exec_menu("View = plot")
      }  
    convnq.verbose=1
  }

//display div hists in graphs -- skips inhibitory cells for now...
proc ShowDivHists () { local from,to,ii,jj,num,rows,cols localobj vt,mystr,o,xo,yo
    mystr=new String()      hflg=2      ers=0
    if(numarg()<1 && divnq!=nil)nqsdel(divnq)
    if(divnq==nil) divnq=DivNQS()
    divnq.verbose=0
    num=0
    for ctt(&from) num+=1 // count the active cells
    if (intfswbfl) {
        for ltr(yo,boxerl) if (strm(yo.name,"DIV")) o=yo
        if (o!=nil) { // reuse this box
            if (o.size!=num) {printf("ERR: wrong # of graphs in tray: %d %d\n",o.size,num) return}
             for ltr(xo,o.gl) xo.erase_all
         } else o=mktray("DIV",num)
        for ctt(&from,&ii) vhistgd[from]=o.gl.o(ii)
      } else for ctt(&from) {
        if(vhistgd[from]==nil || numarg()<1) vhistgd[from]=new Graph() else vhistgd[from].erase_all
      }  
    for ctt(&from,&jj) {
        sprint(mystr.s,"div hist from %s",CTYP.o(from).s)
        vhistgd[from].color(from)
        vhistgd[from].label(0.35,0.95,mystr.s)
        for ctt(&to,&ii){
            if(!div[from][to]) continue
            clr=to
            if(divnq.select("type",from)){
                sprint(mystr.s,"to%s",CTYP.o(to).s)
                vt=divnq.getcol(mystr.s)
                sprint(mystr.s,"to %s avg=%g",CTYP.o(to).s,vt.mean)
                if(vt.min==vt.max){
                    vhistgd[from].mark(vt.min,0,"S",10,clr,4)
                  } else {
                    hist(vhistgd[from],vt)
                  }
                vhistgd[from].color(clr)
                vhistgd[from].label(0.5,0.88-0.05*ii,mystr.s)
              }
          }
        vhistgd[from].exec_menu("View = plot")
      }  
    divnq.verbose=1
  }

//get index of GetCellNQ arg which column is needed, $s1=colname
func getcellnqcolid () { localobj str
    str=new String()
    str.s=$s1
    if(!strcmp($s1,"wexl")){
        return 1
      } else if(!strcmp($s1,"snq")) {
        return 2
      } else if(!strcmp($s1,"fnq")) {
        return 3
      } else if(!strcmp($s1,"C")) {
        return 4
      } else if(!strcmp($s1,"exl")) {
        return 5
      } else if(!strcmp($s1,"excc")) {
        return 6
      } else if(!strcmp($s1,"conv") || strm($s1,"f")) {
        return 7
      } else if(!strcmp($s1,"div") || strm($s1,"to")) {
        return 8
      } else if(!strcmp($s1,"blk")) {
        return 9
      }
    return 0
  }

func ifunc () { return ice(ce.o($1).type) }
//get nqs with cell properties including: centrality, exl, excc, div to all types, conv to all types
//$1=do wexl,$2=do snq,$3=do fnq,$4=do C,$5=do exl,$6=do excc,$7=do convnq,$8=do div,$9=do block
obfunc GetCellNQ () { local i,id,n,doexl,doexcc,doconv,doC,dodiv,doblk\
                       localobj nq,nqt,vv,snq,fnq
    nq=new NQS("id","type") adj=nil
    nq.v[0].indgen(0,allcells-1,1)  nq.v[1].copy(nq.v[0]) nq.v[1].apply("tyfunc")
    if(numarg()>3)doC=$4 else doC=1
    if(numarg()>4)doexl=$5 else doexl=1
    if(numarg()>5)doexcc=$6 else doexcc=1
    if(numarg()>6)doconv=$7 else doconv=1
    if(numarg()>7)dodiv=$8 else dodiv=1
    if(numarg()>8)doblk=$9 else doblk=1
    if(doC){
        if (verbose) printf("getting centrality nq\n") nqt=GetNetECent() 
        nq.resize("C") nq.v[nq.m-1].copy(nqt.v[nqt.m-1]) nqsdel(nqt)
      }
    if(numarg()>0) if($1) {
        {if (verbose) printf("getting wexl\n")
            vv=GetNetWEXL()  nq.resize("wexl") nq.v[nq.m-1].copy(vv)}
      }
    if(doexl){
        {if (verbose) printf("getting exl\n")
            vv=GetNetEXL()  nq.resize("exl") nq.v[nq.m-1].copy(vv)}
      }
    if(doexcc){
        {if (verbose) printf("getting excc\n")
            vv=GetNetEXCC() nq.resize("excc") nq.v[nq.m-1].copy(vv)}
      }
    if(doconv){
        if (verbose) printf("getting convnq\n") nqt=ConvNQS()
        for i=2,nqt.m-1 {
            nq.resize(nqt.s[i].s) nq.v[nq.m-1].copy(nqt.v[i])
          }
        nqsdel(nqt)
      }
    if(dodiv){
        if (verbose) printf("getting divnq\n") nqt=DivNQS()
        for i=2,nqt.m-1 {
            nq.resize(nqt.s[i].s) nq.v[nq.m-1].copy(nqt.v[i])
          }
        nqsdel(nqt)
      }
    {nq.resize("inhib") nq.pad() nq.v[nq.m-1].copy(nq.v[0]) nq.v[nq.m-1].apply("ifunc")}
    if(numarg()>1) if($2) {
        if (verbose) printf("getting spike counts\n")
        vv=printlist.o(0).vec    nq.resize("spikes") nq.pad() nq.v[nq.m-1].fill(0)
        for vtr(&i,vv) nq.v[nq.m-1].x(i)+=1
      }
    if(doblk){
        nq.resize("block") nq.pad() for i=1,allcells-1 nq.v[nq.m-1].x(i)=ce.o(i).spkcnt(i,i,2)
      }
    if(numarg()>2) if($3 && name_declared("FreqNQS")) {
        if (verbose) printf("getting FreqNQS\n")
        snq=SpikeNQS(printlist.o(0))
        fnq=FreqNQS(snq,20,0,0)
        for i=0,allcells-1 if((n=fnq.select("ID",i))) {
            if(n>0){
                nq.v[nq.m-1].x(i)=fnq.getcol("Freq").mean
              } else {
                nq.v[nq.m-1].x(i)=fnq.getcol("Freq").x(0)
              }
          }
      }
    if(snq!=nil)nqsdel(snq)
    if(fnq!=nil)nqsdel(fnq)
    return nq
  }

//get nqs with rand value for each cell, $1==seed
obfunc GetRandCellNQ () { local i localobj nq,rd
    nq=new NQS("id","type","rand")
    rd=new Random()
    rd.ACG($1)
    for i=0,allcells-1 nq.append(i,ce.o(i).type,rd.normal(0,1))
    return nq
  }

// from ShowDivHists()
proc prdiv () { local from,to,jj,ii,num,rows,cols localobj vt,mystr,o,xo,yo
    if (numarg()==1) o=$o1 else o=divnq
    if (o==nil) o=divnq=DivNQS()
    o.verbose=0
    for ctt(&from,&jj) { printf("\ndiv from %s: ",CTYP.o(from).s)
        if (o.select("type",from)) for ctt(&to,&ii) {
            vt=o.getcol(CTYP.o(to).s)
            printf("  to %s avg=%02.3f +- %02.3f",CTYP.o(to).s,vt.mean,vt.stdev) 
        }}
    print ""
    o.verbose=1
  }
proc prconv () { local from,to,jj,ii,num,rows,cols localobj vt,mystr,o,xo,yo
    if (numarg()==1) o=$o1 else o=convnq
    if (o==nil) o=convnq=ConvNQS()
    o.verbose=0
    for ctt(&to,&jj) { printf("\nconv to %s: ",CTYP.o(to).s)
        if (o.select("type",to)) for ctt(&from,&ii) {
            vt=o.getcol(CTYP.o(from).s)
            printf("  from %s avg=%02.3f +- %02.3f",CTYP.o(from).s,vt.mean,vt.stdev) 
        }}
    print ""
    o.verbose=1
  }
// END /usr/site/nrniv/local/hoc/intfsw.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/stats.hoc
// =Id=  stats.hoc,v 1.3 2008/12/22 03:50:27 samn Exp  


//based on code from:
//http://pdos.csail.mit.edu/grid/sim/capacity-ns.tgz/capacity-sim/new-ns/
//hoc template that allows sampling from a pareto power law distribution 
//specified with objref rd
//rd = new rdmpareto($1=avg,$2=shape,[$3=seed])
//then picking values with .pick , or assigning to a vec with assignv(vec)
begintemplate rdmpareto
public avg,shape,rd,seed,pick,repick,paretoc,pareto5,assignv,reset,pareto4,pareto3
double avg[1],shape[1],seed[1]
objref rd
proc init () {
    avg=$1 shape=$2
    if(numarg()>2)seed=$3 else seed=1234
    rd=new Random()
    rd.ACG(seed)
  }
proc reset () {
    rd.ACG(seed)
  }
func paretoc () { local scale,shape,U
    scale=$1 shape=$2 U = rd.uniform(0,1)
    return scale * (1.0/ U^(1/shape) )
  }
func pareto5 () { local avg,shape
    avg=$1 shape=$2
    return paretoc( avg * (shape -1)/shape, shape)
  }
func pareto4 () { local alpha,u
    alpha=$2
    u = 1 - rd.uniform(0,1)
    return $1 + 1 / u^(1/alpha)
  }
func pareto3 () { local x,z,b,a
    b = avg // 1 //min value
    a = shape // 10
    x = rd.uniform(0,1)
    z = x^-1/a
    return 1 + b * z
  }
func pick () {
    return pareto5(avg,shape)
  }
func repick () {
    return pick()
  }
func assignv () { local i localobj vi
    vi=$o1 
    for i=0,vi.size-1 vi.x(i)=pick()
  }
endtemplate rdmpareto

func skew () { local a,ret localobj v1
    a=allocvecs(v1)
    $o1.getcol($s2).moment(v1)
    ret=v1.x[4]
    dealloc(a)
    return ret
  }

func skewv () { localobj v1
    v1=new Vector(5)
    $o1.moment(v1)
    return v1.x(4)
  }


//** test rsampsig
objref vIN0,vIN1,vhsout,myrdm,vrs,VA
R0SZ=30000//size of group 0
R1SZ=30000//size of group 1
RPRC=100 // # of trials (combinations)
RS0M=0 //mean of group 0
RS1M=0 //mean of group 1
RS0SD=1 //sdev of group 0
RS1SD=1 //sdev of group 1
proc rsi () {
    if(myrdm==nil) myrdm=new Random()  
    {myrdm.normal(RS0M,RS0SD) vIN0=new Vector(R0SZ) vIN0.setrand(myrdm)}  
    {myrdm.normal(RS1M,RS1SD) vIN1=new Vector(R1SZ) vIN1.setrand(myrdm)}
    vhsout=new Vector(vIN0.size+vIN1.size)
    if(RPRC>1){
        vrs=new Vector(RPRC)
      } else {
        vrs=new Vector(combs_stats(R0SZ+R1SZ,mmax(R0SZ,R1SZ))*RPRC)
      }
    VA=new Vector()  VA.copy(vIN0) VA.append(vIN1)
  }
func hocmeasure () {
    hretval_stats=vhsout.mean
    return vhsout.mean
  }
func compfunc () {
    if(verbose_stats>1) printf("$1=%g,$2=%g\n",$1,$2)
    hretval_stats=$1-$2
    return hretval_stats
  }
onesided=0
nocmbchk=1
pval=tval=0
func testrs () { local dd localobj str
    if(numarg()>0)dd=$1 else dd=1
    str=new String()
    rsi()
    vhsout.resize(vIN0.size+vIN1.size)
    pval=vrs.rsampsig(vIN0,vIN1,RPRC,"hocmeasure","compfunc",vhsout,onesided,nocmbchk)
    tval=ttest(vIN0,vIN1)
    if(dd){
        sprint(str.s,"p(abs(m0-m1))>%g=%g, t=%g, e=%g",abs(vIN0.mean-vIN1.mean),pval,tval,abs(pval-tval)/tval)
        {ge() ers=0 clr=1 hist(g,VA) clr=2  hist(g,vIN0) clr=3  hist(g,vIN1) g.label(0,0.95,str.s)}
        sprint(str.s,"m0=%g, m1=%g, n0=%g, n1=%g, s0=%g, s1=%g",vIN0.mean,vIN1.mean,vIN0.size,vIN1.size,vIN0.stdev,vIN1.stdev)
        g.label(0.0,0.0,str.s)
        sprint(str.s,"m0-m1=%g",vIN0.mean-vIN1.mean)
        g.label(0,0.9,str.s)
        g.exec_menu("View = plot")
      }
    printf("pval=%g, tval=%g, err=%g\n",pval,tval,abs(pval-tval)/tval)
    return pval
  }
// END /usr/site/nrniv/local/hoc/stats.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/infot.hoc
// =Id=  infot.hoc,v 1.43 2009/12/04 01:25:55 samn Exp  


if(!installed_infot) install_infot()

//* tentropsig(v1,v2,nshuf,nbins,twoway,[xpast,ypast,hval])
//significance test of transfer entropy using shuffling
//returns (te - tes) / sds , where te is transfer entropy, tes is transfer entropy
//of shuffled data, sds is std-dev of transfer entrop of shuffled data
//should only accept as significanat values > 4-6
func tentropsig () { local nshuf,i,xp,yp,hv,nbins,te localobj v1,v2,vo
    v1=new Vector() v2=new Vector() vo=new Vector(1)
    v1.copy($o1) v2.copy($o2) nshuf=$3 nbins=$4
    if(numarg()>4) xp=$5 else xp=1
    if(numarg()>5) yp=$6 else yp=2
    if(numarg()>6) hv=$7 else hv=0
    te=v1.tentrop(v2,nbins,xp,yp,nshuf,vo,hv)
    if(1||verbose_infot>2) printf("te=%g,sig=%g\n",te,vo.x(0))
    return vo.x(0)
  }

//** mutinfbshufv(v1,v2,[nshuf,nbins])
//return vector with mutual information from shuffled v1,v2
//used for significance test , i.e. : ((miorig - mishufmean) / mishufstdev) > 2
obfunc mutinfbshufv () { local nshuf,nbins,i localobj v1,v2,ve
    v1=new Vector() v2=new Vector() ve=new Vector()
    v1.copy($o1) v2.copy($o2)
    if(numarg()>2) nshuf=$3 else nshuf=20
    if(numarg()>3) nbins=$4 else nbins=10
    for i=0,nshuf-1 {
        v1.shuffle() v2.shuffle()
        ve.append(v1.mutinfb(v2,nbins))
      }
    return ve
  }

//** mutinfbsig(v1,v2,[nshuf,nbins])
//get significance of mutual information, should be at least > 2
func mutinfbsig () { local nshuf,nbins,st localobj ve
    if(numarg()>2) nshuf=$3 else nshuf=20
    if(numarg()>3) nbins=$4 else nbins=10
    ve=mutinfbshufv($o1,$o2,nshuf,nbins)
    st=ve.stdev
    if(st<=0) st=1
    return ($o1.mutinfb($o2,nbins) - ve.mean) / st
  }

//** tentropspksig(v1,v2,nshuffles)
//get significance of tentropspks using shuffling
//returns (TE - AvgTEShuffle) / StdDevTEShuffle
func tentropspksig () { local nshuf,i,xp,yp,hv,nbins,te,sd localobj v1,v2,ve
    v1=new Vector() v2=new Vector() ve=new Vector()
    v1.copy($o1) v2.copy($o2) nshuf=$3
    te=$o1.tentropspks($o2)
    for i=0,nshuf-1 {
        v1.shuffle()     ve.append(v1.tentropspks(v2))
      }
    if(verbose_infot>2) printf("te=%g,ve.mean=%g,ve.stdev=%g\n",te,ve.mean,ve.stdev)
    if(verbose_infot>2) ve.printf
    sd=ve.stdev()
    if(sd<=0)sd=1
    return (te-ve.mean)/sd
  }

//* normte() get normalized transfer entropy using tentropspks in output vector vo
//vo.x(0)=transfer entropy of $o1->$o2
//vo.x(1)=H($o2Future|$o2Past)
//vo.x(2)=normalized transfer entropy in 0,1 range
//$3==number of shuffles
//$o1,$o2 should both have same size and non-negative values. this func is meant for time-binned spike train data
obfunc normte () { local a localobj ve,vo
    a=allocvecs(ve) vo=new Vector()
    nshuf=0
    nshuf=$3 vrsz(3+nshuf,vo) 
    te=$o1.tentropspks($o2,vo,nshuf)
    if(verbose_infot>2) vo.printf
    if(vo.x(1)<=0 && verbose_infot>0){printf("WARNING H(X2F|X2P)==%g<=0\n",vo.x(1)) vo.x(1)=1 }
    if (nshuf>0) {
        ve.copy(vo,3,vo.size-1)
        vo.resize(4)
        if (ve.mean!=vo.x[2]) printf("normte ERRA\n")
        vo.append(ve.stdev)
      } 
    vo.x[2]=te
    dealloc(a)
    return vo
  }

//* GetTENQ() get an nqs with useful transfer entropy info
obfunc GetTENQ () { local te01,te10,pf01,pf10 localobj nqte,vo1,vo2
    if(numarg()>3) nqte=$o4
    if(nqte==nil) {
        nqte=new NQS("from","to","TE","NTE","HX2|X2P","prefdir","TEshufavg","TEshufstd","sig")
      } else nqte.clear()
    vo1=normte($o1,$o2,$3)
    vo2=normte($o2,$o1,$3)
    te01=vo1.x(2)
    te10=vo2.x(2)
    if(vo1.x(4)<=0)vo1.x(4)=1
    if(vo2.x(4)<=0)vo2.x(4)=1
    if(te01>0 || te10>0) {
        pf01=(te01-te10)/(te01+te10)
        pf10=(te10-te01)/(te01+te10)
      } else {
        pf01=pf10=0
      }
  nqte.append(0,1,vo1.x(0),te01,vo1.x(1),pf01,vo1.x(3),vo1.x(4),(vo1.x(0)-vo1.x(3))/vo1.x(4))
  nqte.append(1,0,vo2.x(0),te10,vo2.x(1),pf10,vo2.x(3),vo2.x(4),(vo2.x(0)-vo2.x(3))/vo2.x(4))
    return nqte
  }

//** prefdte() get preferred direction of transfer entropy
//$o1=vec 1, $o2=vec 2, $3 = # of times to shuffle
func prefdte () { local nshuf,a,te01,te10,pfd localobj v1,v2,vtmp
    a=allocvecs(v1,v2,vtmp)
    v1.copy($o1) v2.copy($o2) nshuf=$3 vtmp.resize(3)
    v1=normte($o1,$o2,nshuf)
    v2=normte($o2,$o1,nshuf)
    te01=v1.x(2)
    te10=v2.x(2)
    pfd=(te01-te10)/(te01+te10)
    dealloc(a)
    return pfd
  }

//** mkchist() averages entries in window into disc values and returns in new output vec
//$o1=input vec,$2=win size
obfunc mkchist () { local idx,eidx,wsz localobj vin,vout
    vin=$o1 wsz=$2 vout=new Vector() 
    vout.resize(1+vin.size/wsz) vout.resize(0)
    for(idx=0;idx<=vin.size;idx+=wsz) {
        eidx=idx+wsz-1
        if(eidx>=vin.size)eidx=vin.size-1
        if(eidx>idx) vout.append( int(vin.mean(idx,eidx)) )
      }
    return vout
  }

//get magnitude of difference in a preferred direction - just abs of diff, but if theyre both neg, return 0
//$1 = nTE_X->Y
//$2 = nTE_Y->X
func prefdmag () { local n1,n2,s
    n1=$1 n2=$2
    if(n1>0 && n2<=0) return n1-n2 //n1 is relatively strong
    if(n2>0 && n1<=0) return n2-n1 //n2 is relatively strong
    if(n2<0 && n1<0) return 0      //both are weak
    return abs(n1-n2)              //both are weak positive
  }


//** simple test for nte
declare("vb","o[2]","vs","o[2]")
for i=0,1 {
    vb[i]=new Vector()
    vs[i]=new Vector()
  }

//mkspktrain(Random,rate,tmax) -- make a spike train with specified rate,tmax
//Random obj must be initialized
obfunc mkspktrain () { local tmax,rate,t,dt,intt localobj rdp,vs
    rdp=$o1 rate=$2 tmax=$3
    intt=1e3/rate
    t = 0
    vs=new Vector()
    while(t<=tmax) {
        dt = rdp.poisson(intt)
        t += dt
        vs.append(t)
      }
    return vs
  }

//make random spikes with frequency $1, tmax=$2, offset for spikes=$3, alpha=$4 -- ratio of spikes from
//vs[0] that get placed in vs[1] 
//spikes in vs[0] are randomly picked, spikes in vs[1] are same as in vs[0] but shifted forward by $3 offset
//so vs[0] 'drives' vs[1], or can be used to predict it, but vs[1] cant be used to predict vs[0]
proc mkspks () { local tmax,rate,t,dt,intt,off,i,alpha localobj rdp
    rate=$1 tmax=$2 off=$3 
    if(numarg()>3)alpha=$4 else alpha=1
    intt=1e3/rate
    rdp=new Random()
    rdp.ACG(1234)
    rdp.poisson(intt)
    for i=0,1 vs[i].resize(0)
    vs[0]=mkspktrain(rdp,rate,tmax)
    if(alpha < 1.0) {
        for vtr(&t,vs[0]) if(rdp.uniform(0,1) <= alpha) vs[1].append(t+off)
      } else {
        vs[1].copy(vs[0])
        vs[1].add(off)
      }
  }
//test nTE : nTE of X0 -> X1 should be much higher than nTE of X1 -> X0
//optional $1=offset == offset to shift spikes by, in ms
//optional $2=rate == rate of spikes, in Hz
//optional $3=bin size , in ms
//optional $4=alpha == ratio of spikes of X0 that get placed in X1 with offset
//optional $5=max time, in ms
func testnte () { local a,i,bisv,maxt,alpha,off,rate,binsz,dur  localobj nqt,nqout
    if(numarg()>0)off=$1 else off=10
    if(numarg()>1)rate=$2 else rate=50
    if(numarg()>2)binsz=$3 else binsz=10
    if(numarg()>3)alpha=$4 else alpha=1
    if(numarg()>4)dur=$5 else dur=10000
    bisv=binmin_infot binmin_infot=0
    print "output should be close to:\n\t0 1 0.6707 0.9975 0.6707 0.9407 0.003435 0.001672 399.1"
    print "\t1 0 0.02183 0.03049 0.6685 -0.9407 0.002828 0.001442 13.17"
    mkspks(rate,dur,off,alpha)
    maxt=vs[1].max
    printf("maxt=%g\n",maxt)
    if(vs[1].max>maxt)maxt=vs[1].max
    for i=0,1 vb[i].hist(vs[i],0,(maxt+binsz-1)/binsz,binsz)
    nqt=GetTENQ(vb[0],vb[1],200) 
  nqout=new NQS("X1","X2")
  nqout.odec("X1")
  nqout.odec("X2")
  batch_flag=1
  nqout.append(vb[0],vb[1])
  nqout.sv("/u/samn/bpftest/data/09dec17.func.testnte.nqs")
  batch_flag=0
    nqt.pr
    nqsdel(nqt)
    binmin_infot=bisv
    return 1
  }
//get kernel smoothed prob distrib in an nqs
//$o1=input vector
//$2=increment in x , smaller values mean finer resolution
//$3=bandwidth - higher means smoother output
// $4=min value in output, $5=max value in output
obfunc khist () { local min,max,inc,h,x,i,s localobj vx,vy,nq,vin
    vin=$o1 
    if(numarg()>1)inc=$2 else inc=0.1
    if(numarg()>2)h=$3 else h=vin.getbandwidth()
    if(numarg()>3)min=$4 else min=vin.min()
    if(numarg()>4)max=$5 else max=vin.max()
    {vx=new Vector() vy=new Vector()}
    vx.indgen(min,max,inc)
    vy.copy(vx)
    for vtr(&x,vx,&i) vy.x(i) = vin.kprob1D(h,x)
    s=vy.sum 
    if(s!=0) vy.div(vy.sum)
    nq=new NQS("x","y")
    nq.v[0]=vx
    nq.v[1]=vy
    return nq
  }
// END /usr/site/nrniv/local/hoc/infot.hoc
//================================================================
//================================================================
// INSERTED /usr/site/nrniv/local/hoc/decmat.hoc
// =Id=  decmat.hoc,v 1.70 2010/10/07 15:46:39 samn Exp  
 
//** mtriavg(mat,[mask]) - get average of elements in upper triangular part of matrix $o1
// mask is of same size as mat, has 0 for entries to skip
func mtriavg () { local i,j,s,c localobj mm,msk
    mm=$o1 s=c=0
    if(numarg()>1) { msk=$o2
        for i=0,mm.nrow-1 for j=i+1,mm.ncol-1 if(msk.x(i,j)) {
            s+=mm.x[i][j]
            c+=1
          }    
      } else {
        for i=0,mm.nrow-1 for j=i+1,mm.ncol-1 {
            s+=mm.x[i][j]
            c+=1
          }
      }
    if(c>0) return s/c else return 0
  }

//** mltristd(mat,[mask]) - get stdev of elements in upper triangular part of matrix $o1
// mask is of same size as mat, has 0 for entries to skip
func mtristd () { local i,j,s,c,s2,tm localobj mm,msk
    mm=$o1 s=s2=c=0
    if(numarg()>1) { msk=$o2
        for i=0,mm.nrow-1 for j=i+1,mm.ncol-1 if(msk.x(i,j)) {
            s+=mm.x[i][j]
            s2+=mm.x[i][j]^2
            c+=1
          }
      } else {
        for i=0,mm.nrow-1 for j=i+1,mm.ncol-1 {
            s+=mm.x[i][j]
            s2+=mm.x[i][j]^2
            c+=1
          }
      }
    if(c>0) return sqrt(s2/c - (s/c)^2) else return 0
  }

//** mltristd(mat,[mask]) - get std-error of elements in upper triangular part of matrix $o1
// mask is of same size as mat, has 0 for entries to skip
func mtristderr () { local i,j,s,c,s2,tm localobj mm,msk
    mm=$o1 s=s2=c=0
    if(numarg()>0) {
        msk=$o2
        for i=0,mm.nrow-1 for j=i+1,mm.ncol-1 if(msk.x(i,j)) {
            s+=mm.x[i][j]
            s2+=mm.x[i][j]^2
            c+=1
          }
      } else {
        for i=0,mm.nrow-1 for j=i+1,mm.ncol-1 {
            s+=mm.x[i][j]
            s2+=mm.x[i][j]^2
            c+=1
          }
      }
    if(c>0) return sqrt(s2/c - (s/c)^2)/sqrt(c) else return 0
  }

//** vi2mi(ind[,COLS]) take index from vector and print out matrix indices using COLS 
obfunc vi2mi () { local x,co,r,c
    x=$1
    if (argtype(2)==0) co=$2 else co=COLS
    r=int(x/COLS) c=x%COLS
    if (verbose) print r,c
    return new Union(r,c)
  }

//** symmclean(vec[,COLS]) remove redundant entries from vector representing a symm matrix
proc vimiclean() {print "Use symmclean() statt vimiclean()"}
func symmclean () { local ix,dg,cols,ii,n,flag localobj v1
    v1=$o1 
    if (argtype(2)==0) cols=$2 else cols=COLS
    if (argtype(3)==0) flag=$3 else flag=0 // flag gets rid of the diagonal as well
    for ii=0,v1.size-1 { ix=v1.x[ii]
        dg=(n=int(ix/(cols+1)))*(cols+1)
        if (ix<dg || ix>=dg+(cols-n)) v1.x[ii]=-1
        if (flag && ix==dg) v1.x[ii]=-1
      }
    v1.where(">",-1)
    return v1.size
  }

//** msqdif(m1,m2) - get matrix with elements squared difference of m1-m2
obfunc msqdif () { local i,j localobj m1,m2,md
    m1=$o1 m2=$o2
    md=new Matrix(m1.nrow,m1.ncol)
    for i=0,m1.nrow-1 for j=0,m1.ncol-1 md.x[i][j]=(m1.x[i][j]-m2.x[i][j])^2
    return md
  }

//** mthresh(mat,th) - get matrix with mat elements thresholded : values < t set to 0, >= t to 1
obfunc mthresh () { local i,j,t localobj mi,mo
    mi=$o1 t=$2
    mo=new Matrix(mi.nrow,mi.ncol)
    for i=0,mo.nrow-1 for j=0,mo.ncol-1 if(mi.x[i][j]>=t) mo.x[i][j]=1 else mo.x[i][j]=0
    return mo
  }

//** mdif(m1,m2) - get matrix with elements difference of m1-m2
obfunc mdif () { local i,j localobj m1,m2,md
    m1=$o1 m2=$o2
    md=new Matrix(m1.nrow,m1.ncol)
    for i=0,m1.nrow-1 for j=0,m1.ncol-1 md.x[i][j]=(m1.x[i][j]-m2.x[i][j])
    return md
  }

//** getttmat(nqs,[column-name]) - uses NQS $o1 to make time-time correlation matrix
//optional $s2 , otherwise default column-name = 'vc'.
//column $s2 must be .odec with Vector objects
obfunc getttmat () { local i,j,inc,szm localobj mc,nq,v1,v2,str,lc
    {nq=$o1    str=new String()}
    if(numarg()>1)str.s=$s2 else str.s="vc"
    {szm=nq.v.size()  mc=new Matrix(szm,szm)  lc=new List()}
    for i=0,szm-1 lc.append(nq.get(str.s,i).o)
    for i=0,szm-1 {
        mc.x(i,i)=1
        v1=lc.o(i) 
        for j=i+1,szm-1 {
            v2=lc.o(j) 
            mc.x(i,j)=mc.x(j,i)=v1.pcorrel(v2)
          }
      }
    return mc
  }

//** svmat(matrix,path,[writesz,binary]) - save a matrix to file as ascii, each row on new line
//$o1==matrix, $s2==file path -- will overwrite!! , $3 = optional == 1 to include nrows,ncols
// writesz = write rows,cols . binary - use binary output format, this will write using vwrite
// and first two elements of written vector will have rows,cols (so writesz arg is ignored)
func svmat () { local pr,bin,a localobj m,f,myv1,myv2,mt
    {m=$o1 a=allocvecs(myv1,myv2) f=new File() f.wopen($s2)}
    if(!f.isopen()) {
        printf("svmat ERRA: couldnt open output file %s\n",$s2)
        return 0
      }
    if(numarg()>2)pr=$3 else pr=0
    if(numarg()>3)bin=$4 else bin=0
    if(bin) {
        mt=$o1.transpose()
        mt.to_vector(myv1)
        myv2.append($o1.ncol,$o1.nrow)
        myv2.append(myv1)
        myv2.vwrite(f)
      } else {
        if(pr) m.fprint(f) else m.fprint(0,f)
      }
    {f.close() dealloc(a)}
    return 1
  }

//obfunc rdmat () { local pr localobj m,f
  // m=$o1
  // f=new File()
  // f.wopen($s2)
  // if(!f.isopen()) {
    //   printf("svmat ERRA: couldnt open output file %s\n",$s2)
    //   return 0
    // }
  // if(numarg()>2)pr=$3 else pr=0
  // if(pr) m.fprint(f) else m.fprint(0,f)
  // f.close()
  // return 1
  //}

//** matimagesc - display a matrix ($o1) in matlab using matimgsc program
// or a text file $s1 , $2 = min scale value , $3 = max scale value, $4 optional
// binary input flag
func matimagesc () { local x,binflag localobj str
    if(numarg()>3) binflag=$4 else binflag=1
    str=new String2()
    if(argtype(1)==2) {
        str.s=$s1
      } else {
        str.s="__tmp__mat__ml__.txt"
        if(!svmat($o1,str.s,1,binflag)) return 0
      }
    sprint(str.t,"/usr/site/nrniv/local/matlab/matimgsc %s %g %g %d",str.s,$2,$3,binflag)
    x = system(str.t)
    return x
  }

//** pyimagesc - display a matrix ($o1) in python's matplotlib or a text file $s1
//opt:[$2=min scaling for colors, $3=max scaling for colors, [$s4=title,$s5=xlabel,$s6=ylabel]
func pyimagesc () { local i,minc,maxc localobj str,cmd,strout,strt,strl,fp
    str=new String2()
    strout=new String()//collect stdout from script
    if(argtype(1)==2) {
        str.s=$s1
      } else {
        str.s="__tmp__mat__py__.txt"
        if(!svmat($o1,str.s)) return 0
      }
    if(numarg()>1)minc=$2 else minc=-1
    if(numarg()>2)maxc=$3 else maxc=1  
    if(numarg()>3) { //write title,xlabel,ylabel for pyimgsc.py
        {strl=new String() strl.s="__tmp__str__py__.txt"    fp=new File()}
        fp.wopen(strl.s)
        if(!fp.isopen()){
            printf("pyimagesc ERRB: couldnt save tmp file %s\n",strl.s)
            return 0
          }
        for i=4,numarg() fp.printf("%s\n",$si)
        fp.close()
        sprint(str.t,"/u/samn/python/pyimgsc.py %s %g %g %s",str.s,minc,maxc,strl.s)
      } else {
        sprint(str.t,"/u/samn/python/pyimgsc.py %s %g %g",str.s,minc,maxc)
      }
    return system(str.t,strout.s)
  }

//** matspecgram(vec,samplingrate,maxfrequency,fftwinsz,[,dodraw,mincolor,maxcolor])
// if fftwinsz <= 0, matspecgram will pick a WINDOW size for STFT
obfunc matspecgram () { local a,sampr,maxfreq,dodraw,rows,cols,x,y,minc,maxc,fftwinsz\
                         localobj vin,fpin,fpout,str,vop,vof,nqo,strin,strout,vtmp,strd
    vin=$o1 sampr=$2 maxfreq=$3 fftwinsz=$4 fpin=new File() fpout=new File()
    str=new String() strin=new String() strout=new String() strd=new String()
    a=allocvecs(vtmp,vop,vof)  if(numarg()>4)dodraw=$5 else dodraw=1  
    if(!fpin.mktemp || !fpout.mktemp) {
        print "matspecgram ERR0: couldn't make temp files!"
        {dealloc(a) return nil}
      }  
    {strin.s=fpin.getname strout.s=fpout.getname strd.s="/usr/site/nrniv/local/matlab" fpin.wopen(strin.s)}
    if(!fpin.isopen()){printf("matspecgram ERRA: couldn't open %s for writing\n",strin.s) dealloc(a) return nil}
    {vin.vwrite(fpin)  fpin.close()}
    if(dodraw && numarg()>=7) {
        sprint(str.s,"%s/matspecgram %s %g %g %d %d %s %g %g",strd.s,strin.s,sampr,maxfreq,fftwinsz,dodraw,strout.s,$6,$7)
      } else {
        sprint(str.s,"%s/matspecgram %s %g %g %d %d %s",strd.s,strin.s,sampr,maxfreq,fftwinsz,dodraw,strout.s)
      }
    print str.s
    system(str.s)
    fpout.ropen(strout.s) 
    if(!fpout.isopen()){printf("matspecgram ERRB: couldn't open %s for reading\n",strout.s) dealloc(a) return nil}
    {vop.vread(fpout) vof.vread(fpout)}  
    {nqo=new NQS("f","pow")  nqo.odec("pow")}
    {rows=vof.size() cols=vop.size()/rows x=0}
    for y=0,rows-1 { vtmp.resize(0)
        vtmp.copy(vop,x,x+cols-1)
        nqo.append(vof.x(y),vtmp)
        x+=cols
      }
    {fpin.unlink() fpout.unlink()}
    {dealloc(a) return nqo}
  }

//** matpmtm(vec,samplingrate)
// this function calls /usr/site/nrniv/local/matlab/matpmtm to run multitaper power spectra using matlab, returns an nqs
obfunc matpmtm () { local a,sampr,rows,cols,x,y\
                         localobj vin,fpin,fpout,str,vop,vof,nqo,strin,strout
    if(numarg()==0) {printf("%s\n","matpmtm(vec,samplingrate)") return nil}
    vin=$o1 sampr=$2 fpin=new File() fpout=new File() str=new String() strin=new String() strout=new String()
    a=allocvecs(vop,vof)  
    if(!fpin.mktemp || !fpout.mktemp) {
        print "matpmtm ERR0: couldn't make temp files!"
        {dealloc(a) return nil}
      }
    {strin.s=fpin.getname strout.s=fpout.getname}
    {fpin.wopen(strin.s)}
    if(!fpin.isopen()) {printf("matpmtm ERRA: couldn't open %s for writing\n",strin.s) dealloc(a) return nil}
    {vin.vwrite(fpin)  fpin.close()}
    sprint(str.s,"/usr/site/nrniv/local/matlab/matpmtm %s %g %s",strin.s,sampr,strout.s)
    print str.s
    system(str.s)
    fpout.ropen(strout.s) 
    if(!fpout.isopen()){printf("matpmtm ERRB: couldn't open %s for reading\n",strout.s) dealloc(a) return nil}
    {vop.vread(fpout) vof.vread(fpout) nqo=new NQS("f","pow")}
    {nqo.v[0].copy(vof) nqo.v[1].copy(vop) dealloc(a) fpin.unlink() fpout.unlink()}
    return nqo
  }

//** matfftpow(vec,samplingrate,maxfrequency,[dodraw,dosmooth,smoothwindowsz])
// this function calls /usr/site/nrniv/local/matlab/matfftpow to run power spectra using matlab, returns an nqs
// dosmooth controls whether to smooth output, is OFF by default
// smoothwindowsz controls size of running average smoothing of power spectra output
obfunc matfftpow () { local a,sampr,maxfreq,dodraw,rows,cols,x,y,dosmooth\
                         localobj vin,fpin,fpout,str,vop,vof,nqo,strin,strout
    if(numarg()==0) {printf("%s\n","matfftpow(vec,samplingrate,maxfrequency,[dodraw,dosmooth,smoothwindowsz])") return nil}
    vin=$o1 sampr=$2 maxfreq=$3 fpin=new File() fpout=new File() str=new String() strin=new String() strout=new String()
    a=allocvecs(vop,vof)  if(numarg()>3)dodraw=$4 else dodraw=1
    if(numarg()>4)dosmooth=$5 else dosmooth=0
    if(!fpin.mktemp || !fpout.mktemp) {
        print "matfftpow ERR0: couldn't make temp files!"
        {dealloc(a) return nil}
      }
    {strin.s=fpin.getname strout.s=fpout.getname}
    {fpin.wopen(strin.s)}
    if(!fpin.isopen()) {printf("matfftpow ERRA: couldn't open %s for writing\n",strin.s) dealloc(a) return nil}
    {vin.vwrite(fpin)  fpin.close()}
    if(numarg()>5) {
        sprint(str.s,"/usr/site/nrniv/local/matlab/matfftpow %s %g %d %d %s %d %d",strin.s,sampr,maxfreq,dodraw,strout.s,dosmooth,$6)
      } else sprint(str.s,"/usr/site/nrniv/local/matlab/matfftpow %s %g %d %d %s %d",strin.s,sampr,maxfreq,dodraw,strout.s,dosmooth)
    print str.s
    system(str.s)
    fpout.ropen(strout.s) 
    if(!fpout.isopen()){printf("matfftpow ERRB: couldn't open %s for reading\n",strout.s) dealloc(a) return nil}
    {vop.vread(fpout) vof.vread(fpout) nqo=new NQS("f","pow")}
    {nqo.v[0].copy(vof) nqo.v[1].copy(vop) dealloc(a) fpin.unlink() fpout.unlink()}
    return nqo
  }

//** mathilbert(vec,samplingrate,minfrequency,maxfrequency)
obfunc mathilbert () { local a,sampr,minfreq,maxfreq\
                         localobj vin,fp,str,vfilt,vph,vamp,nqo,strin,strout
    vin=$o1 sampr=$2 minfreq=$3 maxfreq=$4 fp=new File() str=new String() strin=new String() strout=new String()
    a=allocvecs(vfilt,vph,vamp) 
    {sprint(strin.s,"__tmp__mat__hilbert__input__vec__.vec")  sprint(strout.s,"__tmp__mat__hilbert_output__vec__.vec")}
    {fp.wopen(strin.s)}
    if(!fp.isopen()) {
        printf("mathilbert ERRA: couldn't open %s for writing\n",strin.s)
        dealloc(a)
        return nil
      }
    {vin.vwrite(fp)  fp.close()}
    sprint(str.s,"/usr/site/nrniv/local/matlab/mathilbert %s %g %g %g %s",strin.s,sampr,minfreq,maxfreq,strout.s)
    print str.s
    system(str.s)
    fp.ropen(strout.s) 
    if(!fp.isopen()) {
        printf("mathilbert ERRB: couldn't open %s for reading\n",strout.s)
        dealloc(a)
        return nil
      }
    {vfilt.vread(fp) vph.vread(fp) vamp.vread(fp) nqo=new NQS("filt","phase","amp","t")}
    {nqo.v[0].copy(vfilt) nqo.v[1].copy(vph) nqo.v[2].copy(vamp)}
    {nqo.v[3].indgen(0,1e3*nqo.v[2].size/sampr,1e3/sampr)  nqo.v[3].resize(nqo.v[2].size)}
    dealloc(a)
    return nqo
  }

//** matprincomp(input Matrix object)
// returns list with : eigenvectors as Vector, scores as Vector, eigenvalues as Vector, scores as Matrix
// scores has same size as $o1, eigenvectors is $o1.ncols^2, eigenvalues is $o1.ncols
// input matrix has rows as observations and columns as dimensions
obfunc matprincomp () { local i,j,k localobj mcin,fp,str,strin,strout,lsout,vcoeff,vscore,vlat,mscore
    mcin=$o1 fp=new File() str=new String() strin=new String() strout=new String() lsout=new List()
    {vcoeff=new Vector() vscore=new Vector() vlat=new Vector()}
    {sprint(strin.s,"__tmp__mat__princomp__input__mat__.txt")  sprint(strout.s,"__tmp__mat__princomp_output__vec__.vec")}
    if(!svmat(mcin,strin.s,1)) {
        printf("matprincomp ERRA: couldn't open %s for writing\n",strin.s)
        return nil
      }
    sprint(str.s,"/usr/site/nrniv/local/matlab/matprincomp %s %s",strin.s,strout.s)
    print str.s
    system(str.s)
    fp.ropen(strout.s) 
    if(!fp.isopen()) {
        printf("matprincomp ERRB: couldn't open %s for reading\n",strout.s)
        return nil
      }
    {vcoeff.vread(fp) vscore.vread(fp) vlat.vread(fp) fp.close()}
    mscore=new Matrix(mcin.nrow,mcin.ncol)
    mscore.from_vector(vscore) //reads it in in column major order
    {lsout.append(vcoeff) lsout.append(vscore) lsout.append(vlat) lsout.append(mscore)}
    return lsout
  }

//** matmin(mat) - return min element of mat
func matmin () { local i,j,me,tmp localobj m
    m=$o1 
    me=m.getrow(0).min()
    for i=1,m.nrow-1 if((tmp=m.getrow(i).min)<me) me=tmp
    return me
  }

//** matmax(mat) - return max element of mat
func matmax () { local i,j,me,tmp localobj m
    m=$o1 
    me=m.getrow(0).max()
    for i=1,m.nrow-1 if((tmp=m.getrow(i).max)>me) me=tmp
    return me
  }

//** mlk(mat) - use vlk to print rows of matrix
// a matrix will have it's lower/smaller rows printed first:
//    1 2 3 
//    4 5 6 
//    7 8 9 
proc mlk () { local i localobj m
    m=$o1
    for i=0,m.nrow-1 vlk(m.getrow(i))
  }

//** mateq(mat1,mat2) - return 1 iff matrix row Vectors are eq, 0 otherwise
func mateq () { local i localobj m1,m2
    m1=$o1 m2=$o2
    if(m1.nrow!=m2.nrow || m1.ncol!=m2.ncol) return 0
    for i=0,m1.nrow-1 if(m1.getrow(i).eq(m2.getrow(i))==0) return 0
    return 1
  }

//** matavg - return average value in Matrix $o1
func matavg () { local i,s localobj m
    m=$o1
    if(m.nrow<1 || m.ncol<1) {
        printf("matavg ERRA: empty matrix!\n")
        return 0
      }
    s=0
    for i=0,m.nrow-1 s += m.getrow(i).sum()
    return s/(m.nrow*m.ncol)
  }

//** avgmat(list of Matrix) - return Matrix that has its elements avg of elements in $o1 List
obfunc avgmat () { local sz,i localobj ma
    sz=$o1.count
    if(sz<1) return nil
    ma=new Matrix($o1.o(0).nrow,$o1.o(0).ncol)
    for i=0,sz-1 ma.add($o1.o(i))
    ma.muls(1.0/sz)
    return ma
  }

//** stdmat(list of Matrix) - return Matrix that has its elements stdev of elements in $o1 List
obfunc stdmat () {  local sz,i,j,k localobj ms,ma
    sz=$o1.count
    if(sz<1) return nil
    ma=new Matrix($o1.o(0).nrow,$o1.o(0).ncol)
    ms=new Matrix($o1.o(0).nrow,$o1.o(0).ncol)
    for i=0,sz-1 for j=0,ma.nrow-1 for k=0,ma.ncol-1 {
        ms.x(j,k) += $o1.o(i).x(j,k)^2
        ma.x(j,k) += $o1.o(i).x(j,k)
      }
    ma.muls(1.0/sz)
    ms.muls(1.0/sz)  
    for j=0,ma.nrow-1 for k=0,ma.ncol-1 {
        ms.x(j,k) -= ma.x(j,k)^2
        if(ms.x(j,k) > 1e-9) ms.x(j,k) = sqrt(ms.x(j,k)) else ms.x(j,k) = 0
      }
    return ms
  }

//** chgmat(list of before Matrices, list of after Matrices) - returns change in each entry in units of std-dev
obfunc chgmat () { local szbef,szaft,i,j,k localobj lbef,laft,mavg,mstd,lchg,mchg,mt
    lbef=$o1 laft=$o2
    szbef=lbef.count szaft=laft.count
    lchg=new List()
    mavg=avgmat(lbef)
    mstd=stdmat(lbef)
    mchg=new Matrix(mavg.nrow,mavg.ncol)
    for i=0,szaft-1 {
        mt=laft.o(i)
        for j=0,mt.nrow-1 for k=0,mt.ncol-1 {
            if(mstd.x(j,k)>1e-9) {
                mchg.x(j,k) += ( mt.x(j,k) - mavg.x(j,k) ) / mstd.x(j,k)
              } else if(szbef==1) {
                mchg.x(j,k) += ( mt.x(j,k) - mavg.x(j,k) ) 
              }
          }
      }
    return mchg
  }

//** getlv(rows,cols) - make a List of Vectors as 2D array
//$1 == # of rows (vectors), $2 == # of cols (size of vectors)
obfunc getlv () { local idx,rows,cols localobj ls
    ls=new List()
    rows=$1 cols=$2
    for idx=0,rows-1 ls.append(new Vector(cols))
    return ls
  }

//** vec2mat(vec,rows) - get a matrix from a vec -- row major order
obfunc vec2mat () { local i,j,k,rows,cols localobj vin,mout
    vin=$o1 rows=$2 cols=vin.size/rows mout=new Matrix(rows,cols) k=0
    for i=0,rows-1 for j=0,cols-1 {
        mout.x(i,j)=vin.x(k)
        k+=1
      }
    return mout
  }

//** mat2vec(mat) - get a vec from a matrix -- row major order 
obfunc mat2vec () { local i,j,k,rows,cols localobj mat,vout
    mat=$o1 rows=mat.nrow cols=mat.ncol i=j=k=0 vout=new Vector(rows*cols)
    for i=0,rows-1 for j=0,cols-1 {
        vout.x(k)=mat.x(i,j)
        k+=1
      }
    return vout
  }
//** mltmed(mat) - get median values from lower-triangular portion - lower triang. means smaller rows
// this matrix printed as (with printf or mlk):
//    1 2 3 
//    4 5 6 
//    7 8 9 
// will have mltmed of 3, since uses 2,3,6 from bottom of matrix to get median
func mltmed () { local i,j,a localobj m,vo
    a=allocvecs(vo) m=$o1
    for i=0,m.nrow-1 for j=i+1,m.ncol-1 vo.append(m.x(i,j))
    return vo.median()
  }
//** mzerout(mat) - zero out everything >= diagonal
// a matrix printed as (with printf or mlk):
//    1 2 3 
//    4 5 6 
//    7 8 9 
// will end up as:
//    0 2 3 
//    0 0 6 
//    0 0 0 
proc mzerout () { local i,j,a localobj m,vo
    a=allocvecs(vo) m=$o1
    for i=0,m.nrow-1 for j=0,i m.x(i,j)=0
  }
//** matsqsymm(matrix) - return 1 iff matrix is square and symmetric
func matsqsymm () { local i,j localobj mc
    mc=$o1  if(mc.nrow!=mc.ncol) return 0
    for i=0,mc.nrow-1 for j=i+1,mc.ncol-1 if(mc.x(i,j)!=mc.x(j,i)) return 0
    return 1
  }
//** getsubmat(matrix,startx,endx,starty,endy) - copy subsection of matrix
// and return in new output matrix
obfunc getsubmat () { local x,y,startx,endx,starty,endy localobj m1,msub
    m1=$o1
    startx=$2 endx=$3 starty=$4 endy=$5
    msub=new Matrix(endy-starty+1,endx-startx+1)
    for y=starty,endy for x=startx,endx msub.x(y-starty,x-startx)=m1.x(y,x)
    return msub
  }
// END /usr/site/nrniv/local/hoc/decmat.hoc
//================================================================

// END init.hoc
//================================================================
//================================================================
// INSERTED mdb.hoc
// =Id=  mdb.hoc,v 1.9 2010/11/01 03:21:19 samn Exp  


//////////////////////////////////////////////////
//load init hoc files , use loadfiles -d to load these
//load_file("nrngui.hoc")
//load_file("setup.hoc")
//load_file("nrnoc.hoc")
//load_file("init.hoc")
//////////////////////////////////////////////////

//////////////////////////////////////////////////
//================================================================
// INSERTED geom.hoc
// =Id=  geom.hoc,v 1.77 2009/09/14 15:14:03 samn Exp 

//* begintemplate CELL
begintemplate CELL		// create a new template object
external RS,IB,LTS,FS,nil
public soma,dend,axon,type,id,col,ofths,setri,poflag,connect2target,ampa,gabaa,nmda,gabab,printV
public up,stim
objref ofths
objref this,up
double type[1],id[1],col[1]

objref ampa,gabaa[2],gabab[2],nmda,stim

create soma[1],dend[1],axon[1]

proc init() { 
    id = $1
    type=$2
    if(numarg()>2) col=$3
    if (argtype(4)==0) poflag=$4 else poflag=0
    initsoma()  //init soma params
    initdend()  //init dend params
    initaxon()  //init axon params
    doconnect() //connect dend,soma,axon
  }

//** initdend()
proc initdend () {
   dend {
       nseg = 1
       diam = 2
       L = 500 
       Ra = 1
       insert pas
       ampa = new AMPA(0.5)
       nmda = new NMDA(0.5)
       gabaa[0] = new GABAa(0.5)
     }
  }

//** initsoma()
proc initsoma () {
    soma {
        diam = 30
        L = 30
        nseg = 1
        Ra = 1
        insert pas
        gabaa[1] = new GABAa(0.5)
      }
  }

//** initaxon()
proc initaxon () {
    axon {
        nseg = 1
        diam = 1 
        L = 200
        Ra = 1
        insert pas
        if (poflag) {ofths = new OFPO(0.5)
          } else       ofths = new OFTH(0.5)
      }
  }

//** doconnect()
proc doconnect () {  
    connect soma(0), axon(1) //connect 0 end of soma to 0 end of axon
    connect dend(0), soma(1) //connect 0 end of dend to 1 end of soma
  }

proc setri () { local gsa,gsd,ga
    gsa=$1 gsd=$2 ga=$3
    soma { Ra=1 Ra=1e3/ri(0.5)/gsa }
    dend { Ra=1 Ra=1e3/ri(0.5)/gsd }
    axon { Ra=1 Ra=1e3/ri(0.5)/ga }
  }

proc printV () {
    printf("dend.v=%g\n",dend.v)
    printf("soma.v=%g\n",soma.v)
    printf("axon.v=%g\n",axon.v)
  }

proc connect2target () { $o2 = new NetCon(ofths,$o1) }
endtemplate CELL
// END geom.hoc
//================================================================
//================================================================
// INSERTED network.hoc
// =Id=  network.hoc,v 1.249 2010/05/14 23:11:21 samn Exp 

//* global variables/settings
 
// iff == 1 dont do wiring and dont make INTFs , used for debugging a single cell
declare("celldbg",0,"celldbgty",I5L) // type of cell to debug

numcols=1 //# of cortical columns
if(celldbg) numcols=1
// scaling factors for pmat,wmat
declare("pmatfctr",1,"wmatfctr",1,"useoldwmat",1)
// gain control on weights, between types, and NMAMR sets NMDA weights to fraction of AMPA weights
declare("EEGain",0.5,"EIGain",1,"IEGain",1,"IIGain",0.5,"NMAMR",0.1)
//EEGain:E->E weights,EIGain:E->I weights,IEGain:I->E weights,IIGain:I->I weights,NMAMR:NMDA/AMPA strength Ratio
declare("EENMGain",1) // E->E NMDA gain

declare("scale",1)//scale for size of sim

declare("wireseed",1234) // random seed for wiring

declare("LearnGainLO",1,"LearnGainHI",1) // gains for learning function

colr=2 // maximal trans-column projection distance; 0 within col; 1 next col etc
double Cix[numcols][CTYPi+1],Cixe[numcols][CTYPi+1]//start,end IDs of types in a column
double div[CTYPi+1][CTYPi+1][2]//div[i][j]==# of outputs from type i->j
double wmat[CTYPi+1][CTYPi+1][STYPi+1][colr+1]
// wmat[i][j][k][c]==weight from type i->j for synapse k onto col at dist c
double delm[CTYPi+1][CTYPi+1][colr+1]//avg. delay from type i->j
double deld[CTYPi+1][CTYPi+1][colr+1]//delay variance from type i->j
double conv[CTYPi+1][CTYPi+1][colr+1],pmat[CTYPi+1][CTYPi+1][colr+1]
double wd0[CTYPi+1][CTYPi+1][STYPi+1][colr+1]
double synloc[CTYPi+1][CTYPi+1]//location of synapses
{DEND=0 SOMA=1 AXON=2}

objref clmpl,clmp,mc,nc,nclnq
double cpercol[CTYPi+1] //cells per column

proc setcpercolkmj () { // (notebook.dol_1:24562)(notebook.dol_1:24492)
    cpercol[E2]  = 142 * scale
    cpercol[E2B] =   8 * scale
    cpercol[E4] =   30 * scale
    cpercol[E5B] =  17 * scale
    cpercol[E5R] =  65 * scale
    cpercol[E6] =   60 * scale
    cpercol[I2L] =  13 * scale
    cpercol[I2]  =  25 * scale
    cpercol[I4L] =  14 * scale 
    cpercol[I4]  =  20 * scale
    cpercol[I5L] =  13 * scale
    cpercol[I5]  =  25 * scale
    cpercol[I6L] =  13 * scale
    cpercol[I6] =   25 * scale
  }

proc setcpercolvc () {
    cpercol[E2]  = 142
    cpercol[E5R] =  65
    cpercol[E5B] =  17
    cpercol[I2]  =  25
    cpercol[I2L] =  13
    cpercol[I5]  =  25
    cpercol[I5L] =  13
    cpercol[E4] =  30
    cpercol[E6] =  60
    cpercol[I6] =  25
    cpercol[I6L] = 13
    scale=1
  }

// see jnphys93:2194.pdf
proc traubsetcpercol () {
    cpercol[E2] = 1e3 * scale       // superficial RS pyramidal
    cpercol[E2B] = 50 * scale       // superficial FRB pyramidal
    cpercol[I2] = 90 * scale        // superficial basket (fast spiking)
    cpercol[I2C] = 90 * scale       // superficial axoaxonic (chandelier) (fast spiking)
    cpercol[I2L] = 90 * scale       // superficial LTS interneuron
    cpercol[E4] = 240 * scale       // spiny stellate
    cpercol[E5B] = 200 * scale      // tufted IB pyramidal
    cpercol[E5R] = 800 * scale      // tufted RS pyramidal
    cpercol[E6] = 500 * scale       // nontufted RS pyramidal
    cpercol[I6] = 100 * scale       // deep basket (fast spiking)
    cpercol[I6C] = 100 * scale      // deep axoaxonic (chandelier) (fast spiking)
    cpercol[I6L] = 100 * scale      // deep LTS interneuron
  }

//* setarrs() sets  up arrays
proc setarrs () { local ct,cnt,cl // set globals
    for ii=0,CTYPi-1 numc[ii]=0
    cnt=allcells=icells=ecells=0
    for ct=0,CTYPi-1 if (cpercol[ct]>0) {
        numc[ct]=cpercol[ct]*numcols
        ix[ct]=cnt ixe[ct]=cnt+numc[ct]-1 cnt+=numc[ct]
        if(ice(ct))icells+=numc[ct] else ecells+=numc[ct]
        for cl=0,numcols-1 {
            Cix[cl][ct]=ix[ct]+cpercol[ct]*cl
            Cixe[cl][ct]=Cix[cl][ct]+cpercol[ct]-1
          }
      }
    allcells=ecells+icells
    npcol = allcells/numcols // number of cells per column
    if(npcol!=int(npcol)){print "Number of allcells and number of columns is inconsistent!" return}  
  }

//* setpmat()
proc setpmat () { local pre,po
    for ii=0,CTYPi-1 for jj=0,CTYPi-1 for kk=0,1 pmat[ii][jj][kk]=0
    pmat[E2][E2][0]=0.187
    pmat[E2][E2][1]=0.14
    pmat[E2][E4][0]=0.024
    pmat[E2][E5B][0]=0.024
    pmat[E2][E5R][0]=0.057
    pmat[E2][E6][0]=0
    pmat[E2][E2B][0]=0.187
    pmat[E2][I2L][0]=0.51
    pmat[E2][I2][0]=0.43
    pmat[E2][I2][1]=0.14
    pmat[E4][E2][0]=0.145
    pmat[E4][E4][0]=0.243
    pmat[E4][E5B][0]=0.122
    pmat[E4][E5R][0]=0.116
    pmat[E4][E6][0]=0.032
    pmat[E4][I4L][0]=0.51
    pmat[E4][I4][0]=0.43
    pmat[E4][I4][1]=0.14
    pmat[E5B][E2][0]=0.018
    pmat[E5B][E2][1]=0.25
    pmat[E5B][E2][2]=0.1
    pmat[E5B][E4][0]=0.007
    pmat[E5B][E5B][0]=0.07
    pmat[E5B][E5B][1]=0.25
    pmat[E5B][E5B][2]=0.1
    pmat[E5B][E5R][0]=0.017
    pmat[E5B][E5R][1]=0.25
    pmat[E5B][E5R][2]=0.1
    pmat[E5B][E6][0]=0.07
    pmat[E5B][I2L][1]=0.14
    pmat[E5B][I2L][2]=0.07
    pmat[E5B][I5L][0]=0.51
    pmat[E5B][I5L][1]=0.14
    pmat[E5B][I5L][2]=0.07
    pmat[E5B][I5][0]=0.43
    pmat[E5B][I5][1]=0.14
    pmat[E5B][I5][2]=0.07
    pmat[E5R][E2][0]=0.022
    pmat[E5R][E4][0]=0.007
    pmat[E5R][E5B][0]=0.08
    pmat[E5R][E5B][1]=0.25
    pmat[E5R][E5R][0]=0.191
    pmat[E5R][E5R][1]=0.14
    pmat[E5R][E6][0]=0.032
    pmat[E5R][I5L][0]=0.51
    pmat[E5R][I5][0]=0.43
    pmat[E5R][I5][1]=0.14
    pmat[E6][E2][0]=0
    pmat[E6][E4][0]=0
    pmat[E6][E5B][0]=0.028
    pmat[E6][E5R][0]=0.006
    pmat[E6][E6][0]=0.028
    pmat[E6][I6L][0]=0.51
    pmat[E6][I6][0]=0.43
    pmat[E6][I6][1]=0.14
    pmat[E2B][E2][0]=0.187
    pmat[E2B][E4][0]=0.024
    pmat[E2B][E5R][0]=0.057
    pmat[E2B][E6][0]=0
    pmat[E2B][E5B][0]=0.024
    pmat[E2B][E2B][0]=0.187
    pmat[E2B][I2L][0]=0.51
    pmat[E2B][I2][0]=0.43
    pmat[I2L][E2][0]=0.35
    pmat[I2L][E5B][0]=0.5
    pmat[I2L][E5R][0]=0.35
    pmat[I2L][E6][0]=0.25
    pmat[I2L][E2B][0]=0.35
    pmat[I2L][I2L][0]=0.09
    pmat[I2L][I2][0]=0.53
    pmat[I2L][I5][0]=0.53
    pmat[I2L][I6][0]=0.53
    pmat[I2][E2][0]=0.44
    pmat[I2][E2B][0]=0.44
    pmat[I2][I2L][0]=0.34
    pmat[I2][I2][0]=0.62
    pmat[I4L][E4][0]=0.35
    pmat[I4L][I4L][0]=0.09
    pmat[I4L][I4][0]=0.53
    pmat[I4][E4][0]=0.44
    pmat[I4][I4L][0]=0.34
    pmat[I4][I4][0]=0.62
    pmat[I5L][E2][0]=0.35
    pmat[I5L][E5B][0]=0.35
    pmat[I5L][E5R][0]=0.35
    pmat[I5L][E6][0]=0.25
    pmat[I5L][I2][0]=0.53
    pmat[I5L][I5L][0]=0.09
    pmat[I5L][I5][0]=0.53
    pmat[I5L][I6][0]=0.53
    pmat[I5][E5B][0]=0.44
    pmat[I5][E5R][0]=0.44
    pmat[I5][I5L][0]=0.34
    pmat[I5][I5][0]=0.62
    pmat[I6L][E2][0]=0.35
    pmat[I6L][E5B][0]=0.25
    pmat[I6L][E5R][0]=0.25
    pmat[I6L][E6][0]=0.35
    pmat[I6L][I2][0]=0.53
    pmat[I6L][I5][0]=0.53
    pmat[I6L][I6L][0]=0.09
    pmat[I6L][I6][0]=0.53
    pmat[I6][E6][0]=0.44
    pmat[I6][I6L][0]=0.34
    pmat[I6][I6][0]=0.62
  }

//* traubsetpmat - set pmat using traub single column densities
proc traubsetpmat () {
    //** inputs from superficial RS pyramidals (E2)
    pmat[E2][E2][0] = .05
    pmat[E2][E2B][0] = .05
    pmat[E2][I2][0]=pmat[E2][I2C][0]=pmat[E2][I2L][0]=.09
    pmat[E2][E4][0]=.003
    pmat[E2][E5B][0]=pmat[E2][E5R][0]=.06
    pmat[E2][I6][0]=pmat[E2][I6C][0]=pmat[E2][I6L][0]=.03
    pmat[E2][E6][0]=.003
  
    //** inputs from superficial FRB pyramidals (E2B)
    pmat[E2B][E2][0] = .1
    pmat[E2B][E2B][0] = .1
    pmat[E2B][I2][0]=pmat[E2B][I2C][0]=pmat[E2B][I2L][0]=.1
    pmat[E2B][E4][0]= .02
    pmat[E2B][E5B][0]=pmat[E2B][E5R][0]=.06
    pmat[E2B][I6][0]=pmat[E2B][I6C][0]=pmat[E2B][I6L][0]=.06
    pmat[E2B][E6][0]=.02
    
    //** inputs from superficial basket cells (I2)
    pmat[I2][E2][0]=pmat[I2][E2B][0]=.2222222 
    pmat[I2][I2][0]=pmat[I2][I2C][0]=pmat[I2][I2L][0]=.2222222
    pmat[I2][E4][0]=.2222222
    
    //** inputs from superficial axoaxonic cells (I2C)
    pmat[I2C][E2][0]=pmat[I2C][E2B][0]=.2222222
    pmat[I2C][E4][0]=.055555556
    pmat[I2C][E5B][0]=pmat[I2C][E5R][0]=pmat[I2C][E6][0]=.055555556
  
    //** inputs from superficial LTS interneurons (I2L)
    //all cortical glutamatergic and gabaergic cells get 20 inputs from I2L neurons
    //see appendix B , page 30
    pmat[I2L][E2][0]=pmat[I2L][I2][0]=pmat[I2L][I2C][0]=pmat[I2L][I2L][0]=.22222222
    pmat[I2L][E4][0]=pmat[I2L][E5B][0]=pmat[I2L][E5R][0]=pmat[I2L][E6][0]=.22222222
    pmat[I2L][I6][0]=pmat[I2L][I6C][0]=pmat[I2L][I6L][0]=.22222222
  
    //** inputs from layer 4 spiny stellate cells (E4)
    pmat[E4][E4][0]=.125
    pmat[E4][E2][0]=pmat[E4][E2B][0]=pmat[E4][I2][0]=pmat[E4][I2C][0]=pmat[E4][I2L][0]=.083333333
    pmat[E4][E5B][0]=pmat[E4][E5R][0]=pmat[E4][E6][0]=pmat[E4][I6][0]=pmat[E4][I6C][0]=pmat[E4][I6L][0]=.083333333
  
    //** inputs from tufted IB pyramidals (E5B)
    pmat[E5B][E2][0]=pmat[E5B][E2B][0]=.0025
    pmat[E5B][E5B][0]=.0625
    pmat[E5B][E5R][0]=pmat[E5B][E4][0]=pmat[E5B][E6][0]=.025
    pmat[E5B][I2][0]=pmat[E5B][I2C][0]=pmat[E5B][I2L][0]=pmat[E5B][I6][0]=pmat[E5B][I6C][0]=pmat[E5B][I6L][0]=.025
  
    //** inputs from tufted RS pyramidals (E5R)
    pmat[E5R][E2][0]=pmat[E5R][E2B][0]=.01
    pmat[E5R][E5R][0]=.05
    pmat[E5R][E4][0]=pmat[E5R][E5B][0]=pmat[E5R][E6][0]=.1
    pmat[E5R][I2][0]=pmat[E5R][I2C][0]=pmat[E5R][I2L][0]=pmat[E5R][I6][0]=pmat[E5R][I6C][0]=pmat[E5R][I6L][0]=.1
  
    //** inputs from nontufted RS pyramidals (E6)
    pmat[E6][E2][0]=pmat[E6][E2B][0]=pmat[E6][E5R][0]=pmat[E6][E5B][0]=pmat[E6][E4][0]=.02
    pmat[E6][I2][0]=pmat[E6][I2C][0]=pmat[E6][I2L][0]=pmat[E6][I6][0]=pmat[E6][I6C][0]=pmat[E6][I6L][0]=.02
    pmat[E6][E6][0]=.04
  
    //** inputs from deep basket cells (I6)
    pmat[I6][E4][0]=pmat[I6][E5B][0]=pmat[I6][E5R][0]=pmat[I6][E6][0]=pmat[I6][I6][0]=pmat[I6][I6C][0]=pmat[I6][I6L][0]=.2
  
    //** inputs from deep axoaxonic cells (I6C)
    pmat[I6C][E2][0]=pmat[I6C][E2B][0]=pmat[I6C][E4][0]=pmat[I6C][E5B][0]=pmat[I6C][E5R][0]=pmat[I6C][E6][0]=.02
  
    //** inputs from deep LTS interneurons (I6L)
    pmat[I6L][E2B][0]=pmat[I6L][E2][0]=pmat[I6L][I2][0]=pmat[I6L][I2C][0]=pmat[I6L][I2L][0]=.1
    pmat[I6L][E4][0]=pmat[I6L][E5B][0]=pmat[I6L][E5R][0]=pmat[I6L][E6][0]=pmat[I6L][I6][0]=pmat[I6L][I6C][0]=pmat[I6L][I6L][0]=.2 
  
  }

//* scalepmat - multiply values in pmat in 
proc scalepmat () { local fctr,from,to,cl
    fctr=$1
    for from=0,CTYPi-1 for to=0,CTYPi-1 for cl=0,1 pmat[from][to][cl] *= fctr
  }

//* myceil($1) - ceiling function
func myceil () { local tmp
    tmp = int($1)
    if($1>=0) {
        if( $1 - tmp > 0 ) return tmp + 1
        return $1
      } else {
        return tmp
      }
  }

//* setdivmat -- set it up based on pmat and numc
proc setdivmat () { local from,to,cl
    for from=0,CTYPi-1 for to=0,CTYPi-1 for cl=0,1 if(pmat[from][to][cl]) {
        div[from][to][cl] =  myceil(pmat[from][to][cl]*cpercol[to])
        conv[from][to][cl] = int(0.5 + pmat[from][to][cl]*cpercol[from])
      }
  }

//* setdelmats -- setup delm,deld
proc setdelmats () { local from,to,cl
    for from=0,CTYPi-1 for to=0,CTYPi-1 for cl=0,1 {
        delm[from][to][cl]=2.0
        deld[from][to][cl]=0.2
      }
  }

//* setwmat -- setup wmat entries -- intrinsic weights in network
// wmat dims : ctype ctype stype column
proc setwmat () { local from,to,cl,sy,gn
    for from=0,CTYPi-1 for to=0,CTYPi-1 for sy=0,STYPi-1 for cl=0,2 wmat[from][to][sy][cl]=0
    if(useoldwmat) { //weights from version 228 that Bill used & got from KMJ as EPSP/IPSP values
        wmat[E2][E2][AM][0]=0.78
        wmat[E2][E2][AM][1]=0.47
        wmat[E2][E4][AM][0]=0.36
        wmat[E2][E5B][AM][0]=0.36
        wmat[E2][E5R][AM][0]=0.93
        wmat[E2][E6][AM][0]=0
        wmat[E2][E2B][AM][0]=0.78
        wmat[E2][I2L][AM][0]=0.23
        wmat[E2][I2][AM][0]=0.23
        wmat[E2][I2][AM][1]=1.5
        wmat[E4][E2][AM][0]=0.58
        wmat[E4][E4][AM][0]=0.95
        wmat[E4][E5B][AM][0]=1.01
        wmat[E4][E5R][AM][0]=0.54
        wmat[E4][E6][AM][0]=2.27
        wmat[E4][I4L][AM][0]=0.23
        wmat[E4][I4][AM][0]=0.23
        wmat[E4][I4][AM][1]=1.5
        wmat[E5B][E2][AM][0]=0.26
        wmat[E5B][E2][AM][1]=0.47
        wmat[E5B][E2][AM][2]=0.47
        wmat[E5B][E4][AM][0]=0.17
        wmat[E5B][E5B][AM][0]=0.71
        wmat[E5B][E5B][AM][1]=0.47
        wmat[E5B][E5B][AM][2]=0.47
        wmat[E5B][E5R][AM][0]=0.24
        wmat[E5B][E5R][AM][1]=0.47
        wmat[E5B][E5R][AM][2]=0.47
        wmat[E5B][E6][AM][0]=0.49
        wmat[E5B][I2L][AM][1]=1.5
        wmat[E5B][I2L][AM][2]=1.5
        wmat[E5B][I5L][AM][0]=0.23
        wmat[E5B][I5L][AM][1]=1.5
        wmat[E5B][I5L][AM][2]=1.5
        wmat[E5B][I5][AM][0]=0.23
        wmat[E5B][I5][AM][1]=1.5
        wmat[E5B][I5][AM][2]=1.5
        wmat[E5R][E2][AM][0]=0.67
        wmat[E5R][E4][AM][0]=0.48
        wmat[E5R][E5B][AM][0]=0.88
        wmat[E5R][E5B][AM][1]=0.47
        wmat[E5R][E5R][AM][0]=0.66
        wmat[E5R][E5R][AM][1]=0.47
        wmat[E5R][E6][AM][0]=0.28
        wmat[E5R][I5L][AM][0]=0.23
        wmat[E5R][I5][AM][0]=0.23
        wmat[E5R][I5][AM][1]=1.5
        wmat[E6][E2][AM][0]=0
        wmat[E6][E4][AM][0]=0
        wmat[E6][E5B][AM][0]=0.53
        wmat[E6][E5R][AM][0]=0.08
        wmat[E6][E6][AM][0]=0.53
        wmat[E6][I6L][AM][0]=0.23
        wmat[E6][I6][AM][0]=0.23
        wmat[E6][I6][AM][1]=1.5
        wmat[E2B][E2][AM][0]=0.78
        wmat[E2B][E4][AM][0]=0.36
        wmat[E2B][E4][AM][0]=0.36
        wmat[E2B][E5R][AM][0]=0.93
        wmat[E2B][E6][AM][0]=0
        wmat[E2B][E2B][AM][0]=0.78
        wmat[E2B][I2L][AM][0]=0.23
        wmat[E2B][I2][AM][0]=0.23
     
        wmat[I2L][E2][GA][0]=0.83
        wmat[I2L][E5B][GA][0]=0.83
        wmat[I2L][E5R][GA][0]=0.83
        wmat[I2L][E6][GA][0]=0.83
        wmat[I2L][E2B][GA][0]=0.83
        wmat[I2L][I2L][GA][0]=1.5
        wmat[I2L][I2][GA][0]=1.5
        wmat[I2L][I5][GA][0]=0.83
        wmat[I2L][I6][GA][0]=0.83
        wmat[I2][E2][GA][0]=1.5
        wmat[I2][E2B][GA][0]=1.5
        wmat[I2][I2L][GA][0]=1.5
        wmat[I2][I2][GA][0]=1.5
        wmat[I4L][E4][GA][0]=0.83
        wmat[I4L][I4L][GA][0]=1.5
        wmat[I4L][I4][GA][0]=1.5
        wmat[I4][E4][GA][0]=1.5
        wmat[I4][I4L][GA][0]=1.5
        wmat[I4][I4][GA][0]=1.5
        wmat[I5L][E2][GA][0]=0.83
        wmat[I5L][E5B][GA][0]=0.83
        wmat[I5L][E5R][GA][0]=0.83
        wmat[I5L][E6][GA][0]=0.83
        wmat[I5L][I2][GA][0]=0.83
        wmat[I5L][I5L][GA][0]=1.5
        wmat[I5L][I5][GA][0]=1.5
        wmat[I5L][I6][GA][0]=0.83
        wmat[I5][E5B][GA][0]=1.5
        wmat[I5][E5R][GA][0]=1.5
        wmat[I5][I5L][GA][0]=1.5
        wmat[I5][I5][GA][0]=1.5
        wmat[I6L][E2][GA][0]=0.83
        wmat[I6L][E5B][GA][0]=0.83
        wmat[I6L][E5R][GA][0]=0.83
        wmat[I6L][E6][GA][0]=0.83
        wmat[I6L][I2][GA][0]=0.83
        wmat[I6L][I5][GA][0]=0.83
        wmat[I6L][I6L][GA][0]=1.5
        wmat[I6L][I6][GA][0]=1.5
        wmat[I6][E6][GA][0]=1.5
        wmat[I6][I6L][GA][0]=1.5
        wmat[I6][I6][GA][0]=1.5
      } else { //weights from calibwmat
        wmat[E6][E6][AM][0]=0.00508834
        wmat[E6][I6][AM][0]=0.00155713
        wmat[E6][I6][AM][1]=0.0106235
        wmat[E6][I6L][AM][0]=0.00101184
        wmat[E6][E5B][AM][0]=0.0120471
        wmat[E6][E5R][AM][0]=0.000757446
        wmat[I6][E6][GA][0]=0.744598
        wmat[I6][I6][GA][0]=0.178905
        wmat[I6][I6L][GA][0]=0.642838
        wmat[I6L][E6][GA][0]=0.152256
        wmat[I6L][I6][GA][0]=0.178905
        wmat[I6L][I6L][GA][0]=0.642838
        wmat[I6L][E5B][GA][0]=0.0453811
        wmat[I6L][E5R][GA][0]=0.152256
        wmat[I6L][I5][GA][0]=0.06624
        wmat[I6L][E2][GA][0]=0.152256
        wmat[I6L][I2][GA][0]=0.06624
        wmat[E5B][E6][AM][0]=0.00469847
        wmat[E5B][E5B][AM][0]=0.0163596
        wmat[E5B][E5B][AM][1]=0.010636
        wmat[E5B][E5B][AM][2]=0.010636
        wmat[E5B][E5R][AM][0]=0.00228355
        wmat[E5B][E5R][AM][1]=0.00450378
        wmat[E5B][E5R][AM][2]=0.00450378
        wmat[E5B][I5][AM][0]=0.00155713
        wmat[E5B][I5][AM][1]=0.0106235
        wmat[E5B][I5][AM][2]=0.0106235
        wmat[E5B][I5L][AM][0]=0.00101184
        wmat[E5B][I5L][AM][1]=0.00684911
        wmat[E5B][I5L][AM][2]=0.00684911
        wmat[E5B][E4][AM][0]=0.00161395
        wmat[E5B][E2][AM][0]=0.00247534
        wmat[E5B][E2][AM][1]=0.00450378
        wmat[E5B][E2][AM][2]=0.00450378
        wmat[E5B][I2L][AM][1]=0.00684911
        wmat[E5B][I2L][AM][2]=0.00684911
        wmat[E5R][E6][AM][0]=0.00266735
        wmat[E5R][E5B][AM][0]=0.0205432
        wmat[E5R][E5B][AM][1]=0.010636
        wmat[E5R][E5R][AM][0]=0.00636207
        wmat[E5R][E5R][AM][1]=0.00450378
        wmat[E5R][I5][AM][0]=0.00155713
        wmat[E5R][I5][AM][1]=0.0106235
        wmat[E5R][I5L][AM][0]=0.00101184
        wmat[E5R][E4][AM][0]=0.00460121
        wmat[E5R][E2][AM][0]=0.00646054
        wmat[I5][E5B][GA][0]=0.0947328
        wmat[I5][E5R][GA][0]=0.744598
        wmat[I5][I5][GA][0]=0.178905
        wmat[I5][I5L][GA][0]=0.642838
        wmat[I5L][E6][GA][0]=0.152256
        wmat[I5L][I6][GA][0]=0.06624
        wmat[I5L][E5B][GA][0]=0.0453811
        wmat[I5L][E5R][GA][0]=0.152256
        wmat[I5L][I5][GA][0]=0.178905
        wmat[I5L][I5L][GA][0]=0.642838
        wmat[I5L][E2][GA][0]=0.152256
        wmat[I5L][I2][GA][0]=0.06624
        wmat[E4][E6][AM][0]=0.0230554
        wmat[E4][E5B][AM][0]=0.0238183
        wmat[E4][E5R][AM][0]=0.00518589
        wmat[E4][E4][AM][0]=0.00924133
        wmat[E4][E4][NM][0]=0.00108665
        wmat[E4][I4][AM][0]=0.00155713
        wmat[E4][I4][AM][1]=0.0106235
        wmat[E4][I4L][AM][0]=0.00101184
        wmat[E4][E2][AM][0]=0.00557694
        wmat[I4][E4][GA][0]=0.744598
        wmat[I4][I4][GA][0]=0.178905
        wmat[I4][I4L][GA][0]=0.642838
        wmat[I4L][E4][GA][0]=0.152256
        wmat[I4L][I4][GA][0]=0.178905
        wmat[I4L][I4L][GA][0]=0.642838
        wmat[E2][E5B][AM][0]=0.00808216
        wmat[E2][E5R][AM][0]=0.00904101
        wmat[E2][E4][AM][0]=0.00343803
        wmat[E2][E2][AM][0]=0.00754708
        wmat[E2][E2][AM][1]=0.00450378
        wmat[E2][E2B][AM][0]=0.0215773
        wmat[E2][I2][AM][0]=0.00155713
        wmat[E2][I2][AM][1]=0.0106235
        wmat[E2][I2L][AM][0]=0.00101184
        wmat[E2B][E5R][AM][0]=0.00904101
        wmat[E2B][E4][AM][0]=0.00343803
        wmat[E2B][E2][AM][0]=0.00754708
        wmat[E2B][E2B][AM][0]=0.0215773
        wmat[E2B][I2][AM][0]=0.00155713
        wmat[E2B][I2L][AM][0]=0.00101184
        wmat[I2][E2][GA][0]=0.744598
        wmat[I2][E2B][GA][0]=0.0579643
        wmat[I2][I2][GA][0]=0.178905
        wmat[I2][I2L][GA][0]=0.642838
        wmat[I2L][E6][GA][0]=0.152256
        wmat[I2L][I6][GA][0]=0.06624
        wmat[I2L][E5B][GA][0]=0.0453811
        wmat[I2L][E5R][GA][0]=0.152256
        wmat[I2L][I5][GA][0]=0.06624
        wmat[I2L][E2][GA][0]=0.152256
        wmat[I2L][E2B][GA][0]=0.00843
        wmat[I2L][I2][GA][0]=0.178905
        wmat[I2L][I2L][GA][0]=0.642838
      }
    //set NMDA weights
    for ctt(&from) for ctt(&to) for cl=0,2 wmat[from][to][NM][cl]=NMAMR*wmat[from][to][AM][cl]
    //gain control
    for from=0,CTYPi-1 for to=0,CTYPi-1 for sy=AM,GA for cl=0,2 if(wmat[from][to][sy][cl] > 0) {
        if(ice(from)) {
            if(ice(to)) {
                gn = IIGain
              } else {
                gn = IEGain
              }
            if(IsLTS(from) && !IsLTS(to)) gn *= 0.5
          } else {
            if(ice(to)) {
                gn = EIGain
                if(IsLTS(to)) gn *= 0.5
              } else {
                gn = EEGain
                if(sy==NM) gn *= EENMGain // E->E NMDA gain
              }
          }
        wmat[from][to][sy][cl] *= gn 
      }
  }

//* IsLTS - return if type is LTS
func IsLTS () {
    return $1 == I2L || $1 == I4L || $1 == I5L || $1 == I6L 
  }
//* IsBurst - return if type is intrinsically bursting
func IsBurst () {
    return $1 == E2B || $1 == E5B
  }
//* IsFRB - return true if type is fast regular bursting
func IsFRB () {
    return $1 == E2B
  }
//* IsRS - return true if type is regular spiking E cell
func IsRS () {
    return $1 == E2 || $1 == E4 || $1 == E5R || $1 == E6
  }
//* IsRF - return true if type is fast spiking iterneuron
func IsFS () {
    return $1 == I2 || $1 == I4 || $1 == I5 || $1 == I6
  }
//* setvcwmat() -- setup wmat entries with values provided by vcu
// rules for weights
// E -> E AM weights are all at 0.025
// E -> E NM weights are all at 0.0025
// 
// I (FS) -> E or I GA weights are all at 0.15
// IL (LTS) -> E or I GA weights are all at 0.07
// 
// E -> I (FS) AM weights are all at 0.032
// E -> I (FS) NM weights are all at 0.0025
// 
// E -> IL (LTS) AM weights are all at 0.0035
// E -> IL (LTS) NM weights are all at 0.00025
// 
//for neighboring columns,  T1->T2 has same value as all E->E iff T1 == T2 and T1==E and T2==E
//T1->T2 has same value as E->I, iff T1 is E RS and T1,T2 are both in same layer and T2 is not LTS
proc setvcwmat () { local from,to,sy,lts,cl,gn,clm
    for ctt(&from) {
        if(ice(from)) { // I -> X
            sy = GA
            cl = 0
            if(IsLTS(from)) { // I LTS -> X
                for ctt(&to) if(div[from][to][cl] > 0) {
                    if(ice(to)) gn = IIGain else gn = IEGain
                    wmat[from][to][sy][cl] = 0.07 * gn
                  }
              } else { // I FS -> X
                for ctt(&to) if(div[from][to][cl] > 0) {
                    if(ice(to)) gn = IIGain else gn = IEGain
                    wmat[from][to][sy][cl] = 0.15 * gn
                  }
              }
          } else { // E -> X
            for ctt(&to) {
                if(to==from||(!IsBurst(from) && GetLyr(from)==GetLyr(to) && ice(to) && !IsLTS(to))){
                    clm=1
                  } else clm=0
                for cl=0,clm if(div[from][to][cl] > 0) {
                    if(ice(to)) { // E -> I
                        gn = EIGain 
                        if(IsLTS(to)) { // E -> I LTS
                            wmat[from][to][AM][cl] = 0.0035 * gn
                            wmat[from][to][NM][cl] = 0.00025 * gn
                          } else { // E -> I FS
                            wmat[from][to][AM][cl] = 0.032 * gn
                            wmat[from][to][NM][cl] = 0.0025 * gn
                          }
                      } else { // E -> E
                        gn = EEGain
            //            if(from==E4 && to==E4) gn *= 2
                        wmat[from][to][AM][cl] = 0.025 * gn
                        wmat[from][to][NM][cl] = 0.0025 * gn
                      }
                  }
              }
          }
      }
  }

//* traubsetwmat - set weights as in traub sim
// from page 34:
// AMPA conductances at spiny stellate -> spiny stellate connections are set to low or high values,
// by multiplying the baseline conductance by 0.25 or 2.0, respectively. In most simulations, all
// other AMPA conductances are twice the baseline values.  Likewise, in most simulations, NMDA
// conductances to cortical interneurons are multiplied by 0.2, as are NMDA conductances on nRT
// cells and TCR cells; cortical principal cell (pyramids and spiny stellates) have NMDA
// conductances multiplied by 2.5. Other rescalings are performed as described in the main text
proc traubsetwmat () { local ii,jj,kk,cl
    for ii=0,CTYPi-1 for jj=0,CTYPi-1 for kk=0,STYPi-1 for cl=0,1 wmat[ii][jj][kk][cl]=0
  
    //** AMPA
    //*** from superficial pyramidals (E2,E2B)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E2][E2][AM][0]=0.25 * EEGain
    wmat[E2][E2B][AM][0]=0.25 * EEGain
    wmat[E2B][E2][AM][0]=0.25 * EEGain
    wmat[E2B][E2B][AM][0]=0.25 * EEGain
    //**** to superficial fast spiking cells (I2,IC)
    wmat[E2][I2][AM][0]=3 * EIGain
    wmat[E2][IC][AM][0]=3 * EIGain
    wmat[E2B][I2][AM][0]=3 * EIGain
    wmat[E2B][IC][AM][0]=3 * EIGain
    //**** to superficial LTS cells (I2L)
    wmat[E2][I2L][AM][0]=2 * EIGain
    wmat[E2B][I2L][AM][0]=2 * EIGain
    //**** to spiny stellates (E4)
    wmat[E2][E4][AM][0]=0.1 * EEGain
    wmat[E2B][E4][AM][0]=0.1 * EEGain
    //**** to tufted pyramids (E5B,E5R)
    wmat[E2][E5B][AM][0]=0.1 * EEGain
    wmat[E2][E5R][AM][0]=0.1 * EEGain
    wmat[E2B][E5B][AM][0]=0.1 * EEGain
    wmat[E2B][E5R][AM][0]=0.1 * EEGain
    //**** to deep interneurons (I6,I6C,I6L)
    wmat[E2][I6][AM][0]=1 * EIGain
    wmat[E2][I6C][AM][0]=1 * EIGain
    wmat[E2][I6L][AM][0]=1 * EIGain
    wmat[E2B][I6][AM][0]=1 * EIGain
    wmat[E2B][I6C][AM][0]=1 * EIGain
    wmat[E2B][I6L][AM][0]=1 * EIGain
    //**** to layer 6 nontufted pyramidals (E6)
    wmat[E2][E6][AM][0]=0.5 * EEGain
    wmat[E2B][E6][AM][0]=0.5 * EEGain
    //*** from layer 4 spiny stellates (E4)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E4][E2][AM][0]=1 * EEGain
    wmat[E4][E2B][AM][0]=1 * EEGain
    //**** to superficial interneurons (I2,I2C,I2L)
    wmat[E4][I2][AM][0]=1 * EIGain
    wmat[E4][I2C][AM][0]=1 * EIGain
    wmat[E4][I2L][AM][0]=1 * EIGain
    //**** to other spiny stellates (E4)
    wmat[E4][E4][AM][0]=1 * EEGain
    //**** to deep pyramids and interneurons
    wmat[E4][E5B][AM][0]=1 * EEGain
    wmat[E4][E5R][AM][0]=1 * EEGain
    wmat[E4][E6][AM][0]=1 * EEGain
    wmat[E4][I6][AM][0]=1 * EIGain
    wmat[E4][I6C][AM][0]=1 * EIGain
    wmat[E4][I6L][AM][0]=1 * EIGain
    //*** from layer 5 tufted IB cells (E5B)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E5B][E2][AM][0]=0.5 * EEGain
    wmat[E5B][E2B][AM][0]=0.5 * EEGain
    //**** to superficial interneurons (I2,I2C,I2L)
    wmat[E5B][I2][AM][0]=1 * EIGain
    wmat[E5B][I2C][AM][0]=1 * EIGain
    wmat[E5B][I2L][AM][0]=1 * EIGain
    //**** to spiny stellates (E4)
    wmat[E5B][E4][AM][0]=0.5 * EEGain
    //**** to other tufted cells (E5B,E5R)
    wmat[E5B][E5B][AM][0]=2 * EEGain
    wmat[E5B][E5R][AM][0]=2 * EEGain
    //**** to deep fast spiking cells (I6,I6C)
    wmat[E5B][I6][AM][0]=3 * EIGain
    wmat[E5B][I6C][AM][0]=3 * EIGain
    //**** to deep LTS cells (I6L)
    wmat[E5B][I6L][AM][0]=2 * EIGain
    //**** to layer 6 nontufted pyramidals (E6)
    wmat[E5B][E6][AM][0]=2 * EEGain
    //*** from layer 5 tufted RS cells (E5R)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E5R][E2][AM][0]=0.5 * EEGain
    wmat[E5R][E2B][AM][0]=0.5 * EEGain
    //**** to superficial interneurons (I2,I2C,I2L)
    wmat[E5R][I2][AM][0]=1 * EIGain
    wmat[E5R][I2C][AM][0]=1 * EIGain
    wmat[E5R][I2L][AM][0]=1 * EIGain
    //**** to spiny stellates (E4)
    wmat[E5R][E4][AM][0]=0.5 * EEGain
    //**** to layer 5 tufted pyramidals (E5B,E5R)
    wmat[E5R][E5B][AM][0]=1 * EEGain
    wmat[E5R][E5R][AM][0]=1 * EEGain
    //**** to deep fast spiking cells (I6,I6C)
    wmat[E5R][I6][AM][0]=3 * EIGain
    wmat[E5R][I6C][AM][0]=3 * EIGain
    //**** to deep LTS cells (I6L)
    wmat[E5R][I6L][AM][0]=2 * EIGain
    //**** to layer 6 nontufted pyramidals (E6)
    wmat[E5R][E6][AM][0]=1 * EEGain
    //*** from layer 6 nontufted RS pyramidals (E6)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E6][E2][AM][0]=0.5 * EEGain
    wmat[E6][E2B][AM][0]=0.5 * EEGain
    //**** to superficial fast spiking cells (I2,I2C)
    wmat[E6][I2][AM][0]=1 * EIGain
    wmat[E6][I2C][AM][0]=1 * EIGain
    //**** to spiny stellate cells (E4)
    wmat[E6][E4][AM][0]=0.5 * EEGain
    //**** to tufted layer 5 pyramidals (E5B,E5R)
    wmat[E6][E5B][AM][0]=1 * EEGain
    wmat[E6][E5R][AM][0]=1 * EEGain
    //**** to deep fast spiking cells (I6,I6C)
    wmat[E6][I6][AM][0]=3 * EIGain
    wmat[E6][I6C][AM][0]=3 * EIGain
    //**** to deep LTS cells (I6L)
    wmat[E6][I6L][AM][0]=2 * EIGain
    //**** to other layer 6 nontufted RS pyramidals (E6)
    wmat[E6][E6][AM][0]=1 * EEGain
    
    //** NMDA
    //*** from superficial RS pyramidals (E2)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E2][E2][NM][0]=0.025 * EEGain
    wmat[E2][E2B][NM][0]=0.025 * EEGain
    //**** to superficial interneurons (I2,I2C,I2L)
    wmat[E2][I2][NM][0]=0.15 * EIGain
    wmat[E2][I2C][NM][0]=0.15 * EIGain
    wmat[E2][I2L][NM][0]=0.15 * EIGain
    //**** to spiny stellates (E4)
    wmat[E2][E4][NM][0]=0.01 * EEGain
    //**** to deep tufted pyramidals (E5B,E5R)
    wmat[E2][E5B][NM][0]=0.01 * EEGain
    wmat[E2][E5R][NM][0]=0.01 * EEGain
    //**** to deep fast spiking cells (I6,I6C)
    wmat[E2][I6][NM][0]=0.1 * EIGain
    wmat[E2][I6C][NM][0]=0.1 * EIGain
    //**** to deep LTS interneurons (I6L)
    wmat[E2][I6L][NM][0]=0.15 * EIGain
    //**** to deep nontufted RS pyramidals (E6)
    wmat[E2][E6][NM][0]=0.05 * EEGain
    //*** from superficial FRB pyramidals (E2B)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E2B][E2][NM][0]=0.025 * EEGain
    wmat[E2B][E2B][NM][0]=0.025 * EEGain
    //**** to superficial interneurons (I2,I2C,I2L)
    wmat[E2B][I2][NM][0]=0.1 * EIGain
    wmat[E2B][I2C][NM][0]=0.1 * EIGain
    wmat[E2B][I2L][NM][0]=0.1 * EIGain
    //**** to spiny stellates (E4)
    wmat[E2B][E4][NM][0]=0.01 * EEGain
    //**** to tufted deep pyramidals (E5B,E5R)
    wmat[E2B][E5B][NM][0]=0.01 * EEGain
    wmat[E2B][E5R][NM][0]=0.01 * EEGain
    //**** to deep interneurons (I6,I6C,I6L)
    wmat[E2B][I6][NM][0]=0.1 * EIGain
    wmat[E2B][I6C][NM][0]=0.1 * EIGain
    wmat[E2B][I6L][NM][0]=0.1 * EIGain
    //**** to deep nontufted pyramidals (E6)
    wmat[E2B][E6][NM][0]=0.05 * EEGain
    //*** from spiny stellates (E4)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E4][E2][NM][0]=0.1 * EEGain
    wmat[E4][E2B][NM][0]=0.1 * EEGain
    //**** to superficial interneurons (I2,I2C,I2L)
    wmat[E4][I2][NM][0]=0.15 * EIGain
    wmat[E4][I2C][NM][0]=0.15 * EIGain
    wmat[E4][I2L][NM][0]=0.15 * EIGain
    //**** to other spiny stellates (E4)
    wmat[E4][E4][NM][0]=0.1 * EEGain
    //**** to deep pyramidals, tufted and non tufted (E5R,E5B,E6)
    wmat[E4][E5R][NM][0]=0.1 * EEGain
    wmat[E4][E5B][NM][0]=0.1 * EEGain
    wmat[E4][E6][NM][0]=0.1 * EEGain
    //**** to deep interneurons (I6,I6C,I6L)
    wmat[E4][I6][NM][0]=0.15 * EIGain
    wmat[E4][I6C][NM][0]=0.15 * EIGain
    wmat[E4][I6L][NM][0]=0.15 * EIGain
    //*** from layer 5 tufted IB pyramidals (E5B)
    //**** to superficial pyramidals (E2,E2B)
    wmat[E5B][E2][NM][0]=0.05 * EEGain
    wmat[E5B][E2B][NM][0]=0.05 * EEGain
    //**** to superficial interneurons (I2,I2C,I2L)
    wmat[E5B][I2][NM][0]=0.15 * EIGain
    wmat[E5B][I2C][NM][0]=0.15 * EIGain
    wmat[E5B][I2L][NM][0]=0.15 * EIGain
    //**** to spiny stellates (E4)
    wmat[E5B][E4][NM][0]=0.05 * EEGain
    //**** to deep pyramidals (tufted and nontufted) (E5B,E5R,E6)
    wmat[E5B][E5B][NM][0]=0.2 * EEGain
    wmat[E5B][E5R][NM][0]=0.2 * EEGain
    wmat[E5B][E6][NM][0]=0.2 * EEGain
    //**** to deep interneurons (I6,I6C,I6L)
    wmat[E5B][I6][NM][0]=0.15 * EIGain
    wmat[E5B][I6C][NM][0]=0.15 * EIGain
    wmat[E5B][I6L][NM][0]=0.15 * EIGain
    //*** from layer 5 tufted RS pyramidals (E5R)
    //**** to superficial pyramidals (RS and FRB) (E2,E2B)
    wmat[E5R][E2][NM][0]=0.05 * EEGain
    wmat[E5R][E2B][NM][0]=0.05 * EEGain
    //**** to superficial interneurons (I2,I2C,I2L)
    wmat[E5R][I2][NM][0]=0.15 * EIGain
    wmat[E5R][I2C][NM][0]=0.15 * EIGain
    wmat[E5R][I2L][NM][0]=0.15 * EIGain
    //**** to spiny stellates (E4)
    wmat[E5R][E4][NM][0]=0.05 * EEGain
    //**** to deep pyramidals (tufted and nontufted) (E5R,E5B,E6)
    wmat[E5R][E5R][NM][0]=0.1 * EEGain
    wmat[E5R][E5B][NM][0]=0.1 * EEGain
    wmat[E5R][E6][NM][0]=0.1 * EEGain
    //**** to deep interneurons (I6,I6C,I6L)
    wmat[E5R][I6][NM][0]=0.1 * EIGain
    wmat[E5R][I6C][NM][0]=0.1 * EIGain
    wmat[E5R][I6L][NM][0]=0.1 * EIGain
    //*** from layer 6 nontufted pyramidals (E6)
    //**** to superficial pyramidals (RS and FRB) (E2,E2B)
    wmat[E6][E2][NM][0]=0.05 * EEGain
    wmat[E6][E2B][NM][0]=0.05 * EEGain
    //**** to superficial baskets (I2)
    wmat[E6][I2][NM][0]=0.1 * EIGain
    //**** to spiny stellates (E4)
    wmat[E6][E4][NM][0]=0.05 * EEGain
    //**** to tufted and nontufted pyramidals (E5B,E5R,E6)
    wmat[E6][E5B][NM][0]=0.1 * EEGain
    wmat[E6][E5R][NM][0]=0.1 * EEGain
    wmat[E6][E6][NM][0]=0.1 * EEGain
    //**** to deep interneurons (I6,I6C,I6L)
    wmat[E6][I6][NM][0]=0.1 * EIGain
    wmat[E6][I6C][NM][0]=0.1 * EIGain
    wmat[E6][I6L][NM][0]=0.1 * EIGain
  
    //** GABAA
    //*** from superficial basket cells (I2)
    //**** to superficial pyramidals (E2,E2B)
    wmat[I2][E2][GA][0]=1.2 * IEGain
    wmat[I2][E2B][GA][0]=1.2 * IEGain
    //**** to other superficial basket cells (I2)
    wmat[I2][I2][GA][0]=0.2 * IIGain
    //**** to superficial axoaxonic cells
    wmat[I2][I2C][GA][0]=0.2 * IIGain
    //**** to superficial LTS interneurons (I2L)
    wmat[I2][I2L][GA][0]=0.5 * IIGain
    //**** to spiny stellates (E4)
    wmat[I2][E4][GA][0]=0.1 * IEGain
    //*** from superficial axoaxonic cells (chandelier) (I2C)
    //**** to superficial pyramidals (E2,E2B)
    wmat[I2C][E2][GA][0]=1.2 * IEGain
    wmat[I2C][E2B][GA][0]=1.2 * IEGain
    //**** to spiny stellates (E4)
    wmat[I2C][E4][GA][0]=0.1 * IEGain
    //**** to deep pyramidals (tufted and nontufted) (E5R,E5B,E6)
    wmat[I2C][E5R][GA][0]=1 * IEGain
    wmat[I2C][E5B][GA][0]=1 * IEGain
    wmat[I2C][E6][GA][0]=1 * IEGain
    //*** from superficial LTS interneurons (I2L)
    //**** to superficial pyramidals (E2,E2B)
    wmat[I2L][E2][GA][0]=0.01 * IEGain
    wmat[I2L][E2B][GA][0]=0.01 * IEGain
    //**** to superficial fast spiking cells (I2,I2C)
    wmat[I2L][I2][GA][0]=0.01 * IIGain
    wmat[I2L][I2C][GA][0]=0.01 * IIGain
    //**** to superficial LTS cells (I2L)
    wmat[I2L][I2L][GA][0]=0.05 * IIGain
    //**** to spiny stellates (E4)
    wmat[I2L][E4][GA][0]=0.01 * IEGain
    //**** to tufted pyramidals (E5B,E5R)
    wmat[I2L][E5B][GA][0]=0.02 * IEGain
    wmat[I2L][E5R][GA][0]=0.02 * IEGain
    //**** to deep fast spiking cells (I6,I6C)
    wmat[I2L][I6][GA][0]=0.01 * IIGain
    wmat[I2L][I6C][GA][0]=0.01 * IIGain
    //**** to deep LTS cells (I6L)
    wmat[I2L][I6L][GA][0]=0.05 * IIGain
    //**** to nontufted deep pyramidals (E6)
    wmat[I2L][E6][GA][0]=0.01 * IEGain
    //*** from deep basket cells (I6)
    //**** to spiny stellates (E4)
    wmat[I6][E4][GA][0]=1.5 * IEGain
    //**** to tufted pyramidals (E5B,E5R)
    wmat[I6][E5B][GA][0]=0.7 * IEGain
    wmat[I6][E5R][GA][0]=0.7 * IEGain
    //**** to deep fast spiking cells (I6,I6C)
    wmat[I6][I6][GA][0]=0.2 * IIGain
    wmat[I6][I6C][GA][0]=0.2 * IIGain
    //**** to deep LTS cells (I6L)
    wmat[I6][I6L][GA][0]=0.7 * IIGain
    //**** to deep nontufted pyramidals (E6)
    wmat[I6][E6][GA][0]=0.7 * IEGain
    //*** from deep axoaxonic cells (I6C)
    //**** to superficial pyramidals (E2B,E2)
    wmat[I6C][E2B][GA][0]=1 * IEGain
    wmat[I6C][E2][GA][0]=1 * IEGain
    //**** to spiny stellates
    wmat[I6C][E4][GA][0]=1.5 * IEGain
    //**** to deep pyramidals (tufted and nontufted) (E5B,E5R,E6)
    wmat[I6C][E5B][GA][0]=1 * IEGain
    wmat[I6C][E5R][GA][0]=1 * IEGain
    wmat[I6C][E6][GA][0]=1 * IEGain
    //*** from deep LTS cells (I6L)
    //**** to superficial pyramidals (E2B,E2)
    wmat[I6L][E2B][GA][0]=0.01 * IEGain
    wmat[I6L][E2][GA][0]=0.01 * IEGain
    //**** to superficial fast spiking cells (I2,I2C)
    wmat[I6L][I2][GA][0]=0.01 * IIGain
    wmat[I6L][I2C][GA][0]=0.01 * IIGain
    //**** to superficial LTS cells (I2L)
    wmat[I6L][I2L][GA][0]=0.05 * IIGain
    //**** to spiny stellates (E4)
    wmat[I6L][E4][GA][0]=0.01 * IEGain
    //**** to tufted IB pyramidals (E5B)
    wmat[I6L][E5B][GA][0]=0.05 * IEGain
    //**** to tufted RS pyramidals (E5R)
    wmat[I6L][E5R][GA][0]=0.02 * IEGain
    //**** to deep fast spiking cells (I6,I6C)
    wmat[I6L][I6][GA][0]=0.01 * IIGain
    wmat[I6L][I6C][GA][0]=0.01 * IIGain
    //**** to deep LTS cells (I6L)
    wmat[I6L][I6L][GA][0]=0.05 * IIGain
    //**** to deep nontufted pyramidals (E6)
    wmat[I6L][E6][GA][0]=0.01 * IEGain
  }

//* scalewmat($1) - mult each entry in wmat by $1
proc scalewmat () { local fctr,from,to,cl,sy
    fctr=$1
    for from=0,CTYPi-1 for to=0,CTYPi-1 for sy=0,STYPi-1 for cl=0,1 wmat[from][to][sy][cl] *= fctr
  }

//* create cells
proc creatns () { local ii,jj,ty,n,m,cn localobj vc
    if (ce==nil) ce=new List()  
    ce.remove_all  m=0
    for ctt(&ty) { 
        if (numc[ty]>0) { cn=jj=0
            for ii=ix[ty],ixe[ty] {
                if(jj>0 && jj%cpercol[ty]==0) cn+=1 //column #
                ce.append(new CELL(m,ty,cn))
                m += 1
                jj += 1
              }
          }
      }
    mc=ce.o(0)
    access mc.soma
  }

//* synapse locations DEND SOMA AXON
proc setsynloc () { local from,to
    for ctt(&from) for ctt(&to) {
        if(ice(from)) {
            if(from==I2L || from==I5L) {
                synloc[from][to]=DEND
              } else {
                synloc[from][to]=SOMA
              }
          } else {
            synloc[from][to]=DEND
          }
      }
  }

//* learnwts - applies synaptic learning via LearnGainLO and LearnGainHI to all internal synapses
proc learnwts () { local i,se,a,lgn localobj myrd,vg,nc
    a=allocvecs(vg)
    if(numarg()>0) se=$1 else se=1234
    myrd=new Random()
    myrd.ACG(se)
    vg.resize(ncl.count)
    myrd.uniform(LearnGainLO,LearnGainHI)
    vg.setrand(myrd)
    for ltr(nc,ncl,&i) nc.weight *= vg.x(i)
    dealloc(a)
  }

//* wirecol(columnID1,columnID2) - wire cells from columnID1->columnID2, iff IDs are equal
//wire within a column
proc wirecol () { local a,cl1,cl2,from,to,ic,y,dv,dly,prid,poid,cdx,lgn\
                   localobj nc,opr,opo,v1,v2,v3,v4,l
    cl1=$1 cl2=$2//column IDs
    a=allocvecs(v1,v2,v3,v4) l=new List() l.append(v1) l.append(v4)
    if(cl1==cl2) {
        printf("wiring column %d\n",cl1)
        cdx=0//intra-column index
      } else {
        printf("connecting column %d to %d\n",cl1,cl2)
        cdx=1//inter-column index
      }
    for ctt(&from) for ctt(&to) if(div[from][to][cdx]>0) {
        dv=div[from][to][cdx]
        ic=ice(from) //inhib?
        for prid=Cix[cl1][from],Cixe[cl1][from] {
            opr=ce.o(prid) //presynaptic cell
            vrsz(4*dv,v1,v2,v3)
            v3.setrnd(5,cpercol[to]) v3.add(Cix[cl2][to])
            if(cl1==cl2 && from==to) { //kill self connect
                v1.cull(v3,prid) v3.copy(v1) v2.resize(v3.size)
              } 
            cnt=v3.uniq(l,1) //puts unsorted uniq vals into v4
            if(cnt>dv)cnt=dv
            vrsz(cnt,v2,v4) //v4 has poids
            v2.setrnd(4,2*deld[from][to][cdx]) //flag 4 provides doubles
            v2.add(delm[from][to][cdx]).sub(deld[from][to][cdx])
            v2.abs() //no negative delays
            if(ic) {
                for vtr2(&poid,&dly,v4,v2) {
                    opo = ce.o(poid)
          
                    opr.connect2target(opo.gabaa[synloc[from][to]],nc) //make inhibitory synapse
                    nc.delay=dly
                    nc.weight=wmat[from][to][GA][cdx]
                    ncl.append(nc)
                    nclnq.append(opr.id,opo.id,opr.type,opo.type,GA,ncl.count-1,opr.col,opo.col)
                  }
              } else {
                for vtr2(&poid,&dly,v4,v2) {
                    opo = ce.o(poid)
          
                    opr.connect2target(opo.ampa,nc) //make excitatory AMPA synapse
                    nc.delay=dly
                    nc.weight=wmat[from][to][AM][cdx]
                    ncl.append(nc)
                    nclnq.append(opr.id,opo.id,opr.type,opo.type,AM,ncl.count-1,opr.col,opo.col)
                    
                    opr.connect2target(opo.nmda,nc) //make excitatory NMDA synapse
                    nc.delay=dly
                    nc.weight=wmat[from][to][NM][cdx]
                    ncl.append(nc)
                    nclnq.append(opr.id,opo.id,opr.type,opo.type,NM,ncl.count-1,opr.col,opo.col)
                  }
              }      
          }
      }
    dealloc(a)
  }

//* wirecols -- setup connectivity directly from div, wires inter/intra columns
proc wirecols () { local cl,lseed
    if(numarg()>0)lseed=$1 else lseed=1234
    hashseed_stats(lseed,lseed,lseed)
    if(ncl==nil) ncl=new List()
    if(nclnq==nil) nclnq=new NQS("prid","poid","prty","poty","sy","ncID","prcl","pocl") else {
        nclnq.clear() }
    for cl=0,numcols-1 wirecol(cl,cl)
    for cl=1,numcols-1 {
        wirecol(cl-1,cl)
        wirecol(cl,cl-1)
      }
  }

//* sywtsoff(synapse type) - turn off weights in ncl between cells with synapses of type $1
proc sywtsoff () { local idx,sy
    sy=$1
    if(nclnq.select(-1,"sy",sy)) for vtr(&idx,nclnq.ind) ncl.o(nclnq.v[5].x(idx)).weight=0
  }

//* wtsoff(celltypevec,syntypevec,columnvec) -- turn off weights in specificed vectors
proc wtsoff () { local ct,sy,cl,idx,ncID localobj vct,vst,vcol,opr,ofth,opo,nc
    vct=$o1 vst=$o2 vcol=$o3
    for vtr(&cl,vcol) for vtr(&ct,vct) for vtr(&sy,vst) for idx=Cix[cl][ct],Cixe[cl][ct] {
        nclnq.select(-1,"prid",idx)
        for vtr(&idx,nclnq.ind) ncl.o(nclnq.v[5].x(idx)).weight=0
      }
  }

//* wtson(celltypevec,syntypevec,columnvec) -- turn on weights in specificed vectors
proc wtson () { local ct,sy,cl,idx,ncID,ci localobj vct,vst,vcol,opr,ofth,opo,nc
    vct=$o1 vst=$o2 vcol=$o3
    for vtr(&cl,vcol) for vtr(&ct,vct) for vtr(&sy,vst) for idx=Cix[cl][ct],Cixe[cl][ct] {
        nclnq.select(-1,"prid",idx)
        for vtr(&idx,nclnq.ind) {
            ci = (ce.o(idx).col != nclnq.v[7].x(idx))
            ncl.o(nclnq.v[5].x(idx)).weight=wmat[nclnq.v[2].x(idx)][nclnq.v[3].x(idx)][sy][ci]
          }
      }
  }

//** setwt() reset weights and delays
proc setwt () { local cdx,i,setdel,from,to,sy localobj nc
    if (numarg()==1) setdel=1 else setdel=0
    setwtmat()
    if(wmatfctr!=1) scalewmat(wmatfctr)
    for i=0,nclnq.size(1)-1 {
        from=nclnq.v[2].x(i) to=nclnq.v[3].x(i) sy=nclnq.v[4].x(i) ic=ice(from)
        cdx = (nclnq.v[6].x(idx)!=nclnq.v[7].x(idx))
        nc=ncl.o(nclnq.v[5].x(i))
        nc.weight=wmat[from][to][sy][cdx]
        if (setdel) { // ??
            //v2.setrnd(4,2*deld[from][to][cdx]) //flag 4 provides doubles
            //v2.add(delm[from][to][cdx]).sub(deld[from][to][cdx])
            //v2.abs() //no negative delays
          }
      }
  }

//* allwtsoff -- turn all internal weights off
proc allwtsoff () { localobj xo
    for ltr(xo,ncl) xo.weight = 0
  }

//* prdivinf -- print pmat,div,synapse info
func prdivinf () { local sy,syt,ct1,ct2,cl,dubE localobj s1,s2
    sy=ct1=ct2=cl=syt=0
    if(numarg()>0)dubE=$1 else dubE=1//count AMPA,NMDA separately
    s1=new String() s2=new String()
    for cl=0,0 for ctt(&ct1) for ctt(&ct2) if(pmat[ct1][ct2][cl]>0) {
        s1.s=CTYP.o(ct1).s
        s2.s=CTYP.o(ct2).s
        printf("pmat[%s][%s][%d]=%g\tdiv[%s][%s][%d]=%d\t",\
               s1.s,s2.s,cl,pmat[ct1][ct2][cl],\
               s1.s,s2.s,cl,div[ct1][ct2][cl])
        if(cl==0) {
            sy = numcols*div[ct1][ct2][cl]*cpercol[ct1]
            if(!ice(ct1) && dubE) sy*=2
            syt += sy
          } else {
            sy = 2*(numcols-1)*div[ct1][ct2][cl]*cpercol[ct1]
            if(!ice(ct1) && dubE) sy*=2
            syt += sy
          }
        printf("syns=%d\n",sy)
      }
    printf("total synapses = %d\n",syt)
    return syt
  }

//* calibwmat -- get an NQS that attempts to calibrate wmat's conductance values so EPSPs produced are
//same as original wmat entries. it assumes that original values in wmat are in units of mV. it then
//attempts to find the conductance values that will create the EPSP/IPSP of these values for each of
//the cell types, pre/po/sy/col. it doesnt change the values of wmat itself. the wmatnew column in the
//output nqs contains the new wmat value found.
//objref NC,NS
obfunc calibwmat () { local prty,poty,sy,col,epsporig,epspnew,fctr,mnw,mxw,curw,eps,targ,i,df\
                       localobj nqt,VC,NS,RS,IB,FRB,LTS,FS,LVC,CC
    if(celldbg==0 || allcells!=1) {
        printf("calibwmat ERRA: must be in single celldbg mode!\n")
        return nil
      }  
    {NS=new NetStim(.5)  NS.number=1  NS.interval=200  NS.start=20  NS.noise=0  LVC=new List()}
    if(ce.count==1) { //setup cells for calibrating wmat
        ncl.remove_all
        {ce.append(( RS = new CELL(1,E2) ))   ix[E2]=ixe[E2]=1     new_printlist_item("ce.o(1).axon.v(0.5)","RS_AxonV")}
        LVC.append(printlist.o(printlist.count-1).vec)
        {ce.append(( IB = new CELL(2,E5B) ))  ix[E5B]=ixe[E5B]=2   new_printlist_item("ce.o(2).axon.v(0.5)","IB_AxonV")}
        LVC.append(printlist.o(printlist.count-1).vec)
        {ce.append(( FRB = new CELL(3,E2B) )) ix[E2B]=ixe[E2B]=3   new_printlist_item("ce.o(3).axon.v(0.5)","FRB_AxonV")}
        LVC.append(printlist.o(printlist.count-1).vec)
        {ce.append(( LTS = new CELL(4,I2L) )) ix[I2L]=ixe[I2L]=4   new_printlist_item("ce.o(4).axon.v(0.5)","LTS_AxonV")}
        LVC.append(printlist.o(printlist.count-1).vec)
        {ce.append(( FS = new CELL(5,I2) ))   ix[I2]=ixe[I2]=5     new_printlist_item("ce.o(5).axon.v(0.5)","FS_AxonV")}
        LVC.append(printlist.o(printlist.count-1).vec)
        for i=0,5 { //setup NetCons
            ncl.append(new NetCon(NS,ce.o(i).ampa))  ncl.append(new NetCon(NS,ce.o(i).nmda))
            ncl.append(new NetCon(NS,ce.o(i).gabaa[0]))  ncl.append(new NetCon(NS,ce.o(i).gabaa[1]))
          }
        {RSparams()    IBparams()    FRBparams()    LTSparams()    FSparams()}
        FRB.stim.amp=0 // turn off persistent stim to E2B so can measure EPSPs better
      }
    nqt=new NQS("sprty","spoty","prty","poty","sy","col","wmatorig","EPSPorig","wmatnew","EPSPnew","dif")
    {nqt.strdec("sprty") nqt.strdec("spoty")}
    {tstop=100   eps=0.00001}
    for ltr(nc,ncl) nc.weight=0//make sure weights @ 0
    for prty=0,CTYPi-1 for poty=0,CTYPi-1 {
        if(IsRS(poty)){
            CC = RS      VC = LVC.o(0) //voltage @ axon
          } else if(IsBurst(poty)) {
            if(poty==E5B) {
                CC = IB        VC = LVC.o(1)
              } else {
                CC = FRB        VC = LVC.o(2)
              }
          } else if(IsLTS(poty)) {
            CC = LTS      VC = LVC.o(3)
          } else {
            CC = FS      VC = LVC.o(4)
          }
        for sy=AM,GA for col=0,2 if((targ=wmat[prty][poty][sy][col])!=0) {
            print "prty ",CTYP.o(prty).s,", poty ",CTYP.o(poty).s," sy ",sy," col ",col,"target: ",targ
            if(sy==AM) {
                nc = ncl.o(CC.id*4 + 0)
              } else if(sy==NM) {
                nc = ncl.o(CC.id*4 + 1)
              } else if(sy==GA) {
                if(synloc[prty][poty]==DEND) {
                    nc = ncl.o(CC.id*4 + 2)
                  } else {
                    nc = ncl.o(CC.id*4 + 3)
                  }
              }
            {nc.weight=targ      run()} // original 
            epspnew=epsporig=abs(VC.max-VC.min) mnw=0 mxw=targ
            print "epsporig ", epsporig
            while((df=abs(epspnew-targ)) > eps && mxw-mnw > 1e-12 ) {
                curw = (mnw + mxw) / 2
                printf("\tcurw:%g,epspnew:%g,mnw:%g,mxw:%g,mxw-mnw:%g,abs(epspnew-targ):%g\n",curw,epspnew,mnw,mxw,mxw-mnw,df)
                {nc.weight=curw        run()} //set current weight & run        
                if((epspnew=abs(VC.max-VC.min)) > targ) { //adjust search bounds for new weight
                    mxw=curw
                  } else {
                    mnw=curw
                  }
              }
            printf("\tfin. curw:%g,epspnew:%g,mnw:%g,mxw:%g,mxw-mnw:%g,abs(epspnew-targ):%g\n",curw,epspnew,mnw,mxw,mxw-mnw,df)
            if(sy==GA) {
                epspnew*=-1 epsporig*=-1
              }
            nqt.append(CTYP.o(prty).s,CTYP.o(poty).s,prty,poty,sy,col,targ,epsporig,nc.weight,epspnew,df)
            nc.weight=0//reset to 0
          }
      }
    return nqt
  }

//* function calls to setup network

setcpercolkmj() //new VCU numbers (09aug24)

if(celldbg) {
    for ct=0,CTYPi-1 cpercol[ct]=0
    cpercol[celldbgty]=1
  }

setarrs()
setpmat()

if(pmatfctr!=1) scalepmat(pmatfctr)

setdivmat()
setwmat() // new KMJ version

if(wmatfctr!=1) scalewmat(wmatfctr)

setsynloc()
setdelmats()

creatns()
if(celldbg==0) wirecols(wireseed) else printf("no wiring: celldbg==1\n")

// setup synaptic learning
if(LearnGainLO!=1 && LearnGainHI!=1 && LearnGainLO<LearnGainHI) learnwts()


// END network.hoc
//================================================================
//================================================================
// INSERTED params.hoc
// =Id=  params.hoc,v 1.139 2010/11/01 02:12:51 samn Exp 

//* declarations
double wmatintf[CTYPi+1][STYPi+1] //weights for intf stims

//* general params
declare("mytstop",1e3)
tstop=mytstop
v_init = 1e3 //let e_pas settle on its own

//* param for cells
declare("E2BAmp",0.2) //current injection amount for E2B cells, used in FRBParams

//* random input params

declare("sgrhzE",200,"sgrhzI",100) // frequency(Hz) of random excitatory(AMPA),inhibitory inputs
declare("sgrhzNM",200) // frequency(Hz) of random inputs to NMDA synapses
declare("sgrdel",0) //onset
declare("sgrdur",tstop-sgrdel) //duration
declare("sgrhzdel",0.2)//variance in sgrhz for an INTF
declare("sgron",1)//iff==1 supply random inputs
declare("sgrTY",-1)//type to provide rand inputs to, only used iff not == -1

//INTWTSOFF: 1 == turn off internal weights entirely, 0.5 == turned off internal weights to 50%,
//0==leave all internal weights on, -1==turn off internal GABAA weights
declare("INTWTSOFF",0)

//** IClamp stimulation -- if popclmp() called
declare("sgrpp",100) //% of cells to stim
sgrcc=E5R //type of cells to stim
sgramp=1.25 //amplitude
declare("DEND",0) //compartment codes
declare("SOMA",1)
declare("AXON",2)
declare("sgrloc",DEND) //compartment to stim

//** other params for INTFs
declare("scrsz",10e3)
declare("combEIntf",0)//combine NMDA,AMPA on dend to have a single INTF source
declare("grpINTF",0)//group INTFs so that each column shares same INTFs
declare("INTFPerCol",60)//60 INTFs per column
declare("EXGain",1)//gain for external INTFs

//** rand input weights
proc initintfwm () { local ct,sy,a localobj vadjam,vadjnm,vadjga
    {a=allocvecs(vadjam,vadjnm,vadjga) vrsz(CTYPi+1,vadjam,vadjnm,vadjga)}
    {vadjam.fill(1) vadjnm.fill(1) vadjga.fill(1)}
    if(INTWTSOFF==-1) {
        vadjga.fill(0)//turns off external GABAA
      } else if(INTWTSOFF>0) {
        vadjga.mul(INTWTSOFF)    vadjam.mul(INTWTSOFF)    vadjnm.mul(INTWTSOFF)
      }
    for ctt(&ct) if(sgrTY==-1 || ct==sgrTY) {
        if(IsLTS(ct)) {
            wmatintf[ct][AM] = 0.080  * vadjam.x(ct)  * .5 * EXGain
            wmatintf[ct][NM] = 0.0125 * vadjnm.x(ct)  * EXGain
            wmatintf[ct][GA] = 0.250  * vadjga.x(ct)  * EXGain
          } else {
            if(ice(ct)) {
                wmatintf[ct][NM] = 0.05 * vadjnm.x(ct)  * EXGain
              } else {
                wmatintf[ct][NM] = 0.025 * vadjnm.x(ct) * EXGain
              }
            wmatintf[ct][AM] = 0.25 * vadjam.x(ct)    * EXGain
            wmatintf[ct][GA] = 0.125 * vadjga.x(ct)   * EXGain
          }
      }
    dealloc(a)
  }

//* setintfwmdisconn -- set external weights to match rates of normal network
// to be used when internal rates off (with allwtsoff() )
proc setintfwmdisconn () {
    initintfwm() //initialize normal external weights
    //reset particular ones that need adjusting
    {wmatintf[E6 ][AM ] *= .76   wmatintf[E6 ][NM ] *= .78   wmatintf[E6 ][GA ] *= 1}           //
    {wmatintf[I6 ][AM ] *= .464   wmatintf[I6 ][NM ] *= .35   wmatintf[I6 ][GA ] *= 1}          //
    {wmatintf[I6L ][AM ] *= 1.48   wmatintf[I6L ][NM ] *= 1.   wmatintf[I6L ][GA ] *= 1}        //
    {wmatintf[E5B ][AM ] *= .677   wmatintf[E5B ][NM ] *= .6   wmatintf[E5B ][GA ] *= 1}        //
    {wmatintf[E5R ][AM ] *= .942   wmatintf[E5R ][NM ] *= .94   wmatintf[E5R ][GA ] *= 1 }      // 
    {wmatintf[I5 ][AM ] *= .5   wmatintf[I5 ][NM ] *= .5   wmatintf[I5 ][GA ] *= 1 }            //
    {wmatintf[I5L ][AM ] *= 2.77   wmatintf[I5L ][NM ] *= 1.1   wmatintf[I5L ][GA ] *= 1 }      //
    {wmatintf[E4 ][AM ] *= 1.15   wmatintf[E4 ][NM ] *= 1.05   wmatintf[E4 ][GA ] *= 1 }        //
    {wmatintf[I4 ][AM ] *= .638   wmatintf[I4 ][NM ] *= .6   wmatintf[I4 ][GA ] *= 1 }          //
    {wmatintf[I4L ][AM ] *= 1.65   wmatintf[I4L ][NM ] *= 1.05   wmatintf[I4L ][GA ] *= 1 }     //
    {wmatintf[E2 ][AM ] *= .92   wmatintf[E2 ][NM ] *= .95   wmatintf[E2 ][GA ] *= 1 }          //
    {wmatintf[E2B ][AM ] *= 2.05   wmatintf[E2B ][NM ] *= 1.05   wmatintf[E2B ][GA ] *= 1 }     //
    {wmatintf[I2 ][AM ] *= .565   wmatintf[I2 ][NM ] *= .5   wmatintf[I2 ][GA ] *= 1 }          //
    {wmatintf[I2L ][AM ] *= 3.78   wmatintf[I2L ][NM ] *= 1.05   wmatintf[I2L ][GA ] *= 1   }   //
    setintfwghts() //sets external weights
  }

//* setintfwminterm(internal gain scale factor) -- set external weights to match rates of normal network
// to be used when internal weights @ intermediate level (i.e., multiply default gains by 0.5)
proc setintfwminterm () {
    initintfwm() //initialize normal external weights
    if($1==0.5) {   //reset particular ones that need adjusting
        {wmatintf[E6 ][AM ] *= 1.4   wmatintf[E6 ][NM ] *= 1   wmatintf[E6 ][GA ] *= 1}           
        {wmatintf[I6 ][AM ] *= 1.11   wmatintf[I6 ][NM ] *= 1   wmatintf[I6 ][GA ] *= 1}          
        {wmatintf[I6L ][AM ] *= 1.44   wmatintf[I6L ][NM ] *= 1.   wmatintf[I6L ][GA ] *= 1}        
        {wmatintf[E5B ][AM ] *= 1.38   wmatintf[E5B ][NM ] *= 1   wmatintf[E5B ][GA ] *= 1}        
        {wmatintf[E5R ][AM ] *= 1.8   wmatintf[E5R ][NM ] *= 1   wmatintf[E5R ][GA ] *= 1 }       
        {wmatintf[I5 ][AM ] *= 1.3   wmatintf[I5 ][NM ] *= 1   wmatintf[I5 ][GA ] *= 1 }            
        {wmatintf[I5L ][AM ] *= 2.5   wmatintf[I5L ][NM ] *= 1.1   wmatintf[I5L ][GA ] *= 1 }      
        {wmatintf[E4 ][AM ] *= 1.84   wmatintf[E4 ][NM ] *= 1.05   wmatintf[E4 ][GA ] *= 1 }        
        {wmatintf[I4 ][AM ] *= 1.55   wmatintf[I4 ][NM ] *= .8   wmatintf[I4 ][GA ] *= 1 }          
        {wmatintf[I4L ][AM ] *= 1.83   wmatintf[I4L ][NM ] *= 1.05   wmatintf[I4L ][GA ] *= 1 }     
        {wmatintf[E2 ][AM ] *= 2.04   wmatintf[E2 ][NM ] *= 1   wmatintf[E2 ][GA ] *= 1 }          
        {wmatintf[E2B ][AM ] *= 2.61   wmatintf[E2B ][NM ] *= 1.05   wmatintf[E2B ][GA ] *= 1 }     
        {wmatintf[I2 ][AM ] *= 1.46   wmatintf[I2 ][NM ] *= 1   wmatintf[I2 ][GA ] *= 1 }          
        {wmatintf[I2L ][AM ] *= 3.62   wmatintf[I2L ][NM ] *= 1.05   wmatintf[I2L ][GA ] *= 1   }   
      } else if($1==0.25) {
        {wmatintf[E6 ][AM ] *= 1.245   wmatintf[E6 ][NM ] *= 1   wmatintf[E6 ][GA ] *= 1}           
        {wmatintf[I6 ][AM ] *= 0.77   wmatintf[I6 ][NM ] *= 0.9   wmatintf[I6 ][GA ] *= 1}          
        {wmatintf[I6L ][AM ] *= 1.54   wmatintf[I6L ][NM ] *= 1.   wmatintf[I6L ][GA ] *= 1}        
        {wmatintf[E5B ][AM ] *= 1.22   wmatintf[E5B ][NM ] *= 1   wmatintf[E5B ][GA ] *= 1}        
        {wmatintf[E5R ][AM ] *= 1.65   wmatintf[E5R ][NM ] *= 1   wmatintf[E5R ][GA ] *= 1 }       
        {wmatintf[I5 ][AM ] *= 0.93   wmatintf[I5 ][NM ] *= 0.95   wmatintf[I5 ][GA ] *= 1 }            
        {wmatintf[I5L ][AM ] *= 2.95   wmatintf[I5L ][NM ] *= 1.1   wmatintf[I5L ][GA ] *= 1 }      
        {wmatintf[E4 ][AM ] *= 1.85   wmatintf[E4 ][NM ] *= 1.05   wmatintf[E4 ][GA ] *= 1 }        
        {wmatintf[I4 ][AM ] *= 1.425   wmatintf[I4 ][NM ] *= .8   wmatintf[I4 ][GA ] *= 1 }          
        {wmatintf[I4L ][AM ] *= 2.155   wmatintf[I4L ][NM ] *= 1.05   wmatintf[I4L ][GA ] *= 1 }     
        {wmatintf[E2 ][AM ] *= 1.825   wmatintf[E2 ][NM ] *= 1   wmatintf[E2 ][GA ] *= 1 }          
        {wmatintf[E2B ][AM ] *= 3.4   wmatintf[E2B ][NM ] *= 1.05   wmatintf[E2B ][GA ] *= 1 }     
        {wmatintf[I2 ][AM ] *= 1.025   wmatintf[I2 ][NM ] *= 1   wmatintf[I2 ][GA ] *= 1 }          
        {wmatintf[I2L ][AM ] *= 4.35   wmatintf[I2L ][NM ] *= 1.05   wmatintf[I2L ][GA ] *= 1   }   
      } else print "unknown scale factor: ", $1
    setintfwghts() //sets external weights
  }

//* printfwm -- print wmatintf entries
proc printfwm () { local ct,sy,a
    for ctt(&ct) for case(&sy,AM,NM,GA) {
        print "wmatintf[", CTYP.o(ct).s,"][" , STYP.o(sy).s, "] = ", wmatintf[ct][sy]
      }
  }

//* initialization -- vsmat init done in functions below
double vsmat[CTYPi+1][3]

//* RSparams()
proc RSparams () { local ii,jj localobj xo,ofths
    for case(&ii,E2,E4,E5R,E6) {
        vsmat[ii][DEND]=-65.0052
        vsmat[ii][SOMA]=-65.0066
        vsmat[ii][AXON]=-65.0095
        for jj=ix[ii],ixe[ii] { xo=ce.o(jj) ofths=xo.ofths
            //** soma
            xo.setri(85,50,50)
            xo.soma {
                insert A
                gmax_A = 145*0.1/area(0.5)
                VhlfMaxm_A = -24
                slopem_A = 3.2 //should stay pos
                taum_A = 82
                VhlfMaxh_A = 8
                slopeh_A = -4.9 //should stay neg
                tauh_A =	5
                erev_A = -82
                
                cm = 1 // getcmdens(19,8.3,L,diam)
                e_pas = -65
                g_pas = 8.3*0.1/area(0.5)
              }
            xo.dend {
                cm = getcmdens(19,8.3,L,diam)
                e_pas = -65
                g_pas = 8.3*0.1/area(0.5)
              }
            xo.axon {
                cm = getcmdens(19,8.3,L,diam)
                e_pas = -65
                g_pas = 8.3*0.1/area(0.5)
                
                ofths.apdur = 0.9 //action potential duration in ms
                ofths.refrac = 1e3/91 //absolute refractory period - 91Hz max frequency
                ofths.gkbase = 0.091//91nS == 0.091uS
                ofths.gkinc = 0.013 //13nS == 0.013uS
                ofths.taugka = 69
                ofths.tauk = 2.3
                ofths.vth = -40
                ofths.vthinc = 0
                ofths.tauvtha = 1
                ofths.gnamax = 0.6 //0.6nS == 0.6uS
                ofths.ena = 55
                ofths.ek = -82
                ofths.gkmin = 1e-5 // 0.01nS == 0.00001uS
              }
          }
      }
  }

//* IBparams()
proc IBparams () { local ii,jj localobj xo,ofths
    for case(&ii,E5B) {
        vsmat[ii][DEND]=-48.6591
        vsmat[ii][SOMA]=-41.9053
        vsmat[ii][AXON]=-48.6793
        for jj=ix[ii],ixe[ii] { xo=ce.o(jj) ofths=xo.ofths
            //** soma
            xo.setri(50,50,50)
            xo.soma {
                insert A
                insert H
                gmax_H = 500*0.1/area(0.5)
                VhlfMaxm_H = -74
                slopem_H = -10
                taum_H = 50
                
                gmax_A = 204*0.1/area(0.5)
                VhlfMaxm_A = 10
                slopem_A = 8.4
                taum_A = 5
                VhlfMaxh_A = 3
                slopeh_A = -5.9
                tauh_A =	20      
                erev_A = -116
                
                cm = getcmdens(19,8.3,L,diam)
                e_pas = -69
                g_pas = 8.3*0.1/area(0.5)/4 
              }
            xo.dend {
                cm = getcmdens(19,8.3,L,diam)
                e_pas = -69
                g_pas = 8.3*0.1/area(0.5)
              }
            xo.axon {
                cm = getcmdens(19,8.3,L,diam)
                
                e_pas = -69
                g_pas = (8.3*0.1/area(0.5))
                
                ofths.apdur = 1.2 //action potential duration in ms
                ofths.refrac = 4.7 //absolute refractory period - 212.76596Hz max frequency
                ofths.gkbase = 0.07// 70nS == 0.07uS 
                ofths.gkinc = 0.002 // 2nS == 0.002uS
                ofths.taugka = 80
                ofths.tauk = 1.2
                ofths.vth = -40
                ofths.vthinc = 1.3
                ofths.tauvtha = 70
                ofths.gnamax = 0.3 // 300nS == 0.3uS
                ofths.ena = 50
                ofths.ek = -116
                ofths.gkmin = 1e-5 // 0.01nS == 0.00001uS
              }
          }
      }
  }

//* FRBparams()
proc FRBparams () { local ii,jj localobj xo,ofths
    for case(&ii,E2B) {
        vsmat[ii][DEND]=-48.6591
        vsmat[ii][SOMA]=-41.9053
        vsmat[ii][AXON]=-48.6793    
        for jj=ix[ii],ixe[ii] { xo=ce.o(jj) ofths=xo.ofths
            //** soma
            xo.setri(50,50,50)
            xo.soma {
                xo.stim=new IClamp(0.5) 
                xo.stim.amp=E2BAmp xo.stim.dur=1e9 // continuously active
                insert A
                insert H
                
                insert ical3
                pcabar_ical3 = 3.0e-4
                
                gmax_H = 500*0.1/area(0.5)
                VhlfMaxm_H = -74
                slopem_H = -10
                taum_H = 50
                
                gmax_A = 1004*0.1/area(0.5)
                VhlfMaxm_A = 10
                slopem_A = 8.4
                taum_A = 5
                VhlfMaxh_A = 3
                slopeh_A = -5.9
                tauh_A =	20      
                erev_A = -116
                
                cm = getcmdens(19,8.3,L,diam)
                e_pas = -69
                g_pas = 8.3*0.1/area(0.5)/4 
              }
            xo.dend {
                cm = getcmdens(19,8.3,L,diam)
                e_pas = -69
                g_pas = 8.3*0.1/area(0.5)
              }
            xo.axon {
                cm = getcmdens(19,8.3,L,diam)
                
                e_pas = -69
                g_pas = (8.3*0.1/area(0.5))
                
                ofths.apdur = 1.2 //action potential duration in ms
                ofths.refrac = 4.7 //absolute refractory period - 212.76596Hz max frequency
                ofths.gkbase = 0.07// 70nS == 0.07uS 
                ofths.gkinc = 0.002 // 2nS == 0.002uS
                ofths.taugka = 80
                ofths.tauk = 1.2
                ofths.vth = -40
                ofths.vthinc = 1.3
                ofths.tauvtha = 70
                ofths.gnamax = 0.3 // 300nS == 0.3uS
                ofths.ena = 50
                ofths.ek = -116
                ofths.gkmin = 1e-5 // 0.01nS == 0.00001uS
              }
          }
      }
  }

//* LTSparams()
proc LTSparams () { local ii,jj localobj xo,ofths
    for case(&ii,I2L,I4L,I5L,I6L) {
        vsmat[ii][DEND]=-66.0619
        vsmat[ii][SOMA]=-65.4508
        vsmat[ii][AXON]=-66.0682    
        for jj=ix[ii],ixe[ii] { xo=ce.o(jj) ofths=xo.ofths
            //** soma
            xo.setri(50,50,50)
            xo.soma {
                insert A
                gmax_A = 860*0.1/area(0.5)
                VhlfMaxm_A = 54
                slopem_A = 11.4
                taum_A = 2
                VhlfMaxh_A = -45
                slopeh_A = -4.9
                tauh_A = 37
                erev_A = -85
                
                cm = getcmdens(11.9,5.2,L,diam)
                e_pas = -60
                g_pas = 0.00018391238 * 1.1
              }
            xo.dend {
                cm = getcmdens(11.9,5.2,L,diam)
                e_pas = -69
                g_pas = 5.2*0.1/area(0.5)
              }
            xo.axon {
                cm = getcmdens(11.9,5.2,L,diam)
                e_pas = -69
                g_pas = 5.2*0.1/area(0.5)
                
                ofths.apdur = 0.5 //action potential duration in ms
                ofths.refrac = 11  //absolute refractory period - ~90.909091Hz max frequency
                ofths.gkbase = 0.06 // 60nS == 0.06uS
                ofths.gkinc = -0.0003 // -0.3nS == -0.0003uS
                ofths.taugka = 107
                ofths.tauk = 1.5
                ofths.vth = -47
                ofths.vthinc = 3.5
                ofths.tauvtha = 89
                ofths.gnamax = 0.6 // 600nS == 0.6uS
                ofths.ena = 51
                ofths.ek = -85
                ofths.gkmin = 0.00001 // 0.01nS == 0.00001uS
              }
          }
      }
  }

//* FSparams()
proc FSparams () { local ii,jj localobj xo,ofths
    for case(&ii,I2,I2C,I4,I5,I6,I6C) {
        vsmat[ii][DEND]=-63.1023
        vsmat[ii][SOMA]=-63.1323
        vsmat[ii][AXON]=-63.1093
        for jj=ix[ii],ixe[ii] { xo=ce.o(jj) ofths=xo.ofths
            //** soma
            xo.setri(80,50,50)
            xo.soma {
                insert A
                gmax_A = 198*0.1/area(0.5)
                VhlfMaxm_A = 13
                slopem_A = 9.4
                taum_A =	2
                VhlfMaxh_A = -14
                slopeh_A = -1.9
                tauh_A = 5
                erev_A = -99.5
                
                cm = 3.8 
                e_pas = -63 
                g_pas = 0.00015 
              }
            xo.dend {
                cm = getcmdens(8.3,9,L,diam)
                e_pas = -63
                g_pas = 9*0.1/area(0.5)
              }
            xo.axon {
                cm = getcmdens(8.3,9,L,diam)
                e_pas = -63
                g_pas = 9*0.1/area(0.5)
                
                ofths.apdur = 0.6 //action potential duration in ms
                ofths.refrac = 1e3/350 //absolute refractory period - 350Hz max frequency
                ofths.gkbase = 0.058 // 58nS == 0.058uS
                ofths.gkinc = 0
                ofths.taugka = 1 //set it to 1 so no div by zero
                ofths.tauk = 1.5
                ofths.vth = -40
                ofths.vthinc = 0
                ofths.tauvtha = 1
                ofths.gnamax = 0.3 // 300nS == 0.3uS
                ofths.ena = 55
                ofths.ek = -91
                ofths.gkmin = 1e-5 // 0.01nS == 0.00001uS
              }
          }
      }
  }

//* utility function
//get microfarad/cm2 given tau in ms,gmax in nS,diam in microns,L in microns
func getcmdens () { local tau,gm
    tau=$1 gm=$2 
    return 100*tau*gm/area(0.5)
  }

RSparams()
IBparams()
FRBparams()
LTSparams()
FSparams()
initintfwm()
// END params.hoc
//================================================================
//================================================================
// INSERTED run.hoc
// =Id=  run.hoc,v 1.297 2010/05/15 03:21:31 samn Exp 

//* display of progress (t) during run
declare("tupdate",50)
objref fih
fih=new FInitializeHandler("mysend()")
proc mysend () { cvode.event(0,"prprogress()") }
proc prprogress () {
    cvode.event(t+tupdate,"prprogress()")
    print "t:", t
  }

//* variables
double scr[scrsz]
objref vit,xo,tmo,str,nclpl,vcty
objref clmpl,clmp
MAXNP=4//max # of signal/pulse sources
objref intfl[STYPi+1],intfconl[STYPi+1],intf,intfll,intfpulse[MAXNP],intfconpulse

vcty=new Vector()

method("CN",0.025)

func setother () { if(ismembrane("other_ion")) return iother(0.5) else return 0} // callback stub
 
proc setMemb () {} //let e_pas settle on its own, v_init should be set to 1e3 for this to work
obfunc csel (){return new Union(ix[$1]+numc[$1]/numcols*$2,ix[$1]+numc[$1]/numcols*($2+1)-1)}

//* INTF lists
st=0
for case(&st,AM,NM,GA) {
    intfl[st]=new List()
    intfconl[st]=new List()
  }
intfll=new List()//List with all INTFs
for i=0,MAXNP-1 intfpulse[i]=new List()//INTF for signals/pulses
intfconpulse=new List()//NetCons for signals/pulses

objref intfcoll[numcols]//column INTF list
objref intfnccoll[numcols]//column NetCon list for INTF inputs
objref nqin
nqin=new NQS("id","type","syn","loc","INTFid","NetConID","pulse")//NQS of inputs from INTFs -> CELLs

//* params for pulse stims
double ctpulse[MAXNP],delpulse[MAXNP],durpulse[MAXNP]
double interpulse[MAXNP],interpulsedel[MAXNP],npulse[MAXNP],wmpulse[MAXNP]

//* variables for LFP

objref lfld,nqfld
declare("usefld",1)//whether to record field

//* recording
proc prl () { local y,z
    str=new String2()
    printlist.remove_all
    if(nclpl==nil)nclpl=new List() else nclpl.remove_all()
    for ltr(xo,ce,&y) {
        if (y==0) {
            new_printlist_nc(xo.ofths, xo.id, "SPKS")
            vit=printlist.o(printlist.count-1)
            nclpl.append(ncl.o(ncl.count-1))
          } else {
            tmo=new NetCon(xo.ofths,nil)
            tmo.record(vit.tvec,vit.vec,xo.id)
            nclpl.append(tmo)
          }
      }
    if (1) for ctt(&y) for(z=0;z<numc[y] && z<2;z+=1) {
        sprint(str.s,"ce.o(%d).axon.v(0.5)",ix[y]+z)
        sprint(str.t,"%s_%d_axonV",CTYP.o(y).s,z)
        new_printlist_item(str.s,str.t)
      }
  }
prl()

//** initfld -- setup LFP for recording
proc initfld () { local i localobj XO
    print "setting up LFP recording"
    lfld=new List()
    for i=0,allcells-1 if(!ice(ce.o(i).type)) { ce.o(i).soma lfld.append(XO=new FIELD(0.5))
        setpointer XO.p1, ce.o(i).dend.v(0.5) // will subtract the dend from soma    
      }
    nqsdel(nqfld)
    nqfld=new NQS("t","field1")
    nqfld.pad(1+tstop/dt)
    XO=lfld.o(0)
    XO.initwrec(nqfld.vl)
  }

//** grspks()
proc grspks () { local ii,ty localobj xo
    ty=$1
    ge(0) gvmarkflag=1
    if (pq==nil) {pq=new NQS("t","ind")
        pq.setcols(printlist.o(0).tvec,printlist.o(0).vec)
      }
    for ii=0,numcols-1 { 
        xo=csel(ty,ii) 
        pq.select("ind","[]",xo.x,xo.x[1])
        pq.gr("ind","t",0,ii+1,8)
      }
    g.exec_menu("View = plot")
  }
  

//* raster graphics
//** colorp() Install color palette
proc colorp () { localobj o
    o=$o1
    o.color(21,"#90EE90") // LightGreen  E2	
    o.color(22,"#D3D3D3") // LightGray   E2B	
    o.color(23,"#ADD8E6") // LightBlue   I2	
    o.color(24,"#FFA500") // Orange      I2C	
    o.color(25,"#FFA07A") // LightRed    I2L	
    o.color(26,"#FFFF00") // Yellow      E4	
    o.color(27,"#008000") // Green       E5R	
    o.color(28,"#000000") // Black       E5B	
    o.color(29,"#0000FF") // Blue        I5	
    o.color(30,"#8B0000") // DarkRed     I5L	
    o.color(31,"#006400") // DarkGreen   E6	
    o.color(32,"#00008B") // DarkBlue    I6	
    o.color(33,"#FF8C00") // DarkOrange  I6C	
    o.color(34,"#800080") // Purple      I6L	
    colorp_init=1
  }

//** rp_tc() spike raster plot
//   rp_tc(0) - coded for cell type and layer
//   rp_tc(1) - coded only for cell type
revec(vcty,I6,I6L,E6,I5,I5L,E5B,E5R,I4,I4L,E4,I2,I2L,E2,E2B)
proc rp_tc () { local a,ty,col,tn,tx,dotsize,pos,gco,gce,gly,ly,rflag\
                  localobj g0,syms,xo,clr,st,vsz
    a=allocvecs(clr,vsz) syms=new List() st=new String2()
    if(vcty.size()>14){print "Can not plot spike raster. Too many cell types (>14)!" return}
    if (pq==nil) {pq=new NQS("t","ind") pq.setcols(printlist.o(0).tvec,printlist.o(0).vec)}
    pq.verbose=0  rflag=1 // rasterlines flag
    a=allocvecs(clr)
    ge(0) if(!colorp_init) colorp(g)
    if (numarg()==2){tn=$1 tx=$2} else {tn=tstop-250 tx=tstop}
    dotsize=10
    if(0){split("T,S,O,+,o,T,T,S,O,+,T,O,+,o",syms) // marks
        clr.append(1,1,1,1,1,2,3,3,3,3,4,4,4,4) } // colors
    if (1) { // split("O,O,O,O,O,O ,+,+,+,+,+,+,+,+",syms) // 6Es, 8Is
        st.s="S" st.t="o"
        for vtr(&x,vcty) {
            if (ice(x)) syms.append(new String(st.s)) else syms.append(new String(st.t))
            clr.append(GetLyr(x))
          }
        // revec(clr,1,3,2,4,5,6,7,9,1,3,2,4,5,6) 
        // revec(clr,21,22,23,24,25,26, 27,28,29,30,31,32,33,34)
      }
    if (0) {  split("O,O,O,O,O,O,O,O,O,O,O,O,O,O",syms) // marks
        clr.append(21,22,23,24,25,26, 27,28,29,30,31,32,33,34) } // colors
    pos=0 gly=40 gce=40 gco=100 // gap between cell groups and between columns
    for col = 1,1 {      // loop over columns 0,numcols-1
        ly=2
        for vtr(&ty,vcty,&ii) if (numc[ty]>0) {    // loop over cell types
            symb=syms.o(ii).s // assign mark to use
            xo=csel(ty,col) 
            if (pq.select("t","[]",tn,tx,"ind","[]",xo.x,xo.x[1])) { // 9-9.25 s
                y=pos-pq.applf(".min","ind")
                XO=pq.cob.v[1]
                if (0&&ty==E2) { print CTYP.o(ty).s,col,pos,XO.uniq,XO.max-XO.min,cpercol[ty] }
                pq.calc("<ind>.add(y)") // global y        
                if (rflag==1) {
                    drline(tn,pos-gce/2,tx,pos-gce/2,g,7,7)
                    sprint(tstr,"%s (%d)",CTYP.o(ty).s,col)
                    g.label(tx+10,pos,tstr,1,1,0,0,clr.x[ii])
                    
                  }
                pos+=(cpercol[ty]+gce)
                pq.cob.v[1].mark(g,pq.cob.v,symb,dotsize,clr.x[ii],4)
              }
            if (ly!=GetLyr(ty)){ly=GetLyr(ty) pos+=gly}
            if(0){printf("DEBUG: gv(%s, %d, %d)\nsymb=%s\n\n",tstr, clr.x[ii],dotsize,symb)}
          }
        if (0) { // only if the new graph was created (g!=g0)
            rasterlines_tc(col+1) // plot horizontal lines between columns
            g.exec_menu("View = plot") // resize the graph    
          }
        pos+=gco
      }
    g.size(tn,tx,0,pos)
    pq.verbose=1
    dealloc(a)
  }

//** rasterlines_tc(col nr={1,2,3,4})
// draw lines between cell layers 
proc rasterlines_tc () { local kk, ii, iii,  y0, y1 localobj o
    kk = $1-1
    for vtr(&ii,vcty,&iii)     {    // loop over cell types
        if(numc[ii]){
            y0 = npcol*kk+(npcol-Cix[0][ii]/4)
            y1 = npcol*kk+(npcol-(Cixe[3][ii]+1)/4)
            if(0) print "y= ",y, "Cix[0][ii]/4 =",Cix[0][ii]/4, "ii=",ii,"kk=",kk, "iii=",iii
            drline(0,y0-0.5,tmax_INTF,y0-0.5,g,7,7)
            //o=mdl2view(g,1,y+1)
          }    
      }
    g.flush
  }

//* stimulation with IClamp -- not used now
proc stim () { local mp,i localobj xo
    i=1
    if (argtype(i)==1) {xo=$oi i+=1} else xo=ce.o(0)
    if (argtype(i)==0) {amp=$i i+=1} else amp=0.2
    xo.soma {
        clmp = new IClamp(0.5)
        clmp.dur=500
        clmp.del=0
        clmp.amp=amp
      }
    if (clmpl==nil) clmpl=new List()
    clmpl.append(clmp)
  }

//* stim a population of cells with IClamp
proc popclmp () { local idx,mx localobj xo
    if(clmpl==nil) clmpl = new List() else clmpl.remove_all()
    mx=int((sgrpp/100)*ixe[sgrcc])
    for idx=ix[sgrcc],mx {
        xo=ce.o(idx)
        if(sgrloc==DEND) {
            xo.dend {
                clmp = new IClamp(0.5)
                clmp.dur=sgrdur
                clmp.del=sgrdel
                clmp.amp=sgramp        
              }
          } else if(sgrloc==SOMA) {
            xo.soma {
                clmp = new IClamp(0.5)
                clmp.dur=sgrdur
                clmp.del=sgrdel
                clmp.amp=sgramp      
              }
          } else {
            xo.axon {
                clmp = new IClamp(0.5)
                clmp.dur=sgrdur
                clmp.del=sgrdel
                clmp.amp=sgramp        
              }
          }
        clmpl.append(clmp)
      }
  }

proc setpulseparams () { local i
    interpulse[1]=tstop // 100//duration between pulses
  //  interpulse[2]=25
    for i=1,MAXNP-1 if(interpulse[i]>0) {
        ctpulse[i]=E4 //cell type to apply pulse to
        delpulse[i]=100 //start of 1st pulse
        durpulse[i]=5  //duration of a single pulse
        interpulsedel[i]=0.2//interpulse variance
        wmpulse[i]=10//multiplier for pulse inputs
        npulse[i] = 1 // -1 //means apply pulses throughout
      }
  }
if(0) setpulseparams()

//* grpintf -- setup a group of INTFs for each column
proc grpintf () { local a,idx,jdx,cdx,ct,kdx localobj xo,nc,vid
    allocvecs(vid)     vid.indgen(0,INTFPerCol-1,1)  jdx = 0 // ID of next INTF cell
    nqin.clear()
    for cdx=0,numcols-1 {
    
        intfcoll[cdx]=new List() intfnccoll[cdx]=new List()
        for idx=0,INTFPerCol-1 {
            intf=new INTF(jdx)
            jdx+=1
            intfcoll[cdx].append(intf)//column INTF list
            intfll.append(intf)//global INTF list
          }
        for ctt(&ct) for idx=Cix[cdx][ct],Cixe[cdx][ct] { xo=ce.o(idx) //each cell picks an INTF for its syns
      
            vid.shuffle() kdx=0 //randomize the INTF IDs
            xo.dend {
                intf = intfcoll[cdx].o(vid.x(kdx)) //get ref to random INTF from this column
                nc=new NetCon(intf,xo.ampa) //create NetCon
                nc.weight = wmatintf[xo.type][AM]    //set weight as AMPA
                nc.delay=0
                intfl[AM].append(intf)    //synapse type INTF list
                intfconl[AM].append(nc)   //synapse type NetCon list
                intfnccoll[cdx].append(nc)//column NetCon list
                nqin.append(xo.id,xo.type,AM,DEND,intf.id,intfconl[AM].count-1,0)
              }
            if( xo.nmda != nil ) {
                xo.dend {
                    if(!combEIntf) kdx += 1
                    intf = intfcoll[cdx].o(vid.x(kdx)) //get ref to random INTF from this column
                    nc=new NetCon(intf,xo.nmda) 
                    nc.weight = wmatintf[xo.type][NM]
                    nc.delay = 0
                    intfl[NM].append(intf)   //synapse type INTF list
                    intfconl[NM].append(nc)  //synapse type NetCon list
                    intfnccoll[cdx].append(nc)//column NetCon list
                    nqin.append(xo.id,xo.type,NM,DEND,intf.id,intfconl[NM].count-1,0)
                  }
              }
            xo.dend {
                kdx += 1 //get next INTF
                intf = intfcoll[cdx].o(vid.x(kdx)) //get ref to random INTF from this column
                nc=new NetCon(intf,xo.gabaa[0]) 
                nc.weight = wmatintf[xo.type][GA]
                nc.delay = 0
                intfl[GA].append(intf)   //synapse type INTF list
                intfconl[GA].append(nc)  //synapse type NetCon list
                intfnccoll[cdx].append(nc)//column NetCon list
                nqin.append(xo.id,xo.type,GA,DEND,intf.id,intfconl[GA].count-1,0)
              }
            xo.soma {
                kdx += 1 //get next INTF
                intf = intfcoll[cdx].o(vid.x(kdx)) //get ref to random INTF from this column
                nc=new NetCon(intf,xo.gabaa[1]) 
                nc.weight = wmatintf[xo.type][GA]
                nc.delay = 0
                intfl[GA].append(intf)   //synapse type INTF list
                intfconl[GA].append(nc)  //synapse type NetCon list
                intfnccoll[cdx].append(nc)//column NetCon list
                nqin.append(xo.id,xo.type,GA,SOMA,intf.id,intfconl[GA].count-1,0)
              }      
          }
      }
    intf = intfl.o(0)
    intf.jitcondiv("intfll")//sets up INTF pointers
    dealloc(a)
  }

//* initintf -- setup an intf+netcon for each synapse
proc initintf () { local idx,jdx,ndx localobj xo,nc
    jdx = 0 nqin.clear()
    for idx=0,allcells - 1 { //setup an intf+netcon for each synapse
        xo=ce.o(idx)
        xo.dend {
            if(sgrhzE > 0) {
                intf = new INTF(jdx)            //AMPA
                nc=new NetCon(intf,xo.ampa)
                nc.weight = wmatintf[xo.type][AM]      nc.delay = 0
                jdx += 1
                intfl[AM].append(intf) intfll.append(intf)
                intfconl[AM].append(nc)
                nqin.append(xo.id,xo.type,AM,DEND,intf.id,intfconl[AM].count-1,0)
              }
            if(sgrhzNM > 0) { // external NMDA inputs have their own rate
                if(!combEIntf) intf = new INTF(jdx)
                nc=new NetCon(intf,xo.nmda)    //NMDA
                nc.weight = wmatintf[xo.type][NM]        nc.delay = 0
                if(!combEIntf) jdx += 1
                intfl[NM].append(intf)
                if(!combEIntf) intfll.append(intf)
                intfconl[NM].append(nc)
                nqin.append(xo.id,xo.type,NM,DEND,intf.id,intfconl[NM].count-1,0)
              }
            if(sgrhzI > 0) {
                intf = new INTF(jdx)          //GABAA
                nc=new NetCon(intf,xo.gabaa[0])
                nc.weight = wmatintf[xo.type][GA]      nc.delay = 0
                jdx += 1
                intfl[GA].append(intf) intfll.append(intf)
                intfconl[GA].append(nc)
                nqin.append(xo.id,xo.type,GA,DEND,intf.id,intfconl[GA].count-1,0)
              }
          }
        if(sgrhzI > 0) {
            xo.soma {
                intf = new INTF(jdx)
                nc=new NetCon(intf,xo.gabaa[1])
                nc.weight = wmatintf[xo.type][GA]      nc.delay = 0
                jdx += 1
                intfl[GA].append(intf) intfll.append(intf)
                intfconl[GA].append(nc)
                nqin.append(xo.id,xo.type,GA,SOMA,intf.id,intfconl[GA].count-1,0)
              }
          }
      }
    //go through each pulse/signal & setup INTFs as signal/pulse sources
    //ndx is the pulse id. 0 == non-pulse, 1 == 1st signal , 2 == 2nd signal, etc.
    for ndx=1,MAXNP-1 if(npulse[ndx]!=0) {
        printf("setting INTFs for pulse/signal %d\n",ndx)
        for idx=ix[ctpulse[ndx]],ixe[ctpulse[ndx]] { 
            xo = ce.o(idx)
            xo.dend {
                intf = new INTF(jdx)
                jdx+=1
                intfpulse.append(intf) intfll.append(intf)
                
                nc=new NetCon(intf,xo.ampa)    //AMPA
                nc.weight = wmatintf[xo.type][AM]*wmpulse[ndx]      nc.delay = 0
                intfconpulse.append(nc)
                nqin.append(xo.id,xo.type,AM,DEND,intf.id,intfconpulse.count-1,ndx)
                
                nc=new NetCon(intf,xo.nmda)    //NMDA
                nc.weight = wmatintf[xo.type][NM]*wmpulse[ndx]      nc.delay = 0
                intfconpulse.append(nc)
                nqin.append(xo.id,xo.type,NM,DEND,intf.id,intfconpulse.count-1,ndx)
              }
          }  
      }
    if(intfl.count > 0) {
        intf = intfl.o(0)
        intf.jitcondiv("intfll")//sets up INTF pointers
      }
  }

if(celldbg==0){
    if(grpINTF) grpintf() else initintf() //setup INTFs
  } else printf("no INTFs: celldbg==1\n")

//* setintfwghts allows adjusting weights of INTF random synapses
proc setintfwghts () { local sy localobj xo,yo
    for case(&sy,AM,NM,GA) for ltr(xo,intfconl[sy]) xo.weight=wmatintf[xo.postcell.type][sy]
  }

//* pulsestim(Random,pulse/signal id) -- set INTF cells to fire fairly synchronously
proc pulsestim () { local ct,pl,a,tt,mint,maxt,ndx localobj vid,rd,vt,vw
    rd=$o1 ndx=$2
    printf("pulse-stim on pulse/signal %d\n",ndx)
    ct=ctpulse[ndx] allocvecs(vid,vt,vw) 
    nqin.select("type",ct,"pulse",ndx) vid.copy(nqin.getcol("INTFid"))
    {vt.resize(vid.size) vw.resize(vid.size) vw.fill(-1)}
    tt=delpulse[ndx] // start time
    mint = interpulse[ndx] - interpulse[ndx]*interpulsedel[ndx]
    maxt = interpulse[ndx] + interpulse[ndx]*interpulsedel[ndx]
    pl = 0 //apply npulse[ndx] pulses , or when npulse[ndx]==-1 apply pulses throughout
    while(tt<tstop && (pl<npulse[ndx] || npulse[ndx]==-1)) { 
        rd.uniform(tt,tt+durpulse[ndx])
        vt.setrand(rd)    vq.v[0].append(vid)    vq.v[1].append(vt)    vq.v[2].append(vw)
        tt += rd.uniform(mint,maxt)
        if(tt>=tstop) break //dont add extra inputs after tstop, since wont be used
        pl += 1 //pulse counter
      }
    dealloc(a)
    nqin.tog("DB")
    printf("\tapplied %d pulses\n",pl)
  }

//* popstim(Random) - setup random INTF firing times (INTFs are inputs to the 'real' cells)
objref vq // intf stim nqs
proc popstim () { local a,se,id,sy,sz,jdx,pos,sglo,sghi,hzlo,hzhi localobj rdm,vsy,xo,vf,vnspks
    a=allocvecs(vsy,vf,vnspks)
    rdm=$o1  vsy.append(GA) vsy.append(AM)  if(!combEIntf) vsy.append(NM)
    vf.resize(STYPi+1) vf.x(AM)=sgrhzE vf.x(NM)=sgrhzNM vf.x(GA)=vf.x(GB)=sgrhzI
    pos=0 sglo=1-sgrhzdel sghi=1+sgrhzdel if(sglo<0) sglo=0
    for vtr(&sy,vsy) if(vf.x(sy) > 0) {
        vnspks.resize(intfl[sy].count)
        hzlo=vf.x(sy)*sglo if(hzlo<1) hzlo=1
        hzhi=vf.x(sy)*sghi if(hzhi<1) hzhi=1
        rdm.discunif(hzlo,hzhi) //pick frequency
        vnspks.setrand(rdm)    
        vnspks.mul(sgrdur/1e3)
        vnspks.apply("int") //set # of spikes per intf
        vq.v[0].resize(vq.v[0].size()+vnspks.sum())
        jdx = 0
        for ltr(xo,intfl[sy]) {
            vq.v[0].fill(xo.id,pos,pos+vnspks.x(jdx)-1)
            pos += vnspks.x(jdx)
            jdx += 1
          }
      }  
    vq.v[1].resize(vq.v[0].size)
    rdm.uniform(sgrdel,sgrdel+sgrdur)
    vq.v[1].setrand(rdm) //intf spike times
    vq.v[2].resize(vq.v[1].size)
    vq.v[2].fill(-1)//guarantee intf spiking
    dealloc(a)
  }

//* setINTFspks - setup spike times of INTFs (INTFs provide inputs to the 'real' cells)
declare("inputseed",1234)
proc setINTFspks () { local se,ndx localobj rdm
    if(intfll.count<=0) { //need INTFs to stim
        printf("no INTFs to stim!\n")
        return
      }
    if(numarg()>0)se=$1 else se=1234 //seed for Random
    rdm=new Random()  rdm.ACG(se) //initialize Random object
    if(vq==nil) vq=new NQS("ind","time","wt") else vq.clear() //NQS storing INTF spike times
    intf.clrvspks() //clear INTF spike times
    if(sgron) popstim(rdm) //add random firing of INTF cells
    for ndx=1,MAXNP-1 if(npulse[ndx]!=0) pulsestim(rdm,ndx) //add pulse-like firing of INTF cells
    vq.sort("time") vq.sort("ind") //finalize INTF spike times
    intf.initvspks(vq.v,vq.v[1],vq.v[2]) // single global call
  }
setINTFspks(inputseed)

//* initMisc1
skipinit1=0
proc initMisc1 () { localobj xo
    if(skipinit1) {
        printf("skipping initMisc1\n")
        return
      }
    for ltr(xo,ce) {
        xo.dend.v = vsmat[xo.type][DEND]
        xo.soma.v = vsmat[xo.type][SOMA]
        xo.axon.v = vsmat[xo.type][AXON]
      }
  }

//* finishMisc
func finishMisc () { localobj XO
    print "finishMisc , at t=",t
    if(lfld.count>0) {
        XO = lfld.o(0)
        XO.global_fini()
      }
    return 1
  }

//* draw lines between cell subpopulations
proc rasterlines () { localobj o
    for ctt() {
        drline(0,ixe[ii],tmax_INTF,ixe[ii],g,2,6)
        // o=mdl2view(g,0,ix[ii]+numc[ii]/10)
        o=mdl2view(g,0.9,ix[ii]+numc[ii]/4)
        g.label(0.9,o.x[3],CTYP.o(ii).s)
      }
    g.flush
  }

if(INTWTSOFF==1) {
    print "turning off all internal weights"
    allwtsoff() // turn off all internal weights
  }

if(usefld) initfld()
// END run.hoc
//================================================================
//================================================================
// INSERTED nload.hoc
// =Id=  nload.hoc,v 1.85 2009/12/15 16:05:54 samn Exp  

strdef strvecs,strvq,strnqin,strnqfld //vecs file, vq nqs file, nqin nqs file, nqfld nqs file
strdef strv
strv="09apr17.18"
objref nqtt,nqte,nqtea,nqktau
skipsnq=1 // iff==1 dont get snq and isinq
binsz=100 //100ms
pflg=1
ers=0
objref nqCO,nqIN,nqCTY,vIN,vOUT,vINDisc,vOUTDisc,snq,nqisi,nqINPLS
vINDisc=new Vector() //discrete input
vINDisc.label("discrete input")
vOUTDisc=new Vector() //discrete output
vOUTDisc.label("discrete output")

//* Deriv() return derivative of input vector
//output vector has same size as input
//$o1 = input vector
//vp = output vector
obfunc Deriv(){ localobj vp
    vp=new Vector($o1.size)
    if($o1.size < 2){
        printf("Deriv ERRAA: input vec size < 2!\n")
        return vp
      }
    vp.deriv($o1,1,2)
    return vp
  }

//* IsiNQS()
obfunc IsiNQS () { local idx,tt,jdx,a localobj vtmp,nqisi,vid
    if(snq==nil)snq=SpikeNQS(vit)
    snq.verbose=0
    nqisi=new NQS("id","isi")
    nqisi.verbose=0
    a=allocvecs(vid)
    for idx=0,allcells-1 {
        snq.select("ID",idx)
        vtmp = Deriv(snq.getcol("SpikeT"))
        vid.resize(vtmp.size)
        vid.fill(idx)
        nqisi.v[0].append(vid)
        nqisi.v[1].append(vtmp)
      }
    snq.tog("DB")
    dealloc(a)
    return nqisi
  }

//* SpikeNQS() returns NQS containing ID,Type,SpikeT
//doesn't check if cell is dead or alive, assumes input is valid
//$o1 = spike vitem
//or
//$o1 = time vec , $o2 = id vec
obfunc SpikeNQS(){ local idx localobj vec,tvec,nq
    if(ce==nil) return nil
    if(numarg()==1){
        vec = $o1.vec tvec = $o1.tvec
      } else if(numarg()==2){
        if(argtype(1)==1 && argtype(2)==1){
            tvec=$o1 vec=$o2
          } else {
            vec = $o1.vec tvec=$o1.tvec
          }
      } else {
        printf("SpikeNQS ERRA: invalid args!\n")
        return nil
      }
    nq = new NQS("ID","Type","SpikeT") 
    nq.v[0].copy(vec)
    nq.v[2].copy(tvec)
    nq.v[1].resize(vec.size)
    for idx=0,vec.size-1 nq.v[1].x(idx)=ce.o(vec.x(idx)).type
    return nq
  }

//* FreqNQS(snq,duration)
//get an NQS with rate of firing of each cell
//$o1 = spikenqs, $2 = duration (starts from 0)
obfunc FreqNQS () { local i,a,ns,tt localobj snq,fnq,vi
    a=allocvecs(vi)
    fnq=new NQS("ID","type","freq")  snq=$o1 tt=$2
    snq.tog("DB")  vi.resize(snq.v.size)  snq.getcol("ID").uniq(vi)
    for vtr(&i,vi) {
        ns=snq.select(-1,"ID",i)
        fnq.append(i,ce.o(i).type,1e3*ns/tt)
      }
    dealloc(a)
    return fnq
  }

//* clrMyNQs - delete nqCO, nqIN
proc clrMyNQs () {
    nqsdel(nqCO)
    nqsdel(nqIN)
    nqsdel(nqCTY)
    nqsdel(snq)
    nqsdel(nqisi)
    nqsdel(nqINPLS)
  }

htmin=sgrdel //min time in histogram
htmax=tstop  //max time in histogram
IOMax=10
func rrounddI () {
    return int($1+0.5)
  }
proc discIO () {
    {vINDisc.copy(vIN) vOUTDisc.copy(vOUT)}
    vINDisc.div(vINDisc.max).mul(IOMax).apply("rrounddI")
    vOUTDisc.div(vOUTDisc.max).mul(IOMax).apply("rrounddI")
  }
func mymax () {
    if($1>$2)return $1 else return $2
  }
//* initMyNQs - init binned value NQSs using raster info from vit and input info from vq
proc initMyNQs () { local ct,idx,pdx,intfid
    if(nqCO==nil) nqCO=new NQS(allcells) else nqCO.clear() //NQS for the binned spike-trains
    vit.vec.ihist(vit.tvec,nqCO.vl,htmin,htmax,binsz)
    if(nqIN==nil) nqIN=new NQS(vq.v[0].max+1) else nqIN.clear() //NQS for the binned input events
    flag_stats=1 //allow vq.v[1] to be unsorted
    vq.v[0].ihist(vq.v[1],nqIN.vl,htmin,htmax,binsz)
    if (1) {// nqCTY: multiunit activity for each of the types of cells
      if(nqCTY==nil) nqCTY=new NQS(CTYPi) else nqCTY.clear() //population sum
      for ct=0,CTYPi-1 {
          nqCTY.v[ct].resize(nqCO.v[0].size)
          nqCTY.v[ct].fill(0)
          nqCTY.v[ct].label(CTYP.o(ct).s)
        }
      for idx=0,allcells-1 nqCTY.v[ce.o(idx).type].add(nqCO.v[idx])
      }
    if(nqINPLS==nil)nqINPLS=new NQS(MAXNP+1) else nqINPLS.clear() //NQS for pulse inputs
    for idx=0,MAXNP nqINPLS.v[idx].resize(nqIN.v[0].size)
    nqin.tog("DB")
    for nqin.qt(&pdx,"pulse",&intfid,"INTFid") nqINPLS.v[pdx].add(nqIN.v[intfid])
  
    if(vIN==nil)vIN=new Vector(nqCTY.v[0].size) else vIN.resize(nqCTY.v[0].size)
    if(vOUT==nil)vOUT=new Vector(vIN.size) else vOUT.resize(vIN.size)
    {vIN.fill(0) vOUT.fill(0)}
    for idx=0,nqCO.m-1 vOUT.add(nqCO.v[idx]) //spatiotemporal output
    for idx=0,nqIN.m-1 vIN.add(nqIN.v[idx])  //spatiotemporal input
    discIO()
    if(!skipsnq) {
        if(snq!=nil) nqsdel(snq)
        snq=SpikeNQS(vit) 
        if(nqisi!=nil) nqsdel(nqisi)
        nqisi=IsiNQS(snq)
      }
  }

//* getTEnq() gets transfer entropy from inputs->cells
obfunc getTEnq () { local a,sy,loc,id,intfid,idx localobj nqt,vte,vtmp,vnte
    sy=loc=id=intfid=0
    nqin.tog("DB")
    nqt=new NQS()
    nqt.copy(nqin)
    initMyNQs()
    a=allocvecs(vte,vnte)
    vrsz(nqt.v[0].size,vte,vnte)  vrsz(0,vte,vnte)
    idx=0
    for nqt.qt(&id,"id",&sy,"sy",&loc,"loc",&intfid,"INTFid") {
        vtmp = normte(nqIN.v[intfid],nqCO.v[id],30)
        vte.append(vtmp.x(0))
        vnte.append(vtmp.x(2))
        if(idx%100==0) printf("idx=%d\n",idx)
        idx+=1
      }
    vte.unnan() //get rid of nans
    nqt.resize("te")
    nqt.v[nqt.m-1].copy(vte)
    nqt.resize("nte")
    nqt.v[nqt.m-1].copy(vnte)
    dealloc(a)
    return nqt
  }

//* getTEnqAll() gets transfer entropy from inputs->ALL cells
obfunc getTEnqAll () { local a,ct,sy,id,poid,pls,prid localobj nqt,vtmp
    nqin.tog("DB")  nqt=new NQS("id","type","prid","poid","pulse","sy","same","te","nte")
    initMyNQs()
    for id=0,allcells-1  { 
        ct = ce.o(id).type
        if(id%10==0) printf("id=%d\n",id)
        for nqin.qt(&poid,"id",&sy,"sy",&prid,"INTFid",&pls,"pulse") {    
            vtmp = normte(nqIN.v[prid],nqCO.v[id],30)
            nqt.append(id,ct,prid,poid,pls,sy,poid==id,vtmp.x(0),vtmp.x(2))
          }
      }
    for id=0,nqt.m-1 nqt.v[id].unnan()
    return nqt
  }

//* getTEnqAllsub -- 
// gets nTE from all inputs of a cell type -> all outputs of a specific cell type
obfunc getTEnqAllsub () { local a,row,ct,sy,id,poid,pls,prid,cts,tyt,\
                           idcol,sycol,INTFidcol,pulsecol,loccol\
                           localobj nqt,vtmp
    cts=$1
    nqin.tog("DB")  nqt=new NQS("id","type","prid","poid","pulse","sy","same","loc","te","nte")
    initMyNQs()
    {idcol=nqin.fi("id")  sycol=nqin.fi("sy")  INTFidcol=nqin.fi("INTFid")}
    {pulsecol=nqin.fi("pulse")  loccol=nqin.fi("loc")}
    {nqin.select(-1,"type",cts)  nqin.verbose=0 pls=0}
    printf("\nid:")
    for id=ix[cts],ixe[cts] {
        ct = ce.o(id).type
        if(id%20==0) printf("\n")
        printf("%d ",id)
        for vtr(&row,nqin.ind) {
            {prid=nqin.v[INTFidcol].x(row)      poid=nqin.v[idcol].x(row)}
            {sy=nqin.v[sycol].x(row)      loc=nqin.v[loccol].x(row)}
            vtmp = normte(nqIN.v[prid],nqCO.v[id],30)
            nqt.append(id,ct,prid,poid,pls,sy,poid==id,loc,vtmp.x(0),vtmp.x(2))
          }
      }
    printf("\n")
    for id=0,nqt.m-1 nqt.v[id].unnan()
    nqin.verbose=1
    return nqt
  }


//* ccntevsbinsz(prid,poid,vbins,nq)
obfunc ccntevsbinsz () { local prid,poid localobj vbins,vtmp,nq
    prid=$1 poid=$2 vbins=$o3
    nq=$o4
    if(nq==nil) nq=new NQS("prid","poid","binsz","te","nte","prty","poty") else nq.tog("DB")
    for vtr(&binsz,vbins) {
        print "binsz" , binsz
        clrMyNQs()
        initMyNQs()
        vtmp = normte(nqCO.v[prid],nqCO.v[poid],30)
        nq.append(prid,poid,binsz,vtmp.x(0),vtmp.x(2),ce.o(prid).type,ce.o(poid).type)
      }
    return nq
  }
//* tyntevsbinsz(Vec of pre-type, Vec of po-type, Vec of bin sizes, nq output)
obfunc tyntevsbinsz () { local prid,poid,prty,poty,verb localobj vbins,vtmp,nq,vprty,vpoty
    vprty=$o1 vpoty=$o2 vbins=$o3 nq=$o4
    if(numarg()>4)verb=$5 else verb=0
    if(nq==nil) nq=new NQS("prid","poid","binsz","te","nte","prty","poty") else nq.tog("DB")
    nclnq.verbose=0
    for vtr(&binsz,vbins) {
        print "binsz " , binsz
        clrMyNQs()
        initMyNQs()
        for vtr(&prty,vprty) for vtr(&poty,vpoty) {
            if(prty==poty || div[prty][poty][0]<1) continue
            print "prty : " , CTYP.o(prty).s, " , poty : ", CTYP.o(poty).s
            for prid=ix[prty],ixe[prty] {
                if(nclnq.select("prid",prid,"poty",poty)) for nclnq.qt(&poid,"poid") {
                    if(verb) print "prid " , prid , " poid " , poid
                    vtmp=normte(nqCO.v[prid],nqCO.v[poid],30)
                    nq.append(prid,poid,binsz,vtmp.x(0),vtmp.x(2),prty,poty)
                  }
              }
          }
      }
    nclnq.verbose=1
    return nq
  }

//* binarize(vec) - set all values > 0 to 1, everything else to 0
proc binarize () { local i,sz localobj vin
    vin=$o1 sz=vin.size()-1
    for i=0,sz if(vin.x(i)>0) vin.x(i)=1 else vin.x(i)=0
  }

//* allntevsbinsz(Vec of bin sizes, nq output, verbose)
obfunc allntevsbinsz () { local prid,poid,prty,poty,verb,cidx,a,intfid,intnte,extnte,sumnte,idx,ty,ic\
                           localobj vbins,vtmp,nq,vprty,vpoty,vam,vgad,vgas,vnm,vint,vprid,vc
    a=allocvecs(vam,vgad,vgas,vnm,vint,vprid,vc)
    vbins=$o1 nq=$o2
    if(numarg()>2)verb=$3 else verb=0
    if(nq==nil) nq=new NQS("id","type","ice","binsz","intnte","extnte","sumnte","sy","loc") else nq.tog("DB")
    if(nclnq.fi("loc")==-1) { // make sure we have a loc column in nclnq
        nclnq.resize("loc")
        nclnq.pad()
        for idx=0,nclnq.v.size-1 nclnq.v[nclnq.m-1].x(idx) = synloc[nclnq.v[2].x(idx)][nclnq.v[3].x(idx)]
      }
    nclnq.verbose=nqin.verbose=0
  
    for vtr(&binsz,vbins) {
        print "binsz " , binsz    
        {clrMyNQs()    initMyNQs()}
        {vrsz(nqCO.v.size,vam,vgad,vgas,vnm,vint)}
        for cidx=0,allcells-1 {     //go thru all cells
      
            {vam.fill(0) vgad.fill(0) vgas.fill(0) vnm.fill(0) vint.fill(0)}
            {ty=ce.o(cidx).type ic=ice(ty)}
      
            if(cidx%100==0) print cidx
            
            // nTE @ AMPA on DEND
            intnte=sumnte=extnte=0
            nqin.select("id",cidx,"syn",AM,"loc",DEND) // external input
            intfid=nqin.fetch("INTFid")
            vam.add(nqIN.v[intfid])
            vtmp=normte(vam,nqCO.v[cidx],30)
            extnte=vtmp.x(2) // external nTE
            vint.fill(0) // sum of internal inputs
            vprid.resize(nclnq.select("poid",cidx,"sy",AM)) //select AM inputs to this cell
            if(vprid.size>0) { 
                nclnq.getcol("prid").uniq(vprid) // IDs to use
                for vtr(&prid,vprid) vint.add(nqCO.v[prid])      
                vtmp=normte(vint,nqCO.v[cidx],30)
                intnte=vtmp.x(2) // internal nTE
                vint.add(vam)  // external + internal inputs
                vtmp=normte(vint,nqCO.v[cidx],30) // nTE of external+internal inputs to cell's spikes
                sumnte=vtmp.x(2)
              } else sumnte=extnte 
            nq.append(cidx,ty,ic,binsz,intnte,extnte,sumnte,AM,DEND) // save it
                  
            // nTE @ NMDA on DEND
            nqin.select("id",cidx,"syn",NM,"loc",DEND)
            intfid=nqin.fetch("INTFid")
            vnm.add(nqIN.v[intfid])
            vtmp=normte(vnm,nqCO.v[cidx],30)
            extnte=vtmp.x(2) // external nTE
            vint.fill(0) // sum of internal inputs
            vprid.resize(nclnq.select("poid",cidx,"sy",NM)) //select NM inputs to this cell
            if(vprid.size>0) { 
                nclnq.getcol("prid").uniq(vprid) // IDs to use
                for vtr(&prid,vprid) vint.add(nqCO.v[prid])      
                vtmp=normte(vint,nqCO.v[cidx],30)
                intnte=vtmp.x(2) // internal nTE
                vint.add(vnm)  // external + internal inputs
                vtmp=normte(vint,nqCO.v[cidx],30) // nTE of external+internal inputs to cell's spikes
                sumnte=vtmp.x(2)
              } else sumnte=extnte
            nq.append(cidx,ty,ic,binsz,intnte,extnte,sumnte,NM,DEND) // save it
      
            // nTE @ GABAA on DEND
            nqin.select("id",cidx,"syn",GA,"loc",DEND)
            intfid=nqin.fetch("INTFid")
            vgad.add(nqIN.v[intfid])
            vtmp=normte(vgad,nqCO.v[cidx],30)
            extnte=vtmp.x(2) // external nTE
            vint.fill(0) // sum of internal inputs
            vprid.resize(nclnq.select("poid",cidx,"sy",GA,"loc",DEND)) //select GA DEND inputs to this cell
            if(vprid.size>0) { 
                nclnq.getcol("prid").uniq(vprid) // IDs to use
                for vtr(&prid,vprid) vint.add(nqCO.v[prid])      
                vtmp=normte(vint,nqCO.v[cidx],30)
                intnte=vtmp.x(2) // internal nTE
                vint.add(vgad)  // external + internal inputs
                vtmp=normte(vint,nqCO.v[cidx],30) // nTE of external+internal inputs to cell's spikes
                sumnte=vtmp.x(2)
              } else sumnte=extnte
            nq.append(cidx,ty,ic,binsz,intnte,extnte,sumnte,GA,DEND) // save it
      
            // nTE @ GABAA on SOMA
            nqin.select("id",cidx,"syn",GA,"loc",SOMA)
            intfid=nqin.fetch("INTFid")
            vgas.add(nqIN.v[intfid])
            vtmp=normte(vgas,nqCO.v[cidx],30)
            extnte=vtmp.x(2) // external nTE
            vint.fill(0) // sum of internal inputs
            vprid.resize(nclnq.select("poid",cidx,"sy",GA,"loc",SOMA)) //select GA DEND inputs to this cell
            if(vprid.size>0) { 
                nclnq.getcol("prid").uniq(vprid) // IDs to use
                for vtr(&prid,vprid) vint.add(nqCO.v[prid])      
                vtmp=normte(vint,nqCO.v[cidx],30)
                intnte=vtmp.x(2) // internal nTE
                vint.add(vgas)  // external + internal inputs
                vtmp=normte(vint,nqCO.v[cidx],30) // nTE of external+internal inputs to cell's spikes
                sumnte=vtmp.x(2)
              } else sumnte=extnte
            nq.append(cidx,ty,ic,binsz,intnte,extnte,sumnte,GA,SOMA) // save it
      
          }
      }
    nclnq.verbose=nqin.verbose=1
    dealloc(a)
    return nq
  }

//* getpopsNQ() gets transfer entropy & k-tau between different populations of cells
obfunc getpopsNQ () { local a,ct1,ct2 localobj nqt,vtmp
    initMyNQs()
    nqt=new NQS("from","to","te","nte","binsz","froms","tos","ktau")
    {nqt.strdec("froms") nqt.strdec("tos")}
    for ctt(&ct1) for ctt(&ct2) if(ct1!=ct2) {
        vtmp = normte(nqCTY.v[ct1],nqCTY.v[ct2],30)
        nqt.append(ct1,ct2,vtmp.x(0),vtmp.x(2),binsz,CTYP.o(ct1).s,CTYP.o(ct2).s,nqCTY.v[ct1].kcorrel(nqCTY.v[ct2],1))
      }
    return nqt
  }

//* gettaunq() gets kendall's tau correlations between inputs/outputs
obfunc gettaunq () { local a,sy,loc,id,intfid,idx,pulseon localobj nqc,vpcor,vktau
    sy=loc=id=intfid=0
    nqin.tog("DB")
    nqc=new NQS()
    if(numarg()>0)pulseon=$1 else pulseon=npulse[1]!=0
    if(pulseon){
        nqc.copy(nqin)
      } else {
        nqin.select("pulse",0)
        nqc.copy(nqin.out)
      }
    initMyNQs()
    a=allocvecs(vpcor,vktau)
    vrsz(nqc.v[0].size,vpcor,vktau)  vrsz(0,vpcor,vktau)
    idx=0
    for nqc.qt(&id,"id",&sy,"sy",&loc,"loc",&intfid,"INTFid") {
        vpcor.append(nqCO.v[id].pcorrel(nqIN.v[intfid]))
        vktau.append(nqCO.v[id].kcorrel(nqIN.v[intfid],1))
        if(idx%100==0) printf("idx=%d\n",idx)
        idx+=1
      }
    vktau.unnan() //get rid of nans
    nqc.resize("pcor")
    nqc.v[nqc.m-1].copy(vpcor)
    nqc.resize("ktau")
    nqc.v[nqc.m-1].copy(vktau)
    dealloc(a)
    return nqc
  }

//* getpopcktaunq() gets correlations between pairs of cells - with sliding time window - used
// for population coordination matrix
// $1=winsz,$2=wininc
obfunc getpopcktaunq () { local a,i,j,kt,ty1,ty2,ic1,winsz,wininc,tt,mx localobj nqcc,v1,v2,vc
    a=allocvecs(v1,v2,vc)
    {winsz=$1 wininc=$2}
    nqcc=new NQS("id1","id2","ty1","ty2","ic1","ic2","ktau","t")
    if(nqCO==nil) initMyNQs()
    for(tt=0;tt<nqCO.v.size;tt+=wininc) {
        vrsz(0,vc,v1,v2)
        for i=0,nqCO.m-1 {
            mx=MIN(tt+winsz,nqCO.v[i].size()-1)
            v1.copy(nqCO.v[i],tt,mx)
            if(i%100==0) printf("i=%d\n",i)
            ty1=ce.o(i).type
            ic1=ice(ty1)
            for j=i+1,nqCO.m-1 {
                ty2=ce.o(j).type
                v2.copy(nqCO.v[j],tt,mx)
                kt=v1.kcorrel(v2,1)
                nqcc.append(i,j,ty1,ty2,ic1,ice(ty2),kt,tt)
              }
          }
      }
    nqcc.v[nqcc.m-2].unnan()
    dealloc(a)
    return nqcc
  }

//* getpopcmat() - get population coordination matrix
//$o1=nqs from getpopcktaunq
obfunc getpopcmat () { local a,tt,idx,jdx localobj mc,nq,vt,ls
    nq=$o1 nq.tog("DB")
    a=allocvecs(vt)
    vt.resize(nq.v.size)
    nq.getcol("t").uniq(vt)
    ls=new List()
    for vtr(&tt,vt) {
        nq.select("t",tt)
        ls.append(new Vector())
        ls.o(ls.count-1).copy(nq.getcol("ktau"))
      }
    mc=new Matrix(ls.count,ls.count)
    for idx=0,ls.count-1 for jdx=idx+1,ls.count-1 mc.x(idx,jdx)=mc.x(jdx,idx)=ls.o(idx).pcorrel(ls.o(jdx))
    for idx=0,ls.count-1 mc.x(idx,idx)=1
    dealloc(a)
    return mc
  }

//* getcellcelltaunq() gets correlations between pairs of cells
obfunc getcellcelltaunq () { local a,i,j,kt,ty1,ty2,ic1,rel localobj nqcc,vpv
    a=allocvecs(vpv) vpv.resize(1)
    nqcc=new NQS("id1","id2","ty1","ty2","ic1","ic2","ktau","pval","rel")
    if(nqCO==nil) initMyNQs()
    for i=0,nqCO.m-1 {
        if(i%100==0) printf("i=%d\n",i)
        ty1=ce.o(i).type
        ic1=ice(ty1)
        for j=i+1,nqCO.m-1 {
            ty2=ce.o(j).type
            kt=nqCO.v[i].kcorrel(nqCO.v[j],1,vpv)
            rel=0 //independent
            if(vpv.x(0) < 0.05) {
                if(kt>0) {
                    rel=1 //positive
                  } else if(kt<0) {
                    rel=-1 //negative
                  } 
              }
            nqcc.append(i,j,ty1,ty2,ic1,ice(ty2),kt,vpv.x(0),rel)
          }
      }
    nqcc.v[nqcc.m-1].unnan()
    dealloc(a)
    return nqcc
  }

//* getcellcelltenq([monosynapticflag]) gets transfer entropies between pairs
// of cells (in both directions)
// iff monosynapticflag == 1 only gets for cell pairs that are connected
obfunc getcellcelltenq () { local a,i,j,kt,ty1,ty2,ic1,spks1,spks2,mon localobj nqte,vtmp
    nqte=new NQS("id1","id2","ty1","ty2","ic1","ic2","te","nte","spks1","spks2")
    if(nqCO==nil) initMyNQs()
    if(numarg()>0)mon=$1 else mon=0
    if(mon) {
        nclnq.verbose=0
        for i=0,nqCO.m-1 {
            if(i%100==0) printf("i=%d\n",i)
            ty1=ce.o(i).type
            ic1=ice(ty1)
            spks1=nqCO.v[i].sum()
            for j=0,nqCO.m-1 {
                if(j==i || !nclnq.select("prid",i,"poid",j))continue
                ty2=ce.o(j).type
                vtmp=normte(nqCO.v[i],nqCO.v[j],30)
                spks2=nqCO.v[j].sum()
                nqte.append(i,j,ty1,ty2,ic1,ice(ty2),vtmp.x(0),vtmp.x(2),spks1,spks2)
              }
          }
        nclnq.verbose=1
      } else {
        for i=0,nqCO.m-1 {
            if(i%100==0) printf("i=%d\n",i)
            ty1=ce.o(i).type
            ic1=ice(ty1)
            spks1=nqCO.v[i].sum()
            for j=0,nqCO.m-1 {
                if(j==i)continue
                ty2=ce.o(j).type
                vtmp=normte(nqCO.v[i],nqCO.v[j],30)
                spks2=nqCO.v[j].sum()
                nqte.append(i,j,ty1,ty2,ic1,ice(ty2),vtmp.x(0),vtmp.x(2),spks1,spks2)
              }
          }
      }
    for i=nqte.m-2,nqte.m-1 nqte.v[i].unnan()
    return nqte
  }

//* getincelltenqt() - get nqs of input->cell normalized transfer entropy vs time
//getincelltenqt(bmin,bmax,binc,winsz)
// bmin is min bin, bmax is max bin, binc is # of bins to move over by, winsz = # of bins to examine
obfunc getincelltenqt () { local a,sy,id,intfid,idx,winsz,bmin,bmax,binc,bb,ty,pls,sh2\
                            localobj nqt,vtmp,v1,v2,visi
    bmin=$1 bmax=$2 binc=$3 winsz=$4
    if(numarg()>4 && nqisi!=nil)sh2=$5 else sh2=0
    sy=id=intfid=0
    nqin.tog("DB")
    nqt=new NQS("id","type","syn","t","nte","INTFid","pulse")
    initMyNQs()
    a=allocvecs(v1,v2,visi)
    vrsz(nqt.v[0].size,v1,v2)  vrsz(0,v1,v2)
    idx=0
    for nqin.qt(&id,"id",&sy,"sy",&intfid,"INTFid",&ty,"type",&pls,"pulse") {
        if(sh2) {
            nqisi.select("id",id)
            visi.copy(nqisi.getcol("isi"))
          }
        for(bb=bmin;bb+winsz<=bmax;bb+=binc){
            v1.copy(nqIN.v[intfid],bb,bb+winsz)
            v2.copy(nqCO.v[id],bb,bb+winsz)
            if(sh2) vtmp=normte(v1,v2,30,visi,binsz,htmin) else vtmp=normte(v1,v2,30)
            vtmp.unnan()
            nqt.append(id,ty,sy,htmin+bb*binsz,vtmp.x(2),intfid,pls)
          }
        if(idx%100==0) printf("idx=%d\n",idx)
        idx+=1
      }
    dealloc(a)
    return nqt
  }

//drawEIktau() $o1=nqc,[$2=pulse ID optional]
proc drawEIktau () { local x,pdx,nn localobj nqc,str
    if(g==nil)gg()
    nqc=$o1
    if(numarg()>1)pdx=$2 else pdx=-1
    str=new String()
    if(pflg==0) g.label(0,0,"counts") else g.label(0,0,"probability")
    ers=0 
    clr=3
    if(pdx>-1) nqc.select("syn",AM,"pulse",pdx) else nqc.select("syn",AM)
    hist(g,nqc.getcol("ktau"))
    sprint(str.s,"E input/output ktau, avg=%g",nqc.getcol("ktau").mean)
    g.label(0,0,str.s)
    if(pdx>-1) nn=nqc.select("syn",GA,"pulse",pdx) else nn=nqc.select("syn",GA)
    if(nn>0) {
        clr=2
        sprint(str.s,"I input/output ktau, avg=%g",nqc.getcol("ktau").mean)
        g.label(0,0,str.s)
        hist(g,nqc.getcol("ktau"))  
      }
  }

//* drawEIcmp() -- draws histo comparing AM vs GA input->output relationship on column $s2
//$o1=nqs, $s2=column to perform comparison on,opt arg 3=pulse id, opt 4th arg=cell-type
proc drawEIcmp () { local x,pdx,nn localobj nq,str
    if(g==nil)gg()
    nq=$o1  str=new String()  g.color(1)
    if(pflg==0) g.label(0,0,"counts") else g.label(0,0,"probability")
    //drline(-1,0,1,0,g,1,3)
    {ers=0   clr=3  g.color(clr)}
    if(numarg()>2)pdx=$3 else pdx=-1
    if(numarg()>3) nq.select("syn",AM,"type",$4) else nq.select("syn",AM)
    if(pdx!=-1)nq.select("&&","pulse",pdx)
    hist(g,nq.getcol($s2))
    if(numarg()>3) {
        sprint(str.s,"%s:E input/output %s, avg=%g",CTYP.o($4).s,$s2,nq.getcol($s2).mean)
      } else {
        sprint(str.s,"E input/output %s, avg=%g",$s2,nq.getcol($s2).mean)
      }
    g.label(0,0,str.s)
  
    //GABAA @ SOMA
    if(numarg()>3) nn=nq.select("syn",GA,"type",$4,"loc",SOMA) else nn=nq.select("syn",GA,"loc",SOMA)
    if(nn<1)return
    if(pdx!=-1)nn=nq.select("&&","pulse",pdx)
    if(nn<1)return
    {clr=2 g.color(clr)}
    if(numarg()>3) {
        sprint(str.s,"%s:SOMA I input/output %s, avg=%g",CTYP.o($4).s,$s2,nq.getcol($s2).mean)
      } else {
        sprint(str.s,"SOMA I input/output %s, avg=%g",$s2,nq.getcol($s2).mean)
      }
    g.label(0,0,str.s)
    hist(g,nq.getcol($s2))  
  
    //GABAA @ DEND
    if(numarg()>3) nn=nq.select("syn",GA,"type",$4,"loc",DEND) else nn=nq.select("syn",GA,"loc",DEND)
    if(nn<1)return
    if(pdx!=-1)nn=nq.select("&&","pulse",pdx)
    if(nn<1)return
    {clr=4 g.color(clr)}
    if(numarg()>3) {
        sprint(str.s,"%s:DEND I input/output %s, avg=%g",CTYP.o($4).s,$s2,nq.getcol($s2).mean)
      } else {
        sprint(str.s,"DEND I input/output %s, avg=%g",$s2,nq.getcol($s2).mean)
      }
    g.label(0,0,str.s)
    hist(g,nq.getcol($s2))  
  }


//nqc.select("syn",GA)
//hist(g,nqc.getcol("ktau"))

//* getvpow(nqf,minf,maxf)
//get the power in a range of frequencies from nqf, the matspecgram spectrogram nqs from nqfld
obfunc getvpow () { local a,minf,maxf,i localobj vtmp,vout,nqf,vf
    nqf=$o1 minf=$2 maxf=$3
    a=allocvecs(vtmp,vf) vout=new Vector()
    {vtmp=nqf.get("pow",0).o print vtmp vout.resize(vtmp.size) vout.fill(0)}
    {vf.resize(nqf.v.size)  nqf.getcol("f").uniq(vf)}
    for i=0,vf.size-1 {
        if(vf.x(i)>=minf && vf.x(i)<=maxf) {
            vtmp=nqf.get("pow",i).o
            vout.add(vtmp)
          }
        if(vf.x(i)>maxf) break
      }
    dealloc(a)
    return vout
  }
//* getpfcormat(nqf) -- nqf is from matspecgram, getpfcormat gets power fluctuation correlation matrix
// can get nqf from nqfld+matspecgram like this: nqf=matspecgram(nqfld.v[1],sampr,100,1)
obfunc getpfcormat () { local r1,r2,a localobj mc,v1,v2,nqf
    a=allocvecs(v1,v2) nqf=$o1
    mc=new Matrix(nqf.v.size,nqf.v.size)
    for r1=0,nqf.v.size-1 {
        v1.copy(nqf.get("pow",r1).o)
        mc.x(r1,r1)=1
        for r2=r1+1,nqf.v.size-1 {
            v2.copy(nqf.get("pow",r2).o)
            mc.x(r1,r2) = mc.x(r2,r1) = v1.pcorrel(v2)
          }
      }
    dealloc(a)
    return mc
  }
//* getsyncarea(nqf,mc,minf,maxf,[th]) -- nqf is from matspecgram, mc is from getpfcormat
// gets the 'synchronization area' -- the ratio of pixels in matrix with r > th / that area of the matrix
// frequencies/area used are in range [minf,maxf]
func getsyncarea () { local r1,c1,sa,cnt,minf,maxf,th localobj nqf,mc
    nqf=$o1 mc=$o2 minf=$3 maxf=$4 sa=cnt=0
    if(numarg()>4)th=$5 else th=0.2
    for r1=0,mc.nrow-1 if(nqf.v[0].x(r1)>=minf && nqf.v[0].x(r1)<=maxf) {
        for c1=0,r1-1 if(nqf.v[0].x(c1)>=minf && nqf.v[0].x(c1)<=maxf) {
            if(mc.x(r1,c1)>th) sa+=1
            cnt+=1
          }
      }
    if(cnt>0) return sa/cnt else return 0
  }

//* FileExists(path) - tests whether file exists by opening in 'r' mode
func FileExists(){ localobj f
    f = new File()
    f.ropen($s1)
    if(f.isopen()){
        f.close()
        return 1
      }
    return 0
  }

//load in data from sim, $s1 == vecs file, $s2 == vq nqs file
//* loadmydat()
func loadmydat () {
    {strvecs=$s1 strvq=$s2}
    printf("reading in %s vecs file\n",strvecs)
    gvnew(strvecs) 
    {vit.vec.resize(0)  vit.tvec.resize(0)}
    panobj.rv_readvec(0,vit.tvec,vit.vec) //read in raster
    clrMyNQs() // free histogram NQSs
    printf("reading in %s vq nqs file\n",strvq)
    vq.rd(strvq) 
    if(numarg()>2) {
        strnqin=$s3
        printf("reading in %s nqin nqs file\n",strnqin)
        nqin.rd(strnqin)
      }
    if(numarg()>3) {
        strnqfld=$s4
        if(FileExists(strnqfld)) {
            printf("reading in %s nqfld nqs file\n",strnqfld)
            nqfld.rd(strnqfld)
          } else printf("%s doesn't exist\n",strnqfld)
      }
    return 1
  }
proc loadwtsoffdat () { //load 09mar30.27 sim raster/vq data , internal weights off
    strvecs="/u/samn/vcsim/data/09mar30.27_wtsoff.vecs"
    strvq="/u/samn/vcsim/data/09mar30.27_wtsoffvq.nqs"
    loadmydat(strvecs,strvq)
  }
proc loadwtsonslowdat () { //load 09mar30.48 sim raster/vq data , internal weights on
    strvecs="/u/samn/vcsim/data/09mar30.48_wtson.vecs"
    strvq="/u/samn/vcsim/data/09mar30.48_wtson_vq.nqs"
    loadmydat(strvecs,strvq)
  }
proc loadwtsonfastdat () { //load 09mar30.46 sim raster/vq data , internal weights on
    strvecs="/u/samn/vcsim/data/09mar30.46_wtson.vecs"
    strvq="/u/samn/vcsim/data/09mar30.46_vq.nqs"
    loadmydat(strvecs,strvq)
  }
proc loadwts15dat () { //load 09apr11.10 sim raster/vq data , internal weights on @ 15%
    strvecs="/u/samn/vcsim/data/09apr11.10_wtson.vecs"
    strvq="/u/samn/vcsim/data/09apr11.10_wtson_vq.nqs"
    loadmydat(strvecs,strvq)
  }
proc pravgrates () { local idx,ct,dur localobj vspk
    if(numarg()>0)dur=$1 else dur=sgrdur
    vspk=new Vector(CTYPi+1)
    idx=ct=0 //print average firing rates from vit, assumes sgrdur,numc same as when ran sim
    for vtr(&idx,vit.vec) vspk.x(ce.o(idx).type)+=1
    for ctt(&ct) printf("avg rate for %s: %gHz\n",CTYP.o(ct).s,(1e3*vspk.x(ct)/dur)/numc[ct])
  }
func prctcellsfired () { local a,i,pr,ct localobj vf
    a=allocvecs(vf) 
    if(numarg()>0) {
        ct=$1
        if(ct<0 || ct>=CTYPi) {
            print "invalid ct = ", ct
            return 0
          }
        vrsz(numc[ct],vf) vf.fill(0)
        for vtr(&i,vit.vec) if(ce.o(i).type==ct) vf.x(i-ix[ct])=1
        pr=vf.count(1)/numc[ct]
      } else {
        vrsz(allcells,vf) vf.fill(0)
        for vtr(&i,vit.vec) vf.x(i)=1  
        pr=vf.count(1)/allcells
      }
    dealloc(a)
    return pr
  }

//* minrunsv() minimal run/save of data , just save vecs, vq, nqin
proc minrunsv () { localobj st
    st=new String()
    time("run()")
    printf("\nran sim for %g\n",tstop)
    sprint(st.s,"data/%s_.vecs",strv)
    panobj.pvplist(st.s,strv)
    printf("saved vecs\n")
    sprint(st.s,"data/%s_vq.nqs",strv)
    vq.tog("DB")
    vq.sv(st.s)
    printf("saved inputs\n")
    sprint(st.s,"data/%s_nqin.nqs",strv)
    nqin.tog("DB")
    nqin.sv(st.s)
    printf("saved nqin\n")
    sprint(st.s,"data/%s_nqfld.nqs",strv)
    nqfld.sv(st.s)
    printf("saved nqfld\n")
  }
//$s1=version string, loads the data created from minrunsv
proc loadminrundat () { localobj st,stt
    st=new String2() stt=new String2()
    sprint(st.s,"data/%s_.vecs",$s1)
    sprint(st.t,"data/%s_vq.nqs",$s1)
    sprint(stt.s,"data/%s_nqin.nqs",$s1)
    sprint(stt.t,"data/%s_nqfld.nqs",$s1)
    loadmydat(st.s,st.t,stt.s,stt.t)
  }

//run sim do some transfer entropy calculations
proc doit () { localobj st
    st=new String()
    htmin=0
    minrunsv() //do the run, save inputs, outputs, LFP
  
    binsz=100 //larger bin for kendall's tau
    clrMyNQs()
    {nqsdel(nqktau) nqktau=gettaunq()} // input -> output ktau
    printf("got ktaunq\n")
    sprint(st.s,"data/%s_nqktau.nqs",strv)
    nqktau.sv(st.s)
    printf("saved nqktau\n")
    
    binsz=10 //smaller binsize for transfer entropy
    clrMyNQs()
    
    {nqsdel(nqte) nqte=getTEnq()} //input -> output nTE
    printf("got TEnq\n")
    sprint(st.s,"data/%s_nqte.nqs",strv)
    nqte.sv(st.s)
    printf("saved nqte\n")
   
    {nqsdel(nqtea) nqtea=getTEnqAllsub(E2)} // nTE of all E2 input -> all E2 output
    sprint(st.s,"data/%s_E2_nqtea.nqs",strv)
    nqtea.sv(st.s)
    printf("saved nqtea E2\n")
  }
//load data from doit, just specify the strv version string before calling it
proc loadit () { localobj st,stt
    clrMyNQs()
    st=new String2() stt=new String2()
    loadminrundat(strv)
    printf("read vecs+inputs+nqin\n")
  
    sprint(st.s,"data/%s_nqktau.nqs",strv)
    if(nqktau==nil) nqktau=new NQS(st.s) else nqktau.rd(st.s)
  
    binsz=10
    htmin=0
  
    sprint(st.s,"data/%s_nqte.nqs",strv)
    if(nqte==nil) nqte=new NQS(st.s) else nqte.rd(st.s)
    printf("read nqte\n")
  
    sprint(st.s,"data/%s_E2_nqtea.nqs",strv)
    if(nqtea==nil) nqtea=new NQS(st.s) else nqtea.rd(st.s)
    printf("read nqtea E2\n")
  }

//* per col functions
proc coldens () { local col,x,uni,tn,tx localobj xo
    if (numarg()==2) {tn=$1 tx=$2} else { tn=0 tx=tstop }
    vcty.reverse()  pq.verbose=0
    printf("|COL\t")
    for col=0,3 printf("|%d\t",col) print "|"
    for vtr(&x,vcty) {
        printf("|%3s: \t",CTYP.o(x).s)
        for col=0,3 { 
            xo=csel(x,col) 
            if (pq.select("t","[]",tn,tx,"ind","[]",xo.x,xo.x[1])) {
                uni=pq.getcol("ind").uniq
              } else uni=0
            printf("|%4.0f\t",uni/cpercol[x]*100,uni)
          }
        print "|"
      }
    vcty.reverse()  pq.verbose=1
  }

//** colfreq()
proc colfreq () { local col,x,tx,tn localobj xo
    if (numarg()==2) { tn=$1 tx=$2 } else {tn=0 tx=tstop}
    printf("COL\t")
    for col=0,3 printf("%d\t",col) print ""
    vcty.reverse()
    for vtr(&x,vcty) { printf("%4s: ",CTYP.o(x).s)
        for col=0,3 { xo=csel(x,col) 
            printf("%4.1f  ",\
                   pq.select(-1,"t","[]",tn,tx,"ind","[]",xo.x,xo.x[1])/cpercol[x]*1e3/(tx-tn))
          }
        print ""
      }
    vcty.reverse()
  }
// END nload.hoc
//================================================================
//////////////////////////////////////////////////

//////////////////////////////////////////////////
// Demo code

declare("myvbox","o[1]","myg","o[5]")

//* dodisp - display output
proc dodisp () { local i,idx localobj vec,tvec
    myvbox=new VBox()
    myvbox.intercept(1)
    for i=0,4 myg[i]=new Graph()
    vit.vec.mark(myg[0],vit.tvec,"O",4,1,1)
    printlist.o(7).vec.label("L5IB")
    printlist.o(9).vec.label("L5RS")
    printlist.o(13).vec.label("L5LTS")
    nqfld.v[1].label("LFP")
    nqfld.v[1].plot(myg[1],nqfld.v[0],1,1)
    idx=2
    for case(&i,7,9,13) {
        {vec=printlist.o(i).vec tvec=printlist.o(i).tvec}
        vec.plot(myg[idx],printStep,1,1)
        idx+=1
      }
    for i=0,4 myg[i].exec_menu("View = plot")
    myvbox.intercept(0)
    myvbox.map()
  }

//* dorun - run & display output
proc dorun () {
    run()
    dodisp()
  }

//* myrunpan - main gui
proc myrunpan () {
    xpanel("Neocortical Column Demo")
    xbutton("Run neocortical column simulation & display output","dorun()")
    xlabel("Neocortical Column Simulation Demo.")
    xlabel("Model described in:")
    xlabel("Synaptic information transfer in computer models of neocortical columns.")
    xlabel("Article by SA Neymotin, KM Jacobs, AA Fenton, and WW Lytton")
    xlabel("Journal of Computational Neuroscience (2010), in press.")
    xlabel("PubMed ID 20556639.")
    xpanel()
  }
myrunpan()

// end Demo code
//////////////////////////////////////////////////
// END mdb.hoc
//================================================================