diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2008, Alex Drummond.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer. Redistributions
+in binary form must reproduce the above copyright notice, this list of
+conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution. The name of the author
+may not be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/RJson.cabal b/RJson.cabal
new file mode 100644
--- /dev/null
+++ b/RJson.cabal
@@ -0,0 +1,29 @@
+Name:          RJson
+Version:       0.1
+Cabal-Version: >= 1.2
+License:       BSD3
+License-File:  LICENSE
+Author:        Alex Drummond
+Maintainer:    a.d.drummond@gmail.com
+Category:      Text
+Synopsis:      A reflective JSON serializer/parser.
+Stability:     experimental
+
+Description:
+  This package uses the Scrap Your Boilerplate With Class approach
+  to generics to implement a reflective Json serializer and deserializer.
+  Nested record types can be automatically converted to corresponding
+  JSON objects and vice versa. In both cases, various aspects of
+  serializing and deserializing can be customized by implementing instances of
+  type classes. Note that only Haskell 98 types can be
+  serialized and deserialized, and that the use of strict constructors will lead
+  to runtime errors with the current implemetation. Apart from the
+  reflective stuff, the package also provides a straightforward
+  Haskell representation of JSON data, together with a unicode-safe
+  parser and a suitable implementation of 'show'. The code hasn't yet
+  been tested for performance; it might be quite slow.
+
+Library
+  Build-Depends:	base, mtl, parsec, bytestring, iconv, array, containers, syb-with-class
+  Exposed-modules:      Text.RJson
+  Extensions:           FlexibleInstances OverlappingInstances MultiParamTypeClasses FlexibleContexts UndecidableInstances
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/Text/RJson.hs b/Text/RJson.hs
new file mode 100644
--- /dev/null
+++ b/Text/RJson.hs
@@ -0,0 +1,750 @@
+module Text.RJson (TranslateField,
+                   TranslateFieldD,
+                   translateField,
+                   ToJson,
+                   ToJsonD,
+                   toJson,
+                   exclude,
+                   arrayPrepend,
+                   arrayAppend,
+                   objectExtras,
+                   genericToJson,
+                   JsonData(..),
+                   FromJson,
+                   FromJsonD,
+                   objectDefaults,
+                   parseJsonString,
+                   parseJsonByteString,
+                   fromJsonString,
+                   fromJsonByteString,
+                   genericFromJson,
+                   stripInitialUnderscores,
+                   toJsonString,
+                   Union(..), Union3, Union4, Union5, Union6,
+                   Union7,Union8,Union9,Union10)
+where
+
+import Data.Generics.SYB.WithClass.Basics
+import Data.Generics.SYB.WithClass.Instances
+import Data.Generics.SYB.WithClass.Context
+import Data.Generics.SYB.WithClass.Derive
+import qualified Data.Map as M
+import qualified Text.Printf as Printf
+import Data.Char
+import Data.Ratio
+import Data.Array
+import Data.Maybe
+import Control.Monad.State.Strict
+import Control.Monad.Trans
+import Control.Monad.Error
+import qualified Text.ParserCombinators.Parsec as P
+import qualified Data.ByteString.Lazy as B
+import System.IO.Unsafe
+import qualified Control.Exception as E
+import Codec.Text.IConv
+import qualified Data.Word as W
+
+
+-- | A Haskell representation of a JSON
+--   data structure.
+data JsonData = JDString String                       |
+                JDNumber Double                       |
+                JDArray [JsonData]                    |
+                JDBool Bool                           |
+                JDObject (M.Map String JsonData)
+
+listJoin :: a -> [a] -> [a]
+listJoin _ [] = []
+listJoin _ l@[x] = l
+listJoin k (x:ys) = x : k : (listJoin k ys)
+
+concatJoin :: String -> [String] -> String
+concatJoin k l = concat (listJoin k l)
+
+alistToJsonDict :: [(String, String)] -> String
+alistToJsonDict l =
+    "{" ++
+    concatJoin "," (map (\(k,v) -> (escapeString k) ++ ":" ++ v) l)
+    ++ "}"
+
+-- Special characters which will be pretty printed.
+escapeMap :: M.Map Char String
+escapeMap = M.fromList [
+    ('\\', "\\"), ('"', "\""), ('\'', "'"), ('\n', "n"),
+    ('\r', "r"), ('\f', "f"), ('\t', "t"), ('\b', "\b")]
+escape :: Char -> Maybe String
+escape c = M.lookup c escapeMap
+
+-- Characters which can safely be printed as literals.
+allowed' c o
+  | o > 127 = True -- Any unicode char is OK.
+  | o >= 32 && o < 127 {- exclude DEL == 127 -} && c /= '"' = True
+  | True = False
+allowed c = allowed' c (ord c)
+
+hexEscape :: Char -> String
+hexEscape c = Printf.printf "\\u%04x" (ord c)
+
+escapeString' :: String -> String
+escapeString' [] = "\""
+escapeString' (c:cs)
+    | allowed c =
+        c : (escapeString' cs)
+    | True =
+        (maybe (hexEscape c) (\s -> "\\" ++ s) (escape c)) ++
+        (escapeString' cs)
+
+escapeString s = '"' : escapeString' s
+
+instance Show JsonData where
+    show (JDString s)   = escapeString s
+    show (JDNumber n)
+        -- Show as an integer if possible, otherwise as a Double.
+        -- TODO: Not sure if this is the proper way of testing whether a
+        --       double is an integer value +/- epsilon.
+        | (fromIntegral (floor n)) == n = show (floor n)
+        | True                          = show n
+    show (JDBool True)  = "true"
+    show (JDBool False) = "false"
+    show (JDArray l)    = "[" ++ concatJoin "," (map show l) ++ "]"
+    show (JDObject o)   = alistToJsonDict (map (\(k,v) -> (k, show v)) (M.toList o))
+
+
+--
+-- TranslateField class.
+--
+class TranslateField a where
+    -- | By default, Haskell record field names are converted into
+    --   JSON object field names by stripping any initial underscores.
+    --   Specialize this method to define a different behavior.
+    translateField :: a -> String -> String
+
+data TranslateFieldD a = TranslateFieldD { translateFieldD :: a -> String -> String }
+
+translateFieldProxy :: Proxy TranslateFieldD
+translateFieldProxy = error "'translateFieldProxy' value should never be evaluated!"
+
+instance (TranslateField t) => Sat (TranslateFieldD t) where
+    dict = TranslateFieldD { translateFieldD = translateField }
+
+-- | Removes initial underscores from a string.
+stripInitialUnderscores ""      = ""
+stripInitialUnderscores ('_':s) = stripInitialUnderscores s
+stripInitialUnderscores s       = s
+
+instance (Data TranslateFieldD a) => TranslateField a where
+    translateField _ x = stripInitialUnderscores x
+
+
+--
+-- ToJson class plus SYB boilerplate.
+--
+-- | New instances can be added to this class to customize
+--   JSON serialization.
+class ToJson a where
+    toJson :: a -> JsonData
+
+    -- For lists (same trick used by the Prelude to allow special
+    -- handling of list types for Show).
+    lToJson  :: [a] -> JsonData
+    lToJson l = JDArray (map toJson l)
+
+    -- | You can specialize this method to prevent fields from being serialized.
+    --   The method should return a list of the Haskell names of the fields to
+    --   be excluded.
+    exclude  :: a -> String -> Bool
+    exclude _ _ = False
+
+    -- | Types that will be converted to JSON arrays can override
+    --   this method to specify additional elements to be prepended to the array.
+    arrayPrepend :: a -> [JsonData]
+    arrayPrepend _ = []
+
+    -- | Types that will be converted to JSON arrays can override
+    --   this method to specify additional elements to be appended to the array.
+    arrayAppend :: a -> [JsonData]
+    arrayAppend _ = []
+
+    -- | Types that will be converted to JSON objects can override
+    --   this method to specify additional fields of the object.
+    objectExtras :: a -> [(String, JsonData)]
+    objectExtras _ = []
+
+-- Note the inclusion of translateField from TranslateField.
+data ToJsonD a = ToJsonD { toJsonD          :: a -> JsonData,
+                           excludeD         :: a -> String -> Bool,
+                           arrayPrependD    :: a -> [JsonData],
+                           arrayAppendD     :: a -> [JsonData],
+                           objectExtrasD    :: a -> [(String, JsonData)],
+                           translateFieldD' :: a -> String -> String }
+
+toJsonProxy :: Proxy ToJsonD
+toJsonProxy = error "'toJsonProxy' value should never be evaluated!"
+
+-- Again, note inclusion of translateField from TranslateField,
+-- and TranslateField qualification on variable 't' (in addition
+-- to the expected ToJson qualification).
+instance (TranslateField t, ToJson t) => Sat (ToJsonD t) where
+    dict = ToJsonD { toJsonD          = toJson,
+                     excludeD         = exclude,
+                     arrayPrependD    = arrayPrepend,
+                     arrayAppendD     = arrayAppend,
+                     objectExtrasD    = objectExtras,
+                     translateFieldD' = translateField }
+
+
+--
+-- Implementations of toJson for different data types.
+--
+instance ToJson Bool where
+    toJson b = JDBool b
+
+instance ToJson Int where
+    toJson i = JDNumber (fromIntegral i)
+instance ToJson Integer where
+    toJson i = JDNumber (fromIntegral i)
+--instance Json Float where
+--    toJson i = JDNumber (floatToDouble i)
+instance ToJson Double where
+    toJson i = JDNumber i
+instance Integral a => ToJson (Ratio a) where
+    toJson i = JDNumber $ (fromIntegral (numerator i)) / (fromIntegral (denominator i))
+                        
+instance ToJson Char where
+    lToJson s = JDString s
+    toJson c = JDString [c]
+
+instance ToJson a => ToJson (M.Map String a) where
+    toJson x = JDObject (M.map toJson x)
+
+instance (Typeable a, ToJson a) => ToJson [a] where
+    toJson = lToJson
+
+-- TODO: Add instances for the other array types supported by GHC.
+instance (Typeable a, ToJson a, Ix i) => ToJson (Array i a) where
+    toJson a = toJson (elems a)
+
+-- | Use this for merging two or more records together.
+--   Sensible instances of FromJson and ToJson are already defined for this type.
+data Union a b = Union a b deriving Show
+-- | Nested Unions are left-branching by convention (since this is what you get
+--   by using the constructor as an infix operator).
+type Union3 a b c = (Union (Union a b) c)
+type Union4 a b c d = (Union (Union3 a b c) d)
+type Union5 a b c d e = (Union (Union4 a b c d) e)
+type Union6 a b c d e f = (Union (Union5 a b c d e) f)
+type Union7 a b c d e f g = (Union (Union6 a b c d e f) g)
+type Union8 a b c d e f g h = (Union (Union7 a b c d e f g) h)
+type Union9 a b c d e f g h i = (Union (Union8 a b c d e f g h) i)
+type Union10 a b c d e f g h i j = (Union (Union9 a b c d e f g h i) j)
+
+-- Used by the (ToJson Union) instance below.
+isJDObject (JDObject _) = True
+isJDObject _            = False
+jdObjectMap (JDObject m) = m
+
+instance (ToJson a, ToJson b) => ToJson (Union a b) where
+    toJson (Union x y) =
+        let jx = toJson x
+            jy = toJson y
+        in
+          if isJDObject jx && isJDObject jy
+              then JDObject (M.union (jdObjectMap jx) (jdObjectMap jy))
+              else error "Bad toJson conversion: Attempt to unify JSON values which aren't both objects"
+
+getFields :: Data ToJsonD a => a -> [String]
+getFields = constrFields . (toConstr toJsonProxy)
+
+typename x = dataTypeName (dataTypeOf toJsonProxy x)
+
+-- | This is the implementation of 'toJson' for the generic instance declaration,
+-- but it's useful to be able to use the same implentation for
+-- other instance declarations which override the default implementation
+-- of 'exclude'.
+genericToJson :: (Data ToJsonD a, ToJson a, TranslateField a) => a -> JsonData
+genericToJson x
+        | isAlgType (dataTypeOf toJsonProxy x) =
+            case (map (translateFieldD' dict x) (filter (not . (excludeD dict x)) (getFields x))) of
+              [] -> JDArray $
+                      arrayPrependD dict x ++
+                      (JDString (dataTypeName (dataTypeOf toJsonProxy x)) :
+                       (gmapQ toJsonProxy (toJsonD dict) x)) ++
+                      arrayAppendD dict x
+              fs -> JDObject (M.fromList (objectExtrasD dict x ++ (zip fs (gmapQ toJsonProxy (toJsonD dict) x))))
+        | True =
+            error ("Unable to serialize the primitive type '" ++ typename x ++ "'")
+
+instance (Data ToJsonD t, TranslateField t) => ToJson t where
+    toJson = genericToJson
+
+-- Instances for tuples up to n=10.
+-- Tuples are converted to (hetrogenous) JSON lists.
+instance (ToJson a, ToJson b) => ToJson (a, b) where
+    toJson (a,b) = JDArray [toJson a, toJson b]
+instance (ToJson a, ToJson b, ToJson c) => ToJson (a,b,c) where
+    toJson (a,b,c) = JDArray [toJson a, toJson b, toJson c]
+instance (ToJson a, ToJson b, ToJson c, ToJson d) => ToJson (a,b,c,d) where
+    toJson (a,b,c,d) = JDArray [toJson a, toJson b, toJson c, toJson d]
+instance (ToJson a, ToJson b, ToJson c, ToJson d, ToJson e) => ToJson (a,b,c,d,e) where
+    toJson (a,b,c,d,e) = JDArray [toJson a, toJson b, toJson c, toJson d, toJson e]
+instance (ToJson a, ToJson b, ToJson c, ToJson d, ToJson e, ToJson f) =>
+         ToJson (a,b,c,d,e,f) where
+    toJson (a,b,c,d,e,f) = JDArray [toJson a, toJson b, toJson c, toJson d, toJson e,
+                                   toJson f]
+instance (ToJson a, ToJson b, ToJson c, ToJson d, ToJson e, ToJson f, ToJson g) =>
+         ToJson (a,b,c,d,e,f,g) where
+    toJson (a,b,c,d,e,f,g) = JDArray [toJson a, toJson b, toJson c, toJson d, toJson e,
+                                     toJson f, toJson g]
+instance (ToJson a, ToJson b, ToJson c, ToJson d, ToJson e, ToJson f, ToJson g, ToJson h) =>
+         ToJson (a,b,c,d,e,f,g,h) where
+    toJson (a,b,c,d,e,f,g,h) = JDArray [toJson a, toJson b, toJson c, toJson d, toJson e,
+                                       toJson f, toJson g, toJson h]
+instance (ToJson a, ToJson b, ToJson c, ToJson d, ToJson e, ToJson f, ToJson g, ToJson h, ToJson i) =>
+         ToJson (a,b,c,d,e,f,g,h,i) where
+    toJson (a,b,c,d,e,f,g,h,i) = JDArray [toJson a, toJson b, toJson c, toJson d, toJson e,
+                                         toJson f, toJson g, toJson h, toJson i]
+instance (ToJson a, ToJson b, ToJson c, ToJson d, ToJson e, ToJson f, ToJson g, ToJson h, ToJson i, ToJson j) =>
+         ToJson (a,b,c,d,e,f,g,h,i,j) where
+    toJson (a,b,c,d,e,f,g,h,i,j) = JDArray [toJson a, toJson b, toJson c, toJson d, toJson e,
+                                           toJson f, toJson g, toJson h, toJson i, toJson j]
+
+
+--
+-- FromJson
+--
+class FromJson a where
+    fromJson :: a -> JsonData -> Either String a
+
+    -- For lists (same trick used by the Prelude to allow special
+    -- handling of list types for Show).
+    lFromJson :: a -> JsonData -> Either String [a]
+    lFromJson dummy (JDArray l) = mapM (fromJson dummy) l
+
+    -- | In order to specify default values for required fields of a JSON object,
+    --   specialize this method in the instance definition for the relevant
+    --   datatype.
+    objectDefaults :: a -> M.Map String JsonData
+    objectDefaults _ = M.empty
+
+data FromJsonD a = FromJsonD { fromJsonD         :: a -> JsonData -> Either String a,
+                               objectDefaultsD   :: a -> M.Map String JsonData,
+                               translateFieldD'' :: a -> String -> String }
+
+fromJsonProxy :: Proxy FromJsonD
+fromJsonProxy = error "'fromJsonProxy' should never be evaluated!"
+
+instance (FromJson t, TranslateField t) => Sat (FromJsonD t) where
+    dict = FromJsonD { fromJsonD = fromJson,
+                       objectDefaultsD = objectDefaults,
+                       translateFieldD'' = translateField }
+
+instance FromJson Char where
+    fromJson _ (JDString [c]) = Right c
+    fromJson _ _              = Left "Bad fromJson conversion: JSON string not of length 1 to 'Char'"
+
+    lFromJson _ (JDString s) = Right s
+    lFromJson _ _            = Left "Bad fromJson conversion: Non-string to 'String'"
+
+instance FromJson a => FromJson [a] where
+    fromJson _ x = lFromJson undefined x
+
+instance FromJson Int where
+    fromJson _ (JDNumber n)
+      | (fromIntegral (floor n)) == n = Right (floor n)
+      | True =
+          Left "Bad fromJson conversion: number does not approximate an integer ('Int')"
+    fromJson _ _ = Left "Bad fromJson conversion: Non-numeric to 'Int'"
+
+instance FromJson Integer where
+    fromJson _ (JDNumber n)
+      | (fromIntegral (floor n)) == n = Right (floor n)
+      | True =
+          Left "Bad fromJson conversion: number does not approximate an integer ('Integer')"
+    fromJson _ _ = Left "Bad fromJson conversion: Non-numeric to 'Integer'"
+
+instance FromJson Double where
+    fromJson _ (JDNumber d) = Right d
+    fromJson _ _            = Left "Bad fromJson conversion: Non-numeric to 'Double'"
+
+instance Integral a => FromJson (Ratio a) where
+    fromJson _ (JDNumber i) = Right (fromRational (toRational i))
+    fromJson _ _            = Left "Bad fromJson conversion: Non-numeric to instance of 'Ratio'"
+
+instance FromJson Bool where
+    fromJson _ (JDBool b) = Right b
+    fromJson _ _          = Left "Bad fromJson conversion: Non-boolean to 'Bool'"
+
+isRight (Right _) = True
+isRight _         = False
+fromRight (Right x) = x
+-- TODO: Use monads instead of 'ifs' if possible (funky type errors
+-- which I haven't figured out yet, something to do with monomorphism
+-- in let bindings vs. lambda abstraction?).
+instance (FromJson a, FromJson b) => FromJson (Union a b) where
+    fromJson _ o@(JDObject _) =
+        let r1 = fromJson undefined o
+            r2 = fromJson undefined o
+        in
+          if isRight r1 && isRight r2
+             then Right $ Union (fromRight r1) (fromRight r2)
+             else Left "Bad fromJson conversion: error constructing subpart of union"
+    fromJson _ _ = Left "Bad fromJson conversion: attempt to convert non-object to Union"
+
+tuperror :: Int -> Either String a
+tuperror n = Left $ Printf.printf "Bad fromJson conversion: attempt to convert something that was not a list of length %i to a %i-tuple" n n
+
+instance (FromJson a, FromJson b) => FromJson (a,b) where
+    fromJson _ (JDArray [x1,x2]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      return (r1,r2)
+    fromJson _ _ = tuperror 2
+instance (FromJson a, FromJson b, FromJson c) => FromJson (a,b,c) where
+    fromJson _ (JDArray [x1,x2,x3]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      r3 <- fromJson undefined x3
+      return (r1,r2,r3)
+    fromJson _ _ = tuperror 3
+instance (FromJson a, FromJson b, FromJson c, FromJson d) => FromJson(a,b,c,d) where
+    fromJson _ (JDArray [x1,x2,x3,x4]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      r3 <- fromJson undefined x3
+      r4 <- fromJson undefined x4
+      return (r1,r2,r3,r4)
+    fromJson _ _ = tuperror 4
+instance (FromJson a, FromJson b, FromJson c, FromJson d, FromJson e) => FromJson (a,b,c,d,e) where
+    fromJson _ (JDArray [x1,x2,x3,x4,x5]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      r3 <- fromJson undefined x3
+      r4 <- fromJson undefined x4
+      r5 <- fromJson undefined x5
+      return (r1,r2,r3,r4,r5)
+    fromJson _ _ = tuperror 5
+instance (FromJson a, FromJson b, FromJson c, FromJson d, FromJson e, FromJson f) =>
+         FromJson (a,b,c,d,e,f) where
+    fromJson _ (JDArray [x1,x2,x3,x4,x5,x6]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      r3 <- fromJson undefined x3
+      r4 <- fromJson undefined x4
+      r5 <- fromJson undefined x5
+      r6 <- fromJson undefined x6
+      return (r1,r2,r3,r4,r5,r6)
+    fromJson _ _ = tuperror 6
+instance (FromJson a, FromJson b, FromJson c, FromJson d, FromJson e, FromJson f, FromJson g) =>
+         FromJson (a,b,c,d,e,f,g) where
+    fromJson _ (JDArray [x1,x2,x3,x4,x5,x6,x7]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      r3 <- fromJson undefined x3
+      r4 <- fromJson undefined x4
+      r5 <- fromJson undefined x5
+      r6 <- fromJson undefined x6
+      r7 <- fromJson undefined x7
+      return (r1,r2,r3,r4,r5,r6,r7)
+    fromJson _ _ = tuperror 7
+instance (FromJson a, FromJson b, FromJson c, FromJson d, FromJson e, FromJson f, FromJson g, FromJson h) =>
+         FromJson (a,b,c,d,e,f,g,h) where
+    fromJson _ (JDArray [x1,x2,x3,x4,x5,x6,x7,x8]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      r3 <- fromJson undefined x3
+      r4 <- fromJson undefined x4
+      r5 <- fromJson undefined x5
+      r6 <- fromJson undefined x6
+      r7 <- fromJson undefined x7
+      r8 <- fromJson undefined x8
+      return (r1,r2,r3,r4,r5,r6,r7,r8)
+    fromJson _ _ = tuperror 8
+instance (FromJson a, FromJson b, FromJson c, FromJson d, FromJson e, FromJson f, FromJson g, FromJson h, FromJson i) =>
+         FromJson (a,b,c,d,e,f,g,h,i) where
+    fromJson _ (JDArray [x1,x2,x3,x4,x5,x6,x7,x8,x9]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      r3 <- fromJson undefined x3
+      r4 <- fromJson undefined x4
+      r5 <- fromJson undefined x5
+      r6 <- fromJson undefined x6
+      r7 <- fromJson undefined x7
+      r8 <- fromJson undefined x8
+      r9 <- fromJson undefined x9
+      return (r1,r2,r3,r4,r5,r6,r7,r8,r9)
+    fromJson _ _ = tuperror 9
+instance (FromJson a, FromJson b, FromJson c, FromJson d, FromJson e, FromJson f, FromJson g, FromJson h, FromJson i, FromJson j) =>
+         FromJson (a,b,c,d,e,f,g,h,i,j) where
+    fromJson _ (JDArray [x1,x2,x3,x4,x5,x6,x7,x8,x9,x10]) = do
+      r1 <- fromJson undefined x1
+      r2 <- fromJson undefined x2
+      r3 <- fromJson undefined x3
+      r4 <- fromJson undefined x4
+      r5 <- fromJson undefined x5
+      r6 <- fromJson undefined x6
+      r7 <- fromJson undefined x7
+      r8 <- fromJson undefined x8
+      r9 <- fromJson undefined x9
+      r10 <- fromJson undefined x10
+      return (r1,r2,r3,r4,r5,r6,r7,r8,r9,r10)
+    fromJson _ _ = tuperror 10
+
+elemsOfMap :: Ord k => M.Map k v -> [k] -> Maybe [v]
+elemsOfMap _ [] = Just []
+elemsOfMap m (x:xs) = do
+  r <- M.lookup x m
+  rs <- elemsOfMap m xs
+  return (r : rs)
+
+type ErrorWithState e s a = ErrorT e (State s) a
+
+-- TODO: Not a very descriptive name. Oh well...
+m1 :: (Data FromJsonD a) => a -> ErrorWithState String [JsonData] a
+m1 dummy = do
+  jvl <- lift get
+  (case jvl of
+     []       -> throwError "Bad fromJson conversion: Not enough elements in JSON array to satisfy constructor"
+     (jv:jvs) -> do
+       lift $ put jvs
+       (case fromJsonD dict dummy jv of
+          Left e  -> throwError e
+          Right x -> return x))
+
+-- TODO: Again, uninformative name.
+-- TODO: Some code duplication here.
+m2 :: (Data FromJsonD a) => M.Map String JsonData -> a -> ErrorWithState String (M.Map String JsonData, [String]) a
+m2 defaults dummy = do
+  (m, sl) <- lift get
+  (case sl of
+     []     -> throwError "Bad fromJson conversion: Not enough fields in JSON object to satisfy constructor"
+     (f:fs) -> do
+       lift $ put (m, fs)
+       let stripped = translateFieldD'' dict dummy f
+       (case M.lookup stripped m of
+          Nothing ->
+            case M.lookup stripped defaults of
+              Nothing -> throwError $  "Bad fromJson conversion: Required field not present in JSON object" ++ stripped
+              Just v  ->
+                case fromJsonD dict dummy v of
+                  Left e  -> throwError e
+                  Right x -> return x
+          Just v ->
+            case fromJsonD dict dummy v of
+              Left e  -> throwError e
+              Right x -> return x))
+
+genericFromJson :: Data FromJsonD a => a -> JsonData -> Either String a
+genericFromJson _     (JDArray []) = Left "Bad fromJson conversion: JSON array must contain at least one element"
+genericFromJson dummy (JDArray l) =
+    case datarep (dataTypeOf fromJsonProxy dummy) of
+      AlgRep (c:_) ->
+          evalState (runErrorT (gmapM fromJsonProxy m1 (fromConstr fromJsonProxy c))) (tail l)
+      AlgRep _     -> Left "Bad fromJson conversion: Type with no constructors!"
+      _            -> Left "Bad fromJson conversion: Non-algebraic datatype given to 'genericFromJson'"
+genericFromJson dummy (JDObject m) =
+    case datarep (dataTypeOf fromJsonProxy dummy) of
+      AlgRep (c:_) ->
+          case constrFields c of
+            [] -> Left "Bad fromJson conversion: Attempt to convert JDObect to a non-record algebraic type"
+            fs -> evalState (runErrorT (gmapM fromJsonProxy (m2 (objectDefaultsD dict dummy)) (fromConstr fromJsonProxy c))) (m, fs)
+      AlgRep _     -> Left "Bad fromJson conversion: Type with no constructors!"
+      _            -> Left "Bad fromJson conversion: Non-algebraic datatype given to 'genericFromJson'"
+          
+instance (Data FromJsonD t) => FromJson t where
+    fromJson = genericFromJson
+
+
+--
+-- JSON parser.
+--
+
+-- Determine the unicode encoding of a byte stream
+-- on the assumption that it begins with two ASCII characters.
+getEncoding :: B.ByteString -> EncodingName
+getEncoding s
+  | B.length s < 4 = "UTF-8" -- If the string is shorter than 4 bytes,
+                             -- we have no way of determining the encoding.
+  | True =
+      let bs1 = B.index s 0
+          bs2 = B.index s 1
+          bs3 = B.index s 2
+          bs4 = B.index s 3
+      in
+        -- Little endian UTF 32/16.
+        if bs1 /= 0 && bs2 == 0 && bs3 == 0 && bs4 == 0
+        then "UTF-32LE"
+        else if bs1 /= 0 && bs2 == 0 && bs3 /= 0 && bs4 == 0
+        then "UTF-16LE"
+        -- Big endian UTF 32/16.
+        else if bs1 == 0 && bs2 == 0 && bs3 == 0 && bs4 /= 0
+        then "UTF-32BE"
+        else if bs1 == 0 && bs2 /= 0 && bs3 == 0 && bs4 /= 0
+        then "UTF-16BE"
+        -- UTF-8
+        else if bs1 /= 0 && bs2 /= 0 && bs3 /= 0 && bs4 /= 0
+        then "UTF-8" -- BOM allowed but not required for UTF-8.
+        -- If we can't figure it out, guess at UTF-8.
+        else "UTF-8"
+
+-- Converts a String of byte values of given encoding to a String of unicode code points.
+toHaskellString :: EncodingName -> B.ByteString -> String
+toHaskellString enc source =
+    stripBOM $ map chr (pairBytes (B.unpack bs))
+    where
+      pairBytes :: [W.Word8] -> [Int]
+      pairBytes [] = []
+      pairBytes (c:c':cs) = ((fromIntegral c) + (fromIntegral c')*256) : (pairBytes cs)
+      bs = convertFuzzy Discard enc "UTF-16LE" source
+
+stripBOM :: String -> String
+stripBOM ('\0':'\0':'\xFE':'\xFF':cs) = cs
+stripBOM ('\xFF':'\xFE':'\0':'\0':cs) = cs
+stripBOM ('\xFE':'\xFF':cs)           = cs
+stripBOM ('\xFF':'\xFE':cs)           = cs
+stripBOM ('\xEF':'\xBB':'\xBF':cs)    = cs
+stripBOM cs                           = cs
+
+(<|>) = (P.<|>)
+
+-- | Converts a ByteString to an instance of JsonData (unicode encoding
+--   is detected automatically).
+parseJsonByteString :: B.ByteString -> Either String JsonData
+parseJsonByteString bs =
+    let
+        decoded = toHaskellString (getEncoding bs) bs
+    in
+      case P.runParser (ws >> jsonValue) () "" decoded of
+        Left e -> Left (show e)
+        Right x -> Right x
+
+-- | Converts a String (interpreted as a true unicode String) to an instance
+--   of JsonData.
+parseJsonString :: String -> Either String JsonData
+parseJsonString s =
+    case P.runParser (ws >> jsonValue) () "" s of
+      Left e -> Left (show e)
+      Right x -> Right x
+
+apply f p = do
+  r <- p
+  return (f r)
+
+pconcat p1 p2 = do
+  l1 <- p1
+  l2 <- p2
+  return $ l1 ++ l2
+
+listify :: P.Parser x -> P.Parser [x]
+listify = apply (:[])
+
+ws = P.many (P.oneOf [' ','\r','\n','\t','\f','\v'])
+
+-- Could use the ParsecToken module, but trying a floating point number
+-- then an integer is a bit inefficient (especially since integers will
+-- be more common).
+number :: P.Parser JsonData
+number = do
+  i <- P.many1 P.digit
+  point <- P.option Nothing (apply Just (P.char '.' >> P.many1 P.digit))
+  exponent <- P.option Nothing (apply Just (P.char 'e' >> pconcat (P.option "" (listify (P.char '-'))) (P.many1 P.digit)))
+  (if point == Nothing && exponent == Nothing
+      then return (JDNumber (read i :: Double))
+      else return (
+          JDNumber (
+              read (i ++ (if point == Nothing then "" else "." ++ fromJust point) ++
+                         (if exponent == Nothing then "" else "e" ++ fromJust exponent))
+              :: Double
+      )))
+
+stringChar :: Char -> P.Parser Char
+stringChar opener = do
+  -- Fail immediately on either single or double quotes or
+  -- on control characters.
+  c <- P.satisfy (\c -> c /= opener && (ord c) > 31)
+  (case c of
+     '\\' ->
+         (P.char '"' >> return '"')   <|>
+         (P.char '\'' >> return '\'') <|>
+         (P.char 'b' >> return '\b')  <|>
+         (P.char 'f' >> return '\f')  <|>
+         (P.char 'n' >> return '\n')  <|>
+         (P.char 'r' >> return '\r')  <|>
+         (P.char 't' >> return '\t')  <|>
+         (do
+           P.char 'u'
+           ds <- P.count 4 P.hexDigit
+           return $ chr (read ("0x" ++ ds) :: Int)) <|>
+         (P.satisfy allowed >>= return) -- "\X" == "X" by default.
+     c -> return c)
+
+string :: P.Parser String
+string = do
+  opener <- P.char '"' <|> P.char '\'' -- JSON spec requires double quotes, but we'll be lenient.
+  cs <- P.many (stringChar opener)
+  P.char opener
+  return cs
+
+jsonString = apply JDString string
+
+kvp :: P.Parser (String, JsonData)
+kvp = do
+  s <- string
+  ws
+  P.char ':'
+  ws
+  v <- jsonValue
+  return (s, v)
+
+jsonArray :: P.Parser JsonData
+jsonArray = do
+  P.char '['
+  ws
+  vs <- P.sepBy jsonValue (ws >> P.char ',' >> ws)
+  ws
+  P.char ']'
+  return $ JDArray vs
+
+object :: P.Parser JsonData
+object = do
+    P.char '{'
+    ws
+    kvps <- P.sepBy kvp (ws >> P.char ',' >> ws)
+    ws
+    P.char '}'
+    return $ JDObject $ M.fromList kvps
+
+boolean :: P.Parser JsonData
+boolean = (P.try (P.string "true") >> return (JDBool True)) <|>
+          (P.string "false" >> return (JDBool False))
+
+jsonValue = number <|> jsonString <|> jsonArray <|> object <|> boolean
+
+
+--
+-- Some other utilities.
+--
+-- | Converts a JSON String (interpreted as a true unicode string) to
+--   a value of the type given by the first (dummy) argument.
+fromJsonString :: FromJson a => a -> String -> Either String a
+fromJsonString dummy s =
+    case parseJsonString s of
+      Left e -> Left (show e)
+      Right js ->
+          case fromJson dummy js of
+            Left e -> Left e
+            Right js -> Right js
+
+-- | Converts a JSON ByteString (with unicode encoding automatically detected)
+--   to a value of the type given by the first (dummy) argument.
+fromJsonByteString :: FromJson a => a -> B.ByteString -> Either String a
+fromJsonByteString dummy s =
+    case parseJsonByteString s of
+      Left e -> Left (show e)
+      Right js ->
+          case fromJson dummy js of
+            Left e -> Left e
+            Right js -> Right js
+
+-- | Converts a value to an ASCII-only JSON String.
+toJsonString :: ToJson a => a -> String
+toJsonString = show . toJson
