This site would, of course, not be possible without Tobi Oetiker's RRDtool software. RRDTool Page Rank Check

rrd.cgi

rrd.cgi is an on-demand, highly configurable perl front-end for rrdtool. It supports, unlimited DEFs, CDEFs, hourly/daily/weekly/montly/yearly graphs, auto-archival of graphs, historical graphs, displaying source of RRDs::graph statements and autorefresh. rrd.cgi runs under cgi-bin or mod_perl.
rrd.cgi is compatible with 1.0.x and 1.2.x versions of rrdtool. No changes were required when upgrading from 1.0.x to 1.2.x. I have been using too many 1.2.x features, so rrd.cgi is no longer compatible with 1.0.x versions of rrdtool. Please upgrade rrdtool. You will be pleasantly surprised.
» RRD graphs
» History
» Downloads/Source Code
» Downloads/Resources
» Configuration file(s)
» Configuration file syntax
» Version Specific Information
» Prep work
» Script used in creating .rrd files
» Scripts used in gathering RRD stats
» Crontab entries
» Support, License, Warranty, Credit and Opinions
» Copyright
» Contact
RRD graphs
Can I look at the output RRD graphs?
To look at the graphs, go here:
Example RRD Graphs (under mod_perl)
Example RRD Graphs (under mod_cgi)
[top]
History
mrtg-rrd.cgi
This script is closely modelled after Jan "Yenya" Kasprzak's script mrtg-rrd.cgi. I started using Yenya's script in 2003 and after making many modifications and adding features, I decided to create this page. (Notably, I didn't like mrtg-rrd.cgi's tight coupling with mrtg.) Please be aware that my script does not work with default mrtg.cfg files.
Features
Downsides
TODO List
[top]
Downloads/Source Code
ViewVC
Bleeding Edge
The bleeding edge version of source for the CGI (written in perl) which generates these graphs is here. The project is hosted on github (starting from November 15th, 2012 onwards). Here is a link to the master branch
Released versions
Changelog history
These changelogs were created using the following commands:
/www/htdocs/rrd/scripts/changelog.sh \
    old_release_tag new_release_tag \
    > /www/htdocs/rrd/scripts/cl.xml
xsltproc -o cl.html cl2html.xsl cl.xml
[top]
Downloads/Resources
Resources and/or dependencies
The following resources are used on my site:
[top]
Configuration file(s)
Main config file
rrd.cfg
Secondary config file(s)
rrd-mysql.cfg
rrd-tomcat.cfg
rrd-network.cfg
rrd-weather.cfg
rrd-sar.cfg
rrd-home.cfg
Specify location of these config files inside rrd.cgi (near the top)
# EDIT THIS to reflect all your RRD config files
BEGIN { @config_files = qw(
    /etc/rrd/rrd.cfg
    /etc/rrd/rrd-mysql.cfg
    /etc/rrd/rrd-tomcat.cfg
    /etc/rrd/rrd-network.cfg
    /etc/rrd/rrd-weather.cfg
    /etc/rrd/rrd-sar.cfg
    /etc/rrd/rrd-home.cfg
); }
[top]
Configuration file syntax
Comments
Lines starting with # are considered comments.
Continuation
Lines starting with a whitespace are considered a continuation of the preceding line.
Global Directives
Global directives are specified as:
DirectiveName: Value
e.g.:
Imagedir: /www/htdocs/rrd/images
The directive names (not the values) are converted internally into lower-case before processing. This means that imagedir is the same as ImAgEdIr.
DirectiveExplanationExample(s)Comment
Imagedir Filesystem path to the directory where images will be stored /www/htdocs/rrd/images Needs to be writable by the process running the web server.
Logdir Filesystem path to the directory where .rrd files (logs) will be stored /www/htdocs/rrd/logs Needs to be writable by the process updating the .rrd files (via crontab, for example).
Resourcedir Web path to the URL for some resources /rrd/resources My resources directory contains rrdtool.gif and some other relic mrtg-*.png files. In addition, to that I now also have a CalendarPopup.js file for easy display of calendar dates. I also have my css file (style.css) in that directory.
Archivedir Filesystem path to the directory where archived images are stored /www/htdocs/rrd/archives Needs to be writable by the process running the crontab entry for archiving of images. Also needs to be web viewable via the Archiveurl directive.
Archiveurl Web path to the URL where archived images are stored /rrd/archives  
Archivecgi Base url for CGI for retrieving images from the front-end http://localhost/perl/rrd.cgi You can specify a fully qualified domain name if localhost doesn't work for you.
Interval Time interval in minutes (for refresh purposes) 5  
Per-stat Directives
Per-stat directives are specified as:
DirectiveName[StatName]: Value
e.g.:
Title[privoxy]: Privoxy filtering proxy
Both the directive names and the stat names (not the values) are converted internally into lower-case before processing. This means that pagetop[title] is the same as PaGeToP[tItLe].
DirectiveExplanationExample(s)Comment
Title Title of the statistic Privoxy filtering proxy  
PageTop HTML heading of the statistic <h1>Privoxy filtering proxy</h1> Note, you can use line continuation by starting a new line with a whitespace.
Directory Subdirectory path where the stats and the images will be stored respectively in Imagedir and Logdir localhost_stats All of my localhost related stats use the Directory directive of localhost_stats.
RelPercent RRDs::graph returns a pointer to an ARRAY containing the x-size and y-size of the created gif and results of the PRINT arguments.
($av,$x,$y) = RRDs::graph ...
print "Gifsize: ${x}x${y}\n",
"Averages: ", (join ", ", @$av);
This directive will be used as the preceding text to display for the relative percentages between two (2) CDEFs or (DEFs) which are the output of PRINT statements found in the Graph directive.
Blocked versus Total requests percentage (Directive is optional). For my privoxy stats, I get the following text output underneath the graph:
Blocked versus Total requests percentage Cur: 4.5% Avg: 15.1% Max: 27.0%
Buggy feature removed in release 1.5.5.
Graph Perhaps the most important section of this configuration file. The syntax for this directive mostly comes straight from man rrdgraph. However, some rules about how the CGI parses the syntax should be explained.

