pygrader.git
12 years agopg.py: set color.USE_COLOR depending on the --color argument.
W. Trevor King [Wed, 19 Sep 2012 17:57:57 +0000 (13:57 -0400)]
pg.py: set color.USE_COLOR depending on the --color argument.

Otherwise the course loading and other things that avoid use_color
keyword args will end up getting printed in color by default.

12 years agoBump to version 0.3. v0.3
W. Trevor King [Sun, 2 Sep 2012 20:06:42 +0000 (16:06 -0400)]
Bump to version 0.3.

12 years agotest: rename maildir messages to have integer unique portions.
W. Trevor King [Sun, 2 Sep 2012 19:39:43 +0000 (15:39 -0400)]
test: rename maildir messages to have integer unique portions.

The `:2,S` portion of the filename means the messages have version 2
status flags (2), and the messages have been seen (S).

12 years agoRan update-copyright.py.
W. Trevor King [Sun, 2 Sep 2012 19:29:49 +0000 (15:29 -0400)]
Ran update-copyright.py.

12 years agoupdate-copyright: add */.gitignore so maildir placeholders don't get tweaked.
W. Trevor King [Sun, 2 Sep 2012 19:29:05 +0000 (15:29 -0400)]
update-copyright: add */.gitignore so maildir placeholders don't get tweaked.

12 years agohandler:grade: add new handler for submitting grades.
W. Trevor King [Sun, 2 Sep 2012 18:29:02 +0000 (14:29 -0400)]
handler:grade: add new handler for submitting grades.

Now profs and TAs can submit grades (points and comments) via email.

12 years agostorage: add save_grade (useful for upcoming `grade` handler).
W. Trevor King [Sun, 2 Sep 2012 18:12:15 +0000 (14:12 -0400)]
storage: add save_grade (useful for upcoming `grade` handler).

12 years agostorage: split load_grade out from load_grades.
W. Trevor King [Sun, 2 Sep 2012 18:10:48 +0000 (14:10 -0400)]
storage: split load_grade out from load_grades.

Also rename _load_grade to parse_grade.

These functions will be useful in the upcoming `grade` handler.

12 years agomailpipe|handler: centralize student/course extraction from subjects.
W. Trevor King [Sun, 2 Sep 2012 17:17:06 +0000 (13:17 -0400)]
mailpipe|handler: centralize student/course extraction from subjects.

12 years agohandler: remove TypeError check InvalidSubjectMessage.__init__.
W. Trevor King [Sun, 2 Sep 2012 16:19:44 +0000 (12:19 -0400)]
handler: remove TypeError check InvalidSubjectMessage.__init__.

Leftover debugging cruft.

12 years agomailpipe: don't double-repr subjects for InvalidHandlerMessage responses.
W. Trevor King [Sun, 2 Sep 2012 15:34:50 +0000 (11:34 -0400)]
mailpipe: don't double-repr subjects for InvalidHandlerMessage responses.

12 years agomailpipe: add extra attributes to errors even if current attribute is None.
W. Trevor King [Sun, 2 Sep 2012 15:30:50 +0000 (11:30 -0400)]
mailpipe: add extra attributes to errors even if current attribute is None.

With the old impementation, a default value of None would keep the
attribute from being added.  For example, if the error is raised with

  error.subject == None

`mailpipe` and `_parse_message` would not override that with their
known value.  Now they will.

12 years agohandler:get: sort submission messages chronologically.
W. Trevor King [Sun, 2 Sep 2012 15:21:21 +0000 (11:21 -0400)]
handler:get: sort submission messages chronologically.

12 years agomailpipe: use `messages.sort(...)`, not `m = sorted(m, ...)`.
W. Trevor King [Sun, 2 Sep 2012 15:18:26 +0000 (11:18 -0400)]
mailpipe: use `messages.sort(...)`, not `m = sorted(m, ...)`.

12 years agohandler:get: skip .gitignore messages a la mailpipe._load_messages.
W. Trevor King [Sun, 2 Sep 2012 15:16:12 +0000 (11:16 -0400)]
handler:get: skip .gitignore messages a la mailpipe._load_messages.

12 years agotest:mail-in: request Frodo's assignment 1 (better data).
W. Trevor King [Sun, 2 Sep 2012 15:11:37 +0000 (11:11 -0400)]
test:mail-in: request Frodo's assignment 1 (better data).

