diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -28,3 +28,27 @@
 0.12.0.0
 	* Added module "ToolShed.TimeAction" to measure the CPU-seconds required for an IO-action.
 	* Added module "Pair".
+0.12.0.1
+	* Removed unnecessary type-context 'Ord' from 'ToolShed.ListPus.mergeBy' and reimplemented 'ToolShed.ListPus.merge' in terms of 'ToolShed.ListPus.mergeBy'.
+	* Added 'ToolShed.ListPlus.runLengthEncode' and 'ToolShed.ListPlus.runLengthDecode'.
+0.13.0.0
+	* Removed module "ToolShed.Unsafe".
+	* Renamed:
+		"ToolShed.ListPlus" to "ToolShed.Data.List"
+		"ToolShed.Pair" to "ToolShed.Data.Pair"
+		"ToolShed.TimeAction" to "ToolShed.System.TimeAction"
+		"ToolShed.TimePure" to "ToolShed.System.TimePure"
+	* Migrated 'ToolShed.Data.List.RunLengthCode' and associated functions, into a new module "ToolShed.Data.List.Runlength".
+	* Migrated 'ToolShed.Data.List.Splits' and associated functions, into a new module "ToolShed.Data.List.Splits".
+	* Replaced function 'ToolShed.Data.List.groupComparing' with the more useful 'ToolShed.Data.List.equalityBy', which can be used with either 'Data.List.groupBy' or 'Data.List.nubBy'.
+	* Added instances of 'ToolShed.SelfValidate.SelfValidator' for 'Data.Maybe.Maybe' '(,)', 'Data.Set.Set', 'Data.Map.Map' and 'Data.Array.IArray.Array'.
+	* Added instance of 'ToolShed.Defaultable.Defaultable' for '(,)'.
+	* Added functions 'ToolShed.Data.List.showListWith', 'ToolShed.Data.List.permutations', 'ToolShed.Data.List.gatherBy', 'ToolShed.Data.List.findConvergenceBy', 'ToolShed.Data.List.findConvergence', 'ToolShed.Data.List.gather'.
+	* Added module "ToolShed.System.File".
+	* Added module "ToolShed.System.Random".
+	* Added method 'ToolShed.SelfValidate.getErrors', and supporting functions 'ToolShed.SelfValidate.getFirstErrors' and 'ToolShed.SelfValidate.extractErrors'.
+	* Create module "ToolShed.Arbitrary.*".
+	* Added "Main", "ToolShed.Test.QuickChecks" and "ToolShed.Test.Data.List" to facilitate testing.
+	* Removed 'ToolShed.Data.Pair.both'.
+	* Replaced "System" with "System.Environment" and "System.Exit".
+	* Removed dependency on "haskell98".
diff --git a/makefile b/makefile
--- a/makefile
+++ b/makefile
@@ -1,18 +1,18 @@
 # Copyright (C) 2010 Dr. Alistair Ward
-# 
+#
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
-# 
+#
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
-# 
+#
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
- 
+
 .PHONY: all build check clean configure copy haddock help hlint install prof sdist
 
 all: install
@@ -50,7 +50,7 @@
 
 clean:
 	runhaskell Setup.hs $@
-	find src -type f \( -name '*.o' -o -name '*.hi' \) -delete
+	find src -type f \( -name '*.hc' -o -name '*.hcr' -o -name '*.hi' -o -name '*.o' \) -delete
 
 help:
 	@grep '^[a-zA-Z].*:' makefile | sed -e 's/:.*//'
