Index: /tools/pytools/README
===================================================================
--- /tools/pytools/README	(revision 18)
+++ /tools/pytools/README	(revision 18)
@@ -0,0 +1,9 @@
+
+General Python tools.
+
+Ole Nielsen 2001,2002
+
+---------------------+
+combinatorics.py  
+compile.py  
+stats.py
Index: /tools/pytools/__init__.py
===================================================================
--- /tools/pytools/__init__.py	(revision 18)
+++ /tools/pytools/__init__.py	(revision 18)
@@ -0,0 +1,5 @@
+from compile import *
+from stats import *
+from combinatorics import *
+from numtools import *
+from misc import *
Index: /tools/pytools/combinatorics.py
===================================================================
--- /tools/pytools/combinatorics.py	(revision 18)
+++ /tools/pytools/combinatorics.py	(revision 18)
@@ -0,0 +1,41 @@
+"""
+  Combinatorial function using NumPy
+  OMN, 2001
+"""  
+	
+import Numeric
+
+def factorial(n):
+  v = Numeric.arange(n)+1
+  return Numeric.multiply.reduce(v)
+
+def binom (n,k):
+  """ Compute the binomial coefficient n!/(k! (n-k)!)
+  """
+  
+  if k > n or n < 0 or k < 0:
+    raise Exception
+  elif k==n or n==0 or k==0:
+    return(1)
+  else:
+    v = Numeric.arange(k) + n-k+1 #[n-k+1, ..., n-1, n]
+    nom = Numeric.multiply.reduce(v)
+    denom = factorial(k)
+    
+    return nom/denom 
+
+def bitvector(i, n):
+    """Compute binary representation of positive integer i in a word of size n
+    """
+    
+    b=[0]*n
+    k=0
+    while i > 0:
+        d = i%2
+        b[k] = d
+        i = i/2
+        k = k+1
+        if k > n: break
+    return b
+
+
Index: /tools/pytools/compile.py
===================================================================
--- /tools/pytools/compile.py	(revision 18)
+++ /tools/pytools/compile.py	(revision 18)
@@ -0,0 +1,240 @@
+"""compile.py - compile Python C-extension
+
+   Commandline usage: 
+     python compile.py <filename>
+
+   Usage from within Python:
+     import compile
+     compile.compile(<filename>,..)
+
+   Ole Nielsen, Oct 2001      
+"""     
+ 
+def compile(FNs=None, CC=None, LD = None, SFLAG = None, verbose = 1):
+  """compile(FNs=None, CC=None, LD = None, SFLAG = None):
+  
+     Compile FN(s) using compiler CC (e.g. mpicc), 
+     Loader LD and shared flag SFLAG.
+     If CC is absent use default compiler dependent on platform
+     if LD is absent CC is used.
+     if SFLAG is absent platform default is used
+     FNs can be either one filename or a list of filenames
+     In the latter case, the first will be used to name so file.
+  """
+  import os, string, sys, types
+  
+  # Input check
+  #
+  assert not FNs is None, "No filename provided"
+
+  if not type(FNs) == types.ListType:
+    FNs = [FNs]
+
+
+  libext = 'so' #Default extension (Unix)
+  libs = ''
+  version = sys.version[:3]
+  
+  # Determine platform and compiler
+  #
+  if sys.platform == 'sunos5':  #Solaris
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'gcc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'G'
+      
+  elif sys.platform == 'osf1V5':  #Compaq AlphaServer
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'cc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'shared'    
+      
+  elif sys.platform == 'linux2':  #Linux
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'gcc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'shared'    
+      
+  elif sys.platform == 'darwin':  #Mac OS X:
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'cc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'bundle -flat_namespace -undefined suppress'
+
+  elif sys.platform == 'cygwin':  #Cygwin (compilation same as linux)
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'gcc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'shared'
+    libext = 'dll'
+    libs = '/lib/python%s/config/libpython%s.dll.a' %(version,version)
+      
+  elif sys.platform == 'win32':  #Windows
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'gcc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'shared'
+    libext = 'dll'
+
+    v = version.replace('.','')
+    dllfilename = 'python%s.dll' %(v)
+    libs = os.path.join(sys.exec_prefix,dllfilename)
+      
+      
+  else:
+    if verbose: print "Unrecognised platform %s - revert to default"\
+                %sys.platform
+    
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'cc'
+    if LD:
+      loader = LD
+    else:  
+      loader = 'ld'
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'G'
+
+            
+  # Find location of include files
+  #
+  if sys.platform == 'win32':  #Windows
+    include = os.path.join(sys.exec_prefix, 'include')    
+  else:  
+    include = os.path.join(os.path.join(sys.exec_prefix, 'include'),
+                           'python'+version)
+
+  # Check existence of Python.h
+  #
+  headerfile = include + os.sep +'Python.h'
+  try:
+    open(headerfile, 'r')
+  except:
+    raise """Did not find Python header file %s.
+    Make sure files for Python C-extensions are installed. 
+    In debian linux, for example, you need to install a
+    package called something like python2.3-dev""" %headerfile
+  
+  
+  # Check filename(s)
+  #
+  object_files = ''
+  for FN in FNs:        
+    root, ext = os.path.splitext(FN)
+    if ext == '':
+      FN = FN + '.c'
+    elif ext.lower() != '.c':
+      raise Exception, "Unrecognised extension: " + FN
+    
+    try:
+      open(FN,'r')
+    except:    
+      raise Exception, "Could not open: " + FN
+
+    if not object_files: root1 = root  #Remember first filename        
+    object_files += root + '.o '  
+  
+  
+    # Compile
+    #
+    
+    s = "%s -c %s -I%s -o %s.o -Wall -O" %(compiler, FN, include, root)
+    if verbose:
+      print s
+    else:
+      s = s + ' 2> /dev/null' #Suppress errors
+  
+    try:
+      err = os.system(s)
+      if err != 0:
+          raise 'Attempting to compile %s failed - please try manually' %FN 
+    except:
+      raise 'Could not compile %s - please try manually' %FN  
+
+  
+  # Make shared library (*.so or *.dll)
+  
+  s = "%s -%s %s -o %s.%s %s -lm" %(loader, sharedflag, object_files, root1, libext, libs)
+  if verbose:
+    print s
+  else:
+    s = s + ' 2> /dev/null' #Suppress warnings
+  
+  try:  
+    err=os.system(s)
+    if err != 0:	
+	raise 'Atempting to link %s failed - please try manually' %root1     
+  except:
+    raise 'Could not link %s - please try manually' %root1
+    
+
+
+
+if __name__ == '__main__':
+
+  import sys
+  
+  # Get file to compile
+  #
+  if len(sys.argv) < 2:
+    print "Usage:"
+    print "  python compile.py <filename>"
+    sys.exit()
+
+  filenames = []
+  for filename in sys.argv[1:]:
+    filenames.append(filename)
+    
+  compile(filenames, verbose=1)
+
Index: /tools/pytools/diskreport.py
===================================================================
--- /tools/pytools/diskreport.py	(revision 18)
+++ /tools/pytools/diskreport.py	(revision 18)
@@ -0,0 +1,112 @@
+"""Cross tabulate old and large files on specified file system
+
+Usage
+
+python diskreport.py /d/cit/7 1080 500000
+"""
+
+
+import os, time, sys
+
+
+if len(sys.argv) > 1:
+    dir = sys.argv[1]
+    days = int(sys.argv[2])
+    filesize = int(sys.argv[3]) 
+else:   
+    dir = '.'
+    days = 180
+    filesize = 500000  #One half megabyte
+
+tempfile = '/tmp/diskreport_' + str(time.time())
+
+
+# Find the largest directories
+cmd = 'du -k %s | sort -nr > %s' %(dir, tempfile)
+print cmd
+os.system(cmd)
+
+fid = open(tempfile)
+lines = fid.readlines()
+fid.close()
+
+txt = 'Top 50 largest directories'
+os.system('echo "%s" > top50.txt' %txt)
+
+fid = open('top50.txt', 'a')
+for line in lines[:50]:
+    l = line.strip()
+    print l
+    fid.write(l + '\n')
+fid.close()
+
+
+
+# Find old files
+#
+cmd = 'find %s -atime +%d > %s 2>/dev/null' %(dir, days, tempfile)
+print cmd
+os.system(cmd)
+
+
+fid = open(tempfile)
+lines = fid.readlines()
+fid.close()
+
+txt = 'Files that haven\'t been accessed for %d days:' %days
+print txt +'%d' %len(lines) + '. See oldfiles.txt for details' 
+
+os.system('echo "%s" > oldfiles.txt' %txt)
+oldfiles = []
+for line in lines:
+    l = line.strip()
+    oldfiles.append(l)
+    cmd = 'ls -lua %s >> oldfiles.txt 2>/dev/null' %l
+    print cmd
+    os.system(cmd)	
+
+
+
+
+# Find big files
+#
+cmd = 'find %s -size +%dc > %s 2>/dev/null' %(dir, filesize, tempfile) 
+print cmd
+os.system(cmd)
+
+
+fid = open(tempfile)
+lines = fid.readlines()
+fid.close()
+
+txt = 'Files that are larger than %.2f MB:' %(filesize/1000000.0)
+print txt +'%d' %len(lines) + '. See bigfiles.txt for details' 
+
+os.system('echo "%s" > bigfiles.txt' %txt)
+bigfiles = []
+for line in lines:
+    l = line.strip()
+    bigfiles.append(l)
+    cmd = 'ls -lua %s >> bigfiles.txt 2>/dev/null' %l
+    print cmd
+    os.system(cmd)	
+fid.close()
+
+os.remove(tempfile)
+
+
+#Find intersection
+txt = 'Files that are larger than %.2f MB and haven\'t been accessed for at least %d days:'\
+       %(filesize/1000000.0, days)
+print txt
+
+os.system('echo "%s" > intersection.txt' %txt)
+for old in oldfiles:
+   if old in bigfiles:
+       cmd = 'ls -lua %s 2>/dev/null >> intersection.txt' %old
+       os.system(cmd)	
+       cmd = 'ls -lua %s 2>/dev/null' %old
+       os.system(cmd)	
+
+
+
Index: /tools/pytools/files.py
===================================================================
--- /tools/pytools/files.py	(revision 18)
+++ /tools/pytools/files.py	(revision 18)
@@ -0,0 +1,97 @@
+"""Useful tools for manipulating files and directories
+"""
+
+def make_filename(s):
+    """Transform argument string into a suitable filename
+    """
+
+    s = s.strip()
+    s = s.replace(' ', '_')
+    #s = s.replace('(', '{')
+    #s = s.replace(')', '}')
+    s = s.replace('(', '')
+    s = s.replace(')', '')
+    s = s.replace('__', '_')                
+        
+    return s
+
+
+def check_dir(path, verbose=None):
+    """Check that specified path exists.
+    If path does not exist it will be created if possible    
+
+    USAGE:
+       checkdir(path, verbose):
+
+    ARGUMENTS:
+        path -- Directory
+        verbose -- Flag verbose output (default: None)
+
+    RETURN VALUE:
+        Verified path including trailing separator
+        
+    """
+
+    import os, sys
+    import os.path
+
+    if sys.platform in ['nt', 'dos', 'win32', 'what else?']:
+        unix = 0
+    else:
+        unix = 1
+
+
+    if path[-1] != os.sep: 
+        path = path + os.sep  # Add separator for directories
+
+    path = os.path.expanduser(path) # Expand ~ or ~user in pathname
+    if not (os.access(path,os.R_OK and os.W_OK) or path == ''):
+        try:
+            exitcode=os.mkdir(path)
+
+            # Change access rights if possible
+            #
+            if unix:
+                exitcode=os.system('chmod 775 '+path)
+            else:
+                pass  # FIXME: What about acces rights under Windows?
+            
+            if verbose: print 'MESSAGE: Directory', path, 'created.'
+          
+        except:
+            print 'WARNING: Directory', path, 'could not be created.'
+            if unix:
+                path = '/tmp/'
+            else:
+                path = 'C:'
+                
+            print 'Using directory %s instead' %path
+
+    return(path)
+
+    
+
+def del_dir(path):
+    """Recursively delete directory path and all its contents
+    """
+
+    import os
+
+    if os.path.isdir(path):
+        for file in os.listdir(path):
+            X = os.path.join(path, file)
+
+
+            if os.path.isdir(X) and not os.path.islink(X):
+                del_dir(X) 
+            else:
+                try:
+                    os.remove(X)
+                except:
+                    print "Could not remove file %s" %X
+
+        os.rmdir(path)
+
+        
+
+
Index: /tools/pytools/graphics.py
===================================================================
--- /tools/pytools/graphics.py	(revision 18)
+++ /tools/pytools/graphics.py	(revision 18)
@@ -0,0 +1,35 @@
+###############################
+def plot(f, delay=1):
+  # Plot it
+  #
+  #
+  from Gnuplot import Gnuplot, GridData
+  g = Gnuplot()
+  g('set grid')
+  
+  
+  if len(f.shape) > 2:
+    # Plot a 2D slice from last two dimensions
+    #  
+    N = len(f.shape)
+    zeros = '0,'*(N-2)
+    s = 'GridData(f[' + zeros + ':,:],with="lines")'
+    data = eval(s)
+    g.splot(data)        
+  
+  else:
+    data = GridData(f,with="lines")
+    g.splot(data)        
+  
+  import types
+  if delay:
+    if type(delay) in [types.IntType, types.FloatType, types.LongType]: 
+      import time  
+      time.sleep(delay)
+    else:
+      raise "Unknown type for delay", delay   
+  else:
+    raw_input('Press any key to stop')
+
+
+      
Index: /tools/pytools/misc.py
===================================================================
--- /tools/pytools/misc.py	(revision 18)
+++ /tools/pytools/misc.py	(revision 18)
@@ -0,0 +1,20 @@
+      
+def merge_dictionaries(D1,D2):
+    """merge_dictionaries(D1,D2)
+  
+       Merge two disjoint dictionaries
+       The first argument D1 is modified to hold the result of the merger.
+       If dictionaries are not disjoint an exception is raised
+    """
+    import types
+
+    for k in D2.keys():
+        val = D2[k]
+        if not D1.has_key(k):
+            D1[k] = val        
+        else:
+            print 'Dictionaries not disjoint'
+            raise Exception
+  
+    return D1
+
Index: /tools/pytools/numtools.py
===================================================================
--- /tools/pytools/numtools.py	(revision 18)
+++ /tools/pytools/numtools.py	(revision 18)
@@ -0,0 +1,133 @@
+"""Functions for numerical computations
+"""
+
+epsilon = 1.0e-15
+
+
+
+
+
+def sum(x):
+  """
+    Attempt to sum up elements in x
+  """
+
+  import types, Numeric
+  
+  if type(x) == Numeric.ArrayType:
+    return Numeric.sum(x)
+  elif type(x) in [types.ListType, types.TupleType]:
+    s = x[0]
+    for e in x[1:]:
+      s += e
+    return s  
+
+def mvmul(A, x):
+  """Multiply matrix A onto vector x
+  """
+
+  from Numeric import dot, reshape
+
+  x = reshape(x, (A.shape[1], 1)) #Make x a column vector             
+
+  return dot(A, x)
+
+
+def all_equal(vec):
+
+  equal = 1
+  v0 = vec[0]
+  for v in vec:
+    if v != v0:
+      equal = 0   
+
+  return equal
+
+
+def meshgrid(N):
+  """Make meshgrid (a' la Matlab)  
+  """
+  
+  from Numeric import ones, arange, Float, multiply
+
+  d = len(N)
+
+  X = [] 
+  for s in range(d):
+    local_shape = ones(d)
+    local_shape[s] = N[s]
+    a = arange(N[s])
+    if N[s] > 1:
+      a = a.astype(Float)/(N[s]-1)
+    else:
+      a = a.astype(Float)
+    
+    # Put ones in all other dimensions
+    #
+    e = [] 
+    for t in range(d):
+      if s == t:  
+        e.append(a)
+      else:
+        e.append(ones(N[t]))
+    
+    # Take kronecker product of all dimensions
+    #
+    x = 1  
+    for t in range(d):
+      x=multiply.outer(x,e[t])
+
+    #print x, x.shape
+    X.append(x)
+    
+  return X    
+    
+
+def expand(x, mask):
+  """Expand vector x into into vector of length equal to vector
+     mask such that elements of x are placed where mask is one.
+     Number of ones in mask must equal len(x)."""
+
+  from Numeric import sum, ArrayType, zeros
+
+  assert type(x) == ArrayType
+  assert type(mask) == ArrayType
+  #FIXME: Assert that mask contains only ones and zeros
+  assert len(x) == sum(mask), 'Number of ones in mask must equal length of x'
+
+  d = len(mask)
+  y = zeros(d, x.typecode())
+
+  i = 0
+  for s in range(d):
+    if mask[s]:
+      y[s] = x[i] 
+      i += 1
+
+  return y    
+
+
+def pwr2trunc(N, e = None, dir = 0): 
+    """N1 = pwr2trunc(N, e, dir)
+
+    If e is None, let e be the largest integer such that N > 2**e.
+    
+    If dir = 0 (default)
+      Compute the nearest number smaller than N divisible by 2^e
+    if dir == 1
+      Compute the nearest number greater than N divisible by 2^e
+
+     
+    """  
+
+    import math
+
+    if e is None:
+        e = int(math.log(N)/math.log(2))  # Maximal exponent
+
+    k = N % 2**e
+    N1 = N - k
+    if dir == 1:
+        N1  = 2*N1
+
+    return N1, e
Index: /tools/pytools/rcvs.py
===================================================================
--- /tools/pytools/rcvs.py	(revision 18)
+++ /tools/pytools/rcvs.py	(revision 18)
@@ -0,0 +1,323 @@
+#!/usr/bin/env python
+
+""" This script (rcvs) executes cvs on a remote cvs client. 
+Useful when cvs access is only allowed from one particular host.
+
+Definitions
+    CVS server: host where CVS repository resides
+    CVS client: host from which access to CVS server is allowed
+    local host: host that must access CVS repository through CVS client
+
+
+Assumptions:
+
+   1:CVS client can be reached from local host without passwords 
+     using ssh and rsync
+
+   2:Usernames on CVS client and CVS server are the same
+
+   3:Details about CVS Host are supplied at the top of this script
+   
+   4:CVSROOT environment variable point to CVS client so that username and CVS client
+     can be inferred automatically 
+
+   5:Each user has a directory called sandpit in their home directory on the CVS client
+
+   6:CVS client has a UNIX/Linux file structure 
+
+   7:That user has performed a CVS login once from CVS client to CVS host 
+
+   
+Modus operandi:     
+   
+The rcvs script will do updates, add and commit plus download (unique to rcvs)
+Commands such as tag, remove etc mus be done on cvs client.
+
+
+Examples:
+
+  
+  rcvs checkout repository     (checkout and download repository from cvs client)  
+
+  rcvs add [files...]          (add named files to repository)
+  
+  rcvs update [files...]       (update named files from cvs server)
+
+  rcvs com -m "msg" [files...] (Commit changes with log message)
+
+  rcvs log [files...]          (List log history for files)  
+
+  rcvs download repository     (download repository from cvs client)
+
+
+If files are omitted command will work on all files in repository.
+
+SSH Setup
+To get cgywin ssh working, wothout using passwords;
+1) Set the environment variable
+   CYGWIN = smbntsec
+2) In windows explorer/permissions/security, make sure the private key has
+   only 1 user
+
+Copyright 2004
+Ole Nielsen and Duncan Gray
+Geoscience Australia
+"""
+
+#Details about CVS Host
+protocol = 'pserver'
+cvs_host = 'cuttlefish.anu.edu.au'
+cvs_dir = '/home/cvs'
+
+
+rsep = '/'          #Separator on cvs client
+from os import sep  #Separator on local machine
+
+import sys, os
+
+#Get Username and cvs client - assumed to be the same on cvs host and remote cvs client
+
+s = os.getenv('CVSROOT')
+username = ''
+cvs_client = ''
+if len(s) > 0:
+    atsign = s.index('@')
+
+    #Username
+    i = atsign-1
+    while i > 0 and s[i] != ':':
+        username = s[i] + username
+        i -= 1
+
+    #CVS client
+    i = atsign+1
+    while i < len(s) and s[i] != ':':
+        cvs_client += s[i]
+        i += 1
+
+if len(username) == 0:
+    msg = 'Could not infer user name from environment variable CVSROOT (%s)' %s
+    raise msg
+
+if len(cvs_client) == 0:
+    msg = 'Could not infer CVS client from environment variable CVSROOT (%s)' %s
+    raise msg
+
+
+#CVSROOT = ':pserver:%s@cuttlefish.anu.edu.au:/home/cvs' %username
+CVSROOT = ':%s:%s@%s:%s' %(protocol, username, cvs_host, cvs_dir)
+
+
+#specify location of remote repositories (assuming UNIX separators)
+sandpit = '~' + rsep + 'sandpit'
+
+
+def run(cmd):
+    import os
+    print cmd
+    os.system(cmd)    
+
+
+def upload(dir):
+    files=get_cvsfiles()
+    #s = 'rsync --cvs-exclude -qavz %s %s@%s:%s'\
+    s = 'rsync -qavz %s %s@%s:%s' %(files, username, cvs_client, sandpit + rsep + dir)
+    print '---------- UPLOADING -------------'    
+    run(s)
+
+
+def download(dir):
+    import os
+    
+    s = 'rsync -qavz %s@%s:%s' %(username, cvs_client, sandpit) +\
+        rsep + dir + rsep + '* .'
+    print '---------- DOWNLOADING -------------'        
+    run(s)
+
+
+def cvscmd(dir, cmd, args):
+    x = ''
+    for arg in args:
+        x += str(arg) + ' '
+
+    s = 'ssh -X %s@%s "cd %s; cvs %s %s"' %(username, cvs_client,
+                                            sandpit + rsep + dir,
+                                            cmd, x)
+    print '---------- CVS OUTPUT -------------'
+    run(s)
+
+
+
+#FIXME: Not done yet and maybe it shouldn't
+def get_cvsfiles():
+    """Get files that are registered under CVS
+    """
+    import os
+
+    #Get name of local repository
+    localdir = os.getcwd()
+
+    if not 'CVS' in os.listdir(localdir):
+        raise 'No CVS directory in current directory'
+
+    FN = localdir + sep + 'CVS' + sep + 'Entries'
+    try:
+        fid = open(FN)
+    except:
+        msg = 'Could not open %s' %FN
+        raise msg
+    else:
+        files = ''
+        for entry in fid.readlines():
+            #print entry
+            pass
+            
+
+    return '*'    
+        
+
+def get_repository():
+    """Get name of CVS repository from CVS directory
+    """
+    import os
+
+    #Get name of local repository
+    localdir = os.getcwd()
+
+    if not 'CVS' in os.listdir(localdir):
+        raise 'No CVS directory in current directory'
+
+
+    FN = localdir + sep + 'CVS' + sep + 'Repository'
+    try:
+        fid = open(FN)
+    except:
+        msg = 'Could not open %s' %FN
+        raise msg
+    else:
+        repository = fid.readlines()[0].strip()
+
+
+    #Get actual name of local repository
+    local = os.path.split(localdir)[1]
+
+    #if local != repository:
+    #    msg = 'Local directory (%s) and ' %local
+    #    msg += 'CVS repository (%s) must have the same name' %repository
+    #    raise msg
+
+    return repository
+
+
+if len(sys.argv) > 1:
+    arg = sys.argv[1]
+
+    if arg.find('upd') == 0:
+        dir = get_repository()
+        upload(dir)        
+        cvscmd(dir, 'update', sys.argv[2:])
+        download(dir)
+
+
+    if arg.find('com') == 0 or arg.find('ci') == 0:
+        dir = get_repository()
+        upload(dir)                
+
+        args = sys.argv[2:]
+
+        try:
+            i = args.index('-m')
+        except:
+            comment = 'None'            
+            remaining_args = args
+        else:
+            #We have a text argument for the log file
+            comment = '%s' %(args[i+1])
+            if len(comment) == 0:
+                comment = 'None'
+            remaining_args = args[:i]+args[i+2:]            
+
+        command = 'commit -m """%s"""' %comment
+        #cvscmd(dir, 'update', remaining_args)
+        cvscmd(dir, command, remaining_args)
+        download(dir)
+
+
+    if arg.find('add') == 0:
+        dir = get_repository()
+        upload(dir)                
+        cvscmd(dir, 'add', sys.argv[2:])        
+        download(dir)
+        
+
+    if arg.find('log') == 0:
+        dir = get_repository()     
+        upload(dir)                   
+        cvscmd(dir, 'log', sys.argv[2:])
+        
+    if arg.find('diff') == 0:
+        dir = get_repository()     
+        upload(dir)                   
+        cvscmd(dir, 'diff', sys.argv[2:])
+
+    if arg.find('annotate') == 0:
+        dir = get_repository()     
+        upload(dir)                   
+        cvscmd(dir, 'annotate', sys.argv[2:])
+
+
+
+    #FIXME: Maybe Obsolete    
+    if arg.find('down') == 0:
+        import os
+        if len(sys.argv) == 3:
+            arg = sys.argv[2]
+
+            os.mkdir(arg)  #Create local copy of repository
+            os.chdir(arg)  
+            download(arg)
+
+
+    if arg.find('co') == 0 or arg.find('checkout') == 0:
+        import os
+        if len(sys.argv) == 3:
+            arg = sys.argv[2]
+
+            #Create local copy of repository
+            try:
+                os.mkdir(arg)
+            except OSError:
+                pass
+                #msg = 'Could not create directory %s' %arg
+                #raise msg
+                
+            os.chdir(arg)
+
+            #Check out from CVS host
+            s = 'ssh -X %s@%s "cd %s;cvs -d %s checkout %s"'\
+                %(username, cvs_client, sandpit, CVSROOT, arg)
+            print '---------- CVS OUTPUT -------------'
+            run(s)            
+
+            #Download from CVS client
+            download(arg)
+
+else:
+    print 'Usage'
+    print '''
+  rcvs checkout repository     (checkout repository from cvs client)  
+
+  rcvs add [files...]          (add named files to repository)
+  
+  rcvs update [files...]       (update named files from cvs server)
+
+  rcvs com -m "msg" [files...] (Commit changes with log message)
+
+  rcvs log [files...]          (List log history for files)
+  
+  rcvs diff [files...]         (List diffs for files)
+  
+  rcvs annotate [files...]     (List files with cvs annotations)    
+
+  rcvs download repository     (download repository from cvs client)'''
+
Index: /tools/pytools/stats.py
===================================================================
--- /tools/pytools/stats.py	(revision 18)
+++ /tools/pytools/stats.py	(revision 18)
@@ -0,0 +1,89 @@
+#def mean(x):
+#  import Numeric, caching
+#  reload(caching)#
+#
+#  sum = caching.cache(Numeric.sum,x,verbose=0)
+#  #sum = Numeric.sum(x)  
+#  avg = float(sum)/len(x)
+#
+#  return(avg)
+
+def mean(x):
+  import Numeric
+
+  sum = Numeric.sum(x)  
+  avg = float(sum)/len(x)
+
+  return(avg)
+
+
+def cov(x,y=None):
+  import Numeric
+  if y is None:
+    y = x 
+
+  assert(len(x)==len(y))
+  N = len(x)
+ 
+  cx = x - mean(x)  
+  cy = y - mean(y)  
+
+  p = Numeric.innerproduct(cx,cy) / N
+
+
+  return(p)
+
+
+def err(x,y=0,n=2):
+  """Relative error of ||x-y|| to ||y||
+     n = 2:    Two norm
+     n = None: Max norm
+
+     If denominator evaluates to zero, absolute error is returned
+  """
+
+  
+  if n == 2:
+      err = norm(x-y)
+      try:
+          err = err/norm(y)
+      except:
+          pass
+
+  else:
+      err = max(abs(x-y))
+      try:
+          err = err/max(abs(y))    
+      except:
+          pass
+        
+  return err
+  
+
+def norm(x):
+  """2-norm of x
+  """
+  
+  import Numeric  
+  y = Numeric.ravel(x)
+  p = Numeric.sqrt(Numeric.innerproduct(y,y))
+  return p
+    
+  
+def corr(x,y=None):
+  import caching  
+  from math import sqrt
+  if y is None:
+    y = x 
+
+  varx = caching.cache(cov,x,verbose=0)
+  vary = caching.cache(cov,y,verbose=0)
+  #varx = cov(x)
+  #vary = cov(y)
+
+  if varx == 0 or vary == 0:
+    C = 0
+  else:  
+    C = cov(x,y)/ sqrt(varx * vary)   
+
+  return(C)
Index: /tools/pytools/test_pytools.py
===================================================================
--- /tools/pytools/test_pytools.py	(revision 18)
+++ /tools/pytools/test_pytools.py	(revision 18)
@@ -0,0 +1,52 @@
+import unittest
+import Numeric
+from combinatorics import bitvector
+from numtools import expand 
+
+#-------------------------------------------------------------
+
+class TestCase(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def test_bitvector(self):
+
+        d = 4
+        assert Numeric.allclose(bitvector(0, d), Numeric.array([0,0,0,0]))
+        assert Numeric.allclose(bitvector(1, d), Numeric.array([1,0,0,0]))
+        assert Numeric.allclose(bitvector(2, d), Numeric.array([0,1,0,0]))
+        assert Numeric.allclose(bitvector(3, d), Numeric.array([1,1,0,0]))
+        assert Numeric.allclose(bitvector(4, d), Numeric.array([0,0,1,0]))
+        assert Numeric.allclose(bitvector(5, d), Numeric.array([1,0,1,0]))
+        assert Numeric.allclose(bitvector(6, d), Numeric.array([0,1,1,0]))
+        assert Numeric.allclose(bitvector(7, d), Numeric.array([1,1,1,0]))
+        assert Numeric.allclose(bitvector(8, d), Numeric.array([0,0,0,1]))
+        assert Numeric.allclose(bitvector(9, d), Numeric.array([1,0,0,1]))
+        assert Numeric.allclose(bitvector(10, d), Numeric.array([0,1,0,1]))
+        assert Numeric.allclose(bitvector(11, d), Numeric.array([1,1,0,1]))
+        assert Numeric.allclose(bitvector(12, d), Numeric.array([0,0,1,1]))
+        assert Numeric.allclose(bitvector(13, d), Numeric.array([1,0,1,1]))
+        assert Numeric.allclose(bitvector(14, d), Numeric.array([0,1,1,1]))
+        assert Numeric.allclose(bitvector(15, d), Numeric.array([1,1,1,1]))
+        
+
+    def test_expand(self):
+
+        d = 4
+        mask = Numeric.array([0,1,1,0,1])
+        v = Numeric.array([2,3,4])
+
+        assert Numeric.allclose(expand(v, mask), Numeric.array([0,2,3,0,4]))
+
+
+        
+            
+                          
+#-------------------------------------------------------------
+if __name__ == "__main__":
+
+    mysuite = unittest.makeSuite(TestCase,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(mysuite)
+
