@@ -5,16 +5,19 @@
5{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE GADTs #-}
6{-# LANGUAGE GADTs #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE NamedFieldPuns #-}
8{-# LANGUAGE NoImplicitPrelude #-}
9{-# LANGUAGE NoImplicitPrelude #-}
9{-# LANGUAGE OverloadedStrings #-}
10{-# LANGUAGE OverloadedStrings #-}
10−{-# LANGUAGE PolyKinds #-}
11{-# LANGUAGE RecordWildCards #-}
11{-# LANGUAGE RecordWildCards #-}
12{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE ScopedTypeVariables #-}
13{-# LANGUAGE TypeOperators #-}
13{-# LANGUAGE TypeOperators #-}
14−{-# LANGUAGE TupleSections #-}
15{-# LANGUAGE UndecidableInstances #-}
14{-# LANGUAGE UndecidableInstances #-}
16{-# LANGUAGE ViewPatterns #-}
15{-# LANGUAGE ViewPatterns #-}
17+#if __GLASGOW_HASKELL__ >= 706
18+{-# LANGUAGE PolyKinds #-}
18#include "incoherent-compat.h"
21#include "incoherent-compat.h"
19#include "overlapping-compat.h"
22#include "overlapping-compat.h"
@@ -118,9 +121,9 @@ import GHC.Generics
118import Numeric.Natural (Natural)
121import Numeric.Natural (Natural)
119import Text.ParserCombinators.ReadP (readP_to_S)
122import Text.ParserCombinators.ReadP (readP_to_S)
120import Unsafe.Coerce (unsafeCoerce)
123import Unsafe.Coerce (unsafeCoerce)
124+import qualified Data.Aeson.Compat as Compat
121import qualified Data.Aeson.Parser.Time as Time
125import qualified Data.Aeson.Parser.Time as Time
122import qualified Data.Attoparsec.ByteString.Char8 as A (endOfInput, parseOnly, scientific)
126import qualified Data.Attoparsec.ByteString.Char8 as A (endOfInput, parseOnly, scientific)
123−import qualified Data.ByteString.Lazy as L
124import qualified Data.DList as DList
127import qualified Data.DList as DList
125import qualified Data.HashMap.Strict as H
128import qualified Data.HashMap.Strict as H
126import qualified Data.HashSet as HashSet
129import qualified Data.HashSet as HashSet
@@ -155,8 +158,18 @@ import qualified Data.Primitive.UnliftedArray as PM
155import qualified Data.Primitive.PrimArray as PM
158import qualified Data.Primitive.PrimArray as PM
161+#ifndef HAS_COERCIBLE
162+#define HAS_COERCIBLE (__GLASGOW_HASKELL__ >= 707)
159import Data.Coerce (Coercible, coerce)
166import Data.Coerce (Coercible, coerce)
167+coerce' :: Coercible a b => a -> b
171+coerce' = unsafeCoerce
161parseIndexedJSON :: (Value -> Parser a) -> Int -> Value -> Parser a
174parseIndexedJSON :: (Value -> Parser a) -> Int -> Value -> Parser a
162parseIndexedJSON p idx value = p value <?> Index idx
175parseIndexedJSON p idx value = p value <?> Index idx
@@ -428,7 +441,11 @@ class FromJSONKey a where
428-- At the moment this type is intentionally not exported. 'FromJSONKeyFunction'
441-- At the moment this type is intentionally not exported. 'FromJSONKeyFunction'
429-- can be inspected, but cannot be constructed.
442-- can be inspected, but cannot be constructed.
430data CoerceText a where
443data CoerceText a where
431 CoerceText :: Coercible Text a => CoerceText a
445 CoerceText :: Coercible Text a => CoerceText a
447+ CoerceText :: CoerceText a
433-- | This type is related to 'ToJSONKeyFunction'. If 'FromJSONKeyValue' is used in the
450-- | This type is related to 'ToJSONKeyFunction'. If 'FromJSONKeyValue' is used in the
434-- 'FromJSONKey' instance, then 'ToJSONKeyValue' should be used in the 'ToJSONKey'
451-- 'FromJSONKey' instance, then 'ToJSONKeyValue' should be used in the 'ToJSONKey'
@@ -448,7 +465,7 @@ data FromJSONKeyFunction a
449-- | Only law abiding up to interpretation
466-- | Only law abiding up to interpretation
450instance Functor FromJSONKeyFunction where
467instance Functor FromJSONKeyFunction where
451− fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce)
468+ fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce')
452 fmap h (FromJSONKeyText f) = FromJSONKeyText (h . f)
469 fmap h (FromJSONKeyText f) = FromJSONKeyText (h . f)
453 fmap h (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap h . f)
470 fmap h (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap h . f)
454 fmap h (FromJSONKeyValue f) = FromJSONKeyValue (fmap h . f)
471 fmap h (FromJSONKeyValue f) = FromJSONKeyValue (fmap h . f)
@@ -462,7 +479,9 @@ instance Functor FromJSONKeyFunction where
463-- On pre GHC 7.8 this is unconstrainted function.
480-- On pre GHC 7.8 this is unconstrainted function.
464fromJSONKeyCoerce ::
481fromJSONKeyCoerce ::
465 Coercible Text a =>
483 Coercible Text a =>
466 FromJSONKeyFunction a
485 FromJSONKeyFunction a
467fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
486fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
@@ -470,18 +489,29 @@ fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
471-- See note on 'fromJSONKeyCoerce'.
490-- See note on 'fromJSONKeyCoerce'.
472coerceFromJSONKeyFunction ::
491coerceFromJSONKeyFunction ::
473 Coercible a b =>
493 Coercible a b =>
474 FromJSONKeyFunction a -> FromJSONKeyFunction b
495 FromJSONKeyFunction a -> FromJSONKeyFunction b
475coerceFromJSONKeyFunction = coerce
497coerceFromJSONKeyFunction = coerce
499+coerceFromJSONKeyFunction (FromJSONKeyCoerce CoerceText) = FromJSONKeyCoerce CoerceText
500+coerceFromJSONKeyFunction (FromJSONKeyText f) = FromJSONKeyText (coerce' . f)
501+coerceFromJSONKeyFunction (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap coerce' . f)
502+coerceFromJSONKeyFunction (FromJSONKeyValue f) = FromJSONKeyValue (fmap coerce' . f)
478 "FromJSONKeyCoerce: fmap id" forall (x :: FromJSONKeyFunction a).
506 "FromJSONKeyCoerce: fmap id" forall (x :: FromJSONKeyFunction a).
479 fmap id x = x
507 fmap id x = x
482 "FromJSONKeyCoerce: fmap coerce" forall x .
511 "FromJSONKeyCoerce: fmap coerce" forall x .
483 fmap coerce x = coerceFromJSONKeyFunction x
512 fmap coerce x = coerceFromJSONKeyFunction x
486-- | Same as 'fmap'. Provided for the consistency with 'ToJSONKeyFunction'.
516-- | Same as 'fmap'. Provided for the consistency with 'ToJSONKeyFunction'.
487mapFromJSONKeyFunction :: (a -> b) -> FromJSONKeyFunction a -> FromJSONKeyFunction b
517mapFromJSONKeyFunction :: (a -> b) -> FromJSONKeyFunction a -> FromJSONKeyFunction b
@@ -768,13 +798,13 @@ withBoundedScientific' f v = withBoundedScientific_ id f v
768-- | A variant of 'withBoundedScientific_' parameterized by a function to apply
798-- | A variant of 'withBoundedScientific_' parameterized by a function to apply
769-- to the 'Parser' in case of failure.
799-- to the 'Parser' in case of failure.
770withBoundedScientific_ :: (Parser a -> Parser a) -> (Scientific -> Parser a) -> Value -> Parser a
800withBoundedScientific_ :: (Parser a -> Parser a) -> (Scientific -> Parser a) -> Value -> Parser a
771−withBoundedScientific_ whenFail f (Number scientific) =
801+withBoundedScientific_ whenFail f v@(Number scientific) =
772− if exp10 > 1024
802+ if exponent > 1024
773 then whenFail (fail msg)
803 then whenFail (fail msg)
774 else f scientific
804 else f scientific
776− exp10 = base10Exponent scientific
806+ exponent = base10Exponent scientific
777− msg = "found a number with exponent " ++ show exp10 ++ ", but it must not be greater than 1024"
807+ msg = "found a number with exponent " ++ show exponent ++ ", but it must not be greater than 1024"
778withBoundedScientific_ whenFail _ v =
808withBoundedScientific_ whenFail _ v =
779 whenFail (typeMismatch "Number" v)
809 whenFail (typeMismatch "Number" v)
780{-# INLINE withBoundedScientific_ #-}
810{-# INLINE withBoundedScientific_ #-}
@@ -794,7 +824,7 @@ withBool name _ v = prependContext name (typeMismatch "Boolean" v)
794-- | Decode a nested JSON-encoded string.
824-- | Decode a nested JSON-encoded string.
795withEmbeddedJSON :: String -> (Value -> Parser a) -> Value -> Parser a
825withEmbeddedJSON :: String -> (Value -> Parser a) -> Value -> Parser a
796withEmbeddedJSON _ innerParser (String txt) =
826withEmbeddedJSON _ innerParser (String txt) =
797− either fail innerParser $ eitherDecode (L.fromStrict $ T.encodeUtf8 txt)
827+ either fail innerParser $ eitherDecode (Compat.fromStrict $ T.encodeUtf8 txt)
799 eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON
829 eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON
800 eitherFormatError = either (Left . uncurry formatError) Right
830 eitherFormatError = either (Left . uncurry formatError) Right
@@ -863,7 +893,7 @@ parseFieldMaybe' = (.:!)
863-- E.g. @'explicitParseField' 'parseJSON1' :: ('FromJSON1' f, 'FromJSON' a) -> 'Object' -> 'Text' -> 'Parser' (f a)@
893-- E.g. @'explicitParseField' 'parseJSON1' :: ('FromJSON1' f, 'FromJSON' a) -> 'Object' -> 'Text' -> 'Parser' (f a)@
864explicitParseField :: (Value -> Parser a) -> Object -> Text -> Parser a
894explicitParseField :: (Value -> Parser a) -> Object -> Text -> Parser a
865explicitParseField p obj key = case H.lookup key obj of
895explicitParseField p obj key = case H.lookup key obj of
866− Nothing -> fail $ "key " ++ show key ++ " not found"
896+ Nothing -> fail $ "key " ++ show key ++ " not present"
867 Just v -> p v <?> Key key
897 Just v -> p v <?> Key key
868{-# INLINE explicitParseField #-}
898{-# INLINE explicitParseField #-}
@@ -922,16 +952,6 @@ type ConName = String
922contextType :: TypeName -> Parser a -> Parser a
952contextType :: TypeName -> Parser a -> Parser a
923contextType = prependContext
953contextType = prependContext
925−-- | Add the tagKey that will be looked up while building an ADT
926−-- | Produce the error equivalent to
927−-- | Left "Error in $: parsing T failed, expected an object with keys "tag" and
928−-- | "contents", where "tag" i-- |s associated to one of ["Foo", "Bar"],
929−-- | The parser returned error was: could not find key "tag"
930−contextTag :: Text -> [String] -> Parser a -> Parser a
931−contextTag tagKey cnames = prependFailure
932− ("expected Object with key \"" ++ unpack tagKey ++ "\"" ++
933− " containing one of " ++ show cnames ++ ", ")
935-- | Add the name of the constructor being parsed to a parser's error messages.
955-- | Add the name of the constructor being parsed to a parser's error messages.
936contextCons :: ConName -> TypeName -> Parser a -> Parser a
956contextCons :: ConName -> TypeName -> Parser a -> Parser a
937contextCons cname tname = prependContext (showCons cname tname)
957contextCons cname tname = prependContext (showCons cname tname)
@@ -1110,8 +1130,8 @@ instance ConstructorNames a => ConstructorNames (D1 d a) where
1110 retag (Tagged2 x) = Tagged2 x
1130 retag (Tagged2 x) = Tagged2 x
1112--------------------------------------------------------------------------------
1132--------------------------------------------------------------------------------
1113−parseNonAllNullarySum :: forall f c arity.
1134+parseNonAllNullarySum :: ( FromPair arity f
1115 , FromTaggedObject arity f
1135 , FromTaggedObject arity f
1116 , FromUntaggedValue arity f
1136 , FromUntaggedValue arity f
1117 , ConstructorNames f
1137 , ConstructorNames f
@@ -1121,7 +1141,7 @@ parseNonAllNullarySum p@(tname :* opts :* _) =
1121 case sumEncoding opts of
1141 case sumEncoding opts of
1122 TaggedObject{..} ->
1142 TaggedObject{..} ->
1123 withObject tname $ \obj -> do
1143 withObject tname $ \obj -> do
1124− tag <- contextType tname . contextTag tagKey cnames_ $ obj .: tagKey
1144+ tag <- contextType tname $ obj .: tagKey
1125 fromMaybe (badTag tag <?> Key tagKey) $
1145 fromMaybe (badTag tag <?> Key tagKey) $
1126 parseFromTaggedObject (tag :* contentsFieldName :* p) obj
1146 parseFromTaggedObject (tag :* contentsFieldName :* p) obj
@@ -1129,7 +1149,6 @@ parseNonAllNullarySum p@(tname :* opts :* _) =
1129 badTag tag = failWith_ $ \cnames ->
1149 badTag tag = failWith_ $ \cnames ->
1130 "expected tag field to be one of " ++ show cnames ++
1150 "expected tag field to be one of " ++ show cnames ++
1131 ", but found tag " ++ show tag
1151 ", but found tag " ++ show tag
1132− cnames_ = unTagged2 (constructorTags (constructorTagModifier opts) :: Tagged2 f [String])
1134 ObjectWithSingleField ->
1153 ObjectWithSingleField ->
1135 withObject tname $ \obj -> case H.toList obj of
1154 withObject tname $ \obj -> case H.toList obj of
@@ -1201,9 +1220,9 @@ class FromTaggedObject' arity f isRecord where
1201 :: String :* ConName :* TypeName :* Options :* FromArgs arity a
1220 :: String :* ConName :* TypeName :* Options :* FromArgs arity a
1202 -> Object -> Tagged isRecord (Parser (f a))
1221 -> Object -> Tagged isRecord (Parser (f a))
1204−instance (RecordFromJSON arity f, FieldNames f) => FromTaggedObject' arity f True where
1223+instance (RecordFromJSON arity f) => FromTaggedObject' arity f True where
1205 -- Records are unpacked in the tagged object
1224 -- Records are unpacked in the tagged object
1206− parseFromTaggedObject' (_ :* p) = Tagged . recordParseJSON (True :* p)
1225+ parseFromTaggedObject' (_ :* p) = Tagged . recordParseJSON p
1208instance (ConsFromJSON arity f) => FromTaggedObject' arity f False where
1227instance (ConsFromJSON arity f) => FromTaggedObject' arity f False where
1209 -- Nonnullary nonrecords are encoded in the contents field
1228 -- Nonnullary nonrecords are encoded in the contents field
@@ -1244,11 +1263,11 @@ instance OVERLAPPING_
1244 ) => ConsFromJSON' arity (S1 s a) True where
1263 ) => ConsFromJSON' arity (S1 s a) True where
1245 consParseJSON' p@(cname :* tname :* opts :* fargs)
1264 consParseJSON' p@(cname :* tname :* opts :* fargs)
1246 | unwrapUnaryRecords opts = Tagged . fmap M1 . gParseJSON opts fargs
1265 | unwrapUnaryRecords opts = Tagged . fmap M1 . gParseJSON opts fargs
1247− | otherwise = Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
1266+ | otherwise = Tagged . withObject (showCons cname tname) (recordParseJSON p)
1249instance RecordFromJSON arity f => ConsFromJSON' arity f True where
1268instance RecordFromJSON arity f => ConsFromJSON' arity f True where
1250 consParseJSON' p@(cname :* tname :* _) =
1269 consParseJSON' p@(cname :* tname :* _) =
1251− Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
1270+ Tagged . withObject (showCons cname tname) (recordParseJSON p)
1253instance OVERLAPPING_
1272instance OVERLAPPING_
1254 ConsFromJSON' arity U1 False where
1273 ConsFromJSON' arity U1 False where
@@ -1274,55 +1293,21 @@ instance (ProductFromJSON arity f, ProductSize f
1275--------------------------------------------------------------------------------
1294--------------------------------------------------------------------------------
1277−class FieldNames f where
1278− fieldNames :: f a -> [Text] -> [Text]
1280−instance (FieldNames a, FieldNames b) => FieldNames (a :*: b) where
1282− fieldNames (undefined :: a x) .
1283− fieldNames (undefined :: b y)
1285−instance (Selector s) => FieldNames (S1 s f) where
1286− fieldNames _ = (pack (selName (undefined :: M1 _i s _f _p)) :)
1288class RecordFromJSON arity f where
1296class RecordFromJSON arity f where
1289 recordParseJSON
1297 recordParseJSON
1290− :: Bool :* ConName :* TypeName :* Options :* FromArgs arity a
1291− -> Object -> Parser (f a)
1293−instance ( FieldNames f
1294− , RecordFromJSON' arity f
1295− ) => RecordFromJSON arity f where
1296− recordParseJSON (fromTaggedSum :* p@(cname :* tname :* opts :* _)) =
1297− \obj -> checkUnknown obj >> recordParseJSON' p obj
1299− knownFields :: H.HashMap Text ()
1300− knownFields = H.fromList $ map (,()) $
1301− fieldNames (undefined :: f a)
1302− [pack (tagFieldName (sumEncoding opts)) | fromTaggedSum]
1304− if not (rejectUnknownFields opts)
1305− then \_ -> return ()
1306− else \obj -> case H.keys (H.difference obj knownFields) of
1308− unknownFields -> contextCons cname tname $
1309− fail ("unknown fields: " ++ show unknownFields)
1311−class RecordFromJSON' arity f where
1313 :: ConName :* TypeName :* Options :* FromArgs arity a
1298 :: ConName :* TypeName :* Options :* FromArgs arity a
1314 -> Object -> Parser (f a)
1299 -> Object -> Parser (f a)
1316−instance ( RecordFromJSON' arity a
1301+instance ( RecordFromJSON arity a
1317− , RecordFromJSON' arity b
1302+ , RecordFromJSON arity b
1318− ) => RecordFromJSON' arity (a :*: b) where
1303+ ) => RecordFromJSON arity (a :*: b) where
1319− recordParseJSON' p obj =
1304+ recordParseJSON p obj =
1320− (:*:) <$> recordParseJSON' p obj
1305+ (:*:) <$> recordParseJSON p obj
1321− <*> recordParseJSON' p obj
1306+ <*> recordParseJSON p obj
1323instance OVERLAPPABLE_ (Selector s, GFromJSON arity a) =>
1308instance OVERLAPPABLE_ (Selector s, GFromJSON arity a) =>
1324− RecordFromJSON' arity (S1 s a) where
1309+ RecordFromJSON arity (S1 s a) where
1325− recordParseJSON' (cname :* tname :* opts :* fargs) obj = do
1310+ recordParseJSON (cname :* tname :* opts :* fargs) obj = do
1326 fv <- contextCons cname tname (obj .: label)
1311 fv <- contextCons cname tname (obj .: label)
1327 M1 <$> gParseJSON opts fargs fv <?> Key label
1312 M1 <$> gParseJSON opts fargs fv <?> Key label
@@ -1330,16 +1315,16 @@ instance OVERLAPPABLE_ (Selector s, GFromJSON arity a) =>
1330 sname = selName (undefined :: M1 _i s _f _p)
1315 sname = selName (undefined :: M1 _i s _f _p)
1332instance INCOHERENT_ (Selector s, FromJSON a) =>
1317instance INCOHERENT_ (Selector s, FromJSON a) =>
1333− RecordFromJSON' arity (S1 s (K1 i (Maybe a))) where
1318+ RecordFromJSON arity (S1 s (K1 i (Maybe a))) where
1334− recordParseJSON' (_ :* _ :* opts :* _) obj = M1 . K1 <$> obj .:? pack label
1319+ recordParseJSON (_ :* _ :* opts :* _) obj = M1 . K1 <$> obj .:? pack label
1336 label = fieldLabelModifier opts sname
1321 label = fieldLabelModifier opts sname
1337 sname = selName (undefined :: M1 _i s _f _p)
1322 sname = selName (undefined :: M1 _i s _f _p)
1339-- Parse an Option like a Maybe.
1324-- Parse an Option like a Maybe.
1340instance INCOHERENT_ (Selector s, FromJSON a) =>
1325instance INCOHERENT_ (Selector s, FromJSON a) =>
1341− RecordFromJSON' arity (S1 s (K1 i (Semigroup.Option a))) where
1326+ RecordFromJSON arity (S1 s (K1 i (Semigroup.Option a))) where
1342− recordParseJSON' p obj = wrap <$> recordParseJSON' p obj
1327+ recordParseJSON p obj = wrap <$> recordParseJSON p obj
1344 wrap :: S1 s (K1 i (Maybe a)) p -> S1 s (K1 i (Semigroup.Option a)) p
1329 wrap :: S1 s (K1 i (Maybe a)) p -> S1 s (K1 i (Semigroup.Option a)) p
1345 wrap (M1 (K1 a)) = M1 (K1 (Semigroup.Option a))
1330 wrap (M1 (K1 a)) = M1 (K1 (Semigroup.Option a))
@@ -1576,22 +1561,12 @@ instance FromJSONKey Float where
1576 _ -> Scientific.toRealFloat <$> parseScientificText t
1561 _ -> Scientific.toRealFloat <$> parseScientificText t
1578instance (FromJSON a, Integral a) => FromJSON (Ratio a) where
1563instance (FromJSON a, Integral a) => FromJSON (Ratio a) where
1579− parseJSON (Number x)
1581− , exp10 >= -1024 = return $! realToFrac x
1582− | otherwise = prependContext "Ratio" $ fail msg
1584− exp10 = base10Exponent x
1585− msg = "found a number with exponent " ++ show exp10
1586− ++ ", but it must not be greater than 1024 or less than -1024"
1587− parseJSON o = objParser o
1589− objParser = withObject "Rational" $ \obj -> do
1564+ parseJSON = withObject "Rational" $ \obj -> do
1590− numerator <- obj .: "numerator"
1565+ numerator <- obj .: "numerator"
1591− denominator <- obj .: "denominator"
1566+ denominator <- obj .: "denominator"
1592− if denominator == 0
1567+ if denominator == 0
1593− then fail "Ratio denominator was 0"
1568+ then fail "Ratio denominator was 0"
1594− else pure $ numerator % denominator
1569+ else pure $ numerator % denominator
1595 {-# INLINE parseJSON #-}
1570 {-# INLINE parseJSON #-}
1597-- | This instance includes a bounds check to prevent maliciously
1572-- | This instance includes a bounds check to prevent maliciously
@@ -2006,6 +1981,7 @@ instance FromJSON DotNetTime where
2006-- primitive
1981-- primitive
2007-------------------------------------------------------------------------------
1982-------------------------------------------------------------------------------
1984+#if MIN_VERSION_base(4,7,0)
2009instance FromJSON a => FromJSON (PM.Array a) where
1985instance FromJSON a => FromJSON (PM.Array a) where
2010 -- note: we could do better than this if vector exposed the data
1986 -- note: we could do better than this if vector exposed the data
2011 -- constructor in Data.Vector.
1987 -- constructor in Data.Vector.
@@ -2023,6 +1999,7 @@ instance (PM.PrimUnlifted a,FromJSON a) => FromJSON (PM.UnliftedArray a) where
2023 parseJSON = fmap Exts.fromList . parseJSON
1999 parseJSON = fmap Exts.fromList . parseJSON
2027-------------------------------------------------------------------------------
2004-------------------------------------------------------------------------------