12 years agotest:frodo: add a comment and submission emails.
W. Trevor King [Sun, 2 Sep 2012 15:09:37 +0000 (11:09 -0400)]
test:frodo: add a comment and submission emails.

We can use the new data to excercise the 'get submission' handling.

12 years agotest:mail-in: replace tremily with tower addresses.
W. Trevor King [Sun, 2 Sep 2012 15:07:00 +0000 (11:07 -0400)]
test:mail-in: replace tremily with tower addresses.

12 years agohandler:get: only add comment to submission response if it exists.
W. Trevor King [Sun, 2 Sep 2012 14:55:42 +0000 (10:55 -0400)]
handler:get: only add comment to submission response if it exists.

This avoids potentially confusing responses like:

> Assignment 1 grade: 8.0
>
> None

12 years agotest:mail-in: add test emails excercising `handler.get`.
W. Trevor King [Sun, 2 Sep 2012 14:52:15 +0000 (10:52 -0400)]
test:mail-in: add test emails excercising `handler.get`.

12 years agohandler:get: Responses from this handler are complete.
W. Trevor King [Sun, 2 Sep 2012 14:33:09 +0000 (10:33 -0400)]
handler:get: Responses from this handler are complete.

This avoids double-signing emails and other atrocities.

12 years agomailpipe|handler: add `complete` option to control Response mangling.
W. Trevor King [Sun, 2 Sep 2012 14:32:29 +0000 (10:32 -0400)]
mailpipe|handler: add `complete` option to control Response mangling.

Some handlers may return their emails fully formed, and we won't want
to mess with them.

12 years agomailpipe: respond with the fleshed out message, not the original.
W. Trevor King [Sun, 2 Sep 2012 14:22:26 +0000 (10:22 -0400)]
mailpipe: respond with the fleshed out message, not the original.

We've just added an author, targets, subject, etc.  None of that
matters if you send the original version.

Also print check that the subject is not None before we remove any
subject fields.  This shouldn't matter (del-ing a None subject should
be a no-op), but it seems safer to print the offending message before
messing with it.

12 years agohandler:get: log email construction to troubleshoot parsing.
W. Trevor King [Sun, 2 Sep 2012 14:18:33 +0000 (10:18 -0400)]
handler:get: log email construction to troubleshoot parsing.

12 years agomailpipe|handler: raise exceptions during PGP message verification.
W. Trevor King [Sun, 2 Sep 2012 14:07:42 +0000 (10:07 -0400)]
mailpipe|handler: raise exceptions during PGP message verification.

This avoids the silly "return None on error" convention and allows for
more detailed handling of unsigned messages (vs. improperly signed
messages).

12 years agostorage: cleanup StubCourse after load_course doctest.
W. Trevor King [Sun, 2 Sep 2012 14:00:25 +0000 (10:00 -0400)]
storage: cleanup StubCourse after load_course doctest.

12 years agopg.py|mailpipe: add --trust-email-infrastructure.
W. Trevor King [Sun, 2 Sep 2012 13:33:57 +0000 (09:33 -0400)]
pg.py|mailpipe: add --trust-email-infrastructure.

12 years agopg.py: send_emails (and thus, Responder) no longer takes use_color.
W. Trevor King [Sun, 2 Sep 2012 13:32:34 +0000 (09:32 -0400)]
pg.py: send_emails (and thus, Responder) no longer takes use_color.

12 years agopg.py: fix incomming -> incoming typo for --respond help.
W. Trevor King [Sun, 2 Sep 2012 13:26:22 +0000 (09:26 -0400)]
pg.py: fix incomming -> incoming typo for --respond help.

12 years agomailpipe: sort messages chronologically before processing.
W. Trevor King [Sun, 2 Sep 2012 13:16:22 +0000 (09:16 -0400)]
mailpipe: sort messages chronologically before processing.

12 years agomailpipe: print error messages when we continue_after_invalid_message.
W. Trevor King [Sun, 2 Sep 2012 13:06:17 +0000 (09:06 -0400)]
mailpipe: print error messages when we continue_after_invalid_message.

Since we're not raising the message, we should log it.  Otherwise the
user may not know that something is amiss.

