diff --git a/cgi-bin~/data_data.py b/cgi-bin~/data_data.py
new file mode 100755
index 0000000000000000000000000000000000000000..7a83e866e47842ed32661ba997595e3b7373d15f
--- /dev/null
+++ b/cgi-bin~/data_data.py
@@ -0,0 +1,240 @@
+#!/usr/bin/python
+# data_data.py
+# CGI retrieves RIG data in an ascii table.
+#
+# Author: Maciek Smuga-Otto <maciek@ssec.wisc.edu>
+# Copyright 2003-2007 University of Wisconsin-Madison
+#
+# example invocation:
+# .../data_data.py?start=2003-03-27+14:05:57&end=2003-03-27+15:05:57&symbols=TEMP41372:CS10162:PAROSCI
+# if no end value provided, assume end = most recent sample.
+# if no begin is provided, assume it is the same as end (return one value only).
+# thus, calling with no begin OR end gives the single most recent sample.
+#
+CVS_ID="$Id: data_data.py,v 1.25 2009/04/29 18:36:57 brucef Exp $"
+
+import cgi, os, sys       # system/cgi utils
+import math
+import psycopg2 as db
+from data_symbols import symalias, precision   # symbol alias table and symbol precision table
+from data_usage import usage
+from dewpoint import dewpoint
+
+DB = ('rig','rig_client','borabora.ssec.wisc.edu','wXn0w')
+
+def get_slice(con, begin, end, resample, resolution, *symbols):
+        """Get data for the specified list of symbols, every resample'th timestamp in the 
+        range defined by [begin, end). 
+        """
+        begin, end = adjust_ts(con, begin, end, resolution)
+        #print 'begin:',begin, 'end:', end # DEBUG
+
+        # construct the wide query
+        dbsymbols, dbtables, dbwhereclause = ("", "", "")
+        c = con.cursor()
+        for symbol in symbols:
+            c.execute("SELECT symbol_id FROM symbols WHERE name='%s'" % symbol)
+            symbol_id = c.fetchone()[0]
+            dbsymbols += ", d_%s.value AS %s" % (symbol, symbol)
+            dbtables += ", data d_" + symbol
+            dbwhereclause += "AND samples.sample_id = d_%s.sample_id AND d_%s.symbol_id = %s " % \
+                             (symbol, symbol, symbol_id)
+            # FIXME - this is a temporary patch to compensate for spurious error values written
+            # into the database for accurain, which will have to get fixed in the java ingest.
+            if symbol_id == 102:
+                dbwhereclause += "AND d_%s.value != -99999 " % symbol
+
+        query = "SELECT stamp%s FROM samples%s WHERE stamp >= '%s' AND stamp <= '%s' %s \
+AND resolution = %s " % (dbsymbols, dbtables, begin, end, dbwhereclause, resolution)
+        if resample > 1:
+            query += "AND floor(extract( epoch from stamp::timestamp - stamp::date)/%s)::int %% (%s) = 0 "% (resolution, resample)
+        query += "ORDER BY stamp"
+            
+        #print query   # for debugging only
+        c.execute(query)
+        return c.fetchall()
+
+def adjust_ts(dbconnection, begin, end, resolution):
+        if not end:
+            c = dbconnection.cursor()
+            if not begin:
+                c.execute("SELECT max(stamp), max(stamp) from samples where resolution=%s" % resolution)
+                return c.fetchone()
+            # the following several lines are for the case where begin timestamp is -hh:mm:ss
+            # indicating that the data be gathered for the past hh hours, mm minutes and ss seconds.
+            begin_seconds_ago = resolution
+            if '-' == begin[0]:
+                (hh,mm,ss) = [int(t) for t in begin[1:].split(':')]
+                begin_seconds_ago = max(ss + 60 * mm + 3600 * hh, resolution)
+            c.execute( "SELECT now(), now() - '%s seconds'::interval" % begin_seconds_ago )
+            (end, maybegin) = c.fetchone()
+            if '-' == begin[0]:
+                begin = maybegin
+
+        elif not begin:
+            c = dbconnection.cursor()
+            c.execute( "SELECT '%s'::timestamp - '%s seconds'::interval" % ( end, resolution ) )
+            begin = c.fetchone()[0]
+
+        return ( begin, end )
+
+       
+
+def cgiheader( html = None ):
+        if html:
+            print "Content-Type: text/html"
+        else:
+            print "Content-Type: text/plain"
+        print "Cache-control: private, no-cache"
+        print "Expires: Thu, 1 Aug 2002 12:23:00 GMT"
+        print "Pragma: no-cache"
+        print
+
+def linearConvert( data, factor = 0, offset = 0 ):
+        return data * factor + offset
+
+def normalize_rh(rh):
+    return rh > 100 and 100 or rh
+
+#######################
+# MAIN
+
+def cgimain():
+        form = cgi.FieldStorage()
+
+        # process CGI input
+        if 'symbols' not in form.keys():
+            cgiheader(1)
+            usage()
+            sys.exit(0)
+
+        begin,end = '','' # begin, end timestamps
+        if 'begin' in form.keys():
+            begin = form['begin'].value
+        if 'end' in form.keys():
+            end = form['end'].value
+
+        altts = 0  # alternate timestamp display - replace dashes and colons with spaces
+        if 'altts' in form.keys():
+            altts = 1
+
+        separator = '' # separates individual fields in an output row. Defaults to aligned column output.
+        if 'separator' in form.keys():
+            separator = form['separator'].value
+
+        resolution = 5 # in seconds. Default for raw Campbell data, must be changed to get Ceilometer (15) or 
+                       # DB-averaged Campbell data.
+        if 'resolution' in form.keys():
+            resolution = int( form['resolution'].value )
+
+        resample = 1
+        if 'interval' in form.keys(): 
+            interval_str = form['interval'].value
+            interval_chunks = interval_str.split(':')
+            int_ss, int_mm, int_hh = 0, 0, 0
+            if len(interval_chunks) == 1:
+                int_ss = int(interval_chunks[0])
+            if len(interval_chunks) == 2:
+                int_mm = int(interval_chunks[0])
+                int_ss = int(interval_chunks[1])
+            if len(interval_chunks) > 2:
+                int_hh = int(interval_chunks[0])
+                int_mm = int(interval_chunks[1])
+                int_ss = int(interval_chunks[2])
+            resample = (int_ss + 60 * int_mm + 3600 * int_hh) / resolution 
+
+        # symaliases are the aliases for (internal) symbols requested by the user (ex. 't' for 'TEMP41372')
+        symaliases = filter( lambda x: x in symalias.keys(), form['symbols'].value.split( ':' ))
+        symbols_raw = [symalias.get( s, None ) for s in symaliases ] # get associated symbols 
+        symbols = filter( lambda x: x not in ('DEWPOINT',), symbols_raw )   # strip out DEWPOINT 
+        # get around the database problem of hanging on too many symbols
+        symbols1 = symbols[:]
+        symbols2 = []
+        if len(symbols) >= 4:
+                symbols1 = symbols[:4]
+                symbols2 = symbols[4:]
+
+
+
+
+        ###################################################################
+        # DB OPS 
+        #
+        con = db.connect("dbname='%s' user='%s' host='%s' password='%s'" % DB)
+
+        dataset1 = get_slice(con, begin, end, resample, resolution, *symbols1)
+        if symbols2:
+            dataset2 = get_slice(con, begin, end, resample, resolution, *symbols2)
+
+        # dewpoint needs a little help...
+
+        if 'DEWPOINT' in symbols_raw:
+            dewdata_in = get_slice(con, begin, end, resample, resolution, 'TEMP41372', 'RH41372')
+            #print "dataset1: %s, dewdata_in: %s" % (len(dataset1), len(dewdata_in)) #DEBUG
+            dewdata = [dewpoint(temp,normalize_rh(relhum)) for (timestamp, temp, relhum) in dewdata_in]  
+
+        con.close()
+        #
+        # END DB OPS 
+        ###################################################################
+
+
+
+
+        cgiheader()
+
+        
+        # print column names
+        symstr= (separator or ' ').join(('YYYY-MM-DD','hh:mm:ss'))
+        if altts:
+            symstr= (separator or ' ').join(('YYYY','MM','DD','hh','mm','ss'))
+        for s in symaliases:
+            if separator:
+                symstr += "%s%s" % (separator, s)
+            else:
+                symstr += " %+7.7s" % s
+        print symstr
+
+        # print data 
+        foldindex = 0 # index into fold-in (computed) arrays, such as dewpoint 
+        for row in dataset1:
+            outstr = ''
+            date =  row[0].strftime('%Y-%m-%d') 
+            time =  row[0].strftime('%H:%M:%S')
+            if altts: # replace dashes and colons with spaces
+                outstr = (separator or ' ').join(tuple(date.split('-') + time.split(':')))
+            else:     # don't
+                outstr = "%s%s%s" % (date, separator or ' ', time)
+        
+            for s in symbols_raw:
+               if s == 'DEWPOINT':
+                   if foldindex < len(dewdata):
+                       data = dewdata[foldindex] # fold in the dewdata array, one element at a time
+                   else:
+                       data = 0
+               # again, reading from the second dataset, to deal with the database bug
+               elif s in symbols2:
+                   data = dataset2[foldindex][ symbols2.index(s)+1 ]
+               else:
+                   data = row[ symbols1.index(s)+1 ]
+               if s in ( 'RAIN380M', 'ACCURAIN' ):
+                   # every tick is 1/100th of an inch, not 1/10'th of a mm as initially supposed. 
+                   data = linearConvert( data, factor=0.1, offset=0 )
+               
+               if s is 'RH41372': # force RH to be no greater than 100
+                   data = normalize_rh(data)
+               
+               if separator:
+                   format_str = '%s%0' + precision( s ) + 'f'
+                   outstr += format_str % (separator,data)
+               else:
+                   format_str = ' %7' + precision( s ) + 'f'
+                   outstr += format_str % data
+            print outstr
+            foldindex += 1
+
+cgimain()
+##### If database down, comment out above line, uncomment the code below
+#cgiheader() 
+#print "Sorry, RIG data app temporarily out of service"
+#print "Please email maciek@ssec.wisc.edu with any questions."
diff --git a/cgi-bin~/data_symbols.py b/cgi-bin~/data_symbols.py
new file mode 100644
index 0000000000000000000000000000000000000000..4142610c257b125ba901f1a2faec2a14ad9273e7
--- /dev/null
+++ b/cgi-bin~/data_symbols.py
@@ -0,0 +1,68 @@
+symalias = {
+'box_p' : 'CS105',
+'box_pressure' : 'CS105',
+'box_rh' : 'CS10162',
+'box_relative_humidity' : 'CS10162',
+'spd' : 'WSPD05305',
+'speed' : 'WSPD05305',
+'dir' : 'WDIR05305',
+'direction' : 'WDIR05305',
+'rh' : 'RH41372',
+'relative_humidity' : 'RH41372',
+'t' : 'TEMP41372',
+'temperature' : 'TEMP41372',
+'flux' : 'LI200X',
+'average_solar_radiation_flux' : 'LI200X',
+'precip' : 'RAIN380M',
+'precipitation' : 'RAIN380M',
+'accum_precip' : 'ACCURAIN',
+'accumulated_precipitation' : 'ACCURAIN',
+'box_t' : 'TEMP107_1',
+'box_temperature' : 'TEMP107_1',
+'outside_box_t' : 'TEMP107_2',
+'outside_box_temperature' : 'TEMP107_2',
+'t_6.3m' : 'TEMP107_3',
+'temperature_6.3_meter' : 'TEMP107_3',
+'t_14.5m' : 'TEMP107_4',
+'temperature_14.5_meter' : 'TEMP107_4',
+'t_unk' : 'TEMP107_5',
+'temperature_unknown' : 'TEMP107_5',
+'td' : 'DEWPOINT',
+'dewpoint' : 'DEWPOINT',
+'dew_point' : 'DEWPOINT',
+'p' : 'PAROSCI',
+'pres' : 'PAROSCI',
+'pressure' : 'PAROSCI',
+}
+
+
+temp_precision = '.1'
+rh_precision = '.0'
+press_precision = '.1'
+windspd_precision = '.1'
+winddir_precision = '.0'
+solarrad_precision = '.1'
+default_precision = '.3'
+rain_precision = '.2'
+ceil_precision = '.0'
+
+def precision(symbol): 
+  if symbol in ('CS105', 'PAROSCI'):
+    return press_precision
+  elif symbol in ('CS10162', 'RH41372'):
+    return rh_precision
+  elif symbol in ('TEMP41372', 'TEMP107_1', 'TEMP107_2', 'TEMP107_3', 'TEMP107_4', 'TEMP107_5', 'DEWPOINT'):
+    return temp_precision
+  elif symbol == 'WSPD05305':
+    return windspd_precision
+  elif symbol == 'WDIR05305':
+    return winddir_precision
+  elif symbol == 'LI200X':
+    return solarrad_precision
+  elif symbol in ('RAIN380M', 'ACCURAIN'):
+    return rain_precision
+  else:
+    return default_precision
+
+
+
diff --git a/cgi-bin~/data_usage.py b/cgi-bin~/data_usage.py
new file mode 100644
index 0000000000000000000000000000000000000000..a36f9db7ce75e5cc056dacdfb5bef4de7be388d6
--- /dev/null
+++ b/cgi-bin~/data_usage.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python2
+# usage for data_data.py
+
+
+def usage():
+        print """
+<html><body>
+<em>
+Usage: data_data.py?symbols=sym_1:sym_2:sym_3:...:sym_n&begin=start_timestamp&end=end_timestamp&interval=hh:mm:ss
+</em><br>
+<br>
+ example invocation:<br>
+<br>
+ <a href=\"data_data.py?begin=2003-03-27+14:05:57&end=2003-03-27+15:05:57&symbols=t:p:speed:dir\">
+ <code>data_data.py?begin=2003-03-27+14:05:57&end=2003-03-27+15:05:57&symbols=t:p:speed:dir</code></a><br>
+<br>
+ if no end value provided, assume end = now. For example<br> 
+(to use this, replace below timestamp with one nearer to the present date - else you'll get a lot of data):<br>
+<br>
+ <code>data_data.py?begin=2003-03-27+14:05:57&symbols=t:p:speed:dir</code><br>
+<br>
+ if no begin is provided, assume it is the same as end (return one value only). Example:<br>
+<br>
+ <a href=\"data_data.py?end=2003-03-27+15:05:57&symbols=t:p:dewpoint:accum_precip\">
+ <code>data_data.py?end=2003-03-27+15:05:57&symbols=t:p:dewpoint:accum_precip</code></a><br>
+<br> 
+ thus, calling with no begin OR end gives the single most recent sample.<br>
+<br>
+<i>NEW as of 2006-07-26:</i>
+If no end is provided, but begin is of the form -hh:mm:ss, then the most recent hh hours, mm minutes
+and ss seconds of data are provided.
+<br>
+
+------------- Other Options --------------------------<br>
+
+To separate the fields in the timestamp with spaces (useful for some automated scripts),
+append <code>altts=1</code> to the CGI parameter list as follows:<br>
+<br>
+ <a href=\"data_data.py?begin=2003-04-08+23:05:57&end=2003-04-09+01:15:57&symbols=t:rp:dewpoint:accum_precip&altts=1\">
+ <code>data_data.py?begin=2003-04-08+23:05:57&end=2003-04-09+01:15:57&symbols=t:rp:dewpoint:accum_precip&altts=1</code></a><br>
+<br>
+<br> 
+
+To separate the datafields with various characters (commas, spaces, etc) as opposed to constant-width
+column output,
+append <code>separator=,</code> (or <code>separator=+</code>, etc..) to the CGI parameter list as follows:<br>
+<br>
+ <a href=\"data_data.py?begin=2003-04-08+23:05:57&end=2003-04-09+01:15:57&symbols=t:rp:dewpoint:accum_precip&separator=,\">
+ <code>data_data.py?begin=2003-04-08+23:05:57&end=2003-04-09+01:15:57&symbols=t:rp:dewpoint:accum_precip&separator=,</code></a><br>
+<br>
+<br> 
+It's also possible to get data at intervals greater than five seconds.
+To do this, specify the interval time as one of<br>
+<ul>
+  <li><code>interval=ss</code></li>
+  <li><code>interval=mm:ss</code></li>
+  <li><code>interval=hh:mm:ss</code></li>
+</ul><br>
+<br>
+<em>For correct operation, only specify intervals which are multiples of 5 seconds</em>. \
+For example:</br>
+<br>
+ <a href=\"data_data.py?begin=2003-03-27+14:05:57&end=2003-03-27+15:05:57&symbols=t:p:speed:dir&interval=1:00\">
+ <code>data_data.py?begin=2003-03-27+14:05:57&end=2003-03-27+15:05:57&symbols=t:p:speed:dir&interval=1:00</code></a><br>
+<br>
+will give you one sample every minute. 
+<br>
+<br>
+
+<em>
+A list of requested symbols (click on symbol to get latest value):<br>
+</em>
+<br>
+------------- Standard Parameters --------------------<br>
+* Temperature [deg C] (
+  <a href="data_data.py?symbols=temperature">temperature</a> or 
+  <a href="data_data.py?symbols=t">t</a>)<br>
+* Dew Point Temperature [deg C] (
+  <a href="data_data.py?symbols=dewpoint">dewpoint</a> or 
+  <a href="data_data.py?symbols=dew_point">dew_point</a> or 
+  <a href="data_data.py?symbols=td">td</a>)<br>
+* Wind Direction [degrees] (
+  <a href="data_data.py?symbols=direction">direction</a> or 
+  <a href="data_data.py?symbols=dir">dir</a>)<br>
+* Wind Speed [mps] (
+  <a href="data_data.py?symbols=speed">speed</a> or 
+  <a href="data_data.py?symbols=spd">spd</a>)<br>
+* Pressure [hPa] (
+  <a href="data_data.py?symbols=pressure">pressure</a> or 
+  <a href="data_data.py?symbols=pres">pres</a> or 
+  <a href="data_data.py?symbols=p">p</a>)<br>
+* Relative Humidity [percent] (
+  <a href="data_data.py?symbols=relative_humidity">relative_humidity</a> or
+  <a href="data_data.py?symbols=rh">rh</a>)<br>
+* Precipitation [inches accumulated in last 5 seconds - thus not really useful] (
+  <a href="data_data.py?symbols=precipitation">precipitation</a> or 
+  <a href="data_data.py?symbols=precip">precip</a>)<br>
+* Accumlated Precipitation [inches accumulated since midnight] (
+  <a href="data_data.py?symbols=accumulated_precipitation">accumulated_precipitation</a> or 
+  <a href="data_data.py?symbols=accum_precip">accum_precip</a>)<br>
+* Solar radiation [W / m^2] (
+  <a href="data_data.py?symbols=average_solar_radiation_flux">average_solar_radiation_flux</a> or 
+  <a href="data_data.py?symbols=flux">flux</a>)<br>
+<br>
+---------------- Other temperatures ---------------------<br>
+* Temperature at 6.3m [deg C] (
+  <a href="data_data.py?symbols=temperature_6.3m">temperature_6.3m</a> or 
+  <a href="data_data.py?symbols=t_6.3m">t_6.3m</a>)<br>
+* Temperature at 14.5m [deg C] (
+  <a href="data_data.py?symbols=temperature_14.5m">temperature_14.5m</a> or 
+  <a href="data_data.py?symbols=t_14.5m">t_14.5m</a>)<br>
+* Temperature at (unknown) [deg C] (
+  <a href="data_data.py?symbols=temperature_unknown">temperature_unknown</a> or 
+  <a href="data_data.py?symbols=t_unk">t_unk</a>)<br>
+<br>
+---------------- Box Values --------------------<br>
+* Temperature of instrument box [deg C] (
+  <a href="data_data.py?symbols=box_temperature">box_temperature</a> or 
+  <a href="data_data.py?symbols=box_t">box_t</a>)<br>
+* pressure of the box [hPa] (
+  <a href="data_data.py?symbols=box_pressure">box_pressure</a> or 
+  <a href="data_data.py?symbols=box_p">box_p</a>)<br>
+* Temperature outside box [deg C] (
+  <a href="data_data.py?symbols=outside_box_t">outside_box_t</a>)<br>
+* Box Relative Humidity [percent] (
+  <a href="data_data.py?symbols=box_relative_humidity">box_relative_humidity</a> or 
+  <a href="data_data.py?symbols=box_rh">box_rh</a>)<br>
+<br>
+<br>
+</body></html>
+"""
diff --git a/cgi-bin~/dbget2.py b/cgi-bin~/dbget2.py
new file mode 100644
index 0000000000000000000000000000000000000000..45368fce4f9d4871c013f3b06d793dd83b25ccea
--- /dev/null
+++ b/cgi-bin~/dbget2.py
@@ -0,0 +1,222 @@
+# routines to access data from the penthouse database
+
+DB_SERVER = 'bora2.ssec.wisc.edu'
+DB_NAME = 'rig'
+DB_USER = 'rig'
+
+METEOROLOGY_GROUP_ID=-1
+ENGINEERING_GROUP_ID=-2
+
+import pgdb
+import re
+
+# make a connection to the database
+def connect():
+    return pgdb.connect('%s:%s:%s' % (DB_SERVER, DB_NAME, DB_USER))
+
+# close the connection
+def disconnect(con):
+    con.close()
+
+# get a dataset
+def get_dataset(symbol, res, start, end):
+
+	con = connect()
+	c = con.cursor()
+	c.execute("SELECT symbol_id FROM symbols WHERE name='%s'" % symbol)
+	symbol_id = c.fetchone()[0]
+	c.execute("SELECT stamp, value " +
+	          "FROM data NATURAL JOIN samples " +
+	          ("WHERE symbol_id=%d " % symbol_id) +
+	          ("AND stamp >= '%s' AND stamp <= '%s' " % (start, end)) +
+	          ("AND resolution=%d") % res)
+	tmp = c.fetchall()
+	disconnect(con)
+
+	return tmp
+
+# get a daraset with the specified units (not checked for errors)
+def get_dataset_with_units(symbol, res, start, end, units):
+
+	con = connect()
+	c = con.cursor()
+	c.execute("SELECT symbol_id FROM symbols WHERE name='%s'" % symbol)
+	symbol_id = c.fetchone()[0]
+	c.execute(("SELECT stamp, convert_units(value, '%s') " % units) +
+              "FROM data NATURAL JOIN samples " +
+              ("WHERE symbol_id=%d " % symbol_id) +
+              ("AND stamp >= '%s' AND stamp <= '%s' " % (start, end)) +
+              ("AND resolution=%d") % res)
+	tmp = c.fetchall()
+	disconnect(con)
+
+	return tmp
+
+
+# makes a text file from a dataset - ready for gnuplot
+def makefile(dataset, filename):
+
+	f = open(filename, 'w')
+
+	#dataset = map(lambda x: (x[0][0:x[0].index('.')], x[1]), dataset)
+	for row in dataset:
+		f.write(row[0] + ' ' + str(row[1]) + '\n')
+
+	return (dataset[0][0], dataset[-1][0])
+
+# returns data for the specified symbol
+def get_symbol_data(symbol):
+
+    sym_dict = {}
+
+    con = connect()
+    c = con.cursor()
+    c.execute("SELECT * FROM symbols WHERE name='%s'" % symbol)
+    vals = c.fetchone()
+    for i in range(len(c.description)):
+        sym_dict[c.description[i][0]] = vals[i]
+
+    disconnect(con)
+
+    return sym_dict
+
+# gets all symbol data in a dictionary keyed by name
+# dictionary entries are: (id, long name, units, description)
+def get_all_symbol_data():
+
+    sym_data = {}
+
+    con = connect()
+    c = con.cursor()
+    c.execute("SELECT name, symbol_id, long_name, units, description " +
+              "FROM symbols")
+    for row in c.fetchall():
+        sym_data[row[0]] = tuple(row[1:])
+
+    disconnect(con)
+
+    return sym_data
+
+# returns the names of the symbols
+def get_symbol_names():
+
+    sym_list = []
+
+    con = connect()
+    c = con.cursor()
+    c.execute("SELECT s.name FROM symbols s, group_items g " +
+              "    WHERE g.symbol_id=s.symbol_id AND g.group_id > -3" +
+              "        ORDER BY g.group_id DESC, g.list_order")
+    for l in c.fetchall():
+        if l[0] != "TIME":
+            sym_list.append(l[0])
+
+    disconnect(con)
+
+    return sym_list
+
+# returns long-name data
+def get_long_names():
+
+    names = {}
+    
+    con = connect()
+    c = con.cursor()
+    c.execute("SELECT name, long_name FROM symbols")
+    for name, long_name in c.fetchall():
+        names[name] = long_name
+
+    disconnect(con)
+
+    return names
+
+# gets possible units for the given symbols
+def get_alternate_units(units):
+
+	con = connect()
+	c = con.cursor()
+	c.execute("SELECT type FROM units WHERE label='%s'" % units)
+	type = c.fetchone()[0]
+	c.execute("SELECT label FROM units WHERE type='%s'" % type)
+	tmp = map(lambda x: x[0], c.fetchall())
+
+	disconnect(con)
+
+	return tmp
+
+# returns the names of the symbols for meteorology
+def get_met_symbol_names():
+
+    return get_group_symbol_names(METEOROLOGY_GROUP_ID)
+
+# returns the names of the symbols for engineering sensors
+def get_eng_symbol_names():
+
+	return get_group_symbol_names(ENGINEERING_GROUP_ID)
+
+def get_group_symbol_names(gid):
+
+    sym_list = []
+
+    con = connect()
+    c = con.cursor()
+    c.execute("SELECT s.name FROM symbols s, group_items g " +
+              "    WHERE g.symbol_id=s.symbol_id AND g.group_id=%d" % gid +
+              "        ORDER BY g.list_order")
+    for l in c.fetchall():
+        if l[0] != "TIME":
+            sym_list.append(l[0])
+
+    disconnect(con)
+
+    return sym_list
+
+# returns units data
+def get_units():
+
+    units_dict = {}
+
+    con = connect()
+    c = con.cursor()
+    c.execute("SELECT name, units FROM symbols")
+    for name, units in c.fetchall():
+        units_dict[name] = units
+
+    disconnect(con)
+
+    return units_dict
+
+# returns current conditions tuple: (time_stamp, value_dict)
+def get_current_conds():
+
+    data = {}
+
+    con = connect()
+    c = con.cursor()
+    c.execute("SELECT sample_id, stamp FROM samples WHERE resolution=60 " +
+              "ORDER BY stamp DESC LIMIT 1")
+    sample_id, stamp = tuple(c.fetchone())
+    c.execute("SELECT symbol_id, value from data WHERE sample_id=%d" %
+              sample_id)
+    for row in c.fetchall():
+        data[row[0]] = row[1]
+
+    disconnect(con)
+
+    return (stamp, data)
+
+# returns a dictionary with global values
+def get_globals():
+
+    gd = {}
+
+    con = connect()
+    c = con.cursor()
+    c.execute('SELECT * FROM globals')
+    vals = c.fetchone()
+    for i in range(len(c.description)):
+        gd[c.description[i][0]] = vals[i]
+
+    disconnect(con)
+
+    return gd
diff --git a/cgi-bin~/dewpoint.py b/cgi-bin~/dewpoint.py
new file mode 100644
index 0000000000000000000000000000000000000000..a4ce2458845f729563ec69da0c24e9be8387807f
--- /dev/null
+++ b/cgi-bin~/dewpoint.py
@@ -0,0 +1,37 @@
+# Functions for calculating the dewpoint.
+# $Id: dewpoint.py,v 1.1 2003/04/16 19:38:48 maciek Exp $
+
+import math
+
+def dewpoint(tempC, relhum):
+        """ algorithm from Tom Whittaker 
+tempC is the temperature in degrees Celsius,
+relhum is the relative humidity as a percentage"""
+        gasconst = 461.5
+        latheat = 2500800.0
+
+        dp = 1.0 / ( 1.0 / ( 273.15 + tempC ) - gasconst * math.log(  (0.0 + relhum) / 100 ) / \
+             ( latheat - tempC * 2397.5 ))
+
+        return min(dp - 273.15, tempC)
+
+def awips_dewpoint(tempC, relhum):
+        """ algorithm taken from http://meted.ucar.edu/awips/validate/dewpnt.htm 
+tempC is the temperature in degrees Celsius,
+relhum is the relative humidity as a percentage"""
+        C15 = 26.66082
+        C1  = 0.0091379024
+        C2  = 6106.396
+        C3  = 223.1986
+        C4  = 0.0182758048
+
+        t   = tempC + 273.15  # convert temperature to Kelvin
+        rh  = relhum / 100    # convert relative humidity to ratio
+
+        es = math.exp( C15 - C1 * t - C2 / t )   # saturation vapor pressure
+        e  = rh * es
+        b  = C15 - math.log(e)
+        td = ( b - math.sqrt( b * b - C3 ) ) / C4
+
+        return min(td - 273.15, tempC)
+
diff --git a/cgi-bin~/iqeye/ls.cgi b/cgi-bin~/iqeye/ls.cgi
new file mode 100755
index 0000000000000000000000000000000000000000..869b2470d3554155a9cc6cabd365cbb573691afa
--- /dev/null
+++ b/cgi-bin~/iqeye/ls.cgi
@@ -0,0 +1,123 @@
+#!/var/www/wsgi/python-env/metobs/bin/python
+"""List available EyeQ Camera images.
+
+See `print_usage()` for more information
+"""
+
+import cgi
+import cgitb; cgitb.enable()
+
+import os
+import sys
+from datetime import datetime
+from datetime import timedelta
+
+from metobs import mytime
+
+form = cgi.FieldStorage()
+
+def get(name, default=None):
+    if form.has_key(name):
+        return form[name].value
+    return default
+
+def print_usage():
+    print "ContentType: text/plain"
+    print 
+    print """Provides image listings of SSEC RIG EyeQ Camera images.
+
+Because the images may not be exactly spaced, being that processing may increase
+the interval, images are listed by searching between the date provided and that
+date plus the image resolution.
+
+Parameters
+==========
+
+cam - (required) Camera name. West, East, etc ...
+d   - Date of image in CST (YYYY-MM-DD HH:MM:SS). Defaults to current time.
+"""
+
+#: resolution at which images are generated
+image_rez = 10
+#: timezone for image filename times
+image_tz = mytime.OffsetTimezone(6)
+hostname = 'tahiti.ssec.wisc.edu'
+
+#: convert a file path to a server path`
+url_for = lambda fpth: "http://"+hostname+fpth.replace("/beach", "/pub")
+
+def image_path(cam, dt):
+    """Get a path for an image on disk.
+
+    :param cam: Name of the camera
+    :param dt: datetime of the image file used to parse the name
+    """
+    basedir = '/beach/incoming/Instrument_Data/METOBS/RIG/Cameras'
+    return os.path.join(basedir, cam + dt.strftime('/%Y/%m/%d/%H_%M_%S.trig+00.jpg'))
+
+
+
+#
+#
+# You shouldn't need to change anything below here
+#
+#
+
+
+def redirect_to(url):
+    print "Status: 302 Moved"
+    print "Location: " + url
+    print 
+
+def file_not_found():
+    print "Status: 404 File Not Found"
+    print 
+
+def headers(typ='plain'):
+    print "ContentType: text/" + typ
+    print 
+
+def main():
+
+    # required parameter    
+    camera = get('cam')
+    if not camera:
+        print_usage()
+        return 1
+
+    # parse data from parameter, defaulting to current time in the
+    # timezone specified
+    date = get('d')
+    if not date:
+        date = mytime.utc_now() 
+        date = mytime.set_tz(date, tz=image_tz)
+    else:
+        date = mytime.parse_stamp(date)
+        date = mytime.set_tz(date, tz=image_tz)
+   
+    # images may not be exactly the same interval appart, therefore we have
+    # to attempt to locate the image 
+    url = ""
+    pths = []
+    for i in range(image_rez):
+        fpth = image_path(camera, date + timedelta(seconds=i))
+        pths.append(fpth)
+        if os.path.exists(fpth):
+            url = url_for(fpth)
+            break 
+    
+    # successfully found an image        
+    if url:
+        redirect_to(url)
+
+    if form.has_key('debug'):
+        headers()
+        for pth in pths:
+            print pth
+        return 1
+
+    # we should only get here if the file was not found
+    file_not_found() 
+    return 1
+
+sys.exit(main())
diff --git a/cgi-bin~/symbols.py b/cgi-bin~/symbols.py
new file mode 100644
index 0000000000000000000000000000000000000000..2e390ecc219f3dbf943753bed6f7b847cc62122c
--- /dev/null
+++ b/cgi-bin~/symbols.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python2
+#
+# Creates the SYMBOLS file which is used by the graphing applet
+
+import re
+import pgdb
+
+DB_SERVER = 'bora2.ssec.wisc.edu'
+DB_NAME = 'rig'
+DB_USER = 'rig'
+OUTPUT_FILE = '/home/brucef/public_html/rig_old/SYMBOLS'
+
+if __name__ == '__main__':
+
+	output = open(OUTPUT_FILE, 'w')
+	con = pgdb.connect('%s:%s:%s' % (DB_SERVER, DB_NAME, DB_USER))
+	c = con.cursor()
+	c.execute("SELECT name, long_name, units FROM symbol")
+	for l in c.fetchall():
+
+		# symbol name
+		output.write(l[0] + ' ')
+
+		# long name
+		output.write(re.sub(' ', '+', l[1]) + ' ')
+
+		# units
+		output.write(re.sub(' ', '+', l[2]) + '\n')
+
diff --git a/cgi-bin~/test b/cgi-bin~/test
new file mode 100755
index 0000000000000000000000000000000000000000..5d407129226dcf048cb0595518f214e728558e7d
--- /dev/null
+++ b/cgi-bin~/test
@@ -0,0 +1,3 @@
+#!/bin/ksh
+
+echo "hello world"
diff --git a/cgi-bin~/tower/mobile.cgi b/cgi-bin~/tower/mobile.cgi
new file mode 100755
index 0000000000000000000000000000000000000000..41f9f4a221dae97d9c676cae1b81a65f62e417d4
--- /dev/null
+++ b/cgi-bin~/tower/mobile.cgi
@@ -0,0 +1,88 @@
+#!/var/www/wsgi/python-env/metobs/bin/python
+
+import cgi
+# FOR DEBUG ONLY !!!!!
+#import cgitb; cgitb.enable()
+
+import sqlalchemy as sa
+from sqlalchemy import orm
+from metobs.data import *
+from metobs import db, mytime
+
+TXT = """ UW Lake Mendota Buoy
+ ====================
+ As of: %(stamp)s
+
+ Atmosphere
+ -----------
+ Wind Dir: %(dir)d deg (%(dir2)s)
+ Wind Spd: %(spd).1f m/s (%(spd2).1f knts)
+ Air Temp: %(temp).1f degC (%(temp2).1f degF)
+
+ Water Temperature
+ -----------------
+ Surface   %(surface).1f degC (%(surface2).1f degF)
+ -1m       %(wt1).1f degC (%(wt1-2).1f degF)
+ -5m       %(wt5).1f degC (%(wt5-2).1f degF)
+ -10m      %(wt10).1f degC (%(wt10-2).1f degF)
+ -15m      %(wt15).1f degC (%(wt15-2).1f degF)
+ -20m      %(wt20).1f degC (%(wt20-2).1f degF)
+"""
+
+ERR_TXT = """
+ An Error Occured: Request could not be completed
+"""
+
+symbols = [
+    'WIND_DIRECTION_2.0',
+    'WIND_SPEED_2.0',
+    'AIR_TEMP',
+    'WATER_TEMP_0.0',
+    'WATER_TEMP_1.0',
+    'WATER_TEMP_5.0',
+    'WATER_TEMP_10.0',
+    'WATER_TEMP_15.0',
+    'WATER_TEMP_20.0']
+
+def main():
+    form = cgi.FieldStorage()
+   
+    try: 
+        eng = sa.create_engine('postgres://buoy:vyit@tahiti.ssec.wisc.edu/buoy')
+        session = orm.create_session(bind=eng)
+        db.init_model()
+
+        station = session.query(db.Station, db.Station.name=='Mendota Buoy').one()[0]
+        tmp_syms = dict((s.name, s) for s in station.symbols)
+        qry_syms = [tmp_syms[s] for s in symbols]
+        stamp = db.max_stamp(session, station)
+        print stamp
+    
+        data = db.get_slice(session, station, stamp, symbols=qry_syms)[1][-1]
+        stamp = stamp.astimezone(mytime.OffsetTimezone(6))
+
+        txt = TXT % {
+            'stamp':stamp.strftime('%Y-%m-%d %H:%M:%S CST'),
+            'dir':data[0], 'dir2':dir2txt(data[0]),
+            'spd':data[1], 'spd2':mps2knots(data[1]),
+            'temp':data[2], 'temp2':c2f(data[2]),
+            'surface':data[3], 'surface2':c2f(data[3]),
+            'wt1':data[4], 'wt1-2':c2f(data[4]),
+            'wt5':data[5], 'wt5-2':c2f(data[5]),
+            'wt10':data[6], 'wt10-2':c2f(data[6]),
+            'wt15':data[7], 'wt15-2':c2f(data[7]),
+            'wt20':data[8], 'wt20-2':c2f(data[8])}
+    except Exception, e:
+        txt = ERR_TXT
+        raise e
+
+    print "Content-Type: text/plain; charset=UTF-8"
+    print "Refresh: 120"
+    print "Cache-control: private, no-cache"
+    print "Expires: Thu, 1 Aug 2002 12:23:00 GMT"
+    print "Pragma: no-cache"
+    print
+    print txt
+
+if __name__ == '__main__':
+    main()