I use Text::ParseWords's quotewords method to parse this directive. It parses on whitespace, so every newline must be started with whitespace. In addition, any consecutive spaces inside GPRINT statement must be escaped with a backslash (\). I always use double-quotes for the last part of the GPRINT statement. E.g.,

GPRINT:a:LAST:"\ \ \ \ \ \ \ \ \ Cur\:%3.0lf%"
(note the use of backslashes for consecutive spaces).

A full example of a Graph directive is:
Graph[uptime]:
 -v Days
 --rigid
 -l 0
 DEF:a=/path/to/uptime.rrd:uptime:AVERAGE
 AREA:a#7aafff:Uptime
 GPRINT:a:LAST:"Cur\:%6.1lf"
 GPRINT:a:AVERAGE:"Ave\:%6.1lf"
 GPRINT:a:MAX:"MAX\:%6.1lf"
 LINE1:a#000001:
By the time this is submitted to RRDs::graph, the arguments will have been converted to:
 -v Days
 --rigid
 -l 0
 DEF:a=/path/to/uptime.rrd:uptime:AVERAGE
 AREA:a#7aafff:Uptime
 GPRINT:a:LAST:Cur\:%6.1lf
 GPRINT:a:AVERAGE:Ave\:%6.1lf
 GPRINT:a:MAX:MAX\:%6.1lf
 LINE1:a#000001:
Note: Starting from release 1.4.4 onwards, you can now specify just the relative path in the DEF directives. E.g.,
Graph[uptime]:
DEF:uptime.rrd:uptime:AVERAGE
will be submitted to RRDs::graph as:
DEF:/www/logs/stats/uptime.rrd:uptime:AVERAGE
assuming that you have the following local directives:
Directory[uptime]: stats
and the following global directive:
Logdir:       /www/logs
If the path specified in the DEF directive is an absolute path to begin with, then it will be passed as-is to RRDs::graph.
Please do not name CDEFs that start with numbers when using rrdtool 1.2.x. With a CDEF named like 25PL, rrdtool 1.2.9 will simply assign the value 25 to that CDEF. Later versions may correct this behavior. rrdtool 1.2.10+ fixes this problem.
Suppress You can use this directive to suppress certain detailed graphs.

p for Preview
h for Hourly
d for Daily
w for Weekly
m for Monthly
y for Yearly