12 years agopg.py: default to continue_after_invalid_message=True when calling mailpipe.
W. Trevor King [Sun, 2 Sep 2012 13:03:33 +0000 (09:03 -0400)]
pg.py: default to continue_after_invalid_message=True when calling mailpipe.

This lets us process a whole mailbox without dying on every invalid
message.  Consider an unfiltered, general-purpose mailbox with lots of
unrelated emails, which can be successfully parsed with
`continue_after_invalid_message`.

12 years agomailpipe: add a warning message before loading a message from a stream.
W. Trevor King [Sun, 2 Sep 2012 12:59:05 +0000 (08:59 -0400)]
mailpipe: add a warning message before loading a message from a stream.

This reminds you if you forget to use the `--mailbox` option when
calling `pg.py`, and the process hangs waiting for a message on stdin.

12 years agogitignore: add `dist` (created by `setup.py sdist`).
W. Trevor King [Sun, 2 Sep 2012 12:46:39 +0000 (08:46 -0400)]
gitignore: add `dist` (created by `setup.py sdist`).

12 years agomailpipe: skip `.gitignore` files in Maildir mailboxes.
W. Trevor King [Sun, 2 Sep 2012 12:38:13 +0000 (08:38 -0400)]
mailpipe: skip `.gitignore` files in Maildir mailboxes.

I use empty `.gitignore` files so Git will create the
`test/mail-in/new` and `test/mail-in/tmp` directories on checkout, but
the Maildir mailbox thinks they are messages.  Since the files are
*not* messages, skip them when constucting the Maildir message list.

I don't foresee any side effects from this (it's an odd filename for
real Maildir delivery), but I log the skipped filenames just in case.

12 years agomailpipe: flesh out InvalidMessage attributes before raising exceptions.
W. Trevor King [Sun, 2 Sep 2012 12:35:50 +0000 (08:35 -0400)]
mailpipe: flesh out InvalidMessage attributes before raising exceptions.

This tacks on all the interesting attribute data which the function
that originally raised the exception may not have known about.  We
want this metadata in all cases, not just those where we are
constructing a response message.

12 years agomailpipe: fix InvalidHandlerMessage error message construction.
W. Trevor King [Sun, 2 Sep 2012 12:32:46 +0000 (08:32 -0400)]
mailpipe: fix InvalidHandlerMessage error message construction.

`target` is an explicit argument, not in `**kwargs`.

I also removed the InvalidHandlerMessage error logging, because we're
raising an exception.  The calling function can log the exception if
it catches it.  If it doesn't, the user will see the message in the
traceback.

12 years agohandler: add InvalidMessage.message_id convenience method.
W. Trevor King [Sun, 2 Sep 2012 12:32:12 +0000 (08:32 -0400)]
handler: add InvalidMessage.message_id convenience method.

12 years agotest:mail-in: add example emails for manual testing.
W. Trevor King [Sun, 2 Sep 2012 11:43:02 +0000 (07:43 -0400)]
test:mail-in: add example emails for manual testing.

12 years agocolor: add ColoredFormatter for more transparent coloring.
W. Trevor King [Sat, 1 Sep 2012 23:14:12 +0000 (19:14 -0400)]
color: add ColoredFormatter for more transparent coloring.

This way we don't have to pass use_color around all over the place.

12 years agomailpipe|handler: with the Response framework, handlers don't need `original`.
W. Trevor King [Sat, 1 Sep 2012 19:40:16 +0000 (15:40 -0400)]
mailpipe|handler: with the Response framework, handlers don't need `original`.

12 years agomailpipe: replace `respond` callback with exceptions.
W. Trevor King [Sat, 1 Sep 2012 19:25:58 +0000 (15:25 -0400)]
mailpipe: replace `respond` callback with exceptions.

Now mailpipe sub-functions will raise Response or InvalidMessage when
they want to respond to the incoming email.  This takes advantage of
Python's exception handling to avoid passing the `respond` callback
all over the place.  It also allows us consolidate error message
construction in `_get_error_response`, which will lead to both simpler
program logic and more consistent response messages.

Other changes to make this cleaner:

* Renamed functions in pygrader.email:
    _construct_email -> construct_email
    construct_email -> construct_text_email
* Pulled _get_assignment out of submission.run.

12 years agohandler:get: add `get` handler for grade requests.
W. Trevor King [Sat, 1 Sep 2012 15:06:05 +0000 (11:06 -0400)]
handler:get: add `get` handler for grade requests.