diff --git a/src/Main.hs b/src/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Main.hs
@@ -0,0 +1,85 @@
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]
+
+	* Contains the entry-point to the program.
+
+	* Facilitates testing.
+-}
+
+module Main(
+-- * Types
+-- ** Type-synonyms
+--	CommandLineAction,
+-- * Functions
+	main
+) where
+
+import qualified	Data.List
+import qualified	Data.Version
+import qualified	Distribution.Package
+import qualified	Distribution.Text
+import qualified	Distribution.Version
+import qualified	Paths_toolshed		as Paths	--Either local stub, or package-instance autogenerated by 'Setup.hs build'.
+import qualified	System.Console.GetOpt	as G
+import qualified	System.Environment
+import qualified	System.Exit
+import qualified	System.IO
+import qualified	System.IO.Error
+import qualified	ToolShed.Defaultable
+import qualified	ToolShed.Test.QuickChecks
+
+-- | Used to thread user-defined command-line options, though the list of functions which implement them.
+type CommandLineAction	= () -> IO ()	--Supplied as the type-argument to 'G.OptDescr'.
+
+-- | Parses the command-line arguments, to determine 'Test.CommandOptions.CommandOptions'.
+main :: IO ()
+main	= do
+	progName	<- System.Environment.getProgName
+	args		<- System.Environment.getArgs
+
+	let
+		usage :: String
+		usage	= "Usage:\t" ++ G.usageInfo progName optDescrList
+
+--Define the command-line options, and the 'CommandLineAction's used to handle them.
+		optDescrList :: [G.OptDescr CommandLineAction]
+		optDescrList	= [
+--				 String	[String]		(G.ArgDescr CommandLineAction)												String
+			G.Option "?"	["help"]		(G.NoArg $ const printUsage)												"Display this help-text & then exit.",
+			G.Option ""	["version"]		(G.NoArg $ const printVersion)												"Print version-information & then exit.",
+			G.Option "q"	["runQuickChecks"]	(G.NoArg $ const runQuickChecks)											"Run Quick-checks using arbitrary data & then exit."
+		 ] where
+			printVersion, printUsage, runQuickChecks :: IO ()
+			printVersion	= System.IO.hPutStrLn System.IO.stderr (Distribution.Text.display packageIdentifier ++ "\n\nCopyright (C) 2011 Dr. Alistair Ward.\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by Dr. Alistair Ward.")	>> System.Exit.exitWith System.Exit.ExitSuccess	where
+				packageIdentifier :: Distribution.Package.PackageIdentifier
+				packageIdentifier	= Distribution.Package.PackageIdentifier {
+					Distribution.Package.pkgName	= Distribution.Package.PackageName "toolshed",
+					Distribution.Package.pkgVersion	= Distribution.Version.Version (Data.Version.versionBranch Paths.version) []
+				}
+
+			printUsage	= System.IO.hPutStrLn System.IO.stderr usage	>> System.Exit.exitWith System.Exit.ExitSuccess
+			runQuickChecks	= ToolShed.Test.QuickChecks.run			>> System.Exit.exitWith System.Exit.ExitSuccess
+
+--	G.getOpt :: G.ArgOrder CommandLineAction -> [G.OptDescr Action] -> [String] -> ([Action], [String], [String])
+	case G.getOpt G.RequireOrder optDescrList args of
+		(commandLineActions, _, [])	-> Data.List.foldl' (>>=) (return {-to IO-monad-} ()) commandLineActions	>> System.Exit.exitWith System.Exit.ExitSuccess
+		(_, _, errors)			-> System.IO.Error.ioError . System.IO.Error.userError $ concat errors ++ usage	--Throw.
+
diff --git a/src/ToolShed/Arbitrary/Array.hs b/src/ToolShed/Arbitrary/Array.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Arbitrary/Array.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' for 'Data.Array.IArray.Array'.
+
+ [@EXAMPLE@]	@Test.QuickCheck.sample (Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen.Gen (Data.Array.IArray.Array Char Int))@
+
+ [@CAVEAT@]	An array with arbitrary indices isn't very useful.
+-}
+
+module ToolShed.Arbitrary.Array() where
+
+import			Control.Applicative((<$>))
+import qualified	Data.Array.IArray
+import qualified	Data.Tuple
+import qualified	Test.QuickCheck
+
+instance (Data.Array.IArray.Ix i, Enum i, Test.QuickCheck.Arbitrary i, Test.QuickCheck.Arbitrary e) => Test.QuickCheck.Arbitrary (Data.Array.IArray.Array i e)	where
+	arbitrary	= do
+		pair	<- Test.QuickCheck.arbitrary {-(i, i)-}
+
+		let
+			bounds@(lower, upper)
+				| uncurry (>) pair	= Data.Tuple.swap pair
+				| otherwise		= pair
+
+			indices	= [lower .. upper]
+
+		Data.Array.IArray.array bounds . zip indices <$> Test.QuickCheck.vector (length indices)
+
+#if !(MIN_VERSION_QuickCheck(2,1,0))
+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.
+#endif
+
diff --git a/src/ToolShed/Arbitrary/ArrayElem.hs b/src/ToolShed/Arbitrary/ArrayElem.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Arbitrary/ArrayElem.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]
+
+	Implements 'Test.QuickCheck.Arbitrary' for 'Data.Array.IArray.Array',
+	where the array-index is required to be a /bounded enumerable/ type.
+
+ [@EXAMPLE@]	@Test.QuickCheck.sample (Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen.Gen (Data.Array.IArray.Array Data.Int.Int8 Int))@
+-}
+
+module ToolShed.Arbitrary.ArrayElem() where
+
+import			Control.Applicative((<$>))
+import qualified	Data.Array.IArray
+import qualified	Test.QuickCheck
+
+instance (Bounded i, Data.Array.IArray.Ix i, Enum i, Test.QuickCheck.Arbitrary e) => Test.QuickCheck.Arbitrary (Data.Array.IArray.Array i e)	where
+	arbitrary	= Data.Array.IArray.array bounds . zip [minBound .. maxBound] <$> Test.QuickCheck.vector (succ $ fromEnum (snd bounds) - fromEnum (fst bounds))	where
+		bounds	= (minBound, maxBound)
+
+#if !(MIN_VERSION_QuickCheck(2,1,0))
+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.
+#endif
+
diff --git a/src/ToolShed/Arbitrary/Map.hs b/src/ToolShed/Arbitrary/Map.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Arbitrary/Map.hs
@@ -0,0 +1,39 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' for 'Data.Map.Map'.
+
+ [@EXAMPLE@]	@Test.QuickCheck.sample (Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen.Gen (Data.Map.Map Char Int))@
+-}
+
+module ToolShed.Arbitrary.Map() where
+
+import			Control.Applicative((<$>))
+import qualified	Data.Map
+import qualified	Test.QuickCheck
+
+instance (Ord k, Test.QuickCheck.Arbitrary k, Test.QuickCheck.Arbitrary v) => Test.QuickCheck.Arbitrary (Data.Map.Map k v)	where
+	arbitrary	= Data.Map.fromList <$> Test.QuickCheck.arbitrary {-[(k, v)]-}
+
+#if !(MIN_VERSION_QuickCheck(2,1,0))
+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.
+#endif
+
diff --git a/src/ToolShed/Arbitrary/Set.hs b/src/ToolShed/Arbitrary/Set.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Arbitrary/Set.hs
@@ -0,0 +1,39 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Implements 'Test.QuickCheck.Arbitrary' for 'Data.Set.Set'.
+
+ [@EXAMPLE@]	@Test.QuickCheck.sample (Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen.Gen (Data.Set.Set Int))@
+-}
+
+module ToolShed.Arbitrary.Set() where
+
+import			Control.Applicative((<$>))
+import qualified	Data.Set
+import qualified	Test.QuickCheck
+
+instance (Ord k, Test.QuickCheck.Arbitrary k) => Test.QuickCheck.Arbitrary (Data.Set.Set k)	where
+	arbitrary	= Data.Set.fromList <$> Test.QuickCheck.arbitrary {-[k]-}
+
+#if !(MIN_VERSION_QuickCheck(2,1,0))
+	coarbitrary	= undefined	--CAVEAT: stops warnings from ghc.
+#endif
+
diff --git a/src/ToolShed/Data/List.hs b/src/ToolShed/Data/List.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Data/List.hs
@@ -0,0 +1,171 @@
+{-
+	Copyright (C) 2010 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Miscellaneous polymorphic list-operations.
+-}
+
+module ToolShed.Data.List(
+-- * Types
+-- ** Type-synonyms
+	ChunkLength,
+-- * Functions
+	chunk,
+	excise,
+	equalityBy,
+	findConvergence,
+	findConvergenceBy,
+	gather,
+	gatherBy,
+	linearise,
+	merge,
+	mergeBy,
+	permutations,
+	takeUntil,
+	showListWith,
+--	showListWithChar
+--	showListWithString
+) where
+
+import qualified	Control.Arrow
+import qualified	Data.Foldable
+import qualified	Data.List
+import qualified	Data.Map
+--import qualified	Data.Ord
+
+-- | The length of the chunks into which a list is split.
+type ChunkLength	= Int
+
+{- |
+	* Splits a list into length-@size@ pieces, where @(size >= 0)@.
+
+	* The last chunk will be shorter, if @n@ isn't an aliquot part of the input list-length.
+
+	* If @(size == 0)@, the resulting list will be an infinite sequence of null lists.
+
+	* CAVEAT: a similar function is available in the module /Data.List.Split/, though this one checks for @(size < 0)@.
+-}
+chunk
+	:: ChunkLength
+	-> [a]		-- ^ The polymorphic input list to be chunked.
+	-> [[a]]
+chunk size list
+	| size < 0	= error $ "ToolShed.Data.List.chunk:\tnegative chunk-size=" ++ show size
+	| otherwise	= chunk' list
+	where
+		chunk' :: [a] -> [[a]]
+		chunk' []	= []
+		chunk' a	= uncurry (:) . Control.Arrow.second chunk' $ splitAt size a
+
+-- | Remove the single indexed element from the list.
+excise
+	:: Int	-- ^ The index.
+	-> [a]	-- ^ The polymorphic input list.
+	-> [a]	-- ^ The same list, with the indexed element removed.
+excise 0	= tail	--Just for efficiency.
+excise i	= uncurry (++) . Control.Arrow.second tail . splitAt i
+
+-- | A convenient way to compose the function-parameter required by 'Data.List.groupBy' or 'Data.List.nubBy'.
+equalityBy :: Eq b => (a -> b) -> a -> a -> Bool
+equalityBy f x y	= f x == f y
+
+-- | Take the first element from the list, which compares equal according to the specified predicate, with the subsequent element.
+findConvergenceBy :: (a -> a -> Bool) -> [a] -> a
+findConvergenceBy predicate l	= fst . head . dropWhile (not . uncurry predicate) . zip l $ tail l
+
+-- | A specific instance of 'findConvergenceBy'.
+findConvergence :: Eq a => [a] -> a
+findConvergence	= findConvergenceBy (==)
+
+{- |
+	* Group equal (though not necessarily adjacent) elements, according to the specified comparator.
+
+	* The groups are returned in ascending order, whilst their elements remain in their original order.
+-}
+gatherBy :: (Data.Foldable.Foldable f, Ord b) => (a -> b) -> f a -> [[a]]
+gatherBy f	= Data.Map.elems . Data.Foldable.foldr (\x -> Data.Map.insertWith (++) (f x) [x]) Data.Map.empty
+
+-- | A specific instance of 'gatherBy'.
+gather :: (Data.Foldable.Foldable f, Ord a) => f a -> [[a]]
+gather	= gatherBy id
+
+-- | Converts a list of /Pairs/, into a narrower list.
+linearise :: [(a, a)] -> [a]
+linearise []			= []
+linearise ((l, r) : remainder)	= l : r : linearise remainder	--Recurse.
+
+{- |
+	* Merge two sorted lists, according to the specified order, to product a single sorted list.
+
+	* The merge-process is /stable/, in that where items from each list are equal, they remain in the original order.
+
+	* CAVEAT: duplicates are preserved.
+-}
+mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
+mergeBy cmp	= slave	where
+	slave l@(x : xs) r@(y : ys)
+		| x `cmp` y == GT	= y : slave l ys
+		| otherwise		= x : slave xs r
+	slave [] r	= r
+	slave l []	= l
+
+-- | A specific instance of 'mergeBy'.
+merge :: Ord a => [a] -> [a] -> [a]
+merge	= mergeBy compare
+
+{- |
+	* The list of all permutations, generated by selecting any one datum from each sub-list in turn, from the specified list of lists.
+
+	* Taken from <http://www.haskell.org/pipermail/haskell-cafe/2006-June/015975.html>.
+-}
+permutations :: [[a]] -> [[a]]
+permutations (xs : xss)	= [ x : xs' | x <- xs, xs' <- permutations xss ]
+permutations []		= [[]]
+
+{- |
+	* Take until the specified predicate is satisfied; /including/ the item which satisfied it.
+
+	* NB: @takeWhile (not . test)@ would return one fewer item.
+-}
+takeUntil
+	:: (a -> Bool)	-- ^ Predicate, used to determine the last item taken.
+	-> [a]		-- ^ The polymorphic input list.
+	-> [a]
+takeUntil predicate	= takeUntil'	where
+	takeUntil' (x : xs)	= x {-take regardless-} : if predicate x then [] else takeUntil' xs
+	takeUntil' _		= []
+
+-- | Show a list, delimited by the specified tokens.
+showListWith :: (Show token, Show element)
+	=> (token, token, token)	-- ^ (Start-delimiter, separator, end-delimiter)
+	-> [element]			-- ^ The polymorphic list to show.
+	-> ShowS
+showListWith (startDelimiter, separator, endDelimiter)	= foldr (.) (shows endDelimiter) . (shows startDelimiter :) . Data.List.intersperse (shows separator) . map shows
+
+{-# NOINLINE showListWith #-}
+{-# RULES "showListWith/Char" showListWith = showListWithChar #-}
+{-# RULES "showListWith/String" showListWith = showListWithString #-}
+
+-- | A specialisation of 'showListWith'.
+showListWithChar :: Show element => (Char, Char, Char) -> [element] -> ShowS
+showListWithChar (startDelimiter, separator, endDelimiter)	= foldr (.) (showChar endDelimiter) . (showChar startDelimiter :) . Data.List.intersperse (showChar separator) . map shows
+
+-- | A specialisation of 'showListWith'.
+showListWithString :: Show element => (String, String, String) -> [element] -> ShowS
+showListWithString (startDelimiter, separator, endDelimiter)	= foldr (.) (showString endDelimiter) . (showString startDelimiter :) . Data.List.intersperse (showString separator) . map shows
+
diff --git a/src/ToolShed/Data/List/Runlength.hs b/src/ToolShed/Data/List/Runlength.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Data/List/Runlength.hs
@@ -0,0 +1,55 @@
+{-
+	Copyright (C) 2010 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Run-length encoder and decoder.
+-}
+
+module ToolShed.Data.List.Runlength(
+-- * Types
+-- ** Type-synonyms
+	Code,
+-- * Functions
+	encode,
+	decode,
+-- ** Accessors
+	getLength,
+	getDatum
+) where
+
+import			Control.Arrow((&&&))
+import qualified	Data.List
+
+-- | Describes the number of consecutive equal items in a list.
+type Code a	= (Int, a)
+
+-- | Accessor.
+getLength :: Code a -> Int
+getLength	= fst
+
+-- | Accessor.
+getDatum :: Code a -> a
+getDatum	= snd
+
+-- | /Run-length/ encodes the specified list.
+encode :: Eq a => [a] -> [Code a]
+encode	= map (length &&& head) . Data.List.group
+
+-- | Performs /run-length/ decoding to retrieve the original unencoded list.
+decode :: [Code a] -> [a]
+decode	= concatMap (uncurry replicate)
diff --git a/src/ToolShed/Data/List/Splits.hs b/src/ToolShed/Data/List/Splits.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Data/List/Splits.hs
@@ -0,0 +1,66 @@
+{-
+	Copyright (C) 2010 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]
+-}
+
+module ToolShed.Data.List.Splits(
+-- * Types
+-- ** Type-synonyms
+--	Split,
+-- * Functions
+--	splitsFrom,
+	splitsLeftFrom,
+	splitsRightFrom
+) where
+
+-- | The polymorphic pair, resulting from splitting a list of arbitrary type.
+type Split a	= ([a] {-left list-}, [a] {-right list-})
+
+-- | Use the specified transformation, to generate a list of 'Split's, from the initial one.
+splitsFrom
+	:: (Split a -> Split a)	-- ^ The function used to transform one /split/ into the next.
+	-> Int			-- ^ Index.
+	-> [a]			-- ^ The polymorphic input list from which the /splits/ are generated.
+	-> [Split a]		-- ^ The list of all required splits of the single input list.
+splitsFrom transformation i
+	| i < 0		= error $ "ToolShed.Data.List.Splits.splitsFrom:\tnegative starting-index; " ++ show i
+	| otherwise	= iterate transformation . splitAt i
+
+{- |
+	* Create the set of all 'Split's, migrating left from the specified location.
+
+	* CAVEAT: 'init' fails when 'fst' has been reduced to null.
+-}
+splitsLeftFrom
+	:: Int		-- ^ Index.
+	-> [a]		-- ^ The polymorphic input list from which the /splits/ are generated, as the index is stepped left
+	-> [Split a]	-- ^ The list of all required splits of the single input list.
+splitsLeftFrom	= splitsFrom (\(l, r) -> (init l, last l : r))
+
+{- |
+	* Create the set of all 'Split's, migrating right from the specified location.
+
+	* CAVEAT: pattern-match against @ : @ fails, when 'snd' has been reduced to 'null'.
+-}
+splitsRightFrom
+	:: Int		-- ^ Index.
+	-> [a]		-- ^ The polymorphic input list from which the /splits/ are generated, as the index is stepped right.
+	-> [Split a]	-- ^ The list of all required splits of the single input list.
+splitsRightFrom	= splitsFrom (\(l, r : rs) -> (l ++ [r], rs))
diff --git a/src/ToolShed/Data/Pair.hs b/src/ToolShed/Data/Pair.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Data/Pair.hs
@@ -0,0 +1,37 @@
+{-
+	Copyright (C) 2010 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Miscellaneous operations on Pairs.
+-}
+
+module ToolShed.Data.Pair(
+-- * Functions
+	mirror
+) where
+
+import	Control.Arrow((***))
+
+{- |
+	* Apply the same transformation to both halves of a /Pair/.
+
+	* CAVEAT: the pair is required to have identical types.
+-}
+mirror :: (a -> b) -> (a, a) -> (b, b)
+mirror f	= f *** f
+
diff --git a/src/ToolShed/Defaultable.hs b/src/ToolShed/Defaultable.hs
--- a/src/ToolShed/Defaultable.hs
+++ b/src/ToolShed/Defaultable.hs
@@ -29,3 +29,5 @@
 class Defaultable a	where
 	defaultValue	:: a	-- ^ The default value of the data-type.
 
+instance (Defaultable a, Defaultable b) => Defaultable (a, b)	where
+	defaultValue	= (defaultValue, defaultValue)
diff --git a/src/ToolShed/ListPlus.hs b/src/ToolShed/ListPlus.hs
deleted file mode 100644
--- a/src/ToolShed/ListPlus.hs
+++ /dev/null
@@ -1,168 +0,0 @@
-{-
-	Copyright (C) 2010 Dr. Alistair Ward
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program.  If not, see <http://www.gnu.org/licenses/>.
--}
-{- |
- [@AUTHOR@]	Dr. Alistair Ward
-
- [@DESCRIPTION@]	Miscellaneous polymorphic list-operations.
--}
-
-module ToolShed.ListPlus(
--- * Types
--- ** Type-synonyms
-	ChunkLength,
---	Split,
--- * Functions
-	chunk,
-	excise,
-	groupComparing,
-	linearise,
-	merge,
-	mergeBy,
---	splitsFrom,
-	splitsLeftFrom,
-	splitsRightFrom,
-	takeUntil
-) where
-
-import qualified	Control.Arrow
-import qualified	Data.List
-
--- | The length of the chunks into which a list is split.
-type ChunkLength	= Int
-
-{- |
-	* Splits a list into length-@size@ pieces, where @(size >= 0)@.
-
-	* The last chunk will be shorter, if @n@ isn't an aliquot part of the input list-length.
-
-	* If @(size == 0)@, the resulting list will be an infinite sequence of null lists.
-
-	* CAVEAT: a similar function is available in the module /Data.List.Split/, though this one checks for @(size < 0)@.
--}
-chunk ::
-	ChunkLength
-	-> [a]		-- ^ The polymorphic input list to be chunked.
-	-> [[a]]
-chunk size list
-	| size < 0	= error $ "ToolShed.ListPlus.chunk:\tnegative chunk-size=" ++ show size
-	| otherwise	= chunk' list
-	where
-		chunk' :: [a] -> [[a]]
-		chunk' []	= []
-		chunk' a	= uncurry (:) . Control.Arrow.second chunk' $ splitAt size a
-
--- | Remove the single indexed element from the list.
-excise ::
-	Int	-- ^ The index.
-	-> [a]	-- ^ The polymorphic input list.
-	-> [a]	-- ^ The same list, with the indexed element removed.
-excise 0	= tail	--Just for efficiency.
-excise i	= uncurry (++) . Control.Arrow.second tail . splitAt i
-
-{- |
-	* Much like 'Data.List.GroupBy', but where the normal binary predicate,
-	is composed from equality, after the same unary translation-function has been applied to both list-elements.
-
-	* cf. 'GHC.Exts.groupWith', which uses the function parameter to both sort and group.
--}
-groupComparing :: Eq b
-	=> (a -> b)	-- ^ Translates elements from the list, prior to testing the translated values for equality.
-	-> [a]		-- ^ The polymorphic input list to group.
-	-> [[a]]	-- ^ The same list split into chunks of the required length.
-groupComparing f	= Data.List.groupBy (\a b -> f a == f b)
-
--- | Converts a list of /Pairs/, into a narrower list.
-linearise :: [(a, a)] -> [a]
-linearise []			= []
-linearise ((l, r) : remainder)	= l : r : linearise remainder	--Recurse
-
-{- |
-	* Merge two sorted lists, to product a single sorted list.
-
-	* The merge-process is /stable/, in that where items from each list are equal, they remain in the original order.
--}
-merge :: Ord a => [a] -> [a] -> [a]
-merge [] r		= r
-merge l []		= l
-merge l@(x : xs) r@(y : ys)
-	| x > y		= y : merge l ys
-	| otherwise	= x : merge xs r
-
-{- |
-	* Merge two sorted lists, according to the specified order, to product a single sorted list.
-
-	* The merge-process is /stable/, in that where items from each list are equal, they remain in the original order.
--}
-mergeBy :: Ord a => (a -> a -> Ordering) -> [a] -> [a] -> [a]
-mergeBy _ [] r		= r
-mergeBy _ l []		= l
-mergeBy cmp l@(x : xs) r@(y : ys)
-	| x `cmp` y == GT	= y : mergeBy cmp l ys
-	| otherwise		= x : mergeBy cmp xs r 
-
--- | The polymorphic pair, resulting from splitting a list of arbitrary type.
-type Split a	= ([a] {-left list-}, [a] {-right list-})
-
--- | Use the specified transformation, to generate a list of 'Split's, from the initial one.
-splitsFrom ::
-	(Split a -> Split a)	-- ^ The function used to transform one /split/ into the next.
-	-> Int			-- ^ Index.
-	-> [a]			-- ^ The polymorphic input list from which the /splits/ are generated.
-	-> [Split a]		-- ^ The list of all required splits of the single input list.
-splitsFrom transformation i	= iterate transformation . splitAt i
-
-{- |
-	* Create the set of all 'Split's, migrating left from the specified location.
-
-	* CAVEAT: 'init' fails when 'fst' has been reduced to null.
--}
-splitsLeftFrom ::
-	Int		-- ^ Index.
-	-> [a]		-- ^ The polymorphic input list from which the /splits/ are generated, as the index is stepped left
-	-> [Split a]	-- ^ The list of all required splits of the single input list.
-splitsLeftFrom start
-	| start < 0	= error $ "ToolShed.ListPlus.splitsLeftFrom:\tnegative starting-index; " ++ show start
-	| otherwise	= splitsFrom (\(l, r) -> (init l, last l : r)) start
-
-{- |
-	* Create the set of all 'Split's, migrating right from the specified location.
-
-	* CAVEAT: pattern-match against @ : @ fails, when 'snd' has been reduced to null.
--}
-splitsRightFrom ::
-	Int		-- ^ Index.
-	-> [a]		-- ^ The polymorphic input list from which the /splits/ are generated, as the index is stepped right.
-	-> [Split a]	-- ^ The list of all required splits of the single input list.
-splitsRightFrom start
-	| start < 0	= error $ "ToolShed.ListPlus.splitsRightFrom:\tnegative starting-index; " ++ show start
-	| otherwise	= splitsFrom (\(l, r : rs) -> (l ++ [r], rs)) start
-
-{- |
-	* Take until the specified predicate is satisfied; /including/ the item which satisfied it.
-
-	* NB: @takeWhile (not . test)@ would return one fewer item.
--}
-takeUntil ::
-	(a -> Bool)	-- ^ Predicate, used to determine the last item taken.
-	-> [a]		-- ^ The polymorphic input list.
-	-> [a]
-takeUntil predicate	= takeUntil'	where
-	takeUntil' (x : xs)	= x {-take regardless-} : if predicate x
-		then []
-		else takeUntil' xs
-	takeUntil' _		= []
-
diff --git a/src/ToolShed/Options.hs b/src/ToolShed/Options.hs
--- a/src/ToolShed/Options.hs
+++ b/src/ToolShed/Options.hs
@@ -25,8 +25,8 @@
 	Options(..)
 ) where
 
-import ToolShed.Defaultable	as Defaultable
+import qualified	ToolShed.Defaultable
 
 -- | Similar to the class 'Text.Regex.Base.RegexLike.RegexOptions'.
-class Defaultable a => Options a	where
+class ToolShed.Defaultable.Defaultable a => Options a	where
 	blankValue	:: a	-- ^ The /undefined/ state of the data-type, which may be literal, but could alternatively be a logical starting value.
diff --git a/src/ToolShed/Pair.hs b/src/ToolShed/Pair.hs
deleted file mode 100644
--- a/src/ToolShed/Pair.hs
+++ /dev/null
@@ -1,44 +0,0 @@
-{-
-	Copyright (C) 2010 Dr. Alistair Ward
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program.  If not, see <http://www.gnu.org/licenses/>.
--}
-{- |
- [@AUTHOR@]	Dr. Alistair Ward
-
- [@DESCRIPTION@]	Miscellaneous operations on Pairs.
--}
-
-module ToolShed.Pair(
--- * Functions
-	mirror,
--- ** Predicates
-	both,
-	neither
-) where
-
-import	Control.Arrow((***))
-
--- | Apply the same transformation to both halves of a /Pair/.
-mirror :: (a -> b) -> (a, a) -> (b, b)
-mirror f	= f *** f
-
--- | 'True' if both halves of the /Pair/ are.
-both :: (Bool, Bool) -> Bool
-both	= uncurry (&&)
-
--- | 'True' if neither half of the /Pair/ is.
-neither :: (Bool, Bool) -> Bool
-neither	= not . uncurry (||)
-
diff --git a/src/ToolShed/SelfValidate.hs b/src/ToolShed/SelfValidate.hs
--- a/src/ToolShed/SelfValidate.hs
+++ b/src/ToolShed/SelfValidate.hs
@@ -22,13 +22,51 @@
 
 module ToolShed.SelfValidate(
 -- * Type-classes
-	SelfValidator(..)
+	SelfValidator(..),
+-- ** Functions
+	getFirstError,
+	extractErrors
 ) where
 
+import qualified	Data.Array.IArray
+import qualified	Data.Map
+import qualified	Data.Set
+
 -- | The interface to which data which can self-validate should conform.
-class SelfValidator a	where
-	isValid	:: a -> Bool	-- ^ The data which implements this interface should return 'True' if internally consistent.
+class SelfValidator v	where
+	getErrors	:: v -> [String]	-- ^ Return either null, or the reasons why the data is invalid.
 
-instance SelfValidator a => SelfValidator [a]	where
-	isValid	= all isValid	--NB: a null list is presumed to be OK.
+	isValid		:: v -> Bool		-- ^ The data which implements this interface should return 'True' if internally consistent.
+	isValid	= null . getErrors	--Default implementation.
+
+instance (SelfValidator v) => SelfValidator (Maybe v)	where
+	getErrors (Just v)	= getErrors v
+	getErrors _		= []
+
+instance (SelfValidator a, SelfValidator b) => SelfValidator (a, b)	where
+	getErrors (a, b)	= getErrors a ++ getErrors b
+
+instance SelfValidator v => SelfValidator [v]	where
+	getErrors	= concatMap getErrors
+
+instance SelfValidator v => SelfValidator (Data.Set.Set v)	where
+	getErrors	= Data.Set.fold ((++) . getErrors) []
+
+instance SelfValidator v => SelfValidator (Data.Map.Map k v)	where
+	getErrors	= Data.Map.fold ((++) . getErrors) []
+
+instance (Data.Array.IArray.Ix index, SelfValidator element) => SelfValidator (Data.Array.IArray.Array index element)	where
+	getErrors	= concatMap getErrors . Data.Array.IArray.elems
+
+-- | Returns the first error only (so only call on failure of 'isValid'), since subsequent tests may be based on invalid data.
+getFirstError :: SelfValidator v => v -> String
+getFirstError selfValidator
+	| null errors	= error "ToolShed.SelfValidate.getFirstError:\tzero errors ?!"
+	| otherwise	= head errors
+	where
+		errors	= getErrors selfValidator
+
+-- | Filters failed tests amongst those specified.
+extractErrors :: [(Bool, String)] -> [String]
+extractErrors	= map snd . filter fst
 
diff --git a/src/ToolShed/System/File.hs b/src/ToolShed/System/File.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/System/File.hs
@@ -0,0 +1,96 @@
+
+{-
+	Copyright (C) 2011 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	File-operations.
+-}
+
+module ToolShed.System.File(
+-- * Types
+-- ** Type-synonyms
+	SearchPath,
+	LocatedData,
+-- * Functions
+	locate,
+	getFile,
+	fromFile,
+-- ** Accessors
+	getFilePath,
+	getData
+) where
+
+import			Control.Applicative((<$>))
+import qualified	Control.Exception
+import qualified	Control.Monad
+import qualified	Data.List
+import qualified	System.Directory
+import qualified	System.FilePath
+import			System.FilePath((</>))
+import qualified	System.IO.Error
+
+-- | The ordered sequence of directories, searched for a file.
+type SearchPath	= [System.FilePath.FilePath]
+
+{- |
+	* Locates all instances of the specified file, on the /search-path/.
+
+	* CAVEAT: invalid or duplicate paths are silently removed.
+
+	* CAVEAT: doesn't perform file-globbing.
+-}
+locate :: System.FilePath.FilePath -> SearchPath -> IO [System.FilePath.FilePath]
+locate fileName	= Control.Monad.filterM System.Directory.doesFileExist . filter System.FilePath.isValid . Data.List.nubBy System.FilePath.equalFilePath . map (System.FilePath.normalise . (</> fileName))
+
+-- | A file-path, and the contents read from it.
+type LocatedData a	= (System.FilePath.FilePath, a)
+
+-- | Accessor.
+getFilePath :: LocatedData a -> System.FilePath.FilePath
+getFilePath	= fst
+
+-- | Accessor.
+getData :: LocatedData a -> a
+getData	= snd
+
+{- |
+	Traverse the /search-path/, looking for matching instances of the specified file-name,
+	and either throw an exception, or return a pair composed from the path to the first matching file, together with its contents.
+-}
+getFile :: System.FilePath.FilePath -> SearchPath -> IO (LocatedData String)
+getFile fileName directories	= do
+	filePaths	<- locate fileName directories
+
+	if null filePaths
+		then Control.Exception.throw . System.IO.Error.mkIOError System.IO.Error.doesNotExistErrorType ("Can't find in " ++ show directories) Nothing $ Just fileName
+		else {-located-} let
+			filePath	= head filePaths	--Discard any subsequent paths.
+		in (,) filePath <$> readFile filePath
+
+{- |
+	* Returns the polymorphic data, read from the first matching file on the /search-path/, along with the path from which it was read.
+
+	* Returns an error on failure to parse the contents of the first matching file found on the /search-path/.
+-}
+fromFile :: Read a => System.FilePath.FilePath -> SearchPath -> IO (LocatedData a)
+fromFile fileName directories	= do
+	(filePath, fileContents)	<- getFile fileName directories
+
+	case reads fileContents of
+		[(x, _)]	-> return {-to IO-monad-} (filePath, x)	--CAVEAT: discards any unconsumed text.
+		_		-> error $ "ToolShed.System.File.fromFile:\tfailed to parse file='" ++ filePath ++ "'"
diff --git a/src/ToolShed/System/Random.hs b/src/ToolShed/System/Random.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/System/Random.hs
@@ -0,0 +1,78 @@
+
+{-
+	Copyright (C) 2011 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Utilities related to random-numbers.
+-}
+
+module ToolShed.System.Random(
+-- * Functions
+	randomGens,
+	shuffle,
+	generateSelection,
+	generateSelectionFromBounded,
+	select
+) where
+
+import qualified	Control.Arrow
+import qualified	Data.List
+import qualified	Data.Ord
+import qualified	System.Random
+
+-- | Constructs an infinite list of independent random-generators.
+randomGens :: System.Random.RandomGen randomGen => randomGen -> [randomGen]
+randomGens	= uncurry (:) . Control.Arrow.second randomGens . System.Random.split
+
+{- |
+	* Shuffles the specified finite list.
+
+	* The resulting list has the same length and constituents as the original; only the order has changed.
+
+	* CAVEAT: the implementation /zips/ a list of integers, with the specified polymorphic list, then sorts it,
+	but when identical random integers are generated, the sort-algorithm being /stable/ always return the corresponding items in their original order.
+	The shuffle is therefore imperfect,
+	but on a /64-bit/ machine, it would need such a large list of items, for the probability of randomly generating two identical integers, to be significant,
+	that /sort/ probably wouldn't return in a reasonable time anyway.
+	Ideally, it would be amended to use an /unstable/ sort-algorithm.
+-}
+shuffle :: System.Random.RandomGen randomGen => randomGen -> [a] -> [a]
+shuffle randomGen	= map snd . Data.List.sortBy (Data.Ord.comparing fst) . zip (System.Random.randoms randomGen :: [Int])
+
+{- |
+	* Generate an infinite list of items, each randomly selected from the specified finite list.
+
+	* CAVEAT: because the selections are made non-destructively, duplicates may be returned; cf. 'shuffle'.
+-}
+generateSelection :: System.Random.RandomGen randomGen => randomGen -> [a] -> [a]
+generateSelection randomGen l	= map (l !!) $ System.Random.randomRs (0, pred $ length l) randomGen
+
+-- | Return a random element from the specified list.
+select :: System.Random.RandomGen randomGen => randomGen -> [a] -> a
+select randomGen	= head . generateSelection randomGen
+
+{- |
+	* Generate an infinite list of items, each randomly selected, from the specified finite list of bounded items.
+
+	* Because the selections are made non-destructively, duplicates may be returned.
+
+	* E.g. @ (generateSelectionFromBounded `fmap` System.Random.getStdGen) :: IO [Bool] @.
+-}
+generateSelectionFromBounded :: (System.Random.RandomGen randomGen, Bounded a, System.Random.Random a) => randomGen -> [a]
+generateSelectionFromBounded	= System.Random.randomRs (minBound, maxBound)
+
diff --git a/src/ToolShed/System/TimeAction.hs b/src/ToolShed/System/TimeAction.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/System/TimeAction.hs
@@ -0,0 +1,49 @@
+{-
+	Copyright (C) 2011 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Determines the CPU-time, required to evaluate the specified IO-action.
+
+-}
+
+module ToolShed.System.TimeAction(
+-- * Functions
+	getCPUSeconds,
+	printCPUSeconds
+) where
+
+import qualified	System.CPUTime
+import qualified	System.IO
+
+-- | Time the specified IO-action, returning the required number of CPU-seconds and the result, as a 'Pair'.
+getCPUSeconds :: Fractional seconds => IO result -> IO (seconds, result)
+getCPUSeconds action	= do
+	startTime	<- System.CPUTime.getCPUTime
+	result		<- action
+	endTime		<- System.CPUTime.getCPUTime
+
+	return (fromInteger (endTime - startTime) / 1e12 {-convert from pico-seconds-}, result)
+
+-- | Print the time required by the specified IO-action.
+printCPUSeconds :: IO result -> IO result
+printCPUSeconds action	= do
+	(cpuSeconds, result)	<- getCPUSeconds action
+
+	System.IO.hPutStrLn System.IO.stderr $ "CPU-seconds:\t" ++ show (cpuSeconds :: Double)
+
+	return {-to IO-monad-} result
diff --git a/src/ToolShed/System/TimePure.hs b/src/ToolShed/System/TimePure.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/System/TimePure.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE CPP #-}
+{-
+	Copyright (C) 2010 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Determines the CPU-time, required to evaluate the specified pure expression.
+
+-}
+
+module ToolShed.System.TimePure(
+-- * Functions
+	getCPUSeconds,
+	printCPUSeconds
+) where
+
+import qualified	System.CPUTime
+import qualified	System.IO
+
+{-
+	The function used to force evaluation of the pure expression 'rnf',
+	and the type-class which the polymorphic data must implement 'NFData',
+	has been relocated from module "Control.Parallel.Strategies" to "Control.DeepSeq".
+-}
+#ifdef HAVE_DEEPSEQ
+import			Control.DeepSeq(NFData, deepseq)
+#else
+import			Control.Parallel(pseq)
+import			Control.Parallel.Strategies(NFData, rnf)
+#endif
+
+{- |
+	* Time the specified pure expression, returning the required number of CPU-seconds and the result, as a 'Pair'.
+
+	* CAVEAT: as a side-effect, the expression is /deep/ evaluated.
+-}
+getCPUSeconds :: (Fractional seconds, NFData expression)
+	=> expression			-- ^ Arbitrary polymorphic expression.
+	-> IO (seconds, expression)	-- ^ The original expression, tagged with the CPU-seconds taken.
+getCPUSeconds expression	= do
+	start	<- System.CPUTime.getCPUTime
+	end	<-
+#ifdef HAVE_DEEPSEQ
+		expression `deepseq`
+#else
+		rnf expression `pseq`
+#endif
+			System.CPUTime.getCPUTime
+
+	return {-to IO-monad-} (fromInteger (end - start) / 1e12 {-convert from pico-seconds-}, expression)
+
+{- |
+	* Print the time required by the specified pure expression.
+
+	* CAVEAT: as a side-effect, the expression is /deep/ evaluated.
+-}
+printCPUSeconds :: NFData expression => expression -> IO expression
+printCPUSeconds expression	= do
+	(cpuSeconds, result)	<- getCPUSeconds expression
+
+	System.IO.hPutStrLn System.IO.stderr $ "CPU-seconds:\t" ++ show (cpuSeconds :: Double)
+
+	return {-to IO-monad-} result
+
diff --git a/src/ToolShed/Test/Data/List.hs b/src/ToolShed/Test/Data/List.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/Data/List.hs
@@ -0,0 +1,69 @@
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Defines /QuickCheck/-properties "ToolShed.Data.List".
+-}
+
+module ToolShed.Test.Data.List(
+-- * Functions
+	quickChecks
+) where
+
+import qualified	Data.List
+import qualified	Data.Ord
+import qualified	Data.Set
+import qualified	ToolShed.Data.List
+import qualified	Test.QuickCheck
+import			Test.QuickCheck((==>))
+
+-- | Defines invariant properties.
+quickChecks :: IO ()
+quickChecks =
+	Test.QuickCheck.quickCheck prop_chunk
+	>> Test.QuickCheck.quickCheck `mapM_` [prop_findConvergence, prop_gatherSet]
+	>> Test.QuickCheck.quickCheck prop_gatherBy
+	>> Test.QuickCheck.quickCheck prop_permutations
+	>> Test.QuickCheck.quickCheck prop_linearise
+	>> Test.QuickCheck.quickCheck prop_merge
+	where
+		prop_chunk :: Int -> [Int] -> Test.QuickCheck.Property
+		prop_chunk i l		= Test.QuickCheck.label "prop_chunk" $ concat (ToolShed.Data.List.chunk (succ $ abs i) l) == l
+
+		prop_findConvergence, prop_gatherSet :: Int -> Test.QuickCheck.Property
+		prop_findConvergence	= Test.QuickCheck.label "prop_findConvergence" . (== 0) . ToolShed.Data.List.findConvergence . iterate (fst . (`quotRem` 2))
+		prop_gatherSet n	= Test.QuickCheck.label "prop_gatherSet" . (== l) . concat . ToolShed.Data.List.gather $ Data.Set.fromDistinctAscList l	where
+			l	= [0 .. n `mod` 1024]
+
+		prop_gatherBy :: [Int] -> Test.QuickCheck.Property
+		prop_gatherBy l	= Test.QuickCheck.label "prop_gatherBy" $ map Data.List.sort (
+			ToolShed.Data.List.gatherBy even l
+		 ) == (
+			map Data.List.sort . Data.List.groupBy (ToolShed.Data.List.equalityBy even) $ Data.List.sortBy (Data.Ord.comparing even) l
+		 )
+
+		prop_permutations :: [[Int]] -> Test.QuickCheck.Property
+		prop_permutations l	= not (null l')	==> Test.QuickCheck.label "prop_permutations" $ length (ToolShed.Data.List.permutations l') == product (map length l')	where
+			l'	= take 6 $ map (take 6) l	--Limit the task.
+
+		prop_linearise :: [(Int, Int)] -> Test.QuickCheck.Property
+		prop_linearise l	= Test.QuickCheck.label "prop_linearise" $ map (\[x, y] -> (x, y)) (ToolShed.Data.List.chunk 2 $ ToolShed.Data.List.linearise l) == l
+
+		prop_merge :: [Int] -> [Int] -> Test.QuickCheck.Property
+		prop_merge x y	= Test.QuickCheck.label "prop_merge" $ ToolShed.Data.List.merge (Data.List.sort x) (Data.List.sort y) == Data.List.sort (x ++ y)
+
diff --git a/src/ToolShed/Test/Data/List/Runlength.hs b/src/ToolShed/Test/Data/List/Runlength.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/Data/List/Runlength.hs
@@ -0,0 +1,36 @@
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Defines /QuickCheck/-properties "ToolShed.Data.List.Runlength".
+-}
+
+module ToolShed.Test.Data.List.Runlength(
+-- * Functions
+	quickChecks
+) where
+
+import qualified	ToolShed.Data.List.Runlength
+import qualified	Test.QuickCheck
+
+-- | Defines invariant properties.
+quickChecks :: IO ()
+quickChecks	= Test.QuickCheck.quickCheck prop_runLength where
+	prop_runLength :: [Int] -> Test.QuickCheck.Property
+	prop_runLength l	= Test.QuickCheck.label "prop_runLength" $ ToolShed.Data.List.Runlength.decode (ToolShed.Data.List.Runlength.encode l) == l
+
diff --git a/src/ToolShed/Test/Data/List/Splits.hs b/src/ToolShed/Test/Data/List/Splits.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/Data/List/Splits.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE CPP #-}
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Defines /QuickCheck/-properties "ToolShed.Data.List.Splits".
+-}
+
+module ToolShed.Test.Data.List.Splits(
+-- * Functions
+	quickChecks
+) where
+
+import			Control.Arrow((***))
+import qualified	Data.List
+import qualified	Data.Ord
+import qualified	Data.Set
+import qualified	ToolShed.Data.List.Splits
+import qualified	Test.QuickCheck
+import			Test.QuickCheck((==>))
+
+#if MIN_VERSION_base(4,3,0)
+import	Data.Tuple(swap)
+#else
+-- | Swap the components of a pair.
+swap :: (a, b) -> (b, a)
+swap (a, b)	= (b, a)
+#endif
+
+-- | Defines invariant properties.
+quickChecks :: IO ()
+quickChecks =	Test.QuickCheck.quickCheck prop_splitsFrom where
+	prop_splitsFrom :: Int -> [Int] -> Test.QuickCheck.Property
+	prop_splitsFrom i l	= not (null l) ==> Test.QuickCheck.label "prop_splitsFrom" $ take n (ToolShed.Data.List.Splits.splitsLeftFrom index l) == take n (map (swap . (reverse *** reverse)) . ToolShed.Data.List.Splits.splitsRightFrom (length l - index) $ reverse l)	where
+		index	= i `mod` length l
+		n	= succ index
diff --git a/src/ToolShed/Test/QuickChecks.hs b/src/ToolShed/Test/QuickChecks.hs
new file mode 100644
--- /dev/null
+++ b/src/ToolShed/Test/QuickChecks.hs
@@ -0,0 +1,37 @@
+{-
+	Copyright (C) 2012 Dr. Alistair Ward
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-}
+{- |
+ [@AUTHOR@]	Dr. Alistair Ward
+
+ [@DESCRIPTION@]	Calls the /quickChecks/-functions for modules supporting this feature.
+-}
+
+module ToolShed.Test.QuickChecks(
+-- * Functions
+	run
+) where
+
+import qualified	ToolShed.Test.Data.List
+import qualified	ToolShed.Test.Data.List.Runlength
+import qualified	ToolShed.Test.Data.List.Splits
+
+-- | Run the /quickChecks/-functions for modules supporting this feature.
+run :: IO ()
+run	= putStrLn "Data.List"			>> ToolShed.Test.Data.List.quickChecks
+	>> putStrLn "Data.List.Runlength"	>> ToolShed.Test.Data.List.Runlength.quickChecks
+	>> putStrLn "Data.List.Splits"		>> ToolShed.Test.Data.List.Splits.quickChecks
+
diff --git a/src/ToolShed/TimeAction.hs b/src/ToolShed/TimeAction.hs
deleted file mode 100644
--- a/src/ToolShed/TimeAction.hs
+++ /dev/null
@@ -1,49 +0,0 @@
-{-
-	Copyright (C) 2011 Dr. Alistair Ward
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program.  If not, see <http://www.gnu.org/licenses/>.
--}
-{- |
- [@AUTHOR@]	Dr. Alistair Ward
-
- [@DESCRIPTION@]	Determines the CPU-time, required to evaluate the specified IO-action.
-
--}
-
-module ToolShed.TimeAction(
--- * Functions
-	getCPUSeconds,
-	printCPUSeconds
-) where
-
-import qualified	System.CPUTime
-import qualified	System.IO
-
--- | Time the specified IO-action, returning the seconds and result as a 'Pair'.
-getCPUSeconds :: Fractional seconds => IO result -> IO (seconds, result)
-getCPUSeconds action	= do
-	startTime	<- System.CPUTime.getCPUTime
-	result		<- action
-	endTime		<- System.CPUTime.getCPUTime
-
-	return (fromInteger (endTime - startTime) / 1e12 {-convert from pico-seconds-}, result)
-
--- | Print the time required by the specified IO-action.
-printCPUSeconds :: IO result -> IO result
-printCPUSeconds action	= do
-	(cpuSeconds, result)	<- getCPUSeconds action
-
-	System.IO.hPutStrLn System.IO.stderr $ "CPU-seconds:\t" ++ show (cpuSeconds :: Double)
-
-	return {-to IO-monad-} result
diff --git a/src/ToolShed/TimePure.hs b/src/ToolShed/TimePure.hs
deleted file mode 100644
--- a/src/ToolShed/TimePure.hs
+++ /dev/null
@@ -1,78 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-
-	Copyright (C) 2010 Dr. Alistair Ward
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program.  If not, see <http://www.gnu.org/licenses/>.
--}
-{- |
- [@AUTHOR@]	Dr. Alistair Ward
-
- [@DESCRIPTION@]	Determines the CPU-time, required to evaluate the specified pure expression.
-
--}
-
-module ToolShed.TimePure (
--- * Functions
-	getCPUSeconds,
-	printCPUSeconds
-) where
-
-import qualified	System.CPUTime
-import qualified	System.IO
-
-{-
-	The function used to force evaluation of the pure expression 'rnf',
-	and the type-class which the polymorphic data must implement 'NFData',
-	has been relocated from module "Control.Parallel.Strategies" to "Control.DeepSeq".
--}
-#ifdef HAVE_DEEPSEQ
-import			Control.DeepSeq(NFData, deepseq)
-#else
-import			Control.Parallel(pseq)
-import			Control.Parallel.Strategies(NFData, rnf)
-#endif
-
-{- |
-	* Time the specified pure expression, returning the seconds and result as a 'Pair'.
-
-	* CAVEAT: as a side-effect, the expression is /deep/ evaluated.
--}
-getCPUSeconds :: (Fractional seconds, NFData expression)
-	=> expression			-- ^ Arbitrary polymorphic expression.
-	-> IO (seconds, expression)	-- ^ The original expression, tagged with the CPU-seconds taken.
-getCPUSeconds expression	= do
-	start	<- System.CPUTime.getCPUTime
-	end	<-
-#ifdef HAVE_DEEPSEQ
-		expression `deepseq`
-#else
-		rnf expression `pseq`
-#endif
-			System.CPUTime.getCPUTime
-
-	return {-to IO-monad-} (fromInteger (end - start) / 1e12 {-convert from pico-seconds-}, expression)
-
-{- |
-	* Print the time required by the specified pure expression.
-
-	* CAVEAT: as a side-effect, the expression is /deep/ evaluated.
--}
-printCPUSeconds :: NFData expression => expression -> IO expression
-printCPUSeconds expression	= do
-	(cpuSeconds, result)	<- getCPUSeconds expression
-
-	System.IO.hPutStrLn System.IO.stderr $ "CPU-seconds:\t" ++ show (cpuSeconds :: Double)
-
-	return {-to IO-monad-} result
-
diff --git a/src/ToolShed/Unsafe.hs b/src/ToolShed/Unsafe.hs
deleted file mode 100644
--- a/src/ToolShed/Unsafe.hs
+++ /dev/null
@@ -1,56 +0,0 @@
-{-
-	Copyright (C) 2010 Dr. Alistair Ward
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program.  If not, see <http://www.gnu.org/licenses/>.
--}
-{- |
- [@AUTHOR@]	Dr. Alistair Ward
-
- [@DESCRIPTION@]
-
-	* Provides impure functions to print & return the specified value.
-
-	* The pure interfaces permit calls from outside the /IO-monad/.
-
- [@TODO@]	Review function-names.
--}
-
-module ToolShed.Unsafe(
--- * Functions
-	print',
-	printShow
-) where
-
-import qualified	System.IO
-import qualified	System.IO.Unsafe
-
-{-# NOINLINE print' #-}
--- | A transparent print-function, for use in debugging.
-print' :: Show s
-	=> s	-- ^ Arbitrary polymorphic input-data.
-	-> s	-- ^ Output (identical to input).
-print'	= System.IO.Unsafe.unsafePerformIO . f	where
-	f :: Show s => s -> IO s
-	f x	= System.IO.hPrint System.IO.stderr x	>> return {-to IO-monad-} x
-
-{-# NOINLINE printShow #-}
--- | A transparent print-function, which prepends the specified label, for use in debugging.
-printShow :: Show s
-	=> String	-- ^ The label to be printed before the value of the input data.
-	-> s		-- ^ Arbitrary polymorphic input-data.
-	-> s		-- ^ Output (identical to input).
-printShow label	= System.IO.Unsafe.unsafePerformIO . f label	where
-	f :: Show s => String -> s -> IO s
-	f s x	= System.IO.hPutStrLn System.IO.stderr (s ++ show x)	>> return {-to IO-monad-} x
-
diff --git a/toolshed.cabal b/toolshed.cabal
--- a/toolshed.cabal
+++ b/toolshed.cabal
@@ -1,6 +1,6 @@
 --Package-properties
 Name:			toolshed
-Version:		0.12.0.0
+Version:		0.13.0.0
 Cabal-Version:		>= 1.6
 Copyright:		(C) 2010 Dr. Alistair Ward
 License:		GPL
@@ -30,24 +30,56 @@
     hs-source-dirs:	src
 
     Exposed-modules:
+        ToolShed.Arbitrary.Array
+        ToolShed.Arbitrary.ArrayElem
+        ToolShed.Arbitrary.Map
+        ToolShed.Arbitrary.Set
+        ToolShed.Data.List
+        ToolShed.Data.List.Runlength
+        ToolShed.Data.List.Splits
+        ToolShed.Data.Pair
         ToolShed.Defaultable
-        ToolShed.ListPlus
         ToolShed.Options
-        ToolShed.Pair
         ToolShed.SelfValidate
-        ToolShed.TimeAction
-        ToolShed.TimePure
-        ToolShed.Unsafe 
+        ToolShed.System.File
+        ToolShed.System.Random
+        ToolShed.System.TimeAction
+        ToolShed.System.TimePure
 
-    Build-depends:	base == 4.*
+    Build-depends:
+        array,
+        base == 4.*,
+        containers,
+        directory,
+        filepath,
+        QuickCheck >= 2.2,
+        random
 
     GHC-options:	-Wall -O2
-    GHC-prof-options:	-prof -auto-all -caf-all
 
+    if impl(ghc >= 7.4.1)
+        GHC-prof-options:	-prof -fprof-auto -fprof-cafs
+    else
+        GHC-prof-options:	-prof -auto-all -caf-all
+
     if flag(haveDeepSeq)
         Build-depends:	deepseq >= 1.1
         CPP-options:	-DHAVE_DEEPSEQ
 
     if impl(ghc >= 7.0) && flag(llvm)
         GHC-options:	-fllvm
+
+Executable toolshed
+    hs-source-dirs:	src
+
+    Main-Is:		Main.hs
+
+    Other-modules:
+        ToolShed.Test.QuickChecks
+        ToolShed.Test.Data.List
+        ToolShed.Test.Data.List.Runlength
+        ToolShed.Test.Data.List.Splits
+
+    Build-depends:
+        Cabal >= 1.6 && < 2
 