You can use them in combination as well.
phdw I use the line: Suppress[uptime]: phdw for my Uptime graph to suppress preview, hourly, daily and weekly graphs.
IgnoreTimestamps You can use this directive to ignore the timestamp displayed on the detailed page. yes Use this if you do not care about creating symbolic links which facilitate the display of the "last updated time" of the target by translating the target name to the real .rrd name. See Symbolic Links Gotcha #1.
Debugging Tip
When I'm initially configuring a stat, it is hard to get the configuration just right. In those scenarios, you have to continually keep looking at the graph to see if you got things just right. However, since the CGI only shows you graphs which are either not present or are out of date (stale), you don't really want to wait 5 minutes for your graphs to refresh. In that case, simply deleting the .png graph from the Imagedir for that stat would do the trick.
[top]
Version Specific Information
rrdtool 1.3+ and special characters
rrdtool 1.3+ uses pango for writing text. I had to allow the LANG environment variable to be passed along to the script or pango would complain as follows in the error_log whenever it was writing special characters like ©:
(process:11070): Pango-WARNING **: Invalid UTF-8 string passed to pango_layout_set_text()
On my system LANG environment variable is set to en_US. When running under mod_cgi, I used the following snippet in httpd.conf:
<IfModule env_module>
    PassEnv LANG
</IfModule>
When running under mod_perl, I used the following snippet in httpd.conf:
PerlPassEnv LANG
[top]
Prep work
Prerequisites
rrd.cgi needs the following perl modules (usually available from CPAN)
If you are using the Archive feature, then you can use the Calendar Popup script from Matt Kruse's JavaScript ToolBox to make it easy to select dates. Just put CalendarPopup.js inside the Resourcedir.
Versions
These are the versions of some of the packages that I personally use:
prompt> uname -rsmpio
Linux 2.6.38-gentoo-r4 i686 Intel(R) Core(TM)2 CPU 6600 @ 2.40GHz GenuineIntel GNU/Linux

prompt> ./httpd -v
Server version: Apache/2.2.21 (Unix)

prompt> perl -v
This is perl 5, version 16, subversion 1 (v5.16.1) built for i686-linux

prompt> gcc --version
gcc (Gentoo 4.5.3-r2 p1.1, pie-0.4.7) 4.5.3

prompt> rrdtool --version
RRDtool 1.4.7  Copyright 1997-2012 by Tobias Oetiker <tobi@oetiker.ch>

prompt> perl -MRRDs -le 'print RRDs->VERSION'
1.4007

prompt> perl -Mmod_perl2 -le 'print mod_perl->VERSION'
2.000007

prompt> perl -MCGI -le 'print CGI->VERSION'
3.60

prompt> perl -MDate::Manip -le 'print Date::Manip->VERSION'
6.36

prompt> perl -MLWP::UserAgent -le 'print LWP::UserAgent->VERSION'
6.04

prompt> perl -MText::ParseWords -le 'print Text::ParseWords->VERSION'
3.27

prompt> perl -MImage::Size -le 'print Image::Size->VERSION'
3.232
Directories
Make sure the directories specified in Imagedir, Logdir and Archivedir global directives exist. In addition, make sure all the directories specified in the per-stat Directory sections exist. Here are my directories at the time of original writing (pay attention to the permissions):
/www/htdocs/rrd/images:
total 16
drwxrwsr-x  6 apache apache   86 Sep 27 11:58 .
drwxrwxr-x  8 apache apache   92 Nov 28  2003 ..
drwxrwsr-x  2 apache apache 4096 Jul 14 13:35 localhost_stats
drwxrwsr-x  2 apache apache 4096 Sep 27 14:19 network_stats
drwxrwsr-x  2 apache apache 4096 Aug 19 10:57 tomcat_stats
drwxrwsr-x  2 apache apache 4096 Aug  3 11:03 weather_stats

/www/htdocs/rrd/logs:
total 12
drwxrwsr-x  6 rrd    rrd     110 Sep 27 11:57 .
drwxrwxr-x  8 apache apache   92 Nov 28  2003 ..
drwxrwsr-x  2 rrd    rrd    4096 Jul 14 13:01 localhost_stats
drwxrwsr-x  2 rrd    rrd      54 Sep 27 11:57 network_stats
drwxrwsr-x  2 rrd    rrd      26 Jun 14 11:37 tomcat_stats
drwxrwsr-x  2 rrd    rrd      90 Aug 28 12:57 weather_stats