12 years agohandler:submission: fix non-lowercase subject assignment matching.
W. Trevor King [Sat, 1 Sep 2012 14:50:10 +0000 (10:50 -0400)]
handler:submission: fix non-lowercase subject assignment matching.

Also accept (and ignore) unrecognized keyword arguments in run().
This will allow interoperability with other handlers which may take
other arguments.

12 years agotemplate: add targets argument to construct_student_email.
W. Trevor King [Sat, 1 Sep 2012 13:40:01 +0000 (09:40 -0400)]
template: add targets argument to construct_student_email.

12 years agoREADME: elaborate on grade file format and mailpipe processing.
W. Trevor King [Sat, 1 Sep 2012 12:45:50 +0000 (08:45 -0400)]
README: elaborate on grade file format and mailpipe processing.

12 years agohandler:submission: add doctest to run().
W. Trevor King [Sat, 1 Sep 2012 12:08:40 +0000 (08:08 -0400)]
handler:submission: add doctest to run().

12 years agotemplate: remove extra blank lines from construct student email.
W. Trevor King [Sat, 1 Sep 2012 12:03:48 +0000 (08:03 -0400)]
template: remove extra blank lines from construct student email.

By fixing STUDENT_TEMPLATE to remove blank lines due to grades without
comments.

Also remove NORMALIZE_WHITESPACE from template doctests, which had
been there to match tabs (doctest expands hard tab characters to
spaces using 8-column tab stops).  However, with NORMALIZE_WHITESPACE
it was impossible to test for extra blank lines.

12 years agomailpipe: clarify the source of missing `Return-Path` (bad email)
W. Trevor King [Sat, 1 Sep 2012 10:39:25 +0000 (06:39 -0400)]
mailpipe: clarify the source of missing `Return-Path` (bad email)

12 years agomailpipe: add .authenticated attribute to _get_verified_message results.
W. Trevor King [Sat, 1 Sep 2012 00:51:04 +0000 (20:51 -0400)]
mailpipe: add .authenticated attribute to _get_verified_message results.

This will allow message handlers to easily determine if the message
they're processing is from an authenticated user.

12 years agomailpipe: add support for multi-part subjects in _get_message_subject.
W. Trevor King [Sat, 1 Sep 2012 00:46:54 +0000 (20:46 -0400)]
mailpipe: add support for multi-part subjects in _get_message_subject.

12 years agomailpipe|handler: split mailpipe's submission handler into its own module.
W. Trevor King [Fri, 31 Aug 2012 20:24:23 +0000 (16:24 -0400)]
mailpipe|handler: split mailpipe's submission handler into its own module.

Now you must use a tag target (e.g. `[submit]`) in your email header
to let mailpipe know which handler you want processing your email.
With the new setup, we can easily add additional handlers (e.g. for
grade requests).

12 years agomailpipe: split initial _parse_message processing into sub-functions.
W. Trevor King [Fri, 31 Aug 2012 18:34:16 +0000 (14:34 -0400)]
mailpipe: split initial _parse_message processing into sub-functions.

New functions:

* _get_message_person_and_subject  (which calls the others internally)
* _get_message_person
* _get_decoded_message
* _get_message_subject

With the previous implementation, all the inline error handling was
making the intended logic of _parse_message difficult to follow.

12 years agomailpipe: update doctests now that I'm using GnuPG v2.0.19.
W. Trevor King [Fri, 31 Aug 2012 18:33:23 +0000 (14:33 -0400)]
mailpipe: update doctests now that I'm using GnuPG v2.0.19.

12 years agosetup.py: explicitly list Python 3.2 and 3.3 as supported.
W. Trevor King [Fri, 31 Aug 2012 18:23:12 +0000 (14:23 -0400)]
setup.py: explicitly list Python 3.2 and 3.3 as supported.

12 years agoBump to version 0.2. v0.2
W. Trevor King [Sun, 22 Jul 2012 16:42:04 +0000 (12:42 -0400)]
Bump to version 0.2.

12 years agoAdd MANIFEST.in to distribute COPYING.
W. Trevor King [Sun, 22 Jul 2012 16:40:00 +0000 (12:40 -0400)]
Add MANIFEST.in to distribute COPYING.

