/[libdata]/trunk/admin/install/libdata_install.txt
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/admin/install/libdata_install.txt

Parent Directory Parent Directory | Revision Log Revision Log


Revision 72 - (hide annotations)
Thu Mar 18 20:33:37 2004 UTC (20 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 27566 byte(s)
changes made in version 2.00

1 dpavlin 1 File: libdata_install.txt
2     Title: LibData Installation
3     Author: Paul F. Bramscher brams006@umn.edu
4 dpavlin 72 Date: March 16, 2004
5 dpavlin 1
6    
7     ==============================================================================
8     TABLE OF CONTENTS
9     ==============================================================================
10    
11     1.0 Infrastructure
12     2.0 Architecture
13     3.0 Installation Procedures
14     4.0 Troubleshooting
15    
16     ==============================================================================
17     1.0 INFRASTRUCTURE
18     ==============================================================================
19    
20     Hardware Developed and tested on generic intel-based Linux
21     servers and Sun servers. Other hardware (Macintosh)
22     might be possible with some code modifications.
23     Queries can be complex and frequent to render pages.
24     A 2 GHz+ server with 1 GB RAM is recommended for a modest
25     installation in a production environment.
26     Disk footprint for the PHP code itself is well under 5 MB.
27     Additional disk requirements due to database size depends
28     on your local utilization and data growth rate -- and
29     should be monitored as it grows. However, LibData is
30     strongly normalized and unlikely to ever present a disk
31     space issue.
32    
33     Operating System Developed and tested on both Red Hat Linux 9 and Solaris
34     unix. Other operating systems (BSD, Mac OS X, etc.)
35     might be possible with varying degrees of modification.
36     Extensive modification would likely be required to run
37     LibData on a Windows-based computer with an Apache, PHP,
38     and mySQL installation (NOT recommended).
39    
40     Web Server Apache. It is possible to run LibData on a server
41     without a DNS name, although it must be a routable
42     IP. It is strongly recommended to split LibData into
43     two directories, one serving public interfaces, and the
44     other in an SSL location (refer to installation steps
45     below).
46    
47 dpavlin 72 Database mySQL 3.x. Note that LibData was initially developed on a
48 dpavlin 1 version of mySQL without support for transactions, and this
49     substantially affects the atomicity of the SQL code (lacking
50 dpavlin 72 the rollback feature). Other sites have reported successful
51     installation of LibData on mySQL versions 4.x, with minor
52     modifications to the Perl install script. Also note that
53     the mySQL password() function may create different hashes
54     between mySQL versions 3.x and 4.x, so migrating a fully
55     populated production back-end of LibData from one version to
56     another may require resetting (effectively rehashing) user
57     passwords. LibData has not been developed for 4.x at this
58     stage, so additional modification may be necessary.
59 dpavlin 1
60     Programming Language Written exclusively in PHP. Coding is structured/function
61     based for simplicity, using PHP object encapsulation only for
62     security (session-related) purposes. As this is version 1.0,
63     without outside grants or special funding, code has certainly not
64     been optimized. However, it is highly self-documented and
65     meaningful variable names have generally been used throughout.
66    
67     Recommended Browsers Note that no client-side programming was done (other than HTML
68     and modest usage of CSS). Therefore LibData ought to be quite
69     widely viewable by most any browser available. Additionally,
70     there are no frames to contend with. Viewing is best at 1024 x 768,
71     particularly in the authoring/administrative environments, though
72     800 x 600 is also supported. In keeping with the spirit of open
73     source, we recommend Mozilla which renders HTML cleaner than
74     MSIE (for example, no extra spaces when a FORM tag is within a
75     table cell). LibData was developed with Mozilla specifically in mind.
76    
77     ==============================================================================
78     2.0 ARCHITECTURE
79     ==============================================================================
80    
81     -------------------
82     Directory Locations
83     -------------------
84     The system requires two directories, one serving up the public interfaces
85     (hereafter referred to as "public libdata"), another which contains the
86     administration and authoring side ("administration libdata"). General
87     directory path information and other variables may be customized in a file
88     named global_vars.php. This file must be in either (a) BOTH the libdata
89     administration directory AND public directory or (b) in the Apache-defined
90     default location for server-side inclusions. Check with Apache and/or PHP
91     documentation for this. The "include" subdirectory below the libdata
92     administration directory must always be a subdirectory below administration
93     and cannot currently be renamed or moved without some program modifications.
94     (Although an additional Apache-defined include location for the
95     global_vars.php file may be anywhere). Following is an example arrangement:
96    
97     -----------------
98     Public interfaces
99     -----------------
100     /htdocs/www/libdata
101    
102     /images
103     /styles
104    
105     -------------------------
106     Administration interfaces
107     -------------------------
108     /htdocs/www-ssl/libdata_admin
109    
110     /docs
111     /images
112     /include
113     /install (but should be moved elsewhere at installation Step #11.)
114    
115     Note that the administration side here is piped through SSL (defined by
116     Apache configuration). It is strongly recommended that this portion be
117     SSL, since authentication and user management is handled by this portion
118     of libdata. At the very least, a self-signed server certificate can be
119     created without cost. If this is not possible, then the public and
120     administration portions will likely need to have separate directory names
121     (for example "libdata" for public and "libdata_admin" for the
122     administrative side).
123    
124     If your site is not configured for SSL, you need it only for LibData, and don't
125     mind staff having to click (one time) that they trust the server certificate,
126     following are instructions for creating a self-signed certificate on Red Hat 9:
127     http://www.redhat.com/docs/manuals/linux/RHL-9-Manual/custom-guide/s1-secureserver-overview-certs.html
128    
129     Another good tool, usable for other Linux distributions (tested on SuSE) is TinyCA:
130     http://tinyca.sm-zone.net/
131    
132     ==============================================================================
133     3.0 INSTALLATION PROCEDURES
134     ==============================================================================
135    
136     -------------
137     Initial Setup
138     -------------
139     Before proceeding to the installation steps, it is necessary to configure
140     PHP and Apache for the following:
141    
142     (A) Interpretation of both .php and .phtml file extensions by the php
143     engine. Changing this setting may vary depending on your installation.
144     (try /etc/httpd/conf.d/php.conf with a default Red Hat 9 install).
145     (B) "register_globals = On" should be set in your php.ini file
146     (try /etc/php.ini with a default Red Hat 9 install).
147 dpavlin 72
148    
149     *** Note that future versions of LibData may be written without this
150     required setting, but that LibData's security mechanism is not
151     compromised by setting this ON. The security technique involves storing
152     a session ID in a client side cookie which must match a server stored
153     session ID. Every page and every HTML form submission requires
154     re-checking that the client and server session ID's match. Assuming
155     they match, an access level is pulled from the server and applied only
156     to the current page. This constant re-checking, and storing the actual
157     access level on the server side, makes LibData among the more secure web
158     mechanisms available. Also, unlike built-in PHP session capability,
159     LibData sessions are tied to the IP address. So passing a hacked cookie
160     or GET/POST method -- even with a valid session ID -- would fail unless
161     it was done from the correct IP address.
162    
163 dpavlin 1 (C) Also in the php.ini file, make sure that "magic_quotes_gpc = Off".
164     gpc stands for get/post/cookie, and turning quote escaping on will
165     create problems for interaction at various layers between HTML,
166     PHP and mySQL. Things might get double-escaped, or not escaped at all
167     depending on whether the string has made the "round trip" to the client
168     and back, has been stored in mySQL, etc. Many PHP developers recommend
169     turning this setting off, and LibData has been created with this in mind.
170     If it must be turned on, some work will need to be done with textInmySQL()
171     and textSearchmySQL() to prevent mySQL errors in app_controls.php.
172     (D) Apache SSL should be +StdEnvVars for the SSL port.
173     (E) Server side Includes should be allowed.
174    
175     There may be additional tweaking based on your installation, but the
176     previous are minimal required settings.
177    
178     -------------------------------------------
179     (1) Build the Public LibData html directory
180     -------------------------------------------
181 dpavlin 72 LibData comes as two tar.gz files. One is named libdata_pos.tar.gz. This tar
182 dpavlin 1 contains all of the public HTML and PHP code. The "p" in this package refers to
183     the "public" side of LibData. Extracting the tar will produce a libdata_pos
184     directory which should be moved to a web-servable location on an Apache instance.
185    
186     It's possible to rename this directory to something more meaningful to your
187     installation. Whatever directory name is chosen, changes will need to be made in
188     Step #3 below to configure LibData to recognize it. It's possible to rename the
189     directories after LibData is fully populated with data as well -- the directory names
190     are hardcoded in only two configuration files (refer to Step #3 for further details).
191     Changes are simple and go into effect immediately. So feel free to rename libdata_pos
192     to something more useful.
193    
194     The public and administration portions of LibData should have different directory names.
195     It's possible (but not recommended) to give them the same name if the public portion
196     is in a directory like /www/html/libdata and the administrative resides in
197     /www-ssl/html/libdata. But to avoid confusion, we recommend giving them differing names
198     (as well as locations).
199    
200     File permissions and ownerships should be tweaked by a unix administrator as necessary.
201    
202     ---------------------------------------------------
203     (2) Build the Administration LibData html directory
204     ---------------------------------------------------
205 dpavlin 72 The administration/staff modules are contained in libdata_aos.tar.gz. The "a" in
206 dpavlin 1 this package refers to the "administrative" side of LibData. Extracting the tar will
207     produce a libdata_aos directory which should be moved to a web-servable location on
208     an Apache instance as with the previous step -- but it is HIGHLY recommended that this
209     directory be in an SSL-served location, since passwords and other information will
210     be sent.
211    
212     As with the public portion of LibData, it's possible to rename this directory to something
213     more meaningful to your installation. Whatever directory name is chosen, changes will
214     need to be made in Step #3 below to configure LibData to recognize it.
215    
216     File permissions and ownerships should be tweaked by a unix administrator as necessary.
217    
218     -------------------------
219     (3) Tweak global_vars.php
220     -------------------------
221     There are initially two instances of this file in your installation, one in
222     libdata administration and one in libdata public. The files are initially
223     identical, and should always remain identical. Note that with PHP it's possible to
224     configure a single, default server-side include location. So it's possible to
225     delete one of these files, and move the other to that default include location.
226     (This requires minor tweaking with Apache and/or PHP configuration files.) But it's
227     recommended that you worry about this later -- first get LibData up and running.
228    
229     Both files should be tweaked with information specific to your installation:
230     server name, LibData "system" name, administrator, e-mail contact information, etc. and
231     installation directory locations. Take note of the existing format -- don't add or subtract
232     trailing backslashes. These files can be tweaked any time, during installation or with a
233     fully-populated production LibData. Changes go into effect immediately, there is no
234     process to start/restart, etc.
235    
236     --------------------------------------------------------------------
237     (4) Create the LibData databases (libdata, libstats, and libsession)
238     --------------------------------------------------------------------
239    
240     *** IMPORTANT ****************************************************************
241     Ensure that there are NO existing mysql databases named libdata, libstats or
242     libsession on your server. They will be DESTROYED by the next step. Running
243     the following script will DROP all existing LibData references to ensure a
244     clean install of the databases, a base data set, and mysql users.
245     ******************************************************************************
246    
247 dpavlin 72 *** Also note that the install script works only with mySQL 3.x. mySQL 4.x has
248     additional fields in the mysql.user table and so the install script may need
249     minor tweaking. At any rate, mySQL user rights should be managed very carefully
250     and this script is not meant to provide a definitive solution from a security
251     standpoint. Essentially the mySQL user named "libdata" must have, at a minimum,
252     select, insert, update, and delete capability for the libdata and libstats databases.
253     The mySQL user "libsession" must have select, insert, update, and delete rights
254     to the libsession database. Refer also to the next section (#5) in this document.
255 dpavlin 1
256 dpavlin 72 To run the install script (mySQL 3.x) go to the install directory in the libdata
257     administrative directory.
258    
259 dpavlin 1 Run the script named libload.pl, and follow the instructions given. The script
260     must be run on the server hosting the mySQL daemon, and the mySQL root account is
261     probably the best account for this procedure to avoid access denial issues (though
262     if you have another account capable of dropping/adding databases, making changes
263     to the mysql grants table, and reloading/refreshing them, you may use that account
264     instead.)
265    
266     If you encounter errors with this step, double-check the following:
267     (1) The location of the Perl interpreter might not necessarily be
268     /usr/bin/perl. Please adjust the reference in libload.pl accordingly.
269     Also, make sure that this file is executable (chmod +x libload.pl).
270     (1) The mySQL daemon is initialized (for the first time), up and running.
271     (2) The mySQL account/password you supplied is valid, and may access the
272     mySQL command-line client with permissions required to perform the actions
273     listed above.
274    
275     Keep this script in a secure place, since it contains default mySQL password
276     information. Don't re-run it without backing up all data in libdata, libstats,
277     or libsession that you wish to keep!
278    
279     ----------------------------------
280     (5) Examine mySQL user permissions
281     ----------------------------------
282     This section refers to the "users" that PHP will use in interacting with mySQL
283     LibData databases (libdata, libstats, and libsession). These users are not to
284     be confused with authoring staff accounts -- those are maintained from within
285     LibData itself (and not stored here).
286    
287     Use whichever mySQL client you are most comfortable with (command-line,
288     phpMyAdmin, mySQL Control Center, etc.) access the internal "mysql"
289     system database.
290    
291     In the mysql.user table the libload.pl script (previous step above)
292     should have created basic libdata and libsession accounts with the following
293     rights. Following is an example of entering the rows manually:
294    
295     INSERT INTO user VALUES (‘%’, ‘libdata’, password(‘t0ught0gu355’),
296     ‘Y’, ‘Y’, ‘Y’, ‘Y’, ‘Y’, ‘N’, ‘N’, ‘N’,’N’,’N’,’N’,’N’,’N’,’N’);
297    
298     INSERT INTO user VALUES (‘%’, ‘libsession’, password(‘3v3nt0gh3r’),
299     ‘N’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’,’N’,’N’,’N’,’N’,’N’,’N’);
300    
301     Changing passwords is trivial, and you ought to do it now. For example:
302    
303     UPDATE user SET password = password('newpass') WHERE user = 'libdata';
304     UPDATE user SET password = password('anotherone') WHERE user = 'libsession';
305    
306     Passwords must be 6 characters minimum or you won't be able to login -- LibData's
307     login mechanism will reject even valid passwords under 6 characters in length.
308     Be sure to pick a mixture of numbers and letters, and alternate some upper and
309     lower case.
310    
311     *** Note that making changes to the libdata or libsession usernames or
312     passwords will require corresponding changes in the following files (the
313     username and password must match what exists in the database). Since they
314     appear as plain-text in the PHP scripts below, you'll need to manage
315     unix user access to these files carefully:
316    
317     LibData administration path:
318     include/db_connect.php (general libdata database connection include)
319     include/accessClass.php (determines access rights for current user session)
320     include/sessionClass.php (creates, logs out, and validates existing sessions)
321    
322     LibData public path:
323     db_connect.php (general libdata database connection include)
324    
325     *** Changing the passwords on a scheduled basis is recommended, and should
326     be part of an overall security plan. In fact, they should be changed
327     immediately after installing LibData for the first time so you're not
328     running with default and/or known passwords.
329    
330     Note that this may be tweaked further. If, for example, the PHP scripts will
331     be run on the same server as the mySQL daemon, then the "%" in the first column
332     might be tweaked to include only that DNS/IP address. This prevents the accounts
333     from accessing your mySQL server from any other server. The usernames themselves
334     (libdata and libsession) may also be renamed, so long as changes are made in the
335     files discussed in this section (and the next). But this isn't recommended at
336     this stage. LibData may be fine-tuned later -- and there's little reason to
337     rename them anyway.
338    
339     -----------------------------------------------
340     (6) Examine the mySQL database/host permissions
341     -----------------------------------------------
342     Next, the db table should be examined with regard to similar issues. Following
343     is an example of a manual INSERT into them:
344    
345     INSERT INTO db VALUES (‘%’, ‘libdata’, ‘libdata’,
346     ‘Y’, ‘Y’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’);
347    
348     INSERT INTO db VALUES (‘%’, ‘libsession’, ‘libsession’,
349     ‘Y’, ‘Y’, ‘Y’, ‘Y’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’, ‘N’);
350    
351     Again, note that the initial "%" in the first column might be tweaked to
352     limit to your particular hostname.
353    
354     If you've renamed the libdata and libsession users (Step #5 above) you'll need
355     to rename them here as well.
356    
357     ------------------------------------
358     (7) Configure PHP connection strings
359     ------------------------------------
360     If you've made any changes to the libdata and libsession mysql user passwords
361     (hopefully you have!) double-check that they are correctly referenced in the
362     following files.
363    
364     You'll also need to change the database server strings in each of the files,
365     with an IP or valid DNS name appropriate to the server hosting your instance
366     of LibData:
367    
368     LibData administration path:
369     include/db_connect.php (general libdata database connection include)
370     include/accessClass.php (determines access rights for current user session)
371     include/sessionClass.php (creates, destroys and validates existing session)
372    
373     LibData public path:
374     db_connect.php (general libdata database connection include)
375    
376     ---------------------------------------------------------
377     (8) Reload and refresh the mySQL grant/permissions tables
378     ---------------------------------------------------------
379     The mySQL grants tables should be refreshed and reloaded at this point. This
380     can be done with the mySQL command-line client by the following:
381    
382     mysqladmin -uroot -p reload
383     mysqladmin -uroot -p refresh
384    
385     After each command, it will prompt for the administrator password.
386    
387     -------------------------------------------------------------------------
388     (9) The LibData system should now be functional. Login as administrator.
389     -------------------------------------------------------------------------
390    
391     Go to the appropriate url and login as administrator. For example:
392     https://www.yourlibrary.edu/libdata/login.phtml
393    
394     default username: admin
395     default password: libd4t4
396    
397     (a) Follow the Manager Functions link on the bottom of the main console.
398     (b) Click "Manage Staff List" toward the bottom of the Manager Function menu.
399     (c) Select the radio button for Administrator, System to edit that account.
400     (d) Change the administrator password as desired.
401    
402     Note that passwords, for security purposes, are never displayed on any of
403     the forms. Also, passwords for any account may be purged to NULL. This
404     automatically renders the account inactive (accounts without passwords may
405     not login). Be sure not to purge the password for the admin account, or
406     you'll need to enter mySQL manually, and execute a query like this:
407    
408     UPDATE libdata.staff SET password = password('n3wpassw0rd') WHERE staff_id = 2;
409    
410     or some such in order to log back into the system as administrator.
411    
412     -------------------------------------
413     (10) Test mySQL single-quote escaping
414     -------------------------------------
415    
416     Assuming your LibData configuration is now functional, it's a good idea to
417     test proper escaping of single-quotes. Refer to 3.0 Installation Initial Setup
418     Part C above on why magic_quotes_gpc must be turned Off.
419    
420     On the main authoring console, attempt to enter a resource with a
421     single-quote in the title. For example, Here's a Title. (Also note
422     that it is necessary to select some initial master subject or master
423     information type -- refer to the user manuals on why this functionality
424     was programmed). Pick anything from either drop-down box. Failing to
425     do this will result in a screen why it's (as currently programmed) necessary
426     to pick something.
427    
428     On the resource entry form, click the Save New Resource button. Then
429     update the title field by pulling out the quote, for example: Heres a Title.
430     Click the Update Resource button. Then go back and add the single-quote one
431     more time, Here's a Title. Click Update Resource again. This will test both
432     the insert and update SQL functionality.
433    
434     If LibData reports a SQL error, you'll most likely need to make a tweak here:
435     {libdata admin directory location} include/app_controls.php.
436    
437     Look for the function textInmySQL(). Most all of LibData's mySQL insert/update
438     strings are first routed here. Depending on your mySQL installation, you may need
439     to escape single-quotes with a backslash as follows: \'. Comment out the
440     appropriate pass-through ($outgoing = $incoming) and uncomment the nearby line
441     above which performs this escaping. Add additional filters here as desired,
442     and make sure that the corresponding data entry form (generally stored in
443     include/forms.php) calls this function for each form field to be filtered for
444     input or update.
445    
446     Make the same corresponding change in textSearchmySQL(). This function is
447     virtually identical, but filters text going into (some) SELECT type statements.
448     Both textInmySQL() and textSearchmySQL() might be heavily modified for
449     bullet-proofing, possible security issues, etc.
450    
451     Note that double-quotes typically present a problem on many sites in all but
452     textarea based HTML form fields. Future versions of LibData may resolve this
453     (but there are some limits with using HTML as an interface).
454    
455     One possible mechanism is to convert certain special characters to their HTML hex
456     equivalents with textInmySQL. The next step, then, is to convert all search-entry
457     forms into their hex equivalents as well, so that converted data is searched with
458     user input in the identical syntax.
459    
460     Other variants on these themes use the php functions addslashes() stripslashes().
461     Hopefully everything will be working and you won't need to go down this path.
462    
463     ------------
464     (11) Cleanup
465     ------------
466    
467     Assuming you've successfully installed LibData, this step is important from a
468     security standpoint and should not be neglected.
469    
470     Move the install subdirectory (currently in the administrative directory) out of
471     a web-servable location, and give only root users access to it -- since re-running
472     the install script will DROP a production/populated LibData database. It's also
473     recommended to chmod -x libload.pl to prevent a malicious user (or yourself) from
474     making a grave mistake to a production system...
475    
476     ------------------------------
477     Tips for further configuration
478     ------------------------------
479     (1) The public libdata db_connect.php may, alternatively, use a different
480     username/password from the administrative db_connect.php file. Furthermore,
481     the public connection need have only SELECT rights to the libdata database,
482     and SELECT and INSERT rights to the libstats database. There are several
483     strategies to fine-tune security, some of them are related uniquely to your
484     institution and levels of paranoia.
485 dpavlin 72 (2) The LibData db_connect.php file, independently in both the administrative
486     and public halves of LibData contains a function named xx_tryquery(). This
487     is a light wrapper around the built-in xx_query() function. Note that there
488     is a variable for debug mode ($db_debug). Setting this to 1 (true) will cause
489     all SQL queries which fail to be output to the screen. This is not recommended
490     for production or public side LibData. However, it can be used in conjunction
491     with a mail() type function to the mail the failed query, mySQL error message,
492     and date/time transparently to the system administrator. This functionality is
493     not supplied (and requires a functioning SMTP gateway). However, the programming
494     to enable this is quite minimal given the centralized error-trapping with
495     xx_tryquery() in the db_connect.php files. (Remember that administrative and
496     public LibData utilize their own separate db_connect.php files.)
497 dpavlin 1
498     ==============================================================================
499     4.0 TROUBLESHOOTING
500     ==============================================================================
501    
502     Debugging dynamic database applications offers challenges on several fronts.
503     If there are problems using LibData at this point, there are four main areas
504     to debug:
505    
506     (1) Unix. Are the libdata files set to the appropriate permissions? Are
507     they web servable?
508    
509     (2) Apache. Is it serving up other web basic HTML pages?
510    
511     (3) PHP. Create basic "Hello World" PHP programs with both a .php and .phtml
512     extension. Are they being served? Make sure that Apache is configured to
513     interpret both .PHP and .PHTML pages through the PHP parser. Make sure that
514     the global_vars.php files, in both the public and administration locations,
515     have the correct information. It sometimes helps to run the phpinfo() function
516     (visit the http://www.php.net site for documentation on it) for information
517     gathering purposes. Make sure that PHP is configured with register_globals = On
518     (refer to 3.0 Installation Procedures Initial Setup Step A.). To test if this
519     is functioning properly, write a simple .PHTML page with a form POST method to
520     another .PHTML page. Collect the value on the recipient .PHTML page and simply
521     print it for display. If it comes through properly, then a problem with
522     variable passing may be ruled out.
523    
524     (4) mySQL. Make sure that the affected files (db_connect.php on both the
525     public and administration sides, accessClass.php, and sessionClass.php) all
526     have information which corresponds to the name of your mySQL server, and the
527     correct mySQL accounts and passwords. Ensure that those accounts have the
528     appropriate permissions as specified in the installation procedures above.
529     Be sure to refresh and reload the mySQL grant tables also as specified, since
530     some changes to the grants table do not always go into effect immediately.
531    
532     For installation problems or suggestions, please send an e-mail to the
533     developer, Paul Bramscher (brams006@umn.edu), though neither I nor the
534     University of Minnesota can make any guarantees or warranties with regard to
535     LibData or its support.
536    
537    
538    
539 dpavlin 72 March 16, 2004
540 dpavlin 1 Paul F. Bramscher
541     brams006@umn.edu
542 dpavlin 72 University of Minnesota Libraries

  ViewVC Help
Powered by ViewVC 1.1.26