diff --git a/.git/COMMIT_EDITMSG b/.git/COMMIT_EDITMSG
deleted file mode 100644
--- a/.git/COMMIT_EDITMSG
+++ /dev/null
@@ -1,3 +0,0 @@
-Revert "revert removal of eof marker"
-
-This reverts commit caabd581f6cf7157ce211a91112cf5047e527be7.
diff --git a/.git/FETCH_HEAD b/.git/FETCH_HEAD
deleted file mode 100644
--- a/.git/FETCH_HEAD
+++ /dev/null
@@ -1,1 +0,0 @@
-2353b6eaeee1c824371c12bad78d4053ec52041d		branch 'master' of https://github.com/Porges/email-validate-hs
diff --git a/.git/HEAD b/.git/HEAD
deleted file mode 100644
--- a/.git/HEAD
+++ /dev/null
@@ -1,1 +0,0 @@
-ref: refs/heads/master
diff --git a/.git/ORIG_HEAD b/.git/ORIG_HEAD
deleted file mode 100644
--- a/.git/ORIG_HEAD
+++ /dev/null
@@ -1,1 +0,0 @@
-6eb270b673a8ae8db8e5e2a5e765065933943523
diff --git a/.git/config b/.git/config
deleted file mode 100644
--- a/.git/config
+++ /dev/null
@@ -1,14 +0,0 @@
-[core]
-	repositoryformatversion = 0
-	filemode = false
-	bare = false
-	logallrefupdates = true
-	symlinks = false
-	ignorecase = true
-	hideDotFiles = dotGitOnly
-[remote "origin"]
-	fetch = +refs/heads/*:refs/remotes/origin/*
-	url = https://github.com/Porges/email-validate-hs.git
-[branch "master"]
-	remote = origin
-	merge = refs/heads/master
diff --git a/.git/description b/.git/description
deleted file mode 100644
--- a/.git/description
+++ /dev/null
@@ -1,1 +0,0 @@
-Unnamed repository; edit this file 'description' to name the repository.
diff --git a/.git/hooks/applypatch-msg.sample b/.git/hooks/applypatch-msg.sample
deleted file mode 100644
--- a/.git/hooks/applypatch-msg.sample
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-#
-# An example hook script to check the commit log message taken by
-# applypatch from an e-mail message.
-#
-# The hook should exit with non-zero status after issuing an
-# appropriate message if it wants to stop the commit.  The hook is
-# allowed to edit the commit message file.
-#
-# To enable this hook, rename this file to "applypatch-msg".
-
-. git-sh-setup
-test -x "$GIT_DIR/hooks/commit-msg" &&
-	exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
-:
diff --git a/.git/hooks/commit-msg.sample b/.git/hooks/commit-msg.sample
deleted file mode 100644
--- a/.git/hooks/commit-msg.sample
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-#
-# An example hook script to check the commit log message.
-# Called by "git commit" with one argument, the name of the file
-# that has the commit message.  The hook should exit with non-zero
-# status after issuing an appropriate message if it wants to stop the
-# commit.  The hook is allowed to edit the commit message file.
-#
-# To enable this hook, rename this file to "commit-msg".
-
-# Uncomment the below to add a Signed-off-by line to the message.
-# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
-# hook is more suited to it.
-#
-# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
-# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
-
-# This example catches duplicate Signed-off-by lines.
-
-test "" = "$(grep '^Signed-off-by: ' "$1" |
-	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
-	echo >&2 Duplicate Signed-off-by lines.
-	exit 1
-}
diff --git a/.git/hooks/post-update.sample b/.git/hooks/post-update.sample
deleted file mode 100644
--- a/.git/hooks/post-update.sample
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-#
-# An example hook script to prepare a packed repository for use over
-# dumb transports.
-#
-# To enable this hook, rename this file to "post-update".
-
-exec git update-server-info
diff --git a/.git/hooks/pre-applypatch.sample b/.git/hooks/pre-applypatch.sample
deleted file mode 100644
--- a/.git/hooks/pre-applypatch.sample
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-#
-# An example hook script to verify what is about to be committed
-# by applypatch from an e-mail message.
-#
-# The hook should exit with non-zero status after issuing an
-# appropriate message if it wants to stop the commit.
-#
-# To enable this hook, rename this file to "pre-applypatch".
-
-. git-sh-setup
-test -x "$GIT_DIR/hooks/pre-commit" &&
-	exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
-:
diff --git a/.git/hooks/pre-commit.sample b/.git/hooks/pre-commit.sample
deleted file mode 100644
--- a/.git/hooks/pre-commit.sample
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-#
-# An example hook script to verify what is about to be committed.
-# Called by "git commit" with no arguments.  The hook should
-# exit with non-zero status after issuing an appropriate message if
-# it wants to stop the commit.
-#
-# To enable this hook, rename this file to "pre-commit".
-
-if git rev-parse --verify HEAD >/dev/null 2>&1
-then
-	against=HEAD
-else
-	# Initial commit: diff against an empty tree object
-	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
-fi
-
-# If you want to allow non-ascii filenames set this variable to true.
-allownonascii=$(git config hooks.allownonascii)
-
-# Redirect output to stderr.
-exec 1>&2
-
-# Cross platform projects tend to avoid non-ascii filenames; prevent
-# them from being added to the repository. We exploit the fact that the
-# printable range starts at the space character and ends with tilde.
-if [ "$allownonascii" != "true" ] &&
-	# Note that the use of brackets around a tr range is ok here, (it's
-	# even required, for portability to Solaris 10's /usr/bin/tr), since
-	# the square bracket bytes happen to fall in the designated range.
-	test $(git diff --cached --name-only --diff-filter=A -z $against |
-	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
-then
-	echo "Error: Attempt to add a non-ascii file name."
-	echo
-	echo "This can cause problems if you want to work"
-	echo "with people on other platforms."
-	echo
-	echo "To be portable it is advisable to rename the file ..."
-	echo
-	echo "If you know what you are doing you can disable this"
-	echo "check using:"
-	echo
-	echo "  git config hooks.allownonascii true"
-	echo
-	exit 1
-fi
-
-# If there are whitespace errors, print the offending file names and fail.
-exec git diff-index --check --cached $against --
diff --git a/.git/hooks/pre-rebase.sample b/.git/hooks/pre-rebase.sample
deleted file mode 100644
--- a/.git/hooks/pre-rebase.sample
+++ /dev/null
@@ -1,169 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2006, 2008 Junio C Hamano
-#
-# The "pre-rebase" hook is run just before "git rebase" starts doing
-# its job, and can prevent the command from running by exiting with
-# non-zero status.
-#
-# The hook is called with the following parameters:
-#
-# $1 -- the upstream the series was forked from.
-# $2 -- the branch being rebased (or empty when rebasing the current branch).
-#
-# This sample shows how to prevent topic branches that are already
-# merged to 'next' branch from getting rebased, because allowing it
-# would result in rebasing already published history.
-
-publish=next
-basebranch="$1"
-if test "$#" = 2
-then
-	topic="refs/heads/$2"
-else
-	topic=`git symbolic-ref HEAD` ||
-	exit 0 ;# we do not interrupt rebasing detached HEAD
-fi
-
-case "$topic" in
-refs/heads/??/*)
-	;;
-*)
-	exit 0 ;# we do not interrupt others.
-	;;
-esac
-
-# Now we are dealing with a topic branch being rebased
-# on top of master.  Is it OK to rebase it?
-
-# Does the topic really exist?
-git show-ref -q "$topic" || {
-	echo >&2 "No such branch $topic"
-	exit 1
-}
-
-# Is topic fully merged to master?
-not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
-if test -z "$not_in_master"
-then
-	echo >&2 "$topic is fully merged to master; better remove it."
-	exit 1 ;# we could allow it, but there is no point.
-fi
-
-# Is topic ever merged to next?  If so you should not be rebasing it.
-only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
-only_next_2=`git rev-list ^master           ${publish} | sort`
-if test "$only_next_1" = "$only_next_2"
-then
-	not_in_topic=`git rev-list "^$topic" master`
-	if test -z "$not_in_topic"
-	then
-		echo >&2 "$topic is already up-to-date with master"
-		exit 1 ;# we could allow it, but there is no point.
-	else
-		exit 0
-	fi
-else
-	not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
-	/usr/bin/perl -e '
-		my $topic = $ARGV[0];
-		my $msg = "* $topic has commits already merged to public branch:\n";
-		my (%not_in_next) = map {
-			/^([0-9a-f]+) /;
-			($1 => 1);
-		} split(/\n/, $ARGV[1]);
-		for my $elem (map {
-				/^([0-9a-f]+) (.*)$/;
-				[$1 => $2];
-			} split(/\n/, $ARGV[2])) {
-			if (!exists $not_in_next{$elem->[0]}) {
-				if ($msg) {
-					print STDERR $msg;
-					undef $msg;
-				}
-				print STDERR " $elem->[1]\n";
-			}
-		}
-	' "$topic" "$not_in_next" "$not_in_master"
-	exit 1
-fi
-
-exit 0
-
-################################################################
-
-This sample hook safeguards topic branches that have been
-published from being rewound.
-
-The workflow assumed here is:
-
- * Once a topic branch forks from "master", "master" is never
-   merged into it again (either directly or indirectly).
-
- * Once a topic branch is fully cooked and merged into "master",
-   it is deleted.  If you need to build on top of it to correct
-   earlier mistakes, a new topic branch is created by forking at
-   the tip of the "master".  This is not strictly necessary, but
-   it makes it easier to keep your history simple.
-
- * Whenever you need to test or publish your changes to topic
-   branches, merge them into "next" branch.
-
-The script, being an example, hardcodes the publish branch name
-to be "next", but it is trivial to make it configurable via
-$GIT_DIR/config mechanism.
-
-With this workflow, you would want to know:
-
-(1) ... if a topic branch has ever been merged to "next".  Young
-    topic branches can have stupid mistakes you would rather
-    clean up before publishing, and things that have not been
-    merged into other branches can be easily rebased without
-    affecting other people.  But once it is published, you would
-    not want to rewind it.
-
-(2) ... if a topic branch has been fully merged to "master".
-    Then you can delete it.  More importantly, you should not
-    build on top of it -- other people may already want to
-    change things related to the topic as patches against your
-    "master", so if you need further changes, it is better to
-    fork the topic (perhaps with the same name) afresh from the
-    tip of "master".
-
-Let's look at this example:
-
-		   o---o---o---o---o---o---o---o---o---o "next"
-		  /       /           /           /
-		 /   a---a---b A     /           /
-		/   /               /           /
-	       /   /   c---c---c---c B         /
-	      /   /   /             \         /
-	     /   /   /   b---b C     \       /
-	    /   /   /   /             \     /
-    ---o---o---o---o---o---o---o---o---o---o---o "master"
-
-
-A, B and C are topic branches.
-
- * A has one fix since it was merged up to "next".
-
- * B has finished.  It has been fully merged up to "master" and "next",
-   and is ready to be deleted.
-
- * C has not merged to "next" at all.
-
-We would want to allow C to be rebased, refuse A, and encourage
-B to be deleted.
-
-To compute (1):
-
-	git rev-list ^master ^topic next
-	git rev-list ^master        next
-
-	if these match, topic has not merged in next at all.
-
-To compute (2):
-
-	git rev-list master..topic
-
-	if this is empty, it is fully merged to "master".
diff --git a/.git/hooks/prepare-commit-msg.sample b/.git/hooks/prepare-commit-msg.sample
deleted file mode 100644
--- a/.git/hooks/prepare-commit-msg.sample
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-#
-# An example hook script to prepare the commit log message.
-# Called by "git commit" with the name of the file that has the
-# commit message, followed by the description of the commit
-# message's source.  The hook's purpose is to edit the commit
-# message file.  If the hook fails with a non-zero status,
-# the commit is aborted.
-#
-# To enable this hook, rename this file to "prepare-commit-msg".
-
-# This hook includes three examples.  The first comments out the
-# "Conflicts:" part of a merge commit.
-#
-# The second includes the output of "git diff --name-status -r"
-# into the message, just before the "git status" output.  It is
-# commented because it doesn't cope with --amend or with squashed
-# commits.
-#
-# The third example adds a Signed-off-by line to the message, that can
-# still be edited.  This is rarely a good idea.
-
-case "$2,$3" in
-  merge,)
-    /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
-
-# ,|template,)
-#   /usr/bin/perl -i.bak -pe '
-#      print "\n" . `git diff --cached --name-status -r`
-#	 if /^#/ && $first++ == 0' "$1" ;;
-
-  *) ;;
-esac
-
-# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
-# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff --git a/.git/hooks/update.sample b/.git/hooks/update.sample
deleted file mode 100644
--- a/.git/hooks/update.sample
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/bin/sh
-#
-# An example hook script to blocks unannotated tags from entering.
-# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
-#
-# To enable this hook, rename this file to "update".
-#
-# Config
-# ------
-# hooks.allowunannotated
-#   This boolean sets whether unannotated tags will be allowed into the
-#   repository.  By default they won't be.
-# hooks.allowdeletetag
-#   This boolean sets whether deleting tags will be allowed in the
-#   repository.  By default they won't be.
-# hooks.allowmodifytag
-#   This boolean sets whether a tag may be modified after creation. By default
-#   it won't be.
-# hooks.allowdeletebranch
-#   This boolean sets whether deleting branches will be allowed in the
-#   repository.  By default they won't be.
-# hooks.denycreatebranch
-#   This boolean sets whether remotely creating branches will be denied
-#   in the repository.  By default this is allowed.
-#
-
-# --- Command line
-refname="$1"
-oldrev="$2"
-newrev="$3"
-
-# --- Safety check
-if [ -z "$GIT_DIR" ]; then
-	echo "Don't run this script from the command line." >&2
-	echo " (if you want, you could supply GIT_DIR then run" >&2
-	echo "  $0 <ref> <oldrev> <newrev>)" >&2
-	exit 1
-fi
-
-if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
-	echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
-	exit 1
-fi
-
-# --- Config
-allowunannotated=$(git config --bool hooks.allowunannotated)
-allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
-denycreatebranch=$(git config --bool hooks.denycreatebranch)
-allowdeletetag=$(git config --bool hooks.allowdeletetag)
-allowmodifytag=$(git config --bool hooks.allowmodifytag)
-
-# check for no description
-projectdesc=$(sed -e '1q' "$GIT_DIR/description")
-case "$projectdesc" in
-"Unnamed repository"* | "")
-	echo "*** Project description file hasn't been set" >&2
-	exit 1
-	;;
-esac
-
-# --- Check types
-# if $newrev is 0000...0000, it's a commit to delete a ref.
-zero="0000000000000000000000000000000000000000"
-if [ "$newrev" = "$zero" ]; then
-	newrev_type=delete
-else
-	newrev_type=$(git cat-file -t $newrev)
-fi
-
-case "$refname","$newrev_type" in
-	refs/tags/*,commit)
-		# un-annotated tag
-		short_refname=${refname##refs/tags/}
-		if [ "$allowunannotated" != "true" ]; then
-			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
-			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
-			exit 1
-		fi
-		;;
-	refs/tags/*,delete)
-		# delete tag
-		if [ "$allowdeletetag" != "true" ]; then
-			echo "*** Deleting a tag is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/tags/*,tag)
-		# annotated tag
-		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
-		then
-			echo "*** Tag '$refname' already exists." >&2
-			echo "*** Modifying a tag is not allowed in this repository." >&2
-			exit 1
-		fi
-		;;
-	refs/heads/*,commit)
-		# branch
-		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
-			echo "*** Creating a branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/heads/*,delete)
-		# delete branch
-		if [ "$allowdeletebranch" != "true" ]; then
-			echo "*** Deleting a branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	refs/remotes/*,commit)
-		# tracking branch
-		;;
-	refs/remotes/*,delete)
-		# delete tracking branch
-		if [ "$allowdeletebranch" != "true" ]; then
-			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
-			exit 1
-		fi
-		;;
-	*)
-		# Anything else (is there anything else?)
-		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
-		exit 1
-		;;
-esac
-
-# --- Finished
-exit 0
diff --git a/.git/index b/.git/index
deleted file mode 100644
Binary files a/.git/index and /dev/null differ
diff --git a/.git/info/exclude b/.git/info/exclude
deleted file mode 100644
--- a/.git/info/exclude
+++ /dev/null
@@ -1,6 +0,0 @@
-# git ls-files --others --exclude-from=.git/info/exclude
-# Lines that start with '#' are comments.
-# For a project mostly in C, the following would be a good set of
-# exclude patterns (uncomment them if you want to use them):
-# *.[oa]
-# *~
diff --git a/.git/logs/HEAD b/.git/logs/HEAD
deleted file mode 100644
--- a/.git/logs/HEAD
+++ /dev/null
@@ -1,4 +0,0 @@
-0000000000000000000000000000000000000000 2353b6eaeee1c824371c12bad78d4053ec52041d George Pollard <porges@porg.es> 1353548294 +1300	clone: from https://github.com/Porges/email-validate-hs.git
-2353b6eaeee1c824371c12bad78d4053ec52041d e890c931c46c7b2a4f53db4edcdfbff25943bfb9 George Pollard <porges@porg.es> 1353548540 +1300	revert: Revert "Allow external use"
-caabd581f6cf7157ce211a91112cf5047e527be7 6eb270b673a8ae8db8e5e2a5e765065933943523 George Pollard <porges@porg.es> 1353548588 +1300	revert: Revert "revert removal of eof marker"
-6eb270b673a8ae8db8e5e2a5e765065933943523 2353b6eaeee1c824371c12bad78d4053ec52041d George Pollard <porges@porg.es> 1353548599 +1300	reset: moving to e890c931c46c7b2a4f53db4edcdfbff25943bfb9^
diff --git a/.git/logs/refs/heads/master b/.git/logs/refs/heads/master
deleted file mode 100644
--- a/.git/logs/refs/heads/master
+++ /dev/null
@@ -1,4 +0,0 @@
-0000000000000000000000000000000000000000 2353b6eaeee1c824371c12bad78d4053ec52041d George Pollard <porges@porg.es> 1353548294 +1300	clone: from https://github.com/Porges/email-validate-hs.git
-2353b6eaeee1c824371c12bad78d4053ec52041d e890c931c46c7b2a4f53db4edcdfbff25943bfb9 George Pollard <porges@porg.es> 1353548540 +1300	revert: Revert "Allow external use"
-caabd581f6cf7157ce211a91112cf5047e527be7 6eb270b673a8ae8db8e5e2a5e765065933943523 George Pollard <porges@porg.es> 1353548588 +1300	revert: Revert "revert removal of eof marker"
-6eb270b673a8ae8db8e5e2a5e765065933943523 2353b6eaeee1c824371c12bad78d4053ec52041d George Pollard <porges@porg.es> 1353548599 +1300	reset: moving to e890c931c46c7b2a4f53db4edcdfbff25943bfb9^
diff --git a/.git/logs/refs/remotes/origin/HEAD b/.git/logs/refs/remotes/origin/HEAD
deleted file mode 100644
--- a/.git/logs/refs/remotes/origin/HEAD
+++ /dev/null
@@ -1,1 +0,0 @@
-0000000000000000000000000000000000000000 2353b6eaeee1c824371c12bad78d4053ec52041d George Pollard <porges@porg.es> 1353548294 +1300	clone: from https://github.com/Porges/email-validate-hs.git
diff --git a/.git/logs/refs/remotes/origin/master b/.git/logs/refs/remotes/origin/master
deleted file mode 100644
--- a/.git/logs/refs/remotes/origin/master
+++ /dev/null
@@ -1,1 +0,0 @@
-2353b6eaeee1c824371c12bad78d4053ec52041d 60436f01329fb1e98b20c972b8f2dff34a605e4f George Pollard <porges@porg.es> 1353548635 +1300	update by push
diff --git a/.git/objects/15/b5b61cf94c1a3f745d249cb27c277506e6b163 b/.git/objects/15/b5b61cf94c1a3f745d249cb27c277506e6b163
deleted file mode 100644
Binary files a/.git/objects/15/b5b61cf94c1a3f745d249cb27c277506e6b163 and /dev/null differ
diff --git a/.git/objects/21/2b997b8e6ea14f49212506a6f24add7af4a497 b/.git/objects/21/2b997b8e6ea14f49212506a6f24add7af4a497
deleted file mode 100644
Binary files a/.git/objects/21/2b997b8e6ea14f49212506a6f24add7af4a497 and /dev/null differ
diff --git a/.git/objects/23/53b6eaeee1c824371c12bad78d4053ec52041d b/.git/objects/23/53b6eaeee1c824371c12bad78d4053ec52041d
deleted file mode 100644
Binary files a/.git/objects/23/53b6eaeee1c824371c12bad78d4053ec52041d and /dev/null differ
diff --git a/.git/objects/24/d18fba10dee5c4ce4aa2af9d83aec2514b3fe8 b/.git/objects/24/d18fba10dee5c4ce4aa2af9d83aec2514b3fe8
deleted file mode 100644
Binary files a/.git/objects/24/d18fba10dee5c4ce4aa2af9d83aec2514b3fe8 and /dev/null differ
diff --git a/.git/objects/2d/9f07a20bc1f037e1729cef6419adb04e31cb6a b/.git/objects/2d/9f07a20bc1f037e1729cef6419adb04e31cb6a
deleted file mode 100644
--- a/.git/objects/2d/9f07a20bc1f037e1729cef6419adb04e31cb6a
+++ /dev/null
@@ -1,2 +0,0 @@
-xRÁjÜ0í5ú9åP"9ñ²MYPºÝBIné]¶&¶@¶FYÈÇw¤µ7ôZ-üf43ï½ioàövýnÔnàíÁA['µ³F'ÏÉúñq­jõQ8ÛâHo÷>¾¬P>YW"?¾owÐSê}<Woèc°÷Îéh÷¿8§ü»³éS>ÒèýAwçæ}JaSUs¼jïª	mLD¢Ódà0Ê'MÁG­Û$ZæÛùx\&ý/IÐqô,-à0vì@PúÀÜ(ÅwÌüúºõª®Aj£iÑñj4uF¦cy
-AI7ÖÙ´/£uL¨ÑlåÙÁ{¸Qä§Ø¢<ÙÄ¡GmÄÅ©|g¸på(ó/ËËß~jTëj_5^Eö¤òEÞ&êxy£NC8V°ÑÀCÔpy	w°¾ #a±º×W¸ç¨ºQï¯ êmÏ¡¼ru©×õ­ôEG®&Ö¢ l/#ÏÊàv¿1¦6CÚpYòl¬Úå=W³(þ,eö
diff --git a/.git/objects/30/795b93e4270a5a2a3df24d1e41b7e10a24614a b/.git/objects/30/795b93e4270a5a2a3df24d1e41b7e10a24614a
deleted file mode 100644
Binary files a/.git/objects/30/795b93e4270a5a2a3df24d1e41b7e10a24614a and /dev/null differ
diff --git a/.git/objects/3c/218af146e571eb4c82060eb761dcdb78d51ce6 b/.git/objects/3c/218af146e571eb4c82060eb761dcdb78d51ce6
deleted file mode 100644
Binary files a/.git/objects/3c/218af146e571eb4c82060eb761dcdb78d51ce6 and /dev/null differ
diff --git a/.git/objects/3c/eee01bed32bce1a61c10fd5f2e1446fa00ce0e b/.git/objects/3c/eee01bed32bce1a61c10fd5f2e1446fa00ce0e
deleted file mode 100644
Binary files a/.git/objects/3c/eee01bed32bce1a61c10fd5f2e1446fa00ce0e and /dev/null differ
diff --git a/.git/objects/3f/7084c8c996d45e41dd9ddcb0d1e03c6d4693f0 b/.git/objects/3f/7084c8c996d45e41dd9ddcb0d1e03c6d4693f0
deleted file mode 100644
--- a/.git/objects/3f/7084c8c996d45e41dd9ddcb0d1e03c6d4693f0
+++ /dev/null
@@ -1,1 +0,0 @@
-x+)JMU0¶d040031QKÌÉLI,IÕË(fÈ®³õ{ßÏ¹à_ÛÌbUÇªfwceï
diff --git a/.git/objects/59/a24bf0dd1195866e5f971ac6d70abdb34a29d3 b/.git/objects/59/a24bf0dd1195866e5f971ac6d70abdb34a29d3
deleted file mode 100644
Binary files a/.git/objects/59/a24bf0dd1195866e5f971ac6d70abdb34a29d3 and /dev/null differ
diff --git a/.git/objects/5b/de0de962274e26328ecffabb4e9f6430a10cc9 b/.git/objects/5b/de0de962274e26328ecffabb4e9f6430a10cc9
deleted file mode 100644
Binary files a/.git/objects/5b/de0de962274e26328ecffabb4e9f6430a10cc9 and /dev/null differ
diff --git a/.git/objects/60/436f01329fb1e98b20c972b8f2dff34a605e4f b/.git/objects/60/436f01329fb1e98b20c972b8f2dff34a605e4f
deleted file mode 100644
Binary files a/.git/objects/60/436f01329fb1e98b20c972b8f2dff34a605e4f and /dev/null differ
diff --git a/.git/objects/6b/7e3d59554eef8f09a0fe8699732541b92536dd b/.git/objects/6b/7e3d59554eef8f09a0fe8699732541b92536dd
deleted file mode 100644
Binary files a/.git/objects/6b/7e3d59554eef8f09a0fe8699732541b92536dd and /dev/null differ
diff --git a/.git/objects/6e/b270b673a8ae8db8e5e2a5e765065933943523 b/.git/objects/6e/b270b673a8ae8db8e5e2a5e765065933943523
deleted file mode 100644
--- a/.git/objects/6e/b270b673a8ae8db8e5e2a5e765065933943523
+++ /dev/null
@@ -1,2 +0,0 @@
-xOKj1ëÚ§xd[óü©¥»nKèÞØr27nÎß¤sÒ	I¹Íó©c~ê
-õSì3¼º+É	²ìGWÌUNYd,!q}É5rYvÌls6F¾û±)½£éè£Mh¡ýõ!·m±¼»àO!%zf7&ÿìøGÔpvÚèÊ¹Ýd¢V	wÌ¢gèÆÏãi¡Õ³ÐÚ÷ç_[óòcv
diff --git a/.git/objects/70/b31b49e6f1ff5ad7b25c262ecbdc1d6fc0e1c4 b/.git/objects/70/b31b49e6f1ff5ad7b25c262ecbdc1d6fc0e1c4
deleted file mode 100644
Binary files a/.git/objects/70/b31b49e6f1ff5ad7b25c262ecbdc1d6fc0e1c4 and /dev/null differ
diff --git a/.git/objects/79/14ad75ef8004bc68244408f494abb69913f35c b/.git/objects/79/14ad75ef8004bc68244408f494abb69913f35c
deleted file mode 100644
Binary files a/.git/objects/79/14ad75ef8004bc68244408f494abb69913f35c and /dev/null differ
diff --git a/.git/objects/79/4e34c8dcac0093b4b669bf4847ce4fd4b1fd4c b/.git/objects/79/4e34c8dcac0093b4b669bf4847ce4fd4b1fd4c
deleted file mode 100644
--- a/.git/objects/79/4e34c8dcac0093b4b669bf4847ce4fd4b1fd4c
+++ /dev/null
@@ -1,1 +0,0 @@
-xRÁjÜ0íY_1§J$g½¤KJ·ÛR(ÍÒ¹KÖÄÈÐÈ!ùøµö^k°ßfæ½7ÆoVÝãÞìµóòE{guFñ\ÎWªV7Â»z¿÷õðm½òÙùùõs»û}Ø	=æ.¤sø!µûà½NVp¿!ósÊ¿a¸S6}t/ºÐcÔí¹ysÜTÕ¯mu"¡­MH´a\=&ù¬)óÑ²	)aEÃ|ÛË¤øÉÑ>qCzÒæ>@9¼e6áÏ÷-\¯ëZX¤&¹ÿ§·2ãÌûPÊÚ8ïò24¾FL®GVÔ3!£ÙÊ³÷w°RÆÔ L¹Ì¡CmÅ´§­ËåÏ¥ÍÌßn4ª	}µ/¶ÌJ/ë";RÓ]Þt:"§Ñ-F,ëh4!ð(5\\À-\_BÔ°°µº·7¸ã¨Z©ôÀæO¡iñêR¯í\M>Ô¢ l¯$ÏÊàv¿1&m¶£GÚpYõÉ^µ¶]Í øI÷
diff --git a/.git/objects/7a/b9d07f7dc5409bfbd9d154fd1e16ec97360c39 b/.git/objects/7a/b9d07f7dc5409bfbd9d154fd1e16ec97360c39
deleted file mode 100644
Binary files a/.git/objects/7a/b9d07f7dc5409bfbd9d154fd1e16ec97360c39 and /dev/null differ
diff --git a/.git/objects/7c/cafa1430896619ca670cc5849ba034b871972b b/.git/objects/7c/cafa1430896619ca670cc5849ba034b871972b
deleted file mode 100644
Binary files a/.git/objects/7c/cafa1430896619ca670cc5849ba034b871972b and /dev/null differ
diff --git a/.git/objects/83/a5e0534a073a57d8bf04c7957cb88be1a3f675 b/.git/objects/83/a5e0534a073a57d8bf04c7957cb88be1a3f675
deleted file mode 100644
Binary files a/.git/objects/83/a5e0534a073a57d8bf04c7957cb88be1a3f675 and /dev/null differ
diff --git a/.git/objects/8c/e32485dfe28fdbee865fe42cb2e9992110d022 b/.git/objects/8c/e32485dfe28fdbee865fe42cb2e9992110d022
deleted file mode 100644
Binary files a/.git/objects/8c/e32485dfe28fdbee865fe42cb2e9992110d022 and /dev/null differ
diff --git a/.git/objects/8d/d5f4f7a7503628bf518fb265434b1017385554 b/.git/objects/8d/d5f4f7a7503628bf518fb265434b1017385554
deleted file mode 100644
Binary files a/.git/objects/8d/d5f4f7a7503628bf518fb265434b1017385554 and /dev/null differ
diff --git a/.git/objects/a3/62c7ee447b16dedc823854165c0178c1d37d12 b/.git/objects/a3/62c7ee447b16dedc823854165c0178c1d37d12
deleted file mode 100644
Binary files a/.git/objects/a3/62c7ee447b16dedc823854165c0178c1d37d12 and /dev/null differ
diff --git a/.git/objects/ab/98b6067c8dea629a6d423255d8f6eca4d9addd b/.git/objects/ab/98b6067c8dea629a6d423255d8f6eca4d9addd
deleted file mode 100644
Binary files a/.git/objects/ab/98b6067c8dea629a6d423255d8f6eca4d9addd and /dev/null differ
diff --git a/.git/objects/ca/abd581f6cf7157ce211a91112cf5047e527be7 b/.git/objects/ca/abd581f6cf7157ce211a91112cf5047e527be7
deleted file mode 100644
Binary files a/.git/objects/ca/abd581f6cf7157ce211a91112cf5047e527be7 and /dev/null differ
diff --git a/.git/objects/ce/21b8e64947926b006ca76fe444f5536c355703 b/.git/objects/ce/21b8e64947926b006ca76fe444f5536c355703
deleted file mode 100644
Binary files a/.git/objects/ce/21b8e64947926b006ca76fe444f5536c355703 and /dev/null differ
diff --git a/.git/objects/d5/3be38fca3a8e4e1a736800e156f0e8be0c0d74 b/.git/objects/d5/3be38fca3a8e4e1a736800e156f0e8be0c0d74
deleted file mode 100644
Binary files a/.git/objects/d5/3be38fca3a8e4e1a736800e156f0e8be0c0d74 and /dev/null differ
diff --git a/.git/objects/dc/d45a039547b065e629b98f3a069216070a4032 b/.git/objects/dc/d45a039547b065e629b98f3a069216070a4032
deleted file mode 100644
Binary files a/.git/objects/dc/d45a039547b065e629b98f3a069216070a4032 and /dev/null differ
diff --git a/.git/objects/e2/b34424ef1cefd7197309a466e1c98bc940215b b/.git/objects/e2/b34424ef1cefd7197309a466e1c98bc940215b
deleted file mode 100644
Binary files a/.git/objects/e2/b34424ef1cefd7197309a466e1c98bc940215b and /dev/null differ
diff --git a/.git/objects/e6/ab6abbd47b7761ca51305e98621f6ed101fd4d b/.git/objects/e6/ab6abbd47b7761ca51305e98621f6ed101fd4d
deleted file mode 100644
Binary files a/.git/objects/e6/ab6abbd47b7761ca51305e98621f6ed101fd4d and /dev/null differ
diff --git a/.git/objects/e8/90c931c46c7b2a4f53db4edcdfbff25943bfb9 b/.git/objects/e8/90c931c46c7b2a4f53db4edcdfbff25943bfb9
deleted file mode 100644
Binary files a/.git/objects/e8/90c931c46c7b2a4f53db4edcdfbff25943bfb9 and /dev/null differ
diff --git a/.git/objects/e8/9c8a1a38fe8ad397e3dcc9b0eeb30bbfb78433 b/.git/objects/e8/9c8a1a38fe8ad397e3dcc9b0eeb30bbfb78433
deleted file mode 100644
Binary files a/.git/objects/e8/9c8a1a38fe8ad397e3dcc9b0eeb30bbfb78433 and /dev/null differ
diff --git a/.git/objects/f4/d0360b79923043eee16f821b2073b866c56fec b/.git/objects/f4/d0360b79923043eee16f821b2073b866c56fec
deleted file mode 100644
Binary files a/.git/objects/f4/d0360b79923043eee16f821b2073b866c56fec and /dev/null differ
diff --git a/.git/packed-refs b/.git/packed-refs
deleted file mode 100644
--- a/.git/packed-refs
+++ /dev/null
@@ -1,2 +0,0 @@
-# pack-refs with: peeled 
-2353b6eaeee1c824371c12bad78d4053ec52041d refs/remotes/origin/master
diff --git a/.git/refs/heads/master b/.git/refs/heads/master
deleted file mode 100644
--- a/.git/refs/heads/master
+++ /dev/null
@@ -1,1 +0,0 @@
-60436f01329fb1e98b20c972b8f2dff34a605e4f
diff --git a/.git/refs/remotes/origin/HEAD b/.git/refs/remotes/origin/HEAD
deleted file mode 100644
--- a/.git/refs/remotes/origin/HEAD
+++ /dev/null
@@ -1,1 +0,0 @@
-ref: refs/remotes/origin/master
diff --git a/.git/refs/remotes/origin/master b/.git/refs/remotes/origin/master
deleted file mode 100644
--- a/.git/refs/remotes/origin/master
+++ /dev/null
@@ -1,1 +0,0 @@
-60436f01329fb1e98b20c972b8f2dff34a605e4f
diff --git a/Text/Email/Validate.hs b/Text/Email/Validate.hs
deleted file mode 100644
--- a/Text/Email/Validate.hs
+++ /dev/null
@@ -1,324 +0,0 @@
-{-# LANGUAGE CPP #-}
-module Text.Email.Validate (addrSpec,isValid,validate,EmailAddress(..))
-where
-
-import Control.Arrow ((***))
-import qualified Data.Ranges as Range
-import Data.Char (chr)
-
-#if MIN_VERSION_parsec(3,0,0)
-import Text.Parsec
-import Text.Parsec.Char
-#else 
-import Text.ParserCombinators.Parsec
-#endif
-
--- | Constructor does no checking for invalid emails, so use at own risk.
-data EmailAddress = EmailAddress
-	{
-		localPart :: String,
-		domainPart :: String
-	}
-
-instance Show EmailAddress where
-	show (EmailAddress l d) = l ++ ('@' : d)
-
--- | Validates whether a particular string is an email address
---   according to RFC5322.
-isValid :: String -> Bool
-isValid x = let result = validate x in
-	either (const False) (const True) result
-
-simply = (>> return ())
-
--- | If you want to find out why a particular string is not
---   an email address, use this!
-validate :: String -> Either ParseError EmailAddress
-validate x = case parse addrSpec "" x of
-	Right n -> Right $ EmailAddress local domain
-		where (local,at:domain) = splitAt (length x - n) x
-	Left e -> Left e
-
-#if MIN_VERSION_parsec(3,0,0)
-addrSpec :: Parsec String () Int
-#else
-addrSpec :: CharParser () Int
-#endif
-addrSpec = do
-	localPartParser
-	s1 <- getInput
-	char '@'
-	domain
-	eof
-	return (length s1)
-
-localPartParser = dottedAtoms
-domain = dottedAtoms <|> domainLiteral 
-
-dottedAtoms = simply $ (optional cfws >> (atom <|> quotedString) >> optional cfws)
-	`sepBy1` (char '.')
-atom = simply $ many1 atomText
-atomText = simply $ alphaNum <|> oneOf "!#$%&'*+-/=?^_`{|}~"
-
-domainLiteral =  between (optional cfws >> char '[') (char ']' >> optional cfws) $
-	many (optional fws >> domainText) >> optional fws
-domainText = ranges [(33,90),(94,126)] <|> obsNoWsCtl
-
-
-quotedString = between (char '"') (char '"') $
-	many (optional fws >> quotedContent) >> optional fws
-quotedContent = quotedText <|> quotedPair
-quotedText = ranges [(33,33),(35,91),(93,126)] <|> obsNoWsCtl
-quotedPair = char '\\' >> (vchar <|> wsp <|> lf <|> cr <|> obsNoWsCtl <|> nullChar)
-
-fws = (many1 wsp >> optional (crlf >> many1 wsp))
-	<|> (many1 (crlf >> many1 wsp) >> return ())
-
-cfws = simply $ many (comment <|> fws)
-comment = simply $ between (char '(') (char ')') $
-	many (commentContent <|> fws)
-
-commentContent = commentText <|> quotedPair <|> comment
-commentText = ranges [(33,39),(42,91),(93,126)] <|> obsNoWsCtl
-
-nullChar = simply $ char '\0'
-wsp = simply $ oneOf " \t"
-cr = simply $ char '\r'
-lf = simply $ char '\n'
-crlf = simply $ cr >> lf
-vchar = ranges [(0x21,0x7e)]
-obsNoWsCtl = ranges [(1,8),(11,12),(14,31),(127,127)]
-ranges xs = simply $ satisfy (\c -> Range.inRanges c $ Range.ranges $ map (uncurry Range.range . (chr***chr)) $ xs)
-
-unitTest (x, y, z) = if isValid x == y then "" else (x ++": Should be "++show y ++", got "++show (not y)++"\n\t"++z++"\n")
-
-doSomeTests = do
-	putStr$unitTest("first.last@example.com", True, "")
-	putStr$unitTest("1234567890123456789012345678901234567890123456789012345678901234@example.com", True, "")
-	putStr$unitTest("\"first last\"@example.com", True, "")
-	putStr$unitTest("\"first\\\"last\"@example.com", True, "")
-	putStr$unitTest("first\\@last@example.com", False, "Escaping can only happen within a quoted string")
-	putStr$unitTest("\"first@last\"@example.com", True, "")
-	putStr$unitTest("\"first\\\\last\"@example.com", True, "")
-	putStr$unitTest("x@x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x234", True, "")
-	putStr$unitTest("123456789012345678901234567890123456789012345678901234567890@12345678901234567890123456789012345678901234567890123456789.12345678901234567890123456789012345678901234567890123456789.123456789012345678901234567890123456789012345678901234567890123.example.com", True, "")
-	putStr$unitTest("first.last@[12.34.56.78]", True, "")
-	putStr$unitTest("first.last@[IPv6:::12.34.56.78]", True, "")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333::4444:12.34.56.78]", True, "")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333:4444:5555:6666:12.34.56.78]", True, "")
-	putStr$unitTest("first.last@[IPv6:::1111:2222:3333:4444:5555:6666]", True, "")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333::4444:5555:6666]", True, "")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333:4444:5555:6666::]", True, "")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]", True, "")
-	putStr$unitTest("first.last@x23456789012345678901234567890123456789012345678901234567890123.example.com", True, "")
-	putStr$unitTest("first.last@1xample.com", True, "")
-	putStr$unitTest("first.last@123.example.com", True, "")
-	putStr$unitTest("123456789012345678901234567890123456789012345678901234567890@12345678901234567890123456789012345678901234567890123456789.12345678901234567890123456789012345678901234567890123456789.12345678901234567890123456789012345678901234567890123456789.1234.example.com", False, "Entire address is longer than 256 characters")
-	putStr$unitTest("first.last", False, "No @")
-	putStr$unitTest("12345678901234567890123456789012345678901234567890123456789012345@example.com", False, "Local part more than 64 characters")
-	putStr$unitTest(".first.last@example.com", False, "Local part starts with a dot")
-	putStr$unitTest("first.last.@example.com", False, "Local part ends with a dot")
-	putStr$unitTest("first..last@example.com", False, "Local part has consecutive dots")
-	putStr$unitTest("\"first\"last\"@example.com", False, "Local part contains unescaped excluded characters")
-	putStr$unitTest("\"first\\last\"@example.com", True, "Any character can be escaped in a quoted string")
-	putStr$unitTest("\"\"\"@example.com", False, "Local part contains unescaped excluded characters")
-	putStr$unitTest("\"\\\"@example.com", False, "Local part cannot end with a backslash")
-	putStr$unitTest("\"\"@example.com", False, "Local part is effectively empty")
-	putStr$unitTest("first\\\\@last@example.com", False, "Local part contains unescaped excluded characters")
-	putStr$unitTest("first.last@", False, "No domain")
-	putStr$unitTest("x@x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456", False, "Domain exceeds 255 chars")
-	putStr$unitTest("first.last@[.12.34.56.78]", False, "Only char that can precede IPv4 address is \':\'")
-	putStr$unitTest("first.last@[12.34.56.789]", False, "Can\'t be interpreted as IPv4 so IPv6 tag is missing")
-	putStr$unitTest("first.last@[::12.34.56.78]", False, "IPv6 tag is missing")
-	putStr$unitTest("first.last@[IPv5:::12.34.56.78]", False, "IPv6 tag is wrong")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333::4444:5555:12.34.56.78]", False, "Too many IPv6 groups (4 max)")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333:4444:5555:12.34.56.78]", False, "Not enough IPv6 groups")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:12.34.56.78]", False, "Too many IPv6 groups (6 max)")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777]", False, "Not enough IPv6 groups")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]", False, "Too many IPv6 groups (8 max)")
-	putStr$unitTest("first.last@[IPv6:1111:2222::3333::4444:5555:6666]", False, "Too many \'::\' (can be none or one)")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333::4444:5555:6666:7777]", False, "Too many IPv6 groups (6 max)")
-	putStr$unitTest("first.last@[IPv6:1111:2222:333x::4444:5555]", False, "x is not valid in an IPv6 address")
-	putStr$unitTest("first.last@[IPv6:1111:2222:33333::4444:5555]", False, "33333 is not a valid group in an IPv6 address")
-	putStr$unitTest("first.last@example.123", False, "TLD can\'t be all digits")
-	putStr$unitTest("first.last@com", False, "Mail host must be second- or lower level")
-	putStr$unitTest("first.last@-xample.com", False, "Label can\'t begin with a hyphen")
-	putStr$unitTest("first.last@exampl-.com", False, "Label can\'t end with a hyphen")
-	putStr$unitTest("first.last@x234567890123456789012345678901234567890123456789012345678901234.example.com", False, "Label can\'t be longer than 63 octets")
-	putStr$unitTest("\"Abc\\@def\"@example.com", True, "")
-	putStr$unitTest("\"Fred\\ Bloggs\"@example.com", True, "")
-	putStr$unitTest("\"Joe.\\\\Blow\"@example.com", True, "")
-	putStr$unitTest("\"Abc@def\"@example.com", True, "")
-	putStr$unitTest("\"Fred Bloggs\"@example.com", True, "")
-	putStr$unitTest("user+mailbox@example.com", True, "")
-	putStr$unitTest("customer/department=shipping@example.com", True, "")
-	putStr$unitTest("$A12345@example.com", True, "")
-	putStr$unitTest("!def!xyz%abc@example.com", True, "")
-	putStr$unitTest("_somename@example.com", True, "")
-	putStr$unitTest("dclo@us.ibm.com", True, "")
-	putStr$unitTest("abc\\@def@example.com", False, "This example from RFC3696 was corrected in an erratum")
-	putStr$unitTest("abc\\\\@example.com", False, "This example from RFC3696 was corrected in an erratum")
-	putStr$unitTest("peter.piper@example.com", True, "")
-	putStr$unitTest("Doug\\ \\\"Ace\\\"\\ Lovell@example.com", False, "Escaping can only happen in a quoted string")
-	putStr$unitTest("\"Doug \\\"Ace\\\" L.\"@example.com", True, "")
-	putStr$unitTest("abc@def@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("abc\\\\@def@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("abc\\@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("@example.com", False, "No local part")
-	putStr$unitTest("doug@", False, "Doug Lovell says this should fail")
-	putStr$unitTest("\"qu@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("ote\"@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest(".dot@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("dot.@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("two..dot@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("\"Doug \"Ace\" L.\"@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("Doug\\ \\\"Ace\\\"\\ L\\.@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("hello world@example.com", False, "Doug Lovell says this should fail")
-	putStr$unitTest("gatsby@f.sc.ot.t.f.i.tzg.era.l.d.", False, "Doug Lovell says this should fail")
-	putStr$unitTest("test@example.com", True, "")
-	putStr$unitTest("TEST@example.com", True, "")
-	putStr$unitTest("1234567890@example.com", True, "")
-	putStr$unitTest("test+test@example.com", True, "")
-	putStr$unitTest("test-test@example.com", True, "")
-	putStr$unitTest("t*est@example.com", True, "")
-	putStr$unitTest("+1~1+@example.com", True, "")
-	putStr$unitTest("{_test_}@example.com", True, "")
-	putStr$unitTest("\"[[ test ]]\"@example.com", True, "")
-	putStr$unitTest("test.test@example.com", True, "")
-	putStr$unitTest("\"test.test\"@example.com", True, "")
-	putStr$unitTest("test.\"test\"@example.com", True, "Obsolete form, but documented in RFC2822")
-	putStr$unitTest("\"test@test\"@example.com", True, "")
-	putStr$unitTest("test@123.123.123.x123", True, "")
-	putStr$unitTest("test@123.123.123.123", False, "Top Level Domain won\'t be all-numeric (see RFC3696 Section 2). I disagree with Dave Child on this one.")
-	putStr$unitTest("test@[123.123.123.123]", True, "")
-	putStr$unitTest("test@example.example.com", True, "")
-	putStr$unitTest("test@example.example.example.com", True, "")
-	putStr$unitTest("test.example.com", False, "")
-	putStr$unitTest("test.@example.com", False, "")
-	putStr$unitTest("test..test@example.com", False, "")
-	putStr$unitTest(".test@example.com", False, "")
-	putStr$unitTest("test@test@example.com", False, "")
-	putStr$unitTest("test@@example.com", False, "")
-	putStr$unitTest("-- test --@example.com", False, "No spaces allowed in local part")
-	putStr$unitTest("[test]@example.com", False, "Square brackets only allowed within quotes")
-	putStr$unitTest("\"test\\test\"@example.com", True, "Any character can be escaped in a quoted string")
-	putStr$unitTest("\"test\"test\"@example.com", False, "Quotes cannot be nested")
-	putStr$unitTest("()[]\\;:,><@example.com", False, "Disallowed Characters")
-	putStr$unitTest("test@.", False, "Dave Child says so")
-	putStr$unitTest("test@example.", False, "Dave Child says so")
-	putStr$unitTest("test@.org", False, "Dave Child says so")
-	putStr$unitTest("test@123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012.com", False, "255 characters is maximum length for domain. This is 256.")
-	putStr$unitTest("test@example", False, "Dave Child says so")
-	putStr$unitTest("test@[123.123.123.123", False, "Dave Child says so")
-	putStr$unitTest("test@123.123.123.123]", False, "Dave Child says so")
-	putStr$unitTest("NotAnEmail", False, "Phil Haack says so")
-	putStr$unitTest("@NotAnEmail", False, "Phil Haack says so")
-	putStr$unitTest("\"test\\\\blah\"@example.com", True, "")
-	putStr$unitTest("\"test\\blah\"@example.com", True, "Any character can be escaped in a quoted string")
-	putStr$unitTest("\"test\\\rblah\"@example.com", True, "Quoted string specifically excludes carriage returns unless escaped")
-	putStr$unitTest("\"test\rblah\"@example.com", False, "Quoted string specifically excludes carriage returns")
-	putStr$unitTest("\"test\\\"blah\"@example.com", True, "")
-	putStr$unitTest("\"test\"blah\"@example.com", False, "Phil Haack says so")
-	putStr$unitTest("customer/department@example.com", True, "")
-	putStr$unitTest("_Yosemite.Sam@example.com", True, "")
-	putStr$unitTest("~@example.com", True, "")
-	putStr$unitTest(".wooly@example.com", False, "Phil Haack says so")
-	putStr$unitTest("wo..oly@example.com", False, "Phil Haack says so")
-	putStr$unitTest("pootietang.@example.com", False, "Phil Haack says so")
-	putStr$unitTest(".@example.com", False, "Phil Haack says so")
-	putStr$unitTest("\"Austin@Powers\"@example.com", True, "")
-	putStr$unitTest("Ima.Fool@example.com", True, "")
-	putStr$unitTest("\"Ima.Fool\"@example.com", True, "")
-	putStr$unitTest("\"Ima Fool\"@example.com", True, "")
-	putStr$unitTest("Ima Fool@example.com", False, "Phil Haack says so")
-	putStr$unitTest("phil.h\\@\\@ck@haacked.com", False, "Escaping can only happen in a quoted string")
-	putStr$unitTest("\"first\".\"last\"@example.com", True, "")
-	putStr$unitTest("\"first\".middle.\"last\"@example.com", True, "")
-	putStr$unitTest("\"first\\\\\"last\"@example.com", False, "Contains an unescaped quote")
-	putStr$unitTest("\"first\".last@example.com", True, "obs-local-part form as described in RFC 2822")
-	putStr$unitTest("first.\"last\"@example.com", True, "obs-local-part form as described in RFC 2822")
-	putStr$unitTest("\"first\".\"middle\".\"last\"@example.com", True, "obs-local-part form as described in RFC 2822")
-	putStr$unitTest("\"first.middle\".\"last\"@example.com", True, "obs-local-part form as described in RFC 2822")
-	putStr$unitTest("\"first.middle.last\"@example.com", True, "obs-local-part form as described in RFC 2822")
-	putStr$unitTest("\"first..last\"@example.com", True, "obs-local-part form as described in RFC 2822")
-	putStr$unitTest("foo@[\\1.2.3.4]", False, "RFC 5321 specifies the syntax for address-literal and does not allow escaping")
-	putStr$unitTest("\"first\\\\\\\"last\"@example.com", True, "")
-	putStr$unitTest("first.\"mid\\dle\".\"last\"@example.com", True, "Backslash can escape anything but must escape something")
-	putStr$unitTest("Test.\r\n Folding.\r\n Whitespace@example.com", True, "")
-	putStr$unitTest("first.\"\".last@example.com", False, "Contains a zero-length element")
-	putStr$unitTest("first\\last@example.com", False, "Unquoted string must be an atom")
-	putStr$unitTest("Abc\\@def@example.com", False, "Was incorrectly given as a valid address in the original RFC3696")
-	putStr$unitTest("Fred\\ Bloggs@example.com", False, "Was incorrectly given as a valid address in the original RFC3696")
-	putStr$unitTest("Joe.\\\\Blow@example.com", False, "Was incorrectly given as a valid address in the original RFC3696")
-	putStr$unitTest("first.last@[IPv6:1111:2222:3333:4444:5555:6666:12.34.567.89]", False, "IPv4 part contains an invalid octet")
-	putStr$unitTest("\"test\\\r\n blah\"@example.com", False, "Folding white space can\'t appear within a quoted pair")
-	putStr$unitTest("\"test\r\n blah\"@example.com", True, "This is a valid quoted string with folding white space")
-	putStr$unitTest("{^c\\@**Dog^}@cartoon.com", False, "This is a throwaway example from Doug Lovell\'s article. Actually it\'s not a valid address.")
-	putStr$unitTest("(foo)cal(bar)@(baz)iamcal.com(quux)", True, "A valid address containing comments")
-	putStr$unitTest("cal@iamcal(woo).(yay)com", True, "A valid address containing comments")
-	putStr$unitTest("\"foo\"(yay)@(hoopla)[1.2.3.4]", False, "Address literal can\'t be commented (RFC5321)")
-	putStr$unitTest("cal(woo(yay)hoopla)@iamcal.com", True, "A valid address containing comments")
-	putStr$unitTest("cal(foo\\@bar)@iamcal.com", True, "A valid address containing comments")
-	putStr$unitTest("cal(foo\\)bar)@iamcal.com", True, "A valid address containing comments and an escaped parenthesis")
-	putStr$unitTest("cal(foo(bar)@iamcal.com", False, "Unclosed parenthesis in comment")
-	putStr$unitTest("cal(foo)bar)@iamcal.com", False, "Too many closing parentheses")
-	putStr$unitTest("cal(foo\\)@iamcal.com", False, "Backslash at end of comment has nothing to escape")
-	putStr$unitTest("first().last@example.com", True, "A valid address containing an empty comment")
-	putStr$unitTest("first.(\r\n middle\r\n )last@example.com", True, "Comment with folding white space")
-	putStr$unitTest("first(12345678901234567890123456789012345678901234567890)last@(1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890)example.com", False, "Too long with comments, not too long without")
-	putStr$unitTest("first(Welcome to\r\n the (\"wonderful\" (!)) world\r\n of email)@example.com", True, "Silly example from my blog post")
-	putStr$unitTest("pete(his account)@silly.test(his host)", True, "Canonical example from RFC5322")
-	putStr$unitTest("c@(Chris\'s host.)public.example", True, "Canonical example from RFC5322")
-	putStr$unitTest("jdoe@machine(comment).  example", True, "Canonical example from RFC5322")
-	putStr$unitTest("1234   @   local(blah)  .machine .example", True, "Canonical example from RFC5322")
-	putStr$unitTest("first(middle)last@example.com", False, "Can\'t have a comment or white space except at an element boundary")
-	putStr$unitTest("first(abc.def).last@example.com", True, "Comment can contain a dot")
-	putStr$unitTest("first(a\"bc.def).last@example.com", True, "Comment can contain double quote")
-	putStr$unitTest("first.(\")middle.last(\")@example.com", True, "Comment can contain a quote")
-	putStr$unitTest("first(abc(\"def\".ghi).mno)middle(abc(\"def\".ghi).mno).last@(abc(\"def\".ghi).mno)example(abc(\"def\".ghi).mno).(abc(\"def\".ghi).mno)com(abc(\"def\".ghi).mno)", False, "Can\'t have comments or white space except at an element boundary")
-	putStr$unitTest("first(abc\\(def)@example.com", True, "Comment can contain quoted-pair")
-	putStr$unitTest("first.last@x(1234567890123456789012345678901234567890123456789012345678901234567890).com", True, "Label is longer than 63 octets, but not with comment removed")
-	putStr$unitTest("a(a(b(c)d(e(f))g)h(i)j)@example.com", True, "")
-	putStr$unitTest("a(a(b(c)d(e(f))g)(h(i)j)@example.com", False, "Braces are not properly matched")
-	putStr$unitTest("name.lastname@domain.com", True, "")
-	putStr$unitTest(".@", False, "")
-	putStr$unitTest("a@b", False, "")
-	putStr$unitTest("@bar.com", False, "")
-	putStr$unitTest("@@bar.com", False, "")
-	putStr$unitTest("a@bar.com", True, "")
-	putStr$unitTest("aaa.com", False, "")
-	putStr$unitTest("aaa@.com", False, "")
-	putStr$unitTest("aaa@.123", False, "")
-	putStr$unitTest("aaa@[123.123.123.123]", True, "")
-	putStr$unitTest("aaa@[123.123.123.123]a", False, "extra data outside ip")
-	putStr$unitTest("aaa@[123.123.123.333]", False, "not a valid IP")
-	putStr$unitTest("a@bar.com.", False, "")
-	putStr$unitTest("a@bar", False, "")
-	putStr$unitTest("a-b@bar.com", True, "")
-	putStr$unitTest("+@b.c", True, "TLDs can be any length")
-	putStr$unitTest("+@b.com", True, "")
-	putStr$unitTest("a@-b.com", False, "")
-	putStr$unitTest("a@b-.com", False, "")
-	putStr$unitTest("-@..com", False, "")
-	putStr$unitTest("-@a..com", False, "")
-	putStr$unitTest("a@b.co-foo.uk", True, "")
-	putStr$unitTest("\"hello my name is\"@stutter.com", True, "")
-	putStr$unitTest("\"Test \\\"Fail\\\" Ing\"@example.com", True, "")
-	putStr$unitTest("valid@special.museum", True, "")
-	putStr$unitTest("invalid@special.museum-", False, "")
-	putStr$unitTest("shaitan@my-domain.thisisminekthx", True, "Disagree with Paul Gregg here")
-	putStr$unitTest("test@...........com", False, "......")
-	putStr$unitTest("foobar@192.168.0.1", False, "ip need to be []")
-	putStr$unitTest("\"Joe\\\\Blow\"@example.com", True, "")
-	putStr$unitTest("Invalid \\\n Folding \\\n Whitespace@example.com", False, "This isn\'t FWS so Dominic Sayers says it\'s invalid")
-	putStr$unitTest("HM2Kinsists@(that comments are allowed)this.is.ok", True, "")
-	putStr$unitTest("user%uucp!path@somehost.edu", True, "")
-	putStr$unitTest("\"first(last)\"@example.com", True, "")
-	putStr$unitTest(" \r\n (\r\n x \r\n ) \r\n first\r\n ( \r\n x\r\n ) \r\n .\r\n ( \r\n x) \r\n last \r\n (  x \r\n ) \r\n @example.com", True, "")
-	putStr$unitTest("test.\r\n \r\n obs@syntax.com", True, "obs-fws allows multiple lines")
-	putStr$unitTest("test. \r\n \r\n obs@syntax.com", True, "obs-fws allows multiple lines (test 2: space before break)")
-	putStr$unitTest("test.\r\n\r\n obs@syntax.com", False, "obs-fws must have at least one WSP per line")
-	putStr$unitTest("\"null \\\0\"@char.com", True, "can have escaped null character")
-	putStr$unitTest("\"null \0\"@char.com", False, "cannot have unescaped null character")
-	
-
diff --git a/email-validate.cabal b/email-validate.cabal
--- a/email-validate.cabal
+++ b/email-validate.cabal
@@ -1,5 +1,5 @@
 name:           email-validate
-version:        0.3.2
+version:        1.0.0
 license:        BSD3
 license-file:   LICENSE
 author:         George Pollard
@@ -10,17 +10,31 @@
 description:    Validating an email address string against RFC 5322
 build-type:     Simple
 stability:      experimental
-cabal-version:  >= 1.6
-
+cabal-version:  >= 1.8
 
 source-repository head
     type: git
     location: git://github.com/Porges/email-validate-hs.git
 
 library
-    build-depends: base >= 2 && < 5, parsec >= 3.0 || == 2.1.*, ranges >= 0.2.2
+    build-depends: base >= 4 && < 5, attoparsec >= 0.10.0, bytestring >= 0.9
     ghc-options: -O2
-
-    extensions: CPP
+    hs-source-dirs: src
     exposed-modules:
-            Text.Email.Validate
+            Text.Email.Validate, Text.Email.Parser
+
+Test-Suite Main
+    type: exitcode-stdio-1.0
+    main-is: Main.hs
+    hs-source-dirs: tests
+    test-module Test.Text.Email.Validate
+    x-uses-tf: true
+    build-depends:
+        base >= 4 && < 5,
+        HUnit >= 1.2 && < 2,
+        email-validate,
+        QuickCheck >= 2.4,
+        test-framework >= 0.4.1,
+        test-framework-quickcheck2,
+        test-framework-hunit,
+        bytestring >= 0.9
diff --git a/src/Text/Email/Parser.hs b/src/Text/Email/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Email/Parser.hs
@@ -0,0 +1,100 @@
+module Text.Email.Parser
+	(addrSpec
+	,localPart
+	,domainPart
+	,EmailAddress
+	,toByteString)
+where
+
+import Control.Applicative
+
+import qualified Data.ByteString.Char8 as BS
+import Data.ByteString (ByteString)
+
+import Data.Char (chr)
+import Data.Attoparsec.ByteString.Char8
+import Data.Attoparsec.Combinator
+
+-- | Represents an email address.
+data EmailAddress = EmailAddress ByteString ByteString deriving (Eq,Ord)
+
+instance Show EmailAddress where
+	show = BS.unpack . toByteString
+
+-- | Converts an email address back to a ByteString
+toByteString (EmailAddress l d) = BS.concat [l, BS.singleton '@', d]
+
+-- | Extracts the local part of an email address. 
+localPart :: EmailAddress -> ByteString
+localPart (EmailAddress local _) = local
+
+-- | Extracts the domain part of an email address.
+domainPart :: EmailAddress -> ByteString
+domainPart (EmailAddress _ domain) = domain
+
+-- | A parser for email addresses.
+addrSpec = do
+	localPart <- local
+	char '@'
+	domainPart <- domain
+	endOfInput
+	return (EmailAddress localPart domainPart)
+
+local = dottedAtoms
+domain = dottedAtoms <|> domainLiteral 
+
+dottedAtoms = BS.intercalate (BS.singleton '.') <$> 
+	(optional cfws *> (atom <|> quotedString) <* optional cfws)	`sepBy1` (char '.')
+atom = takeWhile1 isAtomText
+
+isAtomText x = isAlphaNum x || inClass "!#$%&'*+/=?^_`{|}~-" x 
+
+domainLiteral = (BS.cons '[' . flip BS.snoc ']' . BS.concat) <$> (between (optional cfws *> char '[') (char ']' <* optional cfws) $
+	many (optional fws >> takeWhile1 isDomainText) <* optional fws)
+isDomainText x = inClass "\33-\90\94-\126" x || isObsNoWsCtl x
+
+quotedString = (\x -> BS.concat $ [BS.singleton '"', BS.concat x, BS.singleton '"']) <$> (between (char '"') (char '"') $
+	many (optional fws >> quotedContent) <* optional fws)
+
+quotedContent = takeWhile1 isQuotedText <|> quotedPair
+isQuotedText x = inClass "\33\35-\91\93-\126" x || isObsNoWsCtl x
+
+quotedPair = (BS.cons '\\' . BS.singleton) <$> (char '\\' *> (vchar <|> wsp <|> lf <|> cr <|> obsNoWsCtl <|> nullChar))
+
+cfws = ignore $ many (comment <|> fws) 
+
+fws :: Parser ()
+fws = ignore $
+	ignore (wsp1 >> optional (crlf >> wsp1))
+	<|> ignore (many1 (crlf >> wsp1))
+
+ignore :: Parser a -> Parser ()
+ignore x = x >> return ()
+
+between l r x = l *> x <* r
+
+comment :: Parser ()
+comment = ignore ((between (char '(') (char ')') $
+	many (ignore commentContent <|> fws)))
+
+commentContent = skipWhile1 isCommentText <|> ignore quotedPair <|> comment
+isCommentText x = inClass "\33-\39\42-\91\93-\126" x || isObsNoWsCtl x
+
+nullChar = char '\0'
+
+skipWhile1 x = satisfy x >> skipWhile x
+
+wsp1 = skipWhile1 isWsp
+wsp = satisfy isWsp
+isWsp x = x == ' ' || x == '\t'
+
+isAlphaNum x = isDigit x || isAlpha_ascii x
+cr = char '\r'
+lf = char '\n'
+crlf = cr >> lf >> return ()
+
+isVchar = inClass "\x21-\x7e"
+vchar = satisfy isVchar
+
+isObsNoWsCtl = inClass "\1-\8\11-\12\14-\31\127"
+obsNoWsCtl = satisfy isObsNoWsCtl
diff --git a/src/Text/Email/Validate.hs b/src/Text/Email/Validate.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Email/Validate.hs
@@ -0,0 +1,39 @@
+module Text.Email.Validate
+	(isValid
+	,validate
+	,emailAddress
+	,canonicalizeEmail 
+	,EmailAddress -- re-exported
+	,localPart
+	,domainPart
+	,toByteString) 
+where
+
+import qualified Data.ByteString.Char8 as BS
+import Data.ByteString (ByteString)
+import Data.Attoparsec (parseOnly)
+
+import Text.Email.Parser
+
+-- | Smart constructor for an email address
+emailAddress :: ByteString -> Maybe EmailAddress
+emailAddress x =
+	case validate x of
+		Left _  -> Nothing
+		Right em -> Just em
+
+-- | Checks that an email is valid and returns a version of it
+--   where comments and whitespace have been removed.
+canonicalizeEmail :: ByteString -> Maybe ByteString
+canonicalizeEmail = fmap toByteString . emailAddress
+
+-- | Validates whether a particular string is an email address
+--   according to RFC5322.
+isValid :: ByteString -> Bool
+isValid x = let result = validate x in
+	either (const False) (const True) result
+
+-- | If you want to find out *why* a particular string is not
+--   an email address, use this.
+validate :: ByteString -> Either String EmailAddress
+validate = parseOnly addrSpec
diff --git a/tests/Main.hs b/tests/Main.hs
new file mode 100644
--- /dev/null
+++ b/tests/Main.hs
@@ -0,0 +1,281 @@
+module Main where
+
+import Data.Maybe (catMaybes)
+import Text.Email.Validate
+import Test.HUnit
+
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Char8 as BS
+
+import Test.Framework as TF (defaultMain, testGroup, Test)
+import Test.Framework.Providers.HUnit
+import Test.Framework.Providers.QuickCheck2 (testProperty)
+
+import Test.QuickCheck
+
+main :: IO ()
+main = defaultMain tests
+
+tests :: [TF.Test]
+tests = [
+        testGroup "QuickCheck Text.Email.Validate" [
+                testProperty "doubleCanonicalize" prop_doubleCanonicalize
+                ],
+        testGroup "Unit tests Text.Email.Validate" $ flip concatMap units 
+            (\(em, valid, why) -> let email = BS.pack em
+                in 
+                    [
+                    testCase ("doubleCanonicalize '" ++ em ++ "'") (True @=? case emailAddress email of { Nothing -> True; Just ok -> prop_doubleCanonicalize ok }),
+                    testCase ("validity test '" ++ em ++ "'") (valid @=? isValid email)
+                    ])
+       ]
+
+instance Arbitrary ByteString where
+    arbitrary = fmap BS.pack arbitrary
+
+instance Arbitrary EmailAddress where
+    arbitrary = do
+        local <- suchThat arbitrary (\x -> isEmail x (BS.pack "example.com"))
+        domain <- suchThat arbitrary (\x -> isEmail (BS.pack "example") x)
+        let email = makeEmailLike local domain
+        let (Just result) = emailAddress email
+        return result
+
+isEmail l d = isValid (makeEmailLike l d)
+
+makeEmailLike l d = BS.concat [l, BS.singleton '@', d]
+
+prop_doubleCanonicalize email =  Just email == emailAddress (toByteString email)
+
+--unitTest (x, y, z) = if not (isValid (BS.pack x) == y) then "" else (x ++" became "++ (case emailAddress (BS.pack x) of {Nothing -> "fail"; Just em -> show em}) ++": Should be "++show y ++", got "++show (not y)++"\n\t"++z++"\n")
+
+units = [
+    ("first.last@example.com", True, ""),
+    ("1234567890123456789012345678901234567890123456789012345678901234@example.com", True, ""),
+    ("\"first last\"@example.com", True, ""),
+    ("\"first\\\"last\"@example.com", True, ""),
+    ("first\\@last@example.com", False, "Escaping can only happen within a quoted string"),
+    ("\"first@last\"@example.com", True, ""),
+    ("\"first\\\\last\"@example.com", True, ""),
+    ("x@x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x234", True, ""),
+    ("123456789012345678901234567890123456789012345678901234567890@12345678901234567890123456789012345678901234567890123456789.12345678901234567890123456789012345678901234567890123456789.123456789012345678901234567890123456789012345678901234567890123.example.com", True, ""),
+    ("first.last@[12.34.56.78]", True, ""),
+    ("first.last@[IPv6:::12.34.56.78]", True, ""),
+    ("first.last@[IPv6:1111:2222:3333::4444:12.34.56.78]", True, ""),
+    ("first.last@[IPv6:1111:2222:3333:4444:5555:6666:12.34.56.78]", True, ""),
+    ("first.last@[IPv6:::1111:2222:3333:4444:5555:6666]", True, ""),
+    ("first.last@[IPv6:1111:2222:3333::4444:5555:6666]", True, ""),
+    ("first.last@[IPv6:1111:2222:3333:4444:5555:6666::]", True, ""),
+    ("first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]", True, ""),
+    ("first.last@x23456789012345678901234567890123456789012345678901234567890123.example.com", True, ""),
+    ("first.last@1xample.com", True, ""),
+    ("first.last@123.example.com", True, ""),
+    ("first.last", False, "No @"),
+    (".first.last@example.com", False, "Local part starts with a dot"),
+    ("first.last.@example.com", False, "Local part ends with a dot"),
+    ("first..last@example.com", False, "Local part has consecutive dots"),
+    ("\"first\"last\"@example.com", False, "Local part contains unescaped excluded characters"),
+    ("\"first\\last\"@example.com", True, "Any character can be escaped in a quoted string"),
+    ("\"\"\"@example.com", False, "Local part contains unescaped excluded characters"),
+    ("\"\\\"@example.com", False, "Local part cannot end with a backslash"),
+    ("first\\\\@last@example.com", False, "Local part contains unescaped excluded characters"),
+    ("first.last@", False, "No domain"),
+    ("\"Abc\\@def\"@example.com", True, ""),
+    ("\"Fred\\ Bloggs\"@example.com", True, ""),
+    ("\"Joe.\\\\Blow\"@example.com", True, ""),
+    ("\"Abc@def\"@example.com", True, ""),
+    ("\"Fred Bloggs\"@example.com", True, ""),
+    ("user+mailbox@example.com", True, ""),
+    ("customer/department=shipping@example.com", True, ""),
+    ("$A12345@example.com", True, ""),
+    ("!def!xyz%abc@example.com", True, ""),
+    ("_somename@example.com", True, ""),
+    ("dclo@us.ibm.com", True, ""),
+    ("abc\\@def@example.com", False, "This example from RFC3696 was corrected in an erratum"),
+    ("abc\\\\@example.com", False, "This example from RFC3696 was corrected in an erratum"),
+    ("peter.piper@example.com", True, ""),
+    ("Doug\\ \\\"Ace\\\"\\ Lovell@example.com", False, "Escaping can only happen in a quoted string"),
+    ("\"Doug \\\"Ace\\\" L.\"@example.com", True, ""),
+    ("abc@def@example.com", False, "Doug Lovell says this should fail"),
+    ("abc\\\\@def@example.com", False, "Doug Lovell says this should fail"),
+    ("abc\\@example.com", False, "Doug Lovell says this should fail"),
+    ("@example.com", False, "No local part"),
+    ("doug@", False, "Doug Lovell says this should fail"),
+    ("\"qu@example.com", False, "Doug Lovell says this should fail"),
+    ("ote\"@example.com", False, "Doug Lovell says this should fail"),
+    (".dot@example.com", False, "Doug Lovell says this should fail"),
+    ("dot.@example.com", False, "Doug Lovell says this should fail"),
+    ("two..dot@example.com", False, "Doug Lovell says this should fail"),
+    ("\"Doug \"Ace\" L.\"@example.com", False, "Doug Lovell says this should fail"),
+    ("Doug\\ \\\"Ace\\\"\\ L\\.@example.com", False, "Doug Lovell says this should fail"),
+    ("hello world@example.com", False, "Doug Lovell says this should fail"),
+    ("gatsby@f.sc.ot.t.f.i.tzg.era.l.d.", False, "Doug Lovell says this should fail"),
+    ("test@example.com", True, ""),
+    ("TEST@example.com", True, ""),
+    ("1234567890@example.com", True, ""),
+    ("test+test@example.com", True, ""),
+    ("test-test@example.com", True, ""),
+    ("t*est@example.com", True, ""),
+    ("+1~1+@example.com", True, ""),
+    ("{_test_}@example.com", True, ""),
+    ("\"[[ test ]]\"@example.com", True, ""),
+    ("test.test@example.com", True, ""),
+    ("\"test.test\"@example.com", True, ""),
+    ("test.\"test\"@example.com", True, "Obsolete form, but documented in RFC2822"),
+    ("\"test@test\"@example.com", True, ""),
+    ("test@123.123.123.x123", True, ""),
+    ("test@[123.123.123.123]", True, ""),
+    ("test@example.example.com", True, ""),
+    ("test@example.example.example.com", True, ""),
+    ("test.example.com", False, ""),
+    ("test.@example.com", False, ""),
+    ("test..test@example.com", False, ""),
+    (".test@example.com", False, ""),
+    ("test@test@example.com", False, ""),
+    ("test@@example.com", False, ""),
+    ("-- test --@example.com", False, "No spaces allowed in local part"),
+    ("[test]@example.com", False, "Square brackets only allowed within quotes"),
+    ("\"test\\test\"@example.com", True, "Any character can be escaped in a quoted string"),
+    ("\"test\"test\"@example.com", False, "Quotes cannot be nested"),
+    ("()[]\\;:,><@example.com", False, "Disallowed Characters"),
+    ("test@.", False, "Dave Child says so"),
+    ("test@example.", False, "Dave Child says so"),
+    ("test@.org", False, "Dave Child says so"),
+    ("test@[123.123.123.123", False, "Dave Child says so"),
+    ("test@123.123.123.123]", False, "Dave Child says so"),
+    ("NotAnEmail", False, "Phil Haack says so"),
+    ("@NotAnEmail", False, "Phil Haack says so"),
+    ("\"test\\\\blah\"@example.com", True, ""),
+    ("\"test\\blah\"@example.com", True, "Any character can be escaped in a quoted string"),
+    ("\"test\\\rblah\"@example.com", True, "Quoted string specifically excludes carriage returns unless escaped"),
+    ("\"test\rblah\"@example.com", False, "Quoted string specifically excludes carriage returns"),
+    ("\"test\\\"blah\"@example.com", True, ""),
+    ("\"test\"blah\"@example.com", False, "Phil Haack says so"),
+    ("customer/department@example.com", True, ""),
+    ("_Yosemite.Sam@example.com", True, ""),
+    ("~@example.com", True, ""),
+    (".wooly@example.com", False, "Phil Haack says so"),
+    ("wo..oly@example.com", False, "Phil Haack says so"),
+    ("pootietang.@example.com", False, "Phil Haack says so"),
+    (".@example.com", False, "Phil Haack says so"),
+    ("\"Austin@Powers\"@example.com", True, ""),
+    ("Ima.Fool@example.com", True, ""),
+    ("\"Ima.Fool\"@example.com", True, ""),
+    ("\"Ima Fool\"@example.com", True, ""),
+    ("Ima Fool@example.com", False, "Phil Haack says so"),
+    ("phil.h\\@\\@ck@haacked.com", False, "Escaping can only happen in a quoted string"),
+    ("\"first\".\"last\"@example.com", True, ""),
+    ("\"first\".middle.\"last\"@example.com", True, ""),
+    ("\"first\\\\\"last\"@example.com", False, "Contains an unescaped quote"),
+    ("\"first\".last@example.com", True, "obs-local-part form as described in RFC 2822"),
+    ("first.\"last\"@example.com", True, "obs-local-part form as described in RFC 2822"),
+    ("\"first\".\"middle\".\"last\"@example.com", True, "obs-local-part form as described in RFC 2822"),
+    ("\"first.middle\".\"last\"@example.com", True, "obs-local-part form as described in RFC 2822"),
+    ("\"first.middle.last\"@example.com", True, "obs-local-part form as described in RFC 2822"),
+    ("\"first..last\"@example.com", True, "obs-local-part form as described in RFC 2822"),
+    ("foo@[\\1.2.3.4]", False, "RFC 5321 specifies the syntax for address-literal and does not allow escaping"),
+    ("\"first\\\\\\\"last\"@example.com", True, ""),
+    ("first.\"mid\\dle\".\"last\"@example.com", True, "Backslash can escape anything but must escape something"),
+    ("Test.\r\n Folding.\r\n Whitespace@example.com", True, ""),
+    ("first\\last@example.com", False, "Unquoted string must be an atom"),
+    ("Abc\\@def@example.com", False, "Was incorrectly given as a valid address in the original RFC3696"),
+    ("Fred\\ Bloggs@example.com", False, "Was incorrectly given as a valid address in the original RFC3696"),
+    ("Joe.\\\\Blow@example.com", False, "Was incorrectly given as a valid address in the original RFC3696"),
+    ("\"test\\\r\n blah\"@example.com", False, "Folding white space can\'t appear within a quoted pair"),
+    ("\"test\r\n blah\"@example.com", True, "This is a valid quoted string with folding white space"),
+    ("{^c\\@**Dog^}@cartoon.com", False, "This is a throwaway example from Doug Lovell\'s article. Actually it\'s not a valid address."),
+    ("(foo)cal(bar)@(baz)iamcal.com(quux)", True, "A valid address containing comments"),
+    ("cal@iamcal(woo).(yay)com", True, "A valid address containing comments"),
+    ("cal(woo(yay)hoopla)@iamcal.com", True, "A valid address containing comments"),
+    ("cal(foo\\@bar)@iamcal.com", True, "A valid address containing comments"),
+    ("cal(foo\\)bar)@iamcal.com", True, "A valid address containing comments and an escaped parenthesis"),
+    ("cal(foo(bar)@iamcal.com", False, "Unclosed parenthesis in comment"),
+    ("cal(foo)bar)@iamcal.com", False, "Too many closing parentheses"),
+    ("cal(foo\\)@iamcal.com", False, "Backslash at end of comment has nothing to escape"),
+    ("first().last@example.com", True, "A valid address containing an empty comment"),
+    ("first.(\r\n middle\r\n )last@example.com", True, "Comment with folding white space"),
+    ("first(12345678901234567890123456789012345678901234567890)last@(1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890)example.com", False, "Too long with comments, not too long without"),
+    ("first(Welcome to\r\n the (\"wonderful\" (!)) world\r\n of email)@example.com", True, "Silly example from my blog post"),
+    ("pete(his account)@silly.test(his host)", True, "Canonical example from RFC5322"),
+    ("c@(Chris\'s host.)public.example", True, "Canonical example from RFC5322"),
+    ("jdoe@machine(comment).  example", True, "Canonical example from RFC5322"),
+    ("1234   @   local(blah)  .machine .example", True, "Canonical example from RFC5322"),
+    ("first(middle)last@example.com", False, "Can\'t have a comment or white space except at an element boundary"),
+    ("first(abc.def).last@example.com", True, "Comment can contain a dot"),
+    ("first(a\"bc.def).last@example.com", True, "Comment can contain double quote"),
+    ("first.(\")middle.last(\")@example.com", True, "Comment can contain a quote"),
+    ("first(abc(\"def\".ghi).mno)middle(abc(\"def\".ghi).mno).last@(abc(\"def\".ghi).mno)example(abc(\"def\".ghi).mno).(abc(\"def\".ghi).mno)com(abc(\"def\".ghi).mno)", False, "Can\'t have comments or white space except at an element boundary"),
+    ("first(abc\\(def)@example.com", True, "Comment can contain quoted-pair"),
+    ("first.last@x(1234567890123456789012345678901234567890123456789012345678901234567890).com", True, "Label is longer than 63 octets, but not with comment removed"),
+    ("a(a(b(c)d(e(f))g)h(i)j)@example.com", True, ""),
+    ("a(a(b(c)d(e(f))g)(h(i)j)@example.com", False, "Braces are not properly matched"),
+    ("name.lastname@domain.com", True, ""),
+    (".@", False, ""),
+    ("@bar.com", False, ""),
+    ("@@bar.com", False, ""),
+    ("a@bar.com", True, ""),
+    ("aaa.com", False, ""),
+    ("aaa@.com", False, ""),
+    ("aaa@.123", False, ""),
+    ("aaa@[123.123.123.123]", True, ""),
+    ("aaa@[123.123.123.123]a", False, "extra data outside ip"),
+    ("a@bar.com.", False, ""),
+    ("a-b@bar.com", True, ""),
+    ("+@b.c", True, "TLDs can be any length"),
+    ("+@b.com", True, ""),
+    ("-@..com", False, ""),
+    ("-@a..com", False, ""),
+    ("a@b.co-foo.uk", True, ""),
+    ("\"hello my name is\"@stutter.com", True, ""),
+    ("\"Test \\\"Fail\\\" Ing\"@example.com", True, ""),
+    ("valid@special.museum", True, ""),
+    ("shaitan@my-domain.thisisminekthx", True, "Disagree with Paul Gregg here"),
+    ("test@...........com", False, "......"),
+    ("\"Joe\\\\Blow\"@example.com", True, ""),
+    ("Invalid \\\n Folding \\\n Whitespace@example.com", False, "This isn\'t FWS so Dominic Sayers says it\'s invalid"),
+    ("HM2Kinsists@(that comments are allowed)this.is.ok", True, ""),
+    ("user%uucp!path@somehost.edu", True, ""),
+    ("\"first(last)\"@example.com", True, ""),
+    (" \r\n (\r\n x \r\n ) \r\n first\r\n ( \r\n x\r\n ) \r\n .\r\n ( \r\n x) \r\n last \r\n (  x \r\n ) \r\n @example.com", True, ""),
+    ("test.\r\n \r\n obs@syntax.com", True, "obs-fws allows multiple lines"),
+    ("test. \r\n \r\n obs@syntax.com", True, "obs-fws allows multiple lines (test 2: space before break)"),
+    ("test.\r\n\r\n obs@syntax.com", False, "obs-fws must have at least one WSP per line"),
+    ("\"null \\\0\"@char.com", True, "can have escaped null character"),
+    ("\"null \0\"@char.com", False, "cannot have unescaped null character")
+    -- items below here are invalid according to other RFCs (or opinions)
+    --("\"\"@example.com", False, "Local part is effectively empty"),
+    --("foobar@192.168.0.1", False, "ip need to be []"),
+    --("first.last@[.12.34.56.78]", False, "Only char that can precede IPv4 address is \':\'"),
+    --("first.last@[12.34.56.789]", False, "Can\'t be interpreted as IPv4 so IPv6 tag is missing"),
+    --("first.last@[::12.34.56.78]", False, "IPv6 tag is missing"),
+    --("first.last@[IPv5:::12.34.56.78]", False, "IPv6 tag is wrong"),
+    --("first.last@[IPv6:1111:2222:3333::4444:5555:12.34.56.78]", False, "Too many IPv6 groups (4 max)"),
+    --("first.last@[IPv6:1111:2222:3333:4444:5555:12.34.56.78]", False, "Not enough IPv6 groups"),
+    --("first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:12.34.56.78]", False, "Too many IPv6 groups (6 max)"),
+    --("first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777]", False, "Not enough IPv6 groups"),
+    --("first.last@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]", False, "Too many IPv6 groups (8 max)"),
+    --("first.last@[IPv6:1111:2222::3333::4444:5555:6666]", False, "Too many \'::\' (can be none or one)"),
+    --("first.last@[IPv6:1111:2222:3333::4444:5555:6666:7777]", False, "Too many IPv6 groups (6 max)"),
+    --("first.last@[IPv6:1111:2222:333x::4444:5555]", False, "x is not valid in an IPv6 address"),
+    --("first.last@[IPv6:1111:2222:33333::4444:5555]", False, "33333 is not a valid group in an IPv6 address"),
+    --("first.last@example.123", False, "TLD can\'t be all digits"),
+    --("aaa@[123.123.123.333]", False, "not a valid IP"),
+    --("first.last@[IPv6:1111:2222:3333:4444:5555:6666:12.34.567.89]", False, "IPv4 part contains an invalid octet"),
+    --("a@b", False, ""),
+    --("a@bar", False, ""),
+    --("invalid@special.museum-", False, ""),
+    --("a@-b.com", False, ""),
+    --("a@b-.com", False, ""),
+    --("\"foo\"(yay)@(hoopla)[1.2.3.4]", False, "Address literal can\'t be commented (RFC5321)"),
+    --("first.\"\".last@example.com", False, "Contains a zero-length element"),
+    --("test@example", False, "Dave Child says so"),
+    --("12345678901234567890123456789012345678901234567890123456789012345@example.com", False, "Local part more than 64 characters"),
+    --("x@x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456789.x23456", False, "Domain exceeds 255 chars"),
+    --("test@123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012.com", False, "255 characters is maximum length for domain. This is 256."),
+    --("123456789012345678901234567890123456789012345678901234567890@12345678901234567890123456789012345678901234567890123456789.12345678901234567890123456789012345678901234567890123456789.12345678901234567890123456789012345678901234567890123456789.1234.example.com", False, "Entire address is longer than 256 characters"),
+    --("test@123.123.123.123", False, "Top Level Domain won\'t be all-numeric (see RFC3696 Section 2). I disagree with Dave Child on this one."),
+    --("first.last@x234567890123456789012345678901234567890123456789012345678901234.example.com", False, "Label can\'t be longer than 63 octets"),
+    --("first.last@com", False, "Mail host must be second- or lower level"),
+    --("first.last@-xample.com", False, "Label can\'t begin with a hyphen"),
+    --("first.last@exampl-.com", False, "Label can\'t end with a hyphen"),
+    ]