12 years agoAdd --respond option to pg.py's mailpipe command.
W. Trevor King [Tue, 24 Apr 2012 22:02:09 +0000 (18:02 -0400)]
Add --respond option to pg.py's mailpipe command.

12 years agoFinish mailpipe respond() doctests.
W. Trevor King [Tue, 24 Apr 2012 21:45:10 +0000 (17:45 -0400)]
Finish mailpipe respond() doctests.

Also:
* Add course.name configuration to README example.
* Standardize course.name examples on the more formal `Physics 101`.
* Standardize robot nickname examples on `phys-101 robot`.

12 years agoDocument course.robot and assignment.submittable in the README.
W. Trevor King [Tue, 24 Apr 2012 21:16:25 +0000 (17:16 -0400)]
Document course.robot and assignment.submittable in the README.

12 years agoReject attempted submissions for unsubmittable assignments in mailpipe.
W. Trevor King [Tue, 24 Apr 2012 21:14:05 +0000 (17:14 -0400)]
Reject attempted submissions for unsubmittable assignments in mailpipe.

This implements the expected behaviour for the option created by:

  commit 80639ff31b3bc6780659f526d518526cf63fcaec
  Author: W. Trevor King <wking@tremily.us>
  Date:   Tue Apr 24 16:48:56 2012 -0400

    Add Assignment.submittable attribute to configure student submission.

12 years agoInitial `respond` implementation in the `mailpipe` module.
W. Trevor King [Tue, 24 Apr 2012 21:00:30 +0000 (17:00 -0400)]
Initial `respond` implementation in the `mailpipe` module.

12 years agoAdd Assignment.submittable attribute to configure student submission.
W. Trevor King [Tue, 24 Apr 2012 20:48:56 +0000 (16:48 -0400)]
Add Assignment.submittable attribute to configure student submission.

If `Assignment.submittable` is `True`, mailpipe will accept student
submissions for that assignment.  However, there may also be
assignments where you don't want to accept direct submissions
(e.g. attendance and written, in-class exams).  For these assignments,
you should leave the `submittable` option at its default `False`
value.

Note that `mailpipe` doesn't use this value yet (implementation coming
soon).

12 years agopgp_mime.pgp.verify() no longer needs deepcopy().
W. Trevor King [Tue, 24 Apr 2012 20:11:57 +0000 (16:11 -0400)]
pgp_mime.pgp.verify() no longer needs deepcopy().

Since the pgp-mime commit:

  commit 49802119d7846c7ffd6d72a46068aff014361b59
  Author: W. Trevor King <wking@tremily.us>
  Date:   Tue Apr 24 16:01:17 2012 -0400

    Always return a new Message instance from pgp.verify().

12 years agoAdd Course.robot attribute (for automatic email generation).
W. Trevor King [Tue, 24 Apr 2012 19:27:08 +0000 (15:27 -0400)]
Add Course.robot attribute (for automatic email generation).

I'm getting things set up to send automatic responses when mailpipe
processes incoming email, which means someone's going to have to be
signing that email for security.  Since you probably don't want to
leave your secret PGP key on the mailserver, you can now setup a new
(and less important) PGP key for each course.  The Course.robot is
just a Person instance to hold that key and an appropriate nickname.

If you want to use your own key when you call pg.py from the command
line, you can always setup a shell alias.  In Bash:

  alias pg.py='/usr/bin/pg.py --author="John Doe"'

12 years agoPull _construct_email out of construct_email and add construct_response.
W. Trevor King [Tue, 24 Apr 2012 19:09:49 +0000 (15:09 -0400)]
Pull _construct_email out of construct_email and add construct_response.

_construct_email() handles general tasks for setting up the main email
header.  construct_email() combines this with a simple text/plain body,
while construct_response() uses a multipart/mixed format suitable for
sending message receipts to users.

12 years agoFix Built -> Build typo in construct_email docstring.
W. Trevor King [Tue, 24 Apr 2012 18:43:30 +0000 (14:43 -0400)]
Fix Built -> Build typo in construct_email docstring.

12 years agoAdd docstring and doctest to message_time().
W. Trevor King [Tue, 24 Apr 2012 18:34:52 +0000 (14:34 -0400)]
Add docstring and doctest to message_time().

12 years agoAdd Course.name attribute (for clearer email generation).
W. Trevor King [Tue, 24 Apr 2012 18:33:28 +0000 (14:33 -0400)]
Add Course.name attribute (for clearer email generation).