/www/htdocs/rrd/archives:
total 0
drwxrwsr-x  5 rrd    rrd    67 Oct 26 10:22 .
drwxrwxr-x  8 apache apache 84 Oct 25 15:56 ..
drwxrwsr-x  3 rrd    rrd    17 Oct 26 11:05 localhost_stats
drwxrwsr-x  3 rrd    rrd    17 Oct 26 11:05 network_stats
drwxrwsr-x  3 rrd    rrd    17 Oct 26 11:05 tomcat_stats
drwxrwsr-x  3 rrd     rrd    17 Jul 31 23:55 weather_stats
Notice the file permissions and ownerships for the logs (user rrd which runs the crontab data gathering processes), images (user apache which runs my webserver process) and archives (user rrd which runs the crontab for archival) directories respectively
RRD Files
Here's a listing of my .rrd files at the time of original writing:
/www/htdocs/rrd/logs/localhost_stats:
total 3708
drwxrwsr-x  2 rrd  rrd    4096 Jul 14 13:01 .
drwxrwsr-x  6 rrd  rrd      86 Sep 30 11:09 ..
-rw-r--r--  1 rrd  rrd      84 Apr  1  2003 README.txt
-rw-rw-r--  1 rrd  rrd  209300 Sep 30 11:10 cpu.rrd
-rw-rw-r--  1 rrd  rrd  313444 Sep 30 11:10 disk.rrd
lrwxrwxrwx  1 rrd  rrd       8 Jan 21  2004 disk_avail.rrd -> disk.rrd
-rw-rw-r--  1 rrd  rrd  105156 Sep 30 11:10 disk_backup.rrd
lrwxrwxrwx  1 rrd  rrd       8 Jan 21  2004 disk_usage.rrd -> disk.rrd
-rw-rw-r--  1 rrd  rrd  105156 Sep 30 11:10 eth0.rrd
-rw-rw-r--  1 rrd  rrd   53084 Sep 30 11:10 fanrpm.rrd
-rw-rw-r--  1 rrd  rrd  157228 Sep 30 11:10 load_avg.rrd
-rw-rw-r--  1 rrd  rrd  261372 Sep 30 11:10 memory.rrd
-rw-rw-r--  1 rrd  rrd  105156 Sep 30 11:10 privoxy.rrd
-rw-rw-r--  1 rrd  rrd   53084 Sep 30 11:10 procs.rrd
-rw-rw-r--  1 rrd  rrd  105156 Sep 30 11:10 temperature.rrd
-rw-rw-r--  1 rrd  rrd   53084 Sep 30 11:10 uptime.rrd
-rw-rw-r--  1 rrd  rrd   53084 Sep 30 11:10 users.rrd

/www/htdocs/rrd/logs/network_stats:
total 208
drwxrwsr-x  2 rrd  rrd      54 Sep 27 11:57 .
drwxrwsr-x  6 rrd  rrd      86 Sep 30 11:09 ..
-rw-rw-r--  1 rrd  rrd  105156 Sep 30 11:10 ping_external.rrd
-rw-rw-r--  1 rrd  rrd  105156 Sep 30 11:10 ping_internal.rrd

/www/htdocs/rrd/logs/tomcat_stats:
total 208
drwxrwsr-x  2 rrd  rrd      26 Jun 14 11:37 .
drwxrwsr-x  6 rrd  rrd      86 Sep 30 11:09 ..
-rw-rw-r--  1 rrd  rrd  209300 Sep 30 11:10 localhost.rrd
lrwxrwxrwx  1 rrd  rrd      13 Sep 30 16:20 tomcat_memory.rrd -> localhost.rrd
lrwxrwxrwx  1 rrd  rrd      13 Sep 30 16:21 tomcat_sessionactive.rrd -> localhost.rrd
lrwxrwxrwx  1 rrd  rrd      13 Sep 30 16:20 tomcat_threadbusy.rrd -> localhost.rrd
lrwxrwxrwx  1 rrd  rrd      13 Sep 30 16:21 tomcat_threadcount.rrd -> localhost.rrd