12 years agoAdd mailpipe doctests and allow saving from stream to an output maildir.
W. Trevor King [Tue, 24 Apr 2012 18:04:37 +0000 (14:04 -0400)]
Add mailpipe doctests and allow saving from stream to an output maildir.

12 years agoAdd pygrader.test.course for managing testing course directories.
W. Trevor King [Tue, 24 Apr 2012 17:21:37 +0000 (13:21 -0400)]
Add pygrader.test.course for managing testing course directories.

12 years agoAdd pygrader.test with asyncore SMTP client/server implemenations.
W. Trevor King [Tue, 24 Apr 2012 16:21:56 +0000 (12:21 -0400)]
Add pygrader.test with asyncore SMTP client/server implemenations.

This should make it easier to build integration tests for `mailpipe()`.

12 years agoRemove myself as the hardcoded default sender.
W. Trevor King [Mon, 23 Apr 2012 16:24:11 +0000 (12:24 -0400)]
Remove myself as the hardcoded default sender.

Use the first assistant instead, since they are the most likely person
to be running this database.

12 years agoAlways sign/encrypt outgoing email in construct_email().
W. Trevor King [Mon, 23 Apr 2012 16:21:01 +0000 (12:21 -0400)]
Always sign/encrypt outgoing email in construct_email().

Remove the `sign` option.  If you've configured pgp_keys for the
correspondents, it's because you want to use them.

This commit also ensures that the sender is also encluded on the
recipient list for encryption, although there is currently no copy of
the email forwarded to the sender.

12 years agoUpdate to use pgp-mime v0.3
W. Trevor King [Sun, 22 Apr 2012 02:31:00 +0000 (22:31 -0400)]
Update to use pgp-mime v0.3

12 years agoChange my email address from drexel.edu to tremily.us.
W. Trevor King [Wed, 18 Apr 2012 17:22:33 +0000 (13:22 -0400)]
Change my email address from drexel.edu to tremily.us.

12 years agoOops, missed some pygrade -> pygrader updates in model/course.py.
W. Trevor King [Fri, 6 Apr 2012 18:17:38 +0000 (14:17 -0400)]
Oops, missed some pygrade -> pygrader updates in model/course.py.

12 years agoLog the gpg_message in mailpipe._get_verified_message instead of printing it.
W. Trevor King [Fri, 6 Apr 2012 18:14:30 +0000 (14:14 -0400)]
Log the gpg_message in mailpipe._get_verified_message instead of printing it.

12 years agoFix storage.load_person doctest typo (actually print the PGP key).
W. Trevor King [Fri, 6 Apr 2012 18:12:37 +0000 (14:12 -0400)]
Fix storage.load_person doctest typo (actually print the PGP key).

12 years agoAdd AUTHORS to .gitignore (generated by update-copyright.py). v0.1
W. Trevor King [Fri, 23 Mar 2012 20:27:47 +0000 (16:27 -0400)]
Add AUTHORS to .gitignore (generated by update-copyright.py).

12 years agoRemove fingerprint stuff from the README (waiting on a GPGME agent).
W. Trevor King [Fri, 23 Mar 2012 20:26:41 +0000 (16:26 -0400)]
Remove fingerprint stuff from the README (waiting on a GPGME agent).

12 years agoFix link to Alex's pygrade in the README.
W. Trevor King [Fri, 23 Mar 2012 20:25:19 +0000 (16:25 -0400)]
Fix link to Alex's pygrade in the README.

12 years agoOops, missed some pygrade -> pygrader updates in setup.py.
W. Trevor King [Fri, 23 Mar 2012 19:34:33 +0000 (15:34 -0400)]
Oops, missed some pygrade -> pygrader updates in setup.py.

12 years agoMention update-copyright in the README.
W. Trevor King [Fri, 23 Mar 2012 19:27:36 +0000 (15:27 -0400)]
Mention update-copyright in the README.

12 years agoRan update-copyright.py.
W. Trevor King [Fri, 23 Mar 2012 19:25:54 +0000 (15:25 -0400)]
Ran update-copyright.py.

12 years agoBegin versioning! (better late than never)
W. Trevor King [Fri, 23 Mar 2012 19:18:48 +0000 (15:18 -0400)]
Begin versioning!  (better late than never)