/www/htdocs/rrd/logs/weather_stats:
total 408
drwxrwsr-x 2 rrd  rrd     90 Aug 28 12:57 .
drwxrwsr-x 8 rrd  rrd    154 Jul 30 15:23 ..
-rw-rw-r-- 1 rrd  rrd 417592 Oct  8 21:00 cyyz.rrd
lrwxrwxrwx 1 root rrd      8 Aug 28 12:57 humid.rrd -> cyyz.rrd
lrwxrwxrwx 1 root rrd      8 Aug 28 12:57 press.rrd -> cyyz.rrd
lrwxrwxrwx 1 root rrd      8 Jul 31 16:09 temperature.rrd -> cyyz.rrd
lrwxrwxrwx 1 root rrd      8 Aug  2 18:53 wind.rrd -> cyyz.rrd
Gotcha: Logdir needs to be specified twice
If you look inside rrd.cfg (config file), you need to be aware that even though Logdir is specified at the beginning of the file, it is also repeated inside the DEF lines in the Graph section for each stat. E.g., at the beginning of the file:
Logdir:       /www/htdocs/rrd/logs
and then later on,
DEF:a=/www/htdocs/rrd/logs/localhost_stats/privoxy.rrd:ds0:AVERAGE
Clearly, this violates DRY (do not repeat yourself). If you decide to change the path to Logdir, make sure you do it in all of the DEF lines as well. In the future, I might look into improving this behavior.
This has been fixed in release 1.4.4.
Symbolic Links Gotcha #1
The only reason for the existence of the symbolic links is to faciliate the display of the "last updated time" on the detailed screen. There will be cases where your target name will not map exactly to the name of the .rrd file. So, for example, in the case of symoblic links for disk_avail.rrd and disk_usage.rrd, my main RRD file for those stats is disk.rrd. From the reporting point of view disk_avail and disk_usage are separate even though their data is stored in the same RRD file. The config section for disk availability uses disk_avail between the square brackets, e.g., Title[disk_avail]: Disk Free Space. When rrd.cgi tries to find the "last updated" time, it looks for disk_avail.rrd. Without the symoblic link that file would not exist and you will not see a correct "last updated time". Instead you will see something similar to:
Wednesday, 31 December, 19:00:00 EST
In addition, you will see something similar to the following in your web server's error_log:
Could not get status info for
/www/htdocs/rrd/logs/localhost_stats/disk_avail.rrd.
Missing symbolic link or incorrect permissions!
If that is the case, you are indeed missing the symbolic link. See the per-stat directive IgnoreTimestamps if you want to "ignore the timestamps".
Symbolic Links Gotcha #2
If your rrd file is called Disk_Avail.rrd, then naturally you might have specified your directives for that stat as, for e.g., Title[Disk_Avail]: Disk Availability. Since stat names and directives are converted internally into lower-case, rrd.cgi will look for the file disk_avail.rrd instead of Disk_Avail.rrd. To work around this problem, create a symbolic link as follows:
mixedcase_name.rrd -> MiXeDcAsE_NaMe.rrd
Directory layout for Archivedir
The Archivedir contains an archive of daily/monthly/yearly images. At the time of original writing, my directory structure (last 2 directory levels yyyy/mm, created automatically by the script) was as follows:
/www/htdocs/rrd/archives
/www/htdocs/rrd/archives/localhost_stats
/www/htdocs/rrd/archives/localhost_stats/2004
/www/htdocs/rrd/archives/localhost_stats/2004/10
/www/htdocs/rrd/archives/network_stats
/www/htdocs/rrd/archives/network_stats/2004
/www/htdocs/rrd/archives/network_stats/2004/10
/www/htdocs/rrd/archives/tomcat_stats
/www/htdocs/rrd/archives/tomcat_stats/2004
/www/htdocs/rrd/archives/tomcat_stats/2004/10
/www/htdocs/rrd/archives/weather_stats
/www/htdocs/rrd/archives/weather_stats/2004
/www/htdocs/rrd/archives/weather_stats/2004/10
[top]
Script used in creating .rrd files
Commands used to create these .rrd files
create_rrd.sh
[top]
Scripts used in gathering RRD stats
I mostly used a combination of bash/awk/perl/python/snmpget/grep to gather the data and put it into .rrd files using rrdtool update.
Privoxy filtering proxy
privoxy.sh
Disk Usage Percentage
Disk Free Space
disk.sh
disk_backup.sh
Temperatures
Fan RPM
sensors.sh
If you grabbed a version of this script between January 1, 2008 and January 22, 2009, please get a fresh copy. Thanks to Reimer Prochnow for pointing out that I had a crippled version linked here.
hddtemp.sh
Memory Usage
memory.sh
New version of script was updated on August 21st, 2007. Please update if you acquired this script at an earlier date. Used memory is now calculated as: used=total-(free+buff+cached). Swap usage is calculated as: swap=swaptotal-swapfree.
CPU Usage
cpu.sh
If you used this site to obtain info about setting up CPU Usage rrd graphs before September 10th, 2005, I strongly encourage you to re-visit your configuration since the original config for "cpu usage" was erroneous and broken (a typical symptom of the broken graph was CPU usage not adding up to 100% under heavy CPU utilization). I have since fixed the problem and the CPU usage always adds up to 100%. Please compare how you created your cpu.rrd by looking at the cpu.rrd section in create_rrd.sh and also look at the new config section for [cpu] in rrd.cfg.
As of July 15th, 2008, iowait statistics are included. Please recreate the cpu.rrd file by looking at the cpu.rrd portion of create_rrd.sh to see the revised command and also look at the added CDEFs for iowait in the config section for [cpu] in rrd.cfg.
Traffic Analysis
eth0.sh
Uptime
Load Average
Logged on Users
uptime.sh
As of March 10th, 2010, Load Average graphs are no longer stacked. If you think about it, it makes absolutely no sense to stack the 1-min, 5-min and 15-min values, so I have separated them out (I think I got fooled by the cacti default). Grab the latest config files.
Number of Processes
procs.sh
DNS Statistics (Bind 9.5+)
dns.sh
Bind 9.5 statistics are different from earlier versions. As of July 3rd, 2008, I have regenerated the RRD files. Please look at the dnsoverall.rrd and dnsqueries.rrd portions of create_rrd.sh for the revised creation commands and also look at the modified config sections for [dnsoverall] and [dnsqueries] in rrd.cfg.
As of July 17th, 2009, I have regenerated the RRD files. Please look at the dnsoverall.rrd and dnsqueries.rrd portions of create_rrd.sh where I have added sane upper limits (instead of using U for unlimited), so that I don't get huge spikes upon restart of dns (or upon reboot).
Tomcat
tomcat.sh
tomcat.pl
(an alternative program TERRD used by a user written in C using libxml)
Network Latency (Internal)
Network Latency (External)
ping.sh
Weather
weather.py
Sar Statistics ("sar" command is from app-admin/sysstat Gentoo ebuild)
sar.sh
As of July 4th, 2008, I have made changes to this script which make the sar graphs more "responsive". Be sure to grab the latest.
MySQL
mysql.sh
Lennox iComfort Thermostat
myicomfort.pl
[top]
Crontab entries
A crontab entry which gathers the stats every 5 minutes via a script which calls all the other scripts
*/5 * * * * /home/rrd/sbin/get_rrd_data.sh
A crontab entry which gathers the weather stats every 20 minutes
*/20 * * * * /home/rrd/sbin/weather.py
A crontab entry which gathers the sar stats every 10 minutes
*/10 * * * * /home/rrd/sbin/sar.sh
A crontab entry (under the user named to gather the DNS statistics (bind 9.5+) every 5 minutes
*/5 * * * * /var/bind/sbin/dns.sh
A crontab entry which archives the images near midnight every day (this involves crawling the whole tree)
55 23 * * * /www/cgi-bin/rrd.cgi mode=archive
[top]
Support, License, Warranty, Credit and Opinions
Support
Alas, there is no support available with this software. However, if you ask me nicely via email I will try and help you out.
License
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License.
Warranty
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Credit
It would be nice if you gave me credit on your own website by linking back to this page.
Opinions
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
[top]
Copyright
Copyright
This software is copyright © 2003-2013 by Haroon Rafique and Jan "Yenya" Kasprzak.
[top]
Contact
Email
You can contact the author, Haroon Rafique, via email at haroon<dot>rafique<at>utoronto<dot>ca.
